diff --git a/.editorconfig b/.editorconfig index bc137906a6d..7f8c8fcd522 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,5 +14,8 @@ trim_trailing_whitespace = true max_line_length = 0 trim_trailing_whitespace = false +[*.java] +indent_size = 4 + [COMMIT_EDITMSG] max_line_length = 0 diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 38488905279..00000000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules* -dist/ -coverage diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 2ab91655450..00000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,134 +0,0 @@ -module.exports = { - parser: 'vue-eslint-parser', - parserOptions: { - parser: '@typescript-eslint/parser', - ecmaFeatures: { - jsx: true, - legacyDecorators: true, - experimentalObjectRestSpread: true, - }, - ecmaVersion: 2018, - sourceType: 'module', - }, - extends: [ - 'eslint-config-tencent', - 'plugin:react/recommended', - 'plugin:vue/recommended', - 'plugin:import/recommended', - 'plugin:import/typescript', - ], - plugins: [ - 'vue', - '@typescript-eslint', - 'jsx-a11y', - ], - overrides: [ - { - files: ['**/*.ts', '**/*.tsx'], - rules: { - // Allow interface export - 'no-undef': 'off', - - // Disable props checking - 'react/prop-types': 'off', - - // Force use 2 space for indent - '@typescript-eslint/indent': ['error', 2], - - // Note you must disable the base rule as it can report incorrect errors - 'no-unused-vars': 'off', - }, - }, - ], - env: { - browser: true, - node: true, - es6: true, - }, - globals: { - __PLATFORM__: 'readonly', - __GLOBAL__: 'readonly', - Hippy: 'readonly', - WebSocket: 'readonly', - }, - rules: { - semi: ['error', 'always'], - // Allow more than one component per file - 'vue/one-component-per-file': 'off', - - // Allow no default value - 'vue/require-default-prop': 'off', - - // Allow no prop type - 'vue/require-prop-types': 'off', - - // Allow event name not kebab-case - 'vue/custom-event-name-casing': 'off', - - 'import/no-unresolved': 'off', - - // Allow import name different with file name - 'import/no-named-as-default': 'off', - - // Allow import cycle - 'import/no-cycle': 'off', - - // Disable prop-types - 'react/prop-types': 'off', - - // Disable deprecated - 'react/no-deprecated': 'off', - - // Turn of extensions checking temporary - 'import/extensions': 'off', - - // https://github.com/benmosher/eslint-plugin-import/tree/master/docs/rules/namespace.md#allowcomputed - 'import/namespace': [ - 'error', - { - allowComputed: true, - }, - ], - // Allow import from devDependencies - 'import/no-extraneous-dependencies': [ - 'error', - { - devDependencies: [ - 'scripts/*.js', - // FIXME: seems not working - 'packages/**/types/*.d.ts', - 'packages/**/__tests__/*.test.js', - 'examples/**/scripts/*.js', - ], - }, - ], - // Allow tsx as the jsx file - 'react/jsx-filename-extension': [ - 'error', - { - extensions: ['.tsx', '.jsx'], - }, - ], - // Auto range order of imported module - 'import/order': ['error'], - // Allow global underscore in dangle - 'no-underscore-dangle': [ - 'warn', - { - allow: [ - '__ISHIPPY__', - '__GLOBAL__', - '__HIPPYNATIVEGLOBAL__', - '__instanceId__', - '_reactInternalFiber', - '_reactInternals', - ], - }, - ], - }, - settings: { - react: { - version: 'detect', // React version. "detect" automatically picks the version you have installed. - }, - }, -}; diff --git a/.gitattributes b/.gitattributes index 2a5c122ee6e..4d5058735e4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,4 @@ *.cr.so filter=lfs diff=lfs merge=lfs -text *.gz filter=lfs diff=lfs merge=lfs -text *.otf filter=lfs diff=lfs merge=lfs -text -*.png filter=lfs diff=lfs merge=lfs -text -*.jpg filter=lfs diff=lfs merge=lfs -text -*.a filter=lfs diff=lfs merge=lfs -text \ No newline at end of file +*.a filter=lfs diff=lfs merge=lfs -text diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 726e4631a58..c8c211c9e97 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,4 +8,120 @@ # https://help.github.com/en/articles/about-code-owners # -* @ilikethese @churchill-zhang @zoomchan-cxj @siguangli @ozonelmy +# universal files +* @etkmao + +# cmake related +*.cmake @etkmao +CMakeLists.txt @etkmao + +# driver: js +/driver/js/ @etkmao +/driver/js/*.js @zealotchen0 +/driver/js/.eslintignore @zealotchen0 +/driver/js/.eslintrc.js @zealotchen0 +/driver/js/.nycrc @zealotchen0 +/driver/js/tsconfig.json @zealotchen0 +/driver/js/tsdoc.json @zealotchen0 +/driver/js/lerna.json @zealotchen0 +/driver/js/package.json @zealotchen0 +/driver/js/package-lock.json @zealotchen0 +/driver/js/examples/ @zealotchen0 +/driver/js/scripts/ @zealotchen0 +/driver/js/packages/ @zealotchen0 + +# driver: vl: +/driver/vl/ @etkmao + +# framework: android +/framework/android/ @siguangli @iPel +/framework/android/**/src/main/cpp/ @etkmao + +# framework: ios +/framework/ios/ @wwwcg @ruifanyuan + +# framework: voltron +/framework/voltron/ @lvfen @henryjin0511 + +# dom: others +/dom/ @etkmao + +# renderer: native +/renderer/native/android/ @siguangli @iPel +/renderer/native/ios/ @wwwcg @ruifanyuan + +# renderer: tdf +/renderer/tdf/ @vimerzhao +/renderer/tdf/android/ @siguangli @iPel +/renderer/tdf/android/**/src/main/cpp/ @etkmao +/renderer/tdf/ios/ @wwwcg @ruifanyuan + +# renderer: voltron +/renderer/voltron/ @lvfen @henryjin0511 + +# module: vfs +/modules/vfs/ @etkmao +/modules/vfs/android/ @siguangli @iPel +/modules/vfs/android/**/src/main/cpp/ @etkmao +/modules/vfs/ios/ @wwwcg @ruifanyuan +/modules/vfs/voltron/ @lvfen @henryjin0511 + +# module: voltron +/modules/voltron/ @lvfen @henryjin0511 + +# module: android +/modules/android/ @siguangli @iPel +/modules/android/jni/ @etkmao + +# module: ios +/modules/ios/ @wwwcg @ruifanyuan + +# module: footstone +/modules/footstone/ @etkmao + +# devtools: backend +/devtools/ @lavnFan + +# gh: config +/.github/ @zealotchen0 + +# doc: example +/framework/examples/android-demo/ @siguangli @iPel +/framework/examples/android-demo/res/ @zealotchen0 +/framework/examples/ios-demo/ @wwwcg @ruifanyuan +/framework/examples/ios-demo/res/ @zealotchen0 +/framework/examples/voltron-demo/ @henryjin0511 + +# doc: pages +/*.md @zealotchen0 +/docs/ @zealotchen0 + +# build: gradle +/gradle.properties @siguangli @iPel +/gradlew @siguangli @iPel +/gradlew.bat @siguangli @iPel +/settings.gradle @siguangli @iPel +/build.gradle @siguangli @iPel +/gradle/ @siguangli @iPel + +# build: xcode +/HippySDK.xcworkspace/ @wwwcg @ruifanyuan +/hippy.podspec @wwwcg @ruifanyuan +/xcodeinitscript.sh @wwwcg @ruifanyuan + +# build: config +/buildconfig/ @etkmao + +# build: ci +/package.json @zealotchen0 +/package-lock.json @zealotchen0 +/commitlint.config.js @zealotchen0 +/.editorconfig @zealotchen0 +/.gitattributes @zealotchen0 +/.gitignore @zealotchen0 +/.markdownlintrc.json @zealotchen0 +/PUBLISH.md @zealotchen0 +/README.md @zealotchen0 + +# test +/tests/ios/ @wwwcg @ruifanyuan diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 98d50efc95b..be028d8df69 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -5,8 +5,8 @@ Hi! I'm really excited that you are interested in contributing to Hippy. Before - [Code of Conduct](https://github.com/Tencent/Hippy/blob/master/.github/CODE_OF_CONDUCT.md) - [Issue Reporting Guidelines](#issue-reporting-guidelines) - [Pull Request Guidelines](#pull-request-guidelines) -- [Development Setup](https://github.com/Tencent/Hippy#getting-started) -- [Project Structure](https://github.com/Tencent/Hippy#project-structure) +- [Development Setup](https://github.com/Tencent/Hippy#-getting-started) +- [Project Structure](https://github.com/Tencent/Hippy#-project-structure) ## Issue Reporting Guidelines @@ -14,6 +14,8 @@ Hi! I'm really excited that you are interested in contributing to Hippy. Before ## Pull Request Guidelines +- Setting up your local environment to get started. You will need have [git](https://git-scm.com/) and [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) installed locally, then run `npm install` to download all needed dependencies. These are detailed in the [Development Setup guide](https://github.com/Tencent/Hippy#-getting-started). + - Checkout a topic branch from the relevant branch, e.g. `master`, and merge back against that branch. - Test cases have been added/updated/passed for the code you will submit. diff --git a/.github/ISSUE_TEMPLATE/bug-report.zh-CN.yml b/.github/ISSUE_TEMPLATE/bug-report.zh-CN.yml new file mode 100644 index 00000000000..09e7c8e483e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.zh-CN.yml @@ -0,0 +1,59 @@ +name: 反馈 Bug +description: 通过 github 模板进行 Bug 反馈。 +title: "描述问题的标题" +labels: [🐞 bug,🧐 unconfirmed] +body: + - type: markdown + attributes: + value: | + # 🐞 Bug Report + 在发布一个 Issue 前,请确保: + - 在 [官方文档](https://hippy.tds.qq.com/#/architecture/introduction) 和 [Issue列表](https://github.com/Tencent/Hippy/issues?q=is%3Aissue) 中搜索过你的问题。(你的问题可能已有人提出,也可能已在最新版本中被修正) + - 如果你发现一个已经关闭的旧 Issue 在最新版本中仍然存在,不要在旧 Issue 下面留言,请建一个新的 issue。 + + - type: textarea + id: expect + attributes: + label: 期望结果 + placeholder: 请填写 + + - type: textarea + id: actual + attributes: + label: 实际结果 + placeholder: 请填写 + + - type: input + id: reproduce + attributes: + label: 重现链接 + description: 请提供尽可能精简的复现Demo GitHub 仓库的链接,比如Fork仓库的可复现Demo分支。请不要填无关链接,否则你的 Issue 将被关闭。 + placeholder: https://github.com// + + - type: textarea + id: reproduceSteps + attributes: + label: 重现步骤 + description: 请清晰的描述重现该 Issue 的步骤,这能帮助我们快速定位问题。没有清晰重现步骤将不会被修复,标有 'need reproduction' 的 Issue 在 7 天内不提供相关步骤,将被关闭。 + placeholder: | + 1. 安装 '...' + 2. 点击 '...' + 3. 查看 '...' 错误 + + - type: textarea + id: reproduceEnvironment + attributes: + label: 重现环境 + description: 请清晰的描述重现该 Issue 的现场环境,如机型、系统及版本、Hippy SDK版本等信息,这能帮助我们快速定位问题。 + placeholder: | + - Device: [e.g. iPhone12] + - OS and Version: [e.g. iOS 13.3.1] + - Hippy SDK version: [e.g. 3.3.2] + - Other + + - type: textarea + id: remarks + attributes: + label: 补充说明 + description: 可以是遇到这个 bug 的业务场景、崩溃或错误的堆栈或日志等信息。 + placeholder: 请填写 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 8043f0aa3f4..00000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: 'zoomchan-cxj' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Smartphone (please complete the following information):** - -- Device: [e.g. iPhone6] -- OS and version: [e.g. iOS 13.3.1] -- Hippy native SDK version: [e.g. 2.0.0] -- Front-end SDK and version [e.g. @hippy/vue 2.0.1] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-report.zh-CN.yml b/.github/ISSUE_TEMPLATE/feature-report.zh-CN.yml new file mode 100644 index 00000000000..25d316c5af1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-report.zh-CN.yml @@ -0,0 +1,36 @@ +name: 反馈新功能 +description: 通过 github 模板进行新功能反馈。 +title: "描述问题的标题" +labels: [💪🏻 enhancement,🧐 unconfirmed] +body: + - type: markdown + attributes: + value: | + # 🚀 Feature Request + 在发布一个 Issue 前,请确保: + - 在 [官方文档](https://hippy.tds.qq.com/#/architecture/introduction) 和 [Issue列表](https://github.com/Tencent/Hippy/issues?q=is%3Aissue) 中搜索过你的问题。(你的问题可能已有人提出,也可能已在最新版本中被修正) + - 如果你发现一个已经关闭的旧 Issue 在最新版本中仍然存在,不要在旧 Issue 下面留言,请建一个新的 issue。 + + - type: textarea + id: functionContent + attributes: + label: 这个功能解决了什么问题 + description: 请详尽说明这个需求的用例和场景。最重要的是:解释清楚是怎样的用户体验需求催生了这个功能上的需求。我们将考虑添加在现有 API 上无法轻松实现的功能。新功能的用例也应当足够常见。 + placeholder: 请填写 + validations: + required: true + + - type: textarea + id: functionalExpectations + attributes: + label: 你建议的方案是什么 + placeholder: 请填写 + validations: + required: true + + - type: textarea + id: functionalOthers + attributes: + label: 其他补充信息 + description: + placeholder: 请填写 diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index ca2999e04f8..00000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: 'zoomchan-cxj' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/support-request.zh-CN.yml b/.github/ISSUE_TEMPLATE/support-request.zh-CN.yml new file mode 100644 index 00000000000..38cf8ce3d3b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/support-request.zh-CN.yml @@ -0,0 +1,28 @@ +name: 问题咨询 +description: 通过 github 模板进行问题咨询。 +title: "描述问题的标题" +labels: [❓ question,🧐 unconfirmed] +body: + - type: markdown + attributes: + value: | + # ❓ Question or Support Request + 在发布一个 Issue 前,请确保: + - 在 [官方文档](https://hippy.tds.qq.com/#/architecture/introduction) 和 [Issue列表](https://github.com/Tencent/Hippy/issues?q=is%3Aissue) 中搜索过你的问题。(你的问题可能已有人提出,也可能已在最新版本中被修正) + - 如果你发现一个已经关闭的旧 Issue 在最新版本中仍然存在,不要在旧 Issue 下面留言,请建一个新的 issue。 + + - type: textarea + id: supportContent + attributes: + label: 描述你的问题或希望得到什么支持 + description: 清晰简明地描述你的疑问 + placeholder: 请填写 + validations: + required: true + + - type: textarea + id: supportOthers + attributes: + label: 其他补充信息 + description: 编译构建等技术使用类问题,请提供更多复现条件,比如可复现问题的仓库、错误堆栈或日志、构建IDE环境、构建命令等。标有 'need reproduction' 的 Issue 在 7 天内不提供相关步骤,将被关闭。 + placeholder: 请填写 diff --git a/.github/workflows/3rd_prebuilt_sqlite.yml b/.github/workflows/3rd_prebuilt_sqlite.yml new file mode 100644 index 00000000000..6ccd47cf45d --- /dev/null +++ b/.github/workflows/3rd_prebuilt_sqlite.yml @@ -0,0 +1,133 @@ +name: '[3rd] prebuilt sqlite' + +on: + workflow_dispatch: + inputs: + sqlite_version: + description: 'Sqlite TAG(Branch) to build' + type: string + default: '3.42.0' + required: true + sqlite_download_url: + description: 'Sqlite Amalgamation Url' + type: string + default: 'https://sqlite.org/2023/sqlite-amalgamation-3420000.zip' + required: true + hip_sqlite_root: + description: 'HIP Sqlite root path' + type: string + default: 'global_packages' + required: true + writing_mode: + description: 'The mode of writing' + type: choice + options: + - preserve + - overwrite + default: 'preserve' + required: true + +env: + publish_package_script: | + from qcloud_cos import CosS3Client, CosConfig + import hashlib + import os + try: + from urllib.parse import urlencode + except ImportError: + from urllib import urlencode + + metadata = {} + metadata["ci-name"] = "Github Action" + metadata["ci-id"] = "${{ github.run_id }}" + metadata["ci-url"] = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + metadata["sqlite-builder"] = "${{ github.event.sender.login }}" + with open(os.environ["local_file"], "rb") as artifact_file: + metadata["sqlite-md5"] = hashlib.md5(artifact_file.read()).hexdigest() + metadata["sqlite-url"] = "${{ github.event.inputs.sqlite_download_url }}" + metadata["sqlite-version"] = "${{ github.event.inputs.sqlite_version }}" + + config = CosConfig(Region="${{ secrets.COS_REGION }}", SecretId="${{ secrets.TC_SECRET_ID }}", SecretKey="${{ secrets.TC_SECRET_KEY }}") + client = CosS3Client(config) + if "${{ github.event.inputs.writing_mode }}" == "preserve" and client.object_exists( + Bucket="${{ secrets.COS_BUCKET }}", + Key=os.environ["cos_key"] + ): + raise Exception("Package already exists") + + response = client.upload_file( + Bucket="${{ secrets.COS_BUCKET }}", + Key=os.environ["cos_key"], + LocalFilePath=os.environ["local_file"], + EnableMD5=True, + ContentMD5=metadata["sqlite-md5"], + Metadata={"x-cos-tagging": urlencode(metadata)} + ) + print("ETag: " + response["ETag"]) + + cmakelists_template: | + # + # Tencent is pleased to support the open source community by making + # Hippy available. + # + # Copyright (C) 2022 THL A29 Limited, a Tencent company. + # All rights reserved. + # + # 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. + # + cmake_minimum_required(VERSION 3.0) + + project("sqlite") + + add_library(${PROJECT_NAME} STATIC) + target_include_directories(${PROJECT_NAME} INTERFACE "include") + + set(SRC_SET src/sqlite3.c) + target_sources(${PROJECT_NAME} PRIVATE ${SRC_SET}) + +jobs: + prebuilt: + runs-on: ubuntu-latest + steps: + - name: Download sqlite + run: | + file_name=$(basename ${{github.event.inputs.sqlite_download_url}}) + curl -L ${{github.event.inputs.sqlite_download_url}} -o $file_name + unzip -o $file_name + - name: Generate CMakeLists + uses: DamianReeves/write-file-action@v1.0 + with: + path: ./artifact/CMakeLists.txt + write-mode: overwrite + contents: ${{ env.cmakelists_template }} + - name: Prepare package + run: | + unzip_directory=$(basename -s .zip ${{github.event.inputs.sqlite_download_url}}) + mkdir -p artifact/include/sqlite artifact/src + cp ./$unzip_directory/sqlite3.h artifact/include/sqlite + cp ./$unzip_directory/sqlite3ext.h artifact/include/sqlite + cp ./$unzip_directory/sqlite3.c artifact/src + - name: Release package + id: release_package + run: | + tar -zcvf sqlite-${{ github.event.inputs.sqlite_version }}.tgz -C artifact . + - name: Install Requirement + shell: bash + run: | + pip3 install -U cos-python-sdk-v5 + - name: Publish package + shell: python3 {0} + env: + local_file: ./sqlite-${{ github.event.inputs.sqlite_version }}.tgz + cos_key: hippy/${{ github.event.inputs.hip_sqlite_root }}/sqlite/sqlite-${{ github.event.inputs.sqlite_version }}.tgz + run: ${{ env.publish_package_script }} diff --git a/.github/workflows/3rd_prebuilt_v8.yml b/.github/workflows/3rd_prebuilt_v8.yml new file mode 100644 index 00000000000..bbc7c5376d6 --- /dev/null +++ b/.github/workflows/3rd_prebuilt_v8.yml @@ -0,0 +1,532 @@ +name: '[3rd] prebuilt v8' + +on: + workflow_dispatch: + inputs: + v8_revision: + description: 'V8 TAG(Branch) to build' + type: string + required: true + build_args: + description: 'Build args' + type: string + default: 'v8_use_external_startup_data=false v8_enable_i18n_support=false treat_warnings_as_errors=false symbol_level=1 v8_enable_webassembly=false' + required: true + build_type: + description: 'Build type' + type: choice + options: + - debug + - release + default: 'release' + required: true + hip_v8_root: + description: 'HIP V8 root path' + type: string + default: 'global_packages' + required: true + writing_mode: + description: 'The mode of writing' + type: choice + options: + - preserve + - overwrite + default: 'preserve' + required: true + is_build_for_android: + description: 'Build for Android platform' + type: boolean + default: true + required: false + is_build_for_ios: + description: 'Build for iOS platform' + type: boolean + default: false + required: false + is_build_for_windows: + description: 'Build for Windows platform' + type: boolean + default: false + required: false + is_build_for_macos: + description: 'Build for MacOS platform' + type: boolean + default: false + required: false + is_build_for_linux: + description: 'Build for Linux platform' + type: boolean + default: false + required: false + +env: + publish_package_script: | + from qcloud_cos import CosS3Client, CosConfig + import hashlib + import os + try: + from urllib.parse import urlencode + except ImportError: + from urllib import urlencode + + metadata = {} + metadata["ci-name"] = "Github Action" + metadata["ci-id"] = "${{ github.run_id }}" + metadata["ci-url"] = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + metadata["v8-builder"] = "${{ github.event.sender.login }}" + with open(os.environ["local_file"], "rb") as artifact_file: + metadata["v8-md5"] = hashlib.md5(artifact_file.read()).hexdigest() + metadata["v8-revision"] = "${{ github.event.inputs.v8_revision }}" + metadata["v8-head"] = os.environ["v8_head"] + + config = CosConfig(Region="${{ secrets.COS_REGION }}", SecretId="${{ secrets.TC_SECRET_ID }}", SecretKey="${{ secrets.TC_SECRET_KEY }}") + client = CosS3Client(config) + if "${{ github.event.inputs.writing_mode }}" == "preserve" and client.object_exists( + Bucket="${{ secrets.COS_BUCKET }}", + Key=os.environ["cos_key"] + ): + raise Exception("Package already exists") + + response = client.upload_file( + Bucket="${{ secrets.COS_BUCKET }}", + Key=os.environ["cos_key"], + LocalFilePath=os.environ["local_file"], + EnableMD5=True, + ContentMD5=metadata["v8-md5"], + Metadata={"x-cos-tagging": urlencode(metadata)} + ) + print("ETag: " + response["ETag"]) + + cmakelists_template: | + # + # Tencent is pleased to support the open source community by making + # Hippy available. + # + # Copyright (C) 2022 THL A29 Limited, a Tencent company. + # All rights reserved. + # + # 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. + # + cmake_minimum_required(VERSION 3.0) + + project(v8) + + add_library(${{ '${{PROJECT_NAME}}' }} INTERFACE) + target_include_directories(${{ '${{PROJECT_NAME}}' }} + INTERFACE "include" + INTERFACE "include/v8") + + target_compile_definitions(${{ '${{PROJECT_NAME}}' }} + INTERFACE "-DV8_IMMINENT_DEPRECATION_WARNINGS" + INTERFACE "-DV8_DEPRECATION_WARNINGS" + {0}) + + add_library(${{ '${{PROJECT_NAME}}' }}_library STATIC IMPORTED) + set_property(TARGET ${{ '${{PROJECT_NAME}}' }}_library PROPERTY + IMPORTED_LOCATION "{1}") + target_link_libraries(${{ '${{PROJECT_NAME}}' }} + INTERFACE ${{ '${{PROJECT_NAME}}' }}_library) + +jobs: + context_in_lowercase: + if: github.event.inputs.is_build_for_android == 'true' || github.event.inputs.is_build_for_linux == 'true' + runs-on: ubuntu-latest + outputs: + repository_owner: ${{ steps.get_owner.outputs.lowercase }} + steps: + - name: Get repo owner(in lowercase) + id: get_owner + uses: ASzc/change-string-case-action@v2 + with: + string: ${{ github.repository_owner }} + + android_prebuilt: + if: github.event.inputs.is_build_for_android == 'true' + needs: context_in_lowercase + runs-on: [self-hosted, linux, shared] + container: + image: ghcr.io/${{ needs.context_in_lowercase.outputs.repository_owner }}/android-release:latest + options: --user root + strategy: + matrix: + cpu: [arm, arm64, x86, x64] + include: + - cpu: arm + arch: arm + - cpu: arm64 + arch: arm64 + - cpu: x86 + arch: x86 + - cpu: x64 + arch: x86_64 + steps: + - name: Setup GN + run: | + git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git /usr/local/opt/depot_tools + export PATH=/usr/local/opt/depot_tools:$PATH + - name: Fetch v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + fetch v8 + cd v8 + git checkout ${{ github.event.inputs.v8_revision }} + - name: Fetch patch + uses: actions/checkout@v2 + with: + path: ${{ github.repository }} + - name: Apply patch + if: ${{ !startsWith(github.event.inputs.v8_revision, '7.7') }} + working-directory: ./v8 + continue-on-error: true + run: | + git apply ../${{ github.repository }}/.github/workflows/tools/v8_support_16k_pages_for_android.patch + - name: Sync third_party + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + echo "target_os = ['android']" >> ../.gclient + gclient sync -D + - name: Prepare android_ndk + if: ${{ startsWith(github.event.inputs.v8_revision, '7.7') }} + working-directory: ./v8 + run: | + if [ -d third_party/android_tools ]; then + rm -rf third_party/android_tools + mkdir third_party/android_tools + ln -s $ANDROID_NDK_HOME third_party/android_tools/ndk + fi + if [ -f third_party/android_ndk/BUILD.gn ]; then + cp third_party/android_ndk/BUILD.gn $ANDROID_NDK_HOME + fi + if [ -d third_party/android_tools -o -f third_party/android_ndk/BUILD.gn ]; then + rm -rf third_party/android_ndk + ln -s $ANDROID_NDK_HOME third_party/android_ndk + fi + - name: Apply 7.7 build patch + if: ${{ startsWith(github.event.inputs.v8_revision, '7.7') }} + working-directory: ./v8/build + run: | + git apply ../../${{ github.repository }}/.github/workflows/tools/v8_7_7_229_build.patch + - name: Generate ${{ matrix.arch }} + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + gn gen out --args="target_os=\"android\" target_cpu=\"${{ matrix.cpu }}\" v8_target_cpu=\"${{ matrix.cpu }}\" android_ndk_root=\"${ANDROID_NDK_HOME}\" is_component_build=false v8_monolithic=true android32_ndk_api_level=21 android64_ndk_api_level=21 clang_use_chrome_plugins=false use_thin_lto=false use_custom_libcxx=false ${{ github.event.inputs.build_type == 'release' && 'is_debug=false is_official_build=true' || 'is_debug=true' }} ${{ github.event.inputs.build_args }}" + - name: Compile ${{ matrix.arch }} + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + apt-get install -y ninja-build + ninja -C out v8_monolith + - name: Prepare package + working-directory: ./v8/out + run: | + mkdir -p artifact/include/v8 artifact/lib + cp obj/libv8_monolith.a artifact/lib + cp -r ../include/* artifact/include/v8/ + cp -r gen/include/* artifact/include/v8/ + find artifact/include/v8/. ! -name "*.h" -type f -delete + - name: Generate CMakeLists + uses: DamianReeves/write-file-action@v1.0 + with: + path: ./v8/out/artifact/CMakeLists.txt + write-mode: overwrite + contents: ${{ format(env.cmakelists_template, (!startsWith(github.event.inputs.v8_revision, '7.7') && endsWith(matrix.arch, '64')) && 'INTERFACE "-DV8_COMPRESS_POINTERS"' || '', '${CMAKE_CURRENT_SOURCE_DIR}/lib/libv8_monolith.a') }} + - name: Release package + id: release_package + working-directory: ./v8 + run: | + echo "head_full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + cd out + tar -zcvf android-${{ matrix.arch }}.tgz -C artifact . + - name: Install Requirement + shell: bash + run: | + pip3 install -U cos-python-sdk-v5 + - name: Publish package + shell: python3 {0} + env: + local_file: ./v8/out/android-${{ matrix.arch }}.tgz + cos_key: hippy/${{ github.event.inputs.hip_v8_root }}/v8/${{ github.event.inputs.v8_revision }}/${{ github.event.inputs.build_type }}/android-${{ matrix.arch }}.tgz + v8_head: ${{ steps.release_package.outputs.head_full }} + run: ${{ env.publish_package_script }} + + windows_prebuilt: + if: github.event.inputs.is_build_for_windows == 'true' + runs-on: windows-2019 + strategy: + matrix: + arch: [x86, x64, arm64] + steps: + - name: Setup GN + run: | + Invoke-WebRequest -OutFile depot_tools.zip https://storage.googleapis.com/chrome-infra/depot_tools.zip + Expand-Archive depot_tools.zip -DestinationPath C:\depot_tools + rm depot_tools.zip + choco install ninja + - name: Install Clang 15.0.1 + id: install-clang + uses: KyleMayes/install-llvm-action@v1 + with: + version: "15.0.1" + directory: "./llvm" + - name: Checkout v8 + run: | + $env:DEPOT_TOOLS_WIN_TOOLCHAIN = 0 + $env:Path += ";C:\depot_tools" + fetch v8 + cd v8 + git checkout ${{ github.event.inputs.v8_revision }} + gclient sync -D + - name: Generate ${{ matrix.arch }} + working-directory: ./v8 + run: | + $env:DEPOT_TOOLS_WIN_TOOLCHAIN = 0 + $env:Path += ";C:\depot_tools" + $llvmPath = $($env:GITHUB_WORKSPACE + "\llvm") + & $($llvmPath + "\bin\clang.exe") --version + echo $llvmPath + gn gen out --args="target_cpu=""""""${{ matrix.arch }}"""""" v8_target_cpu=""""""${{ matrix.arch }}"""""" is_component_build=false v8_monolithic=true use_custom_libcxx=false chrome_pgo_phase=0 ${{ github.event.inputs.build_type == 'release' && 'is_debug=false is_official_build=true clang_use_chrome_plugins=false clang_base_path=""""$llvmPath""""' || 'is_debug=true enable_iterator_debugging=true' }} ${{ github.event.inputs.build_args }}" + type out/args.gn + - name: Compile ${{ matrix.arch }} + working-directory: ./v8 + run: | + $env:Path += ";C:\depot_tools" + ninja -C out v8_monolith + - name: Prepare package + working-directory: ./v8/out + run: | + New-Item -type directory -Path artifact/include/v8, artifact/lib + Copy-Item obj/v8_monolith.lib artifact/lib + Copy-Item -r ../include/* artifact/include/v8/ + Copy-Item -r gen/include/* artifact/include/v8/ + Get-ChildItem -Exclude *.h -Recurse -File -Path artifact/include/v8 | Remove-Item + - name: Generate CMakeLists + uses: DamianReeves/write-file-action@v1.0 + with: + path: ./v8/out/artifact/CMakeLists.txt + write-mode: overwrite + contents: ${{ format(env.cmakelists_template, endsWith(matrix.arch, '64') && 'INTERFACE "-DV8_COMPRESS_POINTERS"' || '', '${CMAKE_CURRENT_SOURCE_DIR}/lib/v8_monolith.lib') }} + - name: Release package + id: release_package + working-directory: ./v8 + run: | + Write-Output "head_full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + cd out + Compress-Archive -Path artifact\* -DestinationPath windows-${{ matrix.arch }}.zip + - name: Install Requirement + shell: bash + run: | + pip install -U cos-python-sdk-v5 + - name: Publish package + shell: python + env: + local_file: ./v8/out/windows-${{ matrix.arch }}.zip + cos_key: hippy/${{ github.event.inputs.hip_v8_root }}/v8/${{ github.event.inputs.v8_revision }}/${{ github.event.inputs.build_type }}/windows-${{ matrix.arch }}.zip + v8_head: ${{ steps.release_package.outputs.head_full }} + run: ${{ env.publish_package_script }} + + macos_prebuilt: + if: github.event.inputs.is_build_for_macos == 'true' + runs-on: macos-latest + strategy: + matrix: + arch: [x64, arm64] + steps: + - name: Setup GN + run: | + git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git /usr/local/opt/depot_tools + export PATH=/usr/local/opt/depot_tools:$PATH + - name: Checkout v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + fetch v8 + cd v8 + git checkout ${{ github.event.inputs.v8_revision }} + gclient sync -D + - name: Generate ${{ matrix.arch }} + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + gn gen out --args="target_cpu=\"${{ matrix.arch }}\" v8_target_cpu=\"${{ matrix.arch }}\" chrome_pgo_phase=0 is_component_build=false v8_monolithic=true ${{ github.event.inputs.build_type == 'release' && 'is_debug=false is_official_build=true' || 'is_debug=true' }} ${{ github.event.inputs.build_args }}" + - name: Compile ${{ matrix.arch }} + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + ninja -C out v8_monolith + - name: Prepare package + working-directory: ./v8/out + run: | + mkdir -p artifact/include/v8 artifact/lib + cp obj/libv8_monolith.a artifact/lib + cp -r ../include/* artifact/include/v8/ + cp -r gen/include/* artifact/include/v8/ + find artifact/include/v8/. ! -name "*.h" -type f -delete + - name: Generate CMakeLists + uses: DamianReeves/write-file-action@v1.0 + with: + path: ./v8/out/artifact/CMakeLists.txt + write-mode: overwrite + contents: ${{ format(env.cmakelists_template, endsWith(matrix.arch, '64') && 'INTERFACE "-DV8_COMPRESS_POINTERS"' || '', '${CMAKE_CURRENT_SOURCE_DIR}/lib/libv8_monolith.a') }} + - name: Release package + id: release_package + working-directory: ./v8 + run: | + echo "head_full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + cd out + tar -zcvf macos-${{ matrix.arch }}.tgz -C artifact . + - name: Install Requirement + shell: bash + run: | + pip install -U cos-python-sdk-v5 + - name: Publish package + shell: python + env: + local_file: ./v8/out/macos-${{ matrix.arch }}.tgz + cos_key: hippy/${{ github.event.inputs.hip_v8_root }}/v8/${{ github.event.inputs.v8_revision }}/${{ github.event.inputs.build_type }}/macos-${{ matrix.arch }}.tgz + v8_head: ${{ steps.release_package.outputs.head_full }} + run: ${{ env.publish_package_script }} + + linux_prebuilt: + if: github.event.inputs.is_build_for_linux == 'true' + needs: context_in_lowercase + runs-on: [self-hosted, linux, shared] + container: + image: ghcr.io/${{ needs.context_in_lowercase.outputs.repository_owner }}/linux-release:latest + strategy: + matrix: + arch: [x86, x64, arm64, arm] + steps: + - name: Checkout v8 + run: | + fetch v8 + cd v8 + git checkout ${{ github.event.inputs.v8_revision }} + gclient sync -D + - name: Install sysroot(${{ matrix.arch }}) + if: ${{ contains(matrix.arch, 'arm') }} + working-directory: ./v8 + run: | + build/linux/sysroot_scripts/install-sysroot.py --arch=${{ matrix.arch }} + - name: Generate ${{ matrix.arch }} + working-directory: ./v8 + run: | + gn gen out --args="target_cpu=\"${{ matrix.arch }}\" v8_target_cpu=\"${{ matrix.arch }}\" chrome_pgo_phase=0 is_component_build=false v8_monolithic=true ${{ github.event.inputs.build_type == 'release' && 'is_debug=false is_official_build=true' || 'is_debug=true' }} ${{ github.event.inputs.build_args }}" + - name: Compile ${{ matrix.arch }} + working-directory: ./v8 + run: | + ninja -C out v8_monolith + - name: Prepare package + working-directory: ./v8/out + run: | + mkdir -p artifact/include/v8 artifact/lib + cp obj/libv8_monolith.a artifact/lib + cp -r ../include/* artifact/include/v8/ + cp -r gen/include/* artifact/include/v8/ + find artifact/include/v8/. ! -name "*.h" -type f -delete + - name: Generate CMakeLists + uses: DamianReeves/write-file-action@v1.0 + with: + path: ./v8/out/artifact/CMakeLists.txt + write-mode: overwrite + contents: ${{ format(env.cmakelists_template, endsWith(matrix.arch, '64') && 'INTERFACE "-DV8_COMPRESS_POINTERS"' || '', '${CMAKE_CURRENT_SOURCE_DIR}/lib/libv8_monolith.a') }} + - name: Release package + id: release_package + working-directory: ./v8 + run: | + echo "head_full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + cd out + tar -zcvf linux-${{ matrix.arch }}.tgz -C artifact . + - name: Install Requirement + shell: bash + run: | + pip3 install -U cos-python-sdk-v5 + - name: Publish package + shell: python3 {0} + env: + local_file: ./v8/out/linux-${{ matrix.arch }}.tgz + cos_key: hippy/${{ github.event.inputs.hip_v8_root }}/v8/${{ github.event.inputs.v8_revision }}/${{ github.event.inputs.build_type }}/linux-${{ matrix.arch }}.tgz + v8_head: ${{ steps.release_package.outputs.head_full }} + run: ${{ env.publish_package_script }} + + ios_prebuilt: + if: github.event.inputs.is_build_for_ios == 'true' + runs-on: macos-latest + strategy: + matrix: + arch: [x64, arm64] + steps: + - name: Setup GN + run: | + git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git /usr/local/opt/depot_tools + export PATH=/usr/local/opt/depot_tools:$PATH + - name: Checkout v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + fetch v8 + cd v8 + git checkout ${{ github.event.inputs.v8_revision }} + - name: Sync third_party + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + echo "target_os = ['ios']" >> ../.gclient + gclient sync -D + - name: Remove compiler flags + working-directory: ./v8/build/config/compiler + run: | + awk '!/"-mllvm"/' BUILD.gn > BUILD.gn.0 && mv -f BUILD.gn.0 BUILD.gn + awk '!/"-instcombine-lower-dbg-declare=0"/' BUILD.gn > BUILD.gn.0 && mv -f BUILD.gn.0 BUILD.gn + awk '!/ldflags \+= \[ "-Wl,-mllvm,-instcombine-lower-dbg-declare=0" \]/' BUILD.gn > BUILD.gn.0 && mv -f BUILD.gn.0 BUILD.gn + - name: Generate ${{ matrix.arch }} + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + gn gen out --args="target_os=\"ios\" target_cpu=\"${{ matrix.arch }}\" v8_target_cpu=\"${{ matrix.arch }}\" is_component_build=false v8_monolithic=true chrome_pgo_phase=0 enable_ios_bitcode=true ios_deployment_target=10 v8_enable_pointer_compression=false use_custom_libcxx=false ios_enable_code_signing=false ${{ github.event.inputs.build_type == 'release' && 'is_debug=false is_official_build=true' || 'is_debug=true' }} ${{ github.event.inputs.build_args }}" + - name: Compile ${{ matrix.arch }} + working-directory: ./v8 + run: | + export PATH=/usr/local/opt/depot_tools:$PATH + ninja -C out v8_monolith + - name: Prepare package + working-directory: ./v8/out + run: | + mkdir -p artifact/include/v8 artifact/lib + cp obj/libv8_monolith.a artifact/lib + cp -r ../include/* artifact/include/v8/ + cp -r gen/include/* artifact/include/v8/ + find artifact/include/v8/. ! -name "*.h" -type f -delete + - name: Generate CMakeLists + uses: DamianReeves/write-file-action@v1.0 + with: + path: ./v8/out/artifact/CMakeLists.txt + write-mode: overwrite + contents: ${{ format(env.cmakelists_template, '', '${CMAKE_CURRENT_SOURCE_DIR}/lib/libv8_monolith.a') }} + - name: Release package + id: release_package + working-directory: ./v8 + run: | + echo "head_full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + cd out + tar -zcvf ios-${{ matrix.arch }}.tgz -C artifact . + - name: Install Requirement + shell: bash + run: | + pip install -U cos-python-sdk-v5 + - name: Publish package + shell: python + env: + local_file: ./v8/out/ios-${{ matrix.arch }}.tgz + cos_key: hippy/${{ github.event.inputs.hip_v8_root }}/v8/${{ github.event.inputs.v8_revision }}/${{ github.event.inputs.build_type }}/ios-${{ matrix.arch }}.tgz + v8_head: ${{ steps.release_package.outputs.head_full }} + run: ${{ env.publish_package_script }} diff --git a/.github/workflows/android_build_tests.yml b/.github/workflows/android_build_tests.yml new file mode 100644 index 00000000000..1124e3920d7 --- /dev/null +++ b/.github/workflows/android_build_tests.yml @@ -0,0 +1,55 @@ +name: '[android] build tests' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths: + - 'framework/android/**' + - 'driver/js/lib/**' + - 'driver/js/src/**' + - 'driver/js/include/**' + - 'driver/js/CMakeLists.txt' + - 'dom/**' + - 'layout/engine/**' + - 'modules/android/**' + - 'modules/footstone/**' + - 'renderer/native/android/**' + - 'devtools/devtools-backend/**' + - 'gradle/**' + - 'build.gradle' + - 'gradle.properties' + - 'settings.gradle' + - 'gradlew' + - 'gradlew.bat' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + android_build_tests: + runs-on: ${{ github.repository == 'Tencent/Hippy' && fromJson('[''self-hosted'', ''linux'', ''shared'']') || 'ubuntu-latest' }} + container: + image: ghcr.io/tencent/android-release:latest # repository name must be lowercase(${{ github.repository_owner }}) + strategy: + matrix: + type: [debug, release] + v8: [v8_min, v8_target] + include: + - type: debug + task: assembleDebug + - type: release + task: assembleRelease + timeout-minutes: 10 + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + lfs: true + - name: Run ${{ matrix.task }} + run: | + ./gradlew ${{ matrix.task }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true ${{ (matrix.v8 == 'v8_min') && '-PV8_COMPONENT=7.7.299.15' || '' }} diff --git a/.github/workflows/android_build_tests_bypass.yml b/.github/workflows/android_build_tests_bypass.yml new file mode 100644 index 00000000000..e5ad3fbd98f --- /dev/null +++ b/.github/workflows/android_build_tests_bypass.yml @@ -0,0 +1,43 @@ +name: '[android] build tests' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths-ignore: + - 'framework/android/**' + - 'driver/js/lib/**' + - 'driver/js/src/**' + - 'driver/js/include/**' + - 'driver/js/CMakeLists.txt' + - 'dom/**' + - 'layout/engine/**' + - 'modules/android/**' + - 'modules/footstone/**' + - 'renderer/native/android/**' + - 'devtools/devtools-backend/**' + - 'gradle/**' + - 'build.gradle' + - 'gradle.properties' + - 'settings.gradle' + - 'gradlew' + - 'gradlew.bat' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + android_build_tests: + runs-on: ubuntu-latest + strategy: + matrix: + type: [debug, release] + v8: [v8_min, v8_target] + steps: + - name: Build Test Bypass + run: | + echo "No build test required" diff --git a/.github/workflows/build_android_release_image.yml b/.github/workflows/build_android_release_image.yml deleted file mode 100644 index 99c5f137b6b..00000000000 --- a/.github/workflows/build_android_release_image.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: '[android] build release image' - -on: - workflow_dispatch: - inputs: - tag: - description: 'TAG' - default: 'latest' - required: true - push: - branches: - - master - - main - tags-ignore: - - '**' - paths: - - 'docker/android-release/Dockerfile' -jobs: - push_to_registry: - name: Push docker image - runs-on: [self-hosted, linux, trusted] - steps: - - name: Check out the repo - uses: actions/checkout@v2 - - name: Log in - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Get repo owner(in lowercase) - id: get_owner - uses: ASzc/change-string-case-action@v2 - with: - string: ${{ github.repository_owner }} - - name: Push to ghcr.io - uses: docker/build-push-action@v2 - with: - context: docker/android-release - push: true - tags: ghcr.io/${{ steps.get_owner.outputs.lowercase }}/android-release:${{ github.event.inputs.tag || 'latest' }} diff --git a/.github/workflows/commit.yml b/.github/workflows/commit.yml deleted file mode 100644 index 009b6e32c71..00000000000 --- a/.github/workflows/commit.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: '[commit-lint] check commit message format' - -on: [ pull_request ] - -jobs: - commitlint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: setup-node - uses: actions/setup-node@master - with: - node-version: 16.x - - name: Install - run: npm install commitlint-plugin-function-rules@1.4.0 @commitlint/cli@13.1.0 @commitlint/config-conventional@13.1.0 @commitlint/config-conventional@13.1.0 @commitlint/lint@13.1.0 @commitlint/prompt-cli@13.1.0 - - name: commitlint - run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose diff --git a/.github/workflows/config/license-check.json b/.github/workflows/config/license-check.json new file mode 100644 index 00000000000..1393955f528 --- /dev/null +++ b/.github/workflows/config/license-check.json @@ -0,0 +1,49 @@ +{ + "copyright": [ + "Copyright", + "Licensed under the Apache License, Version 2.0 (the \"License\")" + ], + "include": [ + "**/*.{ts,tsx,js,jsx,vue,ejs,mjs,es6}", + "**/*.{css,less,scss}", + "**/*.{h,hpp,hh,h++,hxx}", + "**/*.{c,cc,c++,cpp,C,cxx}", + "**/*.{m,mm,swift}", + "**/*.cmake", + "**/*.java", + "**/*.txt", + "**/*.sh", + "**/*.yaml", + "**/*.bat", + "**/*.dart", + "**/*.py" + ], + "ignore": [ + "**/node_modules/**", + "**/AUTHORS/**", + "**/.git/**", + "**/.gradle/**", + "**/.DS_Store/**", + "**/.nyc_output/**", + "**/.vscode/**", + "**/.vs/**", + "**/.idea/**", + "**/.externalNativeBuild/**", + "**/.cxx/**", + "**/*.xcworkspace/**", + ".github/**", + ".husky/**", + "docs/**", + "framework/examples/android-demo/res/**", + "framework/examples/ios-demo/res/**", + "framework/examples/ios-demo/*.sh", + "framework/examples/voltron-demo/flutter_module/assets/**", + "framework/examples/voltron-demo/flutter_proj/assets/**", + "driver/js/examples/static/**", + "driver/js/examples/hippy-**-demo/**", + "framework/voltron/example/assets/**", + "framework/voltron/script/android/gradlew.bat", + "framework/voltron/script/ios.toolchain.cmake", + "modules/voltron/ffi/core/third_party/**" + ] +} diff --git a/.github/workflows/config/pr-path-labeler.yml b/.github/workflows/config/pr-path-labeler.yml new file mode 100644 index 00000000000..fe09b88b810 --- /dev/null +++ b/.github/workflows/config/pr-path-labeler.yml @@ -0,0 +1,58 @@ +"framework: android": + - framework/android/**/* +"framework: ios": + - framework/ios/**/* +"framework: voltron": + - framework/voltron/**/* +"driver: js": + - driver/js/**/* +"driver: vl": + - driver/vl/**/* +"dom: tree": + - any: ["dom/**/*", "!dom/include/dom/animation/**/*", "!dom/src/dom/animation/**/*"] +"dom: animation": + - dom/include/dom/animation/**/* + - dom/src/dom/animation/**/* +"dom: layout": + - layout/**/* +"renderer: native": + - renderer/native/**/* +"renderer: tdf": + - renderer/tdf/**/* +"renderer: voltron": + - renderer/voltron/**/* +"module: vfs": + - modules/vfs/**/* +"module: footstone": + - modules/footstone/**/* +"module: android": + - modules/android/**/* +"module: ios": + - modules/ios/**/* +"module: voltron": + - modules/voltron/**/* +"doc: example": + - framework/examples/**/* +"doc: pages": + - docs/**/* +"devtools: backend": + - devtools/**/* +"gh: workflow": + - .github/workflows/**/* +"gh: template": + - .github/ISSUE_TEMPLATE/**/* + - .github/PULL_REQUEST_TEMPLATE.md +"gh: owner": + - .github/CODEOWNERS +"build: gradle": + - gradle/**/* + - build.gradle + - gradle.properties + - gradlew + - gradlew.bat + - settings.gradle +"build: xcode": + - Hippy.xcworkspace/**/* + - hippy.podspec +"build: cmake": + - buildconfig/cmake/**/* diff --git a/.github/workflows/config/pr-size-labeler.yml b/.github/workflows/config/pr-size-labeler.yml new file mode 100644 index 00000000000..3586b288e6e --- /dev/null +++ b/.github/workflows/config/pr-size-labeler.yml @@ -0,0 +1,5 @@ +'size: xs': 9 +'size: s': 99 +'size: m': 499 +'size: l': 999 +'size: xl': Infinity diff --git a/.github/workflows/docker_build_image.yml b/.github/workflows/docker_build_image.yml new file mode 100644 index 00000000000..36d46225d54 --- /dev/null +++ b/.github/workflows/docker_build_image.yml @@ -0,0 +1,88 @@ +name: '[docker] build docker image' + +on: + workflow_dispatch: + inputs: + images: + description: 'Images (separated by commas)' + required: true + tag: + description: 'TAG' + default: 'latest' + required: true + push: + branches: + - master + - main + tags-ignore: + - '**' + paths: + - 'buildconfig/docker/**' + +jobs: + changed_images: + runs-on: ubuntu-latest + outputs: + changed_images: ${{ steps.changed_images.outputs.changed_images }} + steps: + - name: Get changed images + id: changed_images + uses: actions/github-script@v6 + with: + script: | + const { basename, sep } = require('path'); + const { appendFileSync } = require('fs'); + const { EOL } = require('os'); + const { eventName } = context; + const { repos } = github.rest; + const push = context.payload; + + const changedImages = new Set(); + + if (eventName === 'workflow_dispatch') { + '${{ github.event.inputs.images }}'.split(',').forEach(image => changedImages.add(image.trim())); + } else if (eventName === 'push') { + const files = await github.paginate(repos.compareCommits, { + ...context.repo, + base: push.before, + head: push.after, + per_page: 100 + }); + + files.filter(({ status, filename }) => + (status === 'added' || status === 'modified' || status === 'changed' || status === 'copied' || status === 'renamed') + && basename(filename) === 'Dockerfile').forEach(({ filename }) => { + changedImages.add(filename.split(sep).slice(-2)[0]); + }); + } + + appendFileSync(process.env.GITHUB_OUTPUT, `changed_images=${JSON.stringify(Array.from(changedImages))}${EOL}`, { encoding: 'utf8' }); + + build_images: + needs: changed_images + runs-on: ${{ github.repository == 'Tencent/Hippy' && fromJson('[''self-hosted'', ''linux'', ''shared'']') || 'ubuntu-latest' }} + strategy: + matrix: + images: ${{ fromJson(needs.changed_images.outputs.changed_images) }} + steps: + - name: Checkout repo + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Log in + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Get repo owner(in lowercase) + id: get_owner + uses: ASzc/change-string-case-action@v2 + with: + string: ${{ github.repository_owner }} + - name: Make & Push to ghcr.io + uses: docker/build-push-action@v4 + with: + context: buildconfig/docker/${{ matrix.images }} + push: true + tags: ghcr.io/${{ steps.get_owner.outputs.lowercase }}/${{ matrix.images }}:${{ github.event.inputs.tag || 'latest' }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 7ff7b1a78de..00000000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: '[markdown-lint] check documents format' - -on: - push: - paths: - - '*.md' - - 'docs/**/*.md' - branches: - # Push events on main branch - - main - # Push events on master branch - - master - tags-ignore: - - '**' - pull_request: - paths: - - '*.md' - - 'docs/**/*.md' - branches: - # Pull request events to main branch - - main - # Pull request events to master branch - - master - tags-ignore: - - '**' - -jobs: - markdownlint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: markdownlint - uses: nosborn/github-action-markdown-cli@v1.1.1 - with: - config_file: .markdownlintrc.json - files: ./README*.md ./PUBLISH*.md ./docs/**/*.md diff --git a/.github/workflows/docs_markdown_lint.yml b/.github/workflows/docs_markdown_lint.yml new file mode 100644 index 00000000000..b520f93f638 --- /dev/null +++ b/.github/workflows/docs_markdown_lint.yml @@ -0,0 +1,30 @@ +name: '[docs] markdown documents format lint' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths: + - '*.md' + - 'docs/**/*.md' + +jobs: + markdownlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: setup-node + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: 'npm' + cache-dependency-path: package-lock.json + - name: Install + run: | + npm install markdown-it@12.3.2 markdownlint-cli@0.31.1 + - name: markdownlint + run: | + npm run markdownlint diff --git a/.github/workflows/docs_markdown_lint_bypass.yml b/.github/workflows/docs_markdown_lint_bypass.yml new file mode 100644 index 00000000000..fb377fa74df --- /dev/null +++ b/.github/workflows/docs_markdown_lint_bypass.yml @@ -0,0 +1,20 @@ +name: '[docs] markdown documents format lint' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths-ignore: + - '*.md' + - 'docs/**/*.md' + +jobs: + markdownlint: + runs-on: ubuntu-latest + steps: + - name: Lint Bypass + run: | + echo "No lint required" diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml deleted file mode 100644 index 4cc74d0d0ee..00000000000 --- a/.github/workflows/frontend.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: '[FrontEnd] check js code' - -on: - push: - paths: - - 'packages/**' - - 'examples/hippy-*-demo/**' - - 'scripts/**/*.js' - - 'core/js/**/*.js' - branches: - # Push events on main branch - - main - # Push events on master branch - - master - tags-ignore: - - '**' - pull_request: - paths: - - 'packages/**' - - 'examples/hippy-*-demo/**' - - 'scripts/**/*.js' - - 'core/js/**/*.js' - branches: - # Pull request events to main branch - - main - # Pull request events to master branch - - master - tags-ignore: - - '**' - -jobs: - check_js: - runs-on: ubuntu-latest - strategy: - matrix: - node: [ 10.x, 16.x ] - steps: - - uses: actions/checkout@v2 - - name: setup-node - uses: actions/setup-node@master - with: - node-version: ${{ matrix.node }} - registry-url: https://npm.pkg.github.com - - name: install - run: npm install - - name: lint - run: npm run lint - - name: test - run: npm run coverage - - name: coverage - if: matrix.node == '16.x' - uses: codecov/codecov-action@v2 - - name: build - run: npm run build diff --git a/.github/workflows/frontend_build_tests.yml b/.github/workflows/frontend_build_tests.yml new file mode 100644 index 00000000000..b21a6b1064d --- /dev/null +++ b/.github/workflows/frontend_build_tests.yml @@ -0,0 +1,43 @@ +name: '[front-end] build tests' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths: + - 'driver/js/packages/**' + - 'package*.json' + - 'driver/js/examples/hippy-*-demo/**' + - 'driver/js/lib/**' + - 'driver/js/scripts/**' +defaults: + run: + working-directory: driver/js +jobs: + frontend_build_tests: + runs-on: ubuntu-latest + strategy: + matrix: + node: [ 16.x, 17.x ] + steps: + - uses: actions/checkout@v3 + - name: setup-node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + registry-url: https://npm.pkg.github.com + cache: 'npm' + cache-dependency-path: driver/js/package-lock.json + - name: install + run: | + npm install && npx lerna bootstrap --no-ci + - name: lint & build + run: npm run lint & npm run build + - name: test + run: npm run coverage + - name: coverage + if: matrix.node == '16.x' + uses: codecov/codecov-action@v2 diff --git a/.github/workflows/frontend_build_tests_bypass.yml b/.github/workflows/frontend_build_tests_bypass.yml new file mode 100644 index 00000000000..3a21e6dacc7 --- /dev/null +++ b/.github/workflows/frontend_build_tests_bypass.yml @@ -0,0 +1,25 @@ +name: '[front-end] build tests' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths-ignore: + - 'driver/js/packages/**' + - 'package*.json' + - 'driver/js/examples/hippy-*-demo/**' + - 'driver/js/lib/**' + - 'driver/js/scripts/**' +jobs: + frontend_build_tests: + runs-on: ubuntu-latest + strategy: + matrix: + node: [ 16.x, 17.x ] + steps: + - name: Build Test Bypass + run: | + echo "No build test required" diff --git a/.github/workflows/gh_action_approve_checks.yml b/.github/workflows/gh_action_approve_checks.yml new file mode 100644 index 00000000000..85bd6da45fc --- /dev/null +++ b/.github/workflows/gh_action_approve_checks.yml @@ -0,0 +1,143 @@ +name: '[gh] action approve checks' + +on: + pull_request_target: + branches: + - master + - main + - v3.0-dev + - v3.0 + types: + - labeled + +jobs: + call_approval_checks_run: + if: github.event.label.name == 'action(approve-checks)' && github.repository == 'Tencent/Hippy' + uses: ./.github/workflows/reuse_approve_checks_run.yml + with: + pull_request_number: ${{ github.event.pull_request.number }} + pull_request_head_sha: ${{ github.event.pull_request.head.sha }} + + approve_checks_action: + needs: call_approval_checks_run + runs-on: ubuntu-latest + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.ACTION_PRIVATE_KEY }} + app-id: ${{ secrets.ACTION_APP_ID }} + - name: Action + uses: actions/github-script@v6.3.3 + env: + COMMENT_MESSAGE: | + :lock: The current `approve-checks` action execution requires privilege escalation. + + Please wait for approval of admin team member ... + + @${{ github.event.sender.login }} + WECHAT_WORK_MESSAGE: | + [${{ github.event.sender.login }}](https://github.com/${{ github.event.sender.login }}) requested privilege escalation action on [#${{ github.event.pull_request.number }}](${{ github.event.pull_request.html_url }}) pull request. + > ${{ github.event.pull_request.title }} + > [${{ github.event.pull_request.html_url }}](${{ github.event.pull_request.html_url }}) + PRIVILEGE_ESCALATION: ${{ needs.call_approval_checks_run.outputs.included_risk_files }} + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { pull_request } = context.payload; + const { issues } = github.rest; + + const p = []; + if (process.env.PRIVILEGE_ESCALATION == 'true') { + p.push(issues.createComment({ + issue_number: pull_request.number, + body: process.env.COMMENT_MESSAGE, + ...context.repo + })); + p.push(github.request("POST ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }}", { + headers: { + "content-type": "application/json" + }, + data: { + chatid: "${{ secrets.WECHAT_WORK_ADMIN_CHAT_ID }}", + msgtype: "markdown", + markdown: { + content: process.env.WECHAT_WORK_MESSAGE, + attachments: [{ + callback_id: "approve", + actions: [{ + name: "approve_btn", + text: "Mark as Approved", + type: "button", + value: "Mark as Approved", + replace_text: "Already approved", + border_color: "2c974b", + text_color: "2c974b" + }, { + name: "reject_btn", + text: "Mark as Rejected", + type: "button", + value: "Mark as Rejected", + replace_text: "Already Rejected", + border_color: "cf222e", + text_color: "cf222e" + }, { + name: "ignored_btn", + text: "Mark as Ignored", + type: "button", + value: "Mark as Ignored", + replace_text: "Already Ignored", + border_color: "6e7781", + text_color: "6e7781" + }] + }] + } + } + })); + } else { + p.push(issues.removeLabel({ + issue_number: pull_request.number, + name: 'action(approve-checks)', + ...context.repo, + }).catch(e => { + console.error('issues.removeLabel', e); + })); + } + + await Promise.all(p); + + call_approval_checks_run_privileged: + needs: [ call_approval_checks_run, approve_checks_action ] + if: needs.call_approval_checks_run.outputs.included_risk_files == 'true' + uses: ./.github/workflows/reuse_approve_checks_run.yml + with: + pull_request_number: ${{ github.event.pull_request.number }} + pull_request_head_sha: ${{ github.event.pull_request.head.sha }} + requied_privilege_escalation: true + + approve_checks_action_privileged: + needs: call_approval_checks_run_privileged + runs-on: ubuntu-latest + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.ACTION_PRIVATE_KEY }} + app-id: ${{ secrets.ACTION_APP_ID }} + - name: Action + uses: actions/github-script@v6.3.3 + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { pull_request } = context.payload; + const { issues } = github.rest; + + await issues.removeLabel({ + issue_number: pull_request.number, + name: 'action(approve-checks)', + ...context.repo, + }).catch(e => { + console.error('issues.removeLabel', e); + }); diff --git a/.github/workflows/gh_action_merge.yml b/.github/workflows/gh_action_merge.yml new file mode 100644 index 00000000000..a2a67c8f734 --- /dev/null +++ b/.github/workflows/gh_action_merge.yml @@ -0,0 +1,355 @@ +name: '[gh] action merge' + +on: + pull_request_target: + branches: + - master + - main + - v3.0-dev + - v3.0 + types: + - labeled + +env: + OUTPUT_FUNCTION: | + function output { + if [ $1 -ne 0 ]; then + if [[ -z "$2" ]]; then + echo "failed_result=(empty response)" >> $GITHUB_OUTPUT + else + echo "failed_result<> $GITHUB_OUTPUT + echo "$2" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + fi + exit 0 + fi + } + +jobs: + call_classify_commits: + if: github.repository == 'Tencent/Hippy' && (github.event.label.name == 'action(squash-merge)' || github.event.label.name == 'action(rebase-merge)') + uses: ./.github/workflows/reuse_classify_commits.yml + with: + pull_request_number: ${{ github.event.pull_request.number }} + + squash_merge_action: + needs: call_classify_commits + if: github.event.label.name == 'action(squash-merge)' + runs-on: ubuntu-latest + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.ACTION_PRIVATE_KEY }} + app-id: ${{ secrets.ACTION_APP_ID }} + - name: Reset + if: "contains(github.event.pull_request.labels.*.name, 'action(squash-merge): failed')" + uses: actions-ecosystem/action-remove-labels@v1.3.0 + with: + github_token: ${{ steps.get-token.outputs.token }} + labels: "action(squash-merge): failed" + - name: Checkout + if: needs.call_classify_commits.outputs.normal_commits_count > 1 + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup + if: needs.call_classify_commits.outputs.normal_commits_count > 1 + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: 'npm' + cache-dependency-path: package-lock.json + - name: Install + if: needs.call_classify_commits.outputs.normal_commits_count > 1 + run: | + npm install commitlint-plugin-function-rules@1.6.0 @commitlint/cli@16.2.1 @commitlint/config-conventional@16.2.1 @commitlint/lint@16.2.1 @commitlint/prompt-cli@16.2.1 + - name: Commitlint + id: commitlint + env: + PULL_REQUEST_TITLE: ${{ github.event.pull_request.title }} + shell: bash {0} + run: | + ${{ env.OUTPUT_FUNCTION }} + if [ ${{ needs.call_classify_commits.outputs.normal_commits_count }} -gt 1 ]; then + result=`echo $PULL_REQUEST_TITLE | npx commitlint -c false 2>&1` + output $? "$result" + fi + - name: Squash + id: squash + if: ${{ !steps.commitlint.outputs.failed_result && github.event.pull_request.user.login != github.event.sender.login }} + env: + GH_TOKEN: ${{ steps.get-token.outputs.token }} + shell: bash {0} + run: | + ${{ env.OUTPUT_FUNCTION }} + result=`gh pr merge ${{ github.event.pull_request.number }} --disable-auto --repo $GITHUB_REPOSITORY 2>&1` + output $? "$result" + result=`gh pr merge ${{ github.event.pull_request.number }} --squash --auto --repo $GITHUB_REPOSITORY 2>&1` + output $? "$result" + - name: Comment + uses: actions/github-script@v6.3.3 + env: + SQUASH_RESULT: ${{ steps.squash.outputs.failed_result }} + CHECK_RESULT: ${{ steps.commitlint.outputs.failed_result }} + FAILED_MESSAGE: | + :warning: `squash-merge` action execution failed, because of **%s**. + + Please check the following details: +
+ + ``` + %s + ``` + +
+ + ${{ github.event.sender.type == 'User' && format('@{0}', github.event.sender.login) || '#help' }} + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { pull_request, sender } = context.payload; + const { issues } = github.rest; + const util = require('util'); + const os = require('os'); + + let body; + if (process.env.CHECK_RESULT) { + body = util.format(process.env.FAILED_MESSAGE, 'pull request title does not meet the [Convention Commit](https://conventionalcommits.org/) guideline', process.env.CHECK_RESULT); + } else if (process.env.SQUASH_RESULT) { + body = util.format(process.env.FAILED_MESSAGE, 'auto squash and merge failed', process.env.SQUASH_RESULT); + } else if (pull_request.user.login === sender.login) { + body = util.format(process.env.FAILED_MESSAGE, 'cannot squash and merge your own pull request', `(empty response)`); + } + + const p = []; + p.push(issues.removeLabel({ + issue_number: pull_request.number, + name: 'action(squash-merge)', + ...context.repo, + }).catch(e => { + console.log('issues.removeLabel', e); + })); + if (body) { + p.push(issues.createComment({ + issue_number: pull_request.number, + body: body, + ...context.repo + })); + p.push(issues.addLabels({ + issue_number: pull_request.number, + labels: [ 'action(squash-merge): failed' ], + ...context.repo + })); + } + await Promise.all(p); + + rebase_merge_action_preparation: + needs: call_classify_commits + if: github.event.label.name == 'action(rebase-merge)' + runs-on: ubuntu-latest + outputs: + permission: ${{ steps.get-permission.outputs.permission }} + steps: + - name: Permission + id: get-permission + uses: actions/github-script@v6.3.3 + with: + script: | + const { repos } = github.rest; + const fs = require('fs'); + const os = require('os'); + + const { data: { permission } } = await repos.getCollaboratorPermissionLevel({ + ...context.repo, + username: "${{ github.event.sender.login }}" + }); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `permission=${permission}${os.EOL}`, { encoding: 'utf8' }); + - name: Token + uses: navikt/github-app-token-generator@v1 + if: steps.get-permission.outputs.permission != 'admin' && needs.call_classify_commits.outputs.normal_commits_count > 1 + id: get-token + with: + private-key: ${{ secrets.ACTION_PRIVATE_KEY }} + app-id: ${{ secrets.ACTION_APP_ID }} + - name: Comment + if: steps.get-token.outputs.token + env: + COMMENT_MESSAGE: | + :lock: `rebase-merge` action execution needs privilege escalation. + + Please wait for admin team member approval ... + + ${{ github.event.sender.type == 'User' && format('@{0}', github.event.sender.login) || '' }} + WECHAT_WORK_MESSAGE: | + [${{ github.event.sender.login }}](https://github.com/${{ github.event.sender.login }}) requested privilege escalation action on [#${{ github.event.pull_request.number }}](${{ github.event.pull_request.html_url }}) pull request. + > ${{ github.event.pull_request.title }} + > [${{ github.event.pull_request.html_url }}](${{ github.event.pull_request.html_url }}) + uses: actions/github-script@v6.3.3 + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { pull_request } = context.payload; + const { issues } = github.rest; + const util = require('util'); + + const p = []; + + p.push(issues.createComment({ + issue_number: pull_request.number, + body: process.env.COMMENT_MESSAGE, + ...context.repo + })); + + p.push(github.request("POST ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }}", { + headers: { + "content-type": "application/json" + }, + data: { + chatid: "${{ secrets.WECHAT_WORK_ADMIN_CHAT_ID }}", + msgtype: "markdown", + markdown: { + content: process.env.WECHAT_WORK_MESSAGE, + attachments: [{ + callback_id: "approve", + actions: [{ + name: "approve_btn", + text: "Mark as Approved", + type: "button", + value: "Mark as Approved", + replace_text: "Already approved", + border_color: "2c974b", + text_color: "2c974b" + }, { + name: "reject_btn", + text: "Mark as Rejected", + type: "button", + value: "Mark as Rejected", + replace_text: "Already Rejected", + border_color: "cf222e", + text_color: "cf222e" + }, { + name: "ignored_btn", + text: "Mark as Ignored", + type: "button", + value: "Mark as Ignored", + replace_text: "Already Ignored", + border_color: "6e7781", + text_color: "6e7781" + }] + }] + } + } + })); + + await Promise.all(p); + + rebase_merge_action: + needs: [ rebase_merge_action_preparation, call_classify_commits ] + runs-on: ubuntu-latest + environment: ${{ (needs.rebase_merge_action_preparation.outputs.permission != 'admin' && needs.call_classify_commits.outputs.normal_commits_count > 1) && 'github-actions-privileged' || '' }} + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.ACTION_PRIVATE_KEY }} + app-id: ${{ secrets.ACTION_APP_ID }} + - name: Check + if: "contains(github.event.pull_request.labels.*.name, 'action(rebase-merge): failed')" + uses: actions-ecosystem/action-remove-labels@v1.3.0 + with: + github_token: ${{ steps.get-token.outputs.token }} + labels: "action(rebase-merge): failed" + - name: Rebase + id: rebase + env: + GH_TOKEN: ${{ steps.get-token.outputs.token }} + shell: bash {0} + run: | + ${{ env.OUTPUT_FUNCTION }} + result=`gh pr merge ${{ github.event.pull_request.number }} --disable-auto --repo $GITHUB_REPOSITORY 2>&1` + output $? "$result" + result=`gh pr merge ${{ github.event.pull_request.number }} --rebase --auto --repo $GITHUB_REPOSITORY 2>&1` + output $? "$result" + - name: Comment + uses: actions/github-script@v6.3.3 + env: + REBASE_RESULT: ${{ steps.rebase.outputs.failed_result }} + FAILED_MESSAGE: | + :warning: `rebase-merge` action execution failed, because of **%s**. + + Please check the following details: +
+ + ``` + %s + ``` + +
+ + ${{ github.event.sender.type == 'User' && format('@{0}', github.event.sender.login) || '#help' }} + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { pull_request } = context.payload; + const { issues } = github.rest; + const util = require('util'); + + const p = []; + p.push(issues.removeLabel({ + issue_number: pull_request.number, + name: 'action(rebase-merge)', + ...context.repo, + }).catch(e => { + console.log('issues.removeLabel', e); + })); + if (process.env.REBASE_RESULT) { + p.push(issues.createComment({ + issue_number: pull_request.number, + body: util.format(process.env.FAILED_MESSAGE, 'auto rebase and merge failed', process.env.REBASE_RESULT), + ...context.repo + })); + p.push(issues.addLabels({ + issue_number: pull_request.number, + labels: [ 'action(rebase-merge): failed' ], + ...context.repo + })); + } + await Promise.all(p); + + rebase_merge_action_rejected: + needs: [ rebase_merge_action ] + if: failure() + runs-on: ubuntu-latest + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.ACTION_PRIVATE_KEY }} + app-id: ${{ secrets.ACTION_APP_ID }} + - name: Label + uses: actions/github-script@v6.3.3 + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { pull_request } = context.payload; + const { issues } = github.rest; + + const p = []; + p.push(issues.removeLabel({ + issue_number: pull_request.number, + name: 'action(rebase-merge)', + ...context.repo, + }).catch(e => { + console.log('issues.removeLabel', e); + })); + p.push(issues.addLabels({ + issue_number: pull_request.number, + labels: [ 'action(rebase-merge): failed' ], + ...context.repo + })); + + await Promise.all(p); diff --git a/.github/workflows/gh_issue_crash_report.yml b/.github/workflows/gh_issue_crash_report.yml new file mode 100644 index 00000000000..8d49d3fd27b --- /dev/null +++ b/.github/workflows/gh_issue_crash_report.yml @@ -0,0 +1,302 @@ +name: '[gh] issue crash report' + +on: + issues: + types: + - opened + +env: + greetings_message: | + 🙇 Thank you for making us aware of the issue. + + Don\'t worry about it, our collaborators will handle it asap. + + If you have any additional information, you can add a new comment in this issue. + translates_addresses_message: | + I will try to translate addresses to human readable format, please wait a moment. + fetch_symbol_failed_message: | + I have searched the artifacts store database, but found no artifacts with version %s and %s architecture. + no_backtrace_message: | + It looks like there is no backtrace addresses in the crash log that needs to be translated. + translate_success_message: | + After my translation, the result is as follows. + ``` + %s + ``` + translate_failed_message: | + Sorry, the addresses translation encountered an error. + +jobs: + triage: + if: github.repository == 'Tencent/Hippy' && contains(github.event.issue.title, 'crash') + runs-on: [self-hosted, linux, shared] + container: + image: node:latest + outputs: + version: ${{ steps.triage-result.outputs.version }} + platform: ${{ steps.triage-result.outputs.platform }} + architecture: ${{ steps.triage-result.outputs.architecture }} + logs: ${{ steps.triage-result.outputs.logs }} + setps: ${{ steps.triage-result.outputs.setps }} + additional: ${{ steps.triage-result.outputs.additional }} + repository_owner: ${{ steps.triage-result.outputs.repository_owner }} + steps: + - name: Greetings + uses: actions/github-script@v6.3.3 + env: + ISSUE_NUMBER: ${{ github.event.issue.number }} + with: + script: | + const { owner, repo } = context.repo; + const { issues, reactions } = github.rest; + const issue_number = Number(process.env.ISSUE_NUMBER); + + const { data: { id } } = await issues.createComment({ + owner, + repo, + issue_number, + body: process.env.greetings_message + }); + await reactions.createForIssue({ + owner, + repo, + issue_number, + content: '+1' + }); + - run: npm install markdown-it + - name: Triage + id: triage-result + uses: actions/github-script@v6.3.3 + env: + issue_body: ${{ github.event.issue.body }} + with: + script: | + const MarkdownIt = require('markdown-it'); + const os = require('os'); + const path = require('path'); + const fs = require('fs'); + + function parse(markdown) { + const tokens = (new MarkdownIt()).parse(markdown, {}); + const result = {}; + + let inHeading = true; + let key = []; + let value = []; + tokens.forEach((token, index) => { + if (token.type === 'heading_open' && token.markup === '###') { + if (key.length > 0) { + result[key.join(os.EOL)] = value.join(os.EOL); + } + key = []; + value = []; + inHeading = true; + } else if (token.type === 'heading_close' && token.markup === '###') { + inHeading = false; + } else { + const { content } = token; + if (content) { + if (inHeading) { + key.push(content); + } else { + value.push(content); + } + } + } + + if (index === tokens.length - 1) { + result[key.join(os.EOL)] = value.join(os.EOL); + } + }); + return result; + } + + const info = parse(process.env.issue_body); + ['Version', 'Platform', 'Architecture', 'Logs', 'Reproduce Condition', 'Additional Information'].forEach(key => { + let value = info[key]; + if (value) { + if (['Version', 'Platform', 'Architecture'].includes(key)) { + value = value.replaceAll(/[^0-9a-z\-_\.]/ig, ''); + } + fs.appendFileSync(process.env.GITHUB_OUTPUT, `${key.toLowerCase()}< 0) { + appendFileSync(process.env.GITHUB_OUTPUT, `backtrace=${JSON.stringify(backtrace)}${EOL}`, { encoding: 'utf8' }); + } + + await issues.createComment({ + owner, + repo, + issue_number, + body: process.env[backtrace.length > 0 ? 'translates_addresses_message' : 'no_backtrace_message'] + }); + - name: Symbols + id: symbols_fetched + if: steps.backtrace_parsed.outputs.backtrace + continue-on-error: true + shell: bash + env: + TRIAGE_ARCHITECTURE: ${{ needs.triage.outputs.architecture }} + TRIAGE_VERSION: ${{ needs.triage.outputs.version }} + run: | + if [[ "$TRIAGE_ARCHITECTURE" == "arm" ]]; then + ZIP_FILE="armeabi-v7a.zip" + elif [[ "$TRIAGE_ARCHITECTURE" == "arm64" ]]; then + ZIP_FILE="arm64-v8a.zip" + elif [[ "$TRIAGE_ARCHITECTURE" == "x86" ]]; then + ZIP_FILE="x86.zip" + elif [[ "$TRIAGE_ARCHITECTURE" == "x86_64" ]]; then + ZIP_FILE="x86_64.zip" + else + echo "Unknown architecture($TRIAGE_ARCHITECTURE)" + exit 1 + fi + curl -Of "https://artifacts-store.openhippy.com/hippy/android/hippy-common/${TRIAGE_VERSION}/symbols/${ZIP_FILE}" + mkdir symbols + unzip -d symbols "$ZIP_FILE" + rm "$ZIP_FILE" + echo "success=1" >> "$GITHUB_OUTPUT" + - uses: actions/github-script@v6.3.3 + if: steps.symbols_fetched.result == 'success' && !steps.symbols_fetched.outputs.success + env: + ISSUE_NUMBER: ${{ github.event.issue.number }} + TRIAGE_VERSION: ${{ needs.triage.outputs.version }} + TRIAGE_ARCHITECTURE: ${{ needs.triage.outputs.architecture }} + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { owner, repo } = context.repo; + const { issues } = github.rest; + const util = require('util'); + const issue_number = Number(process.env.ISSUE_NUMBER); + + await issues.createComment({ + owner, + repo, + issue_number, + body: util.format(process.env.fetch_symbol_failed_message, process.env.TRIAGE_VERSION, process.env.TRIAGE_ARCHITECTURE) + }); + - name: Translates + if: steps.symbols_fetched.outputs.success + uses: actions/github-script@v6.3.3 + env: + BACKTRACE_JSON: ${{ steps.backtrace_parsed.outputs.backtrace }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { owner, repo } = context.repo; + const { issues, reactions } = github.rest; + const { execSync } = require('child_process'); + const path = require('path'); + const fs = require('fs'); + const os = require('os'); + const util = require('util'); + const issue_number = Number(process.env.ISSUE_NUMBER); + + const bin = path.join(process.env['ANDROID_NDK_HOME'], 'toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-addr2line'); + function addr2line(lib, pc) { + const [ func, source ] = execSync(`${bin} -C -f -e ${lib} ${pc}`, { encoding: 'utf8' }).split(os.EOL); + return { func, source }; + } + + const backtrace = JSON.parse(process.env.BACKTRACE_JSON); + + let body; + let error; + try { + const symbols = fs.readdirSync('symbols'); + const formatted = backtrace.map(stack => { + const lib = path.basename(stack.file); + if (symbols.includes(lib)) { + const { func, source} = addr2line(path.join("symbols", lib), stack.pc); + return { + pc: stack.pc, + file: stack.file, + func, + source + } + } + + return stack; + }).map(({ pc, func, file, source }, i) => { + return `#${i} PC ${pc} ${file} ${func ? `(${func})` : ''}${source ? ` [${source}]` : ''}`; + }); + + body = util.format(process.env.translate_success_message, [`translated backtrace:`, ...formatted.map(line => ` ${line}`)].join(os.EOL)); + } catch (e) { + body = process.env.translate_failed_message; + error = e; + } + + const { data: { id } } = await issues.createComment({ + owner, + repo, + issue_number, + body + }); + + if (error) { + throw error; + } + + await reactions.createForIssueComment({ + owner, + repo, + comment_id: id, + content: 'eyes' + }); diff --git a/.github/workflows/gh_licence_checks.yml b/.github/workflows/gh_licence_checks.yml new file mode 100644 index 00000000000..a8e55a942de --- /dev/null +++ b/.github/workflows/gh_licence_checks.yml @@ -0,0 +1,59 @@ +name: '[gh] pull request file license header checks' + +on: + workflow_dispatch: + inputs: + commit-from: + description: 'specify the start of commit hash' + required: true + commit-to: + description: 'specify the end of commit hash' + required: true + pull_request: + branches: + - master + - main + - v3.0-dev + - v3.0 + paths: + - '**.tsx?' + - '**.jsx?' + - '**.vue' + - '**.ejs' + - '**.mjs' + - '**.es6' + - '**.css' + - '**.less' + - '**.scss' + - '**.hh?' + - '**.hpp' + - '**.h\\+\\+' + - '**.hxx' + - '**.cc?' + - '**.c\\+\\+' + - '**.cpp' + - '**.C' + - '**.cxx' + - '**.mm?' + - '**.swift' + - '**.cmake' + - '**.java' + - '**.txt' + - '**.sh' + - '**.yaml' + - '**.bat' + - '**.dart' + - "**.py" + +jobs: + pull_request_license_checks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Check License or Date from github PR files + uses: zoomchan-cxj/actions-license@v0.1.0 + with: + config-path: .github/workflows/config/license-check.json + token: ${{ secrets.GITHUB_TOKEN }} + env: + FORCE_COLOR: 3 diff --git a/.github/workflows/gh_licence_checks_bypass.yml b/.github/workflows/gh_licence_checks_bypass.yml new file mode 100644 index 00000000000..f0f1e7c85f3 --- /dev/null +++ b/.github/workflows/gh_licence_checks_bypass.yml @@ -0,0 +1,46 @@ +name: '[gh] pull request file license header checks' + +on: + pull_request: + branches: + - master + - main + - v3.0-dev + - v3.0 + paths-ignore: + - '**.tsx?' + - '**.jsx?' + - '**.vue' + - '**.ejs' + - '**.mjs' + - '**.es6' + - '**.css' + - '**.less' + - '**.scss' + - '**.hh?' + - '**.hpp' + - '**.h\\+\\+' + - '**.hxx' + - '**.cc?' + - '**.c\\+\\+' + - '**.cpp' + - '**.C' + - '**.cxx' + - '**.mm?' + - '**.swift' + - '**.cmake' + - '**.java' + - '**.txt' + - '**.sh' + - '**.yaml' + - '**.bat' + - '**.dart' + - "**.py" + +jobs: + pull_request_license_checks: + runs-on: ubuntu-latest + steps: + - name: License checks Bypass + run: | + echo "No license checks required" diff --git a/.github/workflows/gh_mark_and_close_stalled.yml b/.github/workflows/gh_mark_and_close_stalled.yml new file mode 100644 index 00000000000..71cf4753d3a --- /dev/null +++ b/.github/workflows/gh_mark_and_close_stalled.yml @@ -0,0 +1,59 @@ +name: '[gh] mark and close stale issues and PRs' + +on: + workflow_dispatch: + schedule: + # Run every day at 19:00 UTC(03:00 UTC+08:00). + - cron: '0 19 * * *' + +env: + CLOSE_PR_MESSAGE: | + Sorry, closing this PR because it has stalled for over 4 months. + Feel free to reopen if this PR is still relevant, or to ping the collaborator if you have any questions. + CLOSE_ISSUE_MESSAGE: | + Sorry, closing this issue because it has stalled for over 3 months. + Feel free to reopen if this issue is still relevant, or to ping the collaborator if you have any questions. + STALE_PR_MESSAGE: | + Pay attention 🛎️ !! + There has been no activity on this PR for 2 months, so I will label it stalled. + It will be automatically closed in 30 days if no more activity. Feel free to leave a comment if you have any questions. + STALE_ISSUE_MESSAGE: | + Pay attention 🛎️ !! + There has been no activity on this issue for 2 months, so I will label it stalled. + It will be automatically closed in 60 days if no more activity. Feel free to leave a comment if you have any questions. + +jobs: + stale: + if: github.repository == 'Tencent/Hippy' + permissions: + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - uses: actions/stale@v6.0.1 + with: + repo-token: ${{ steps.get-token.outputs.token }} + # pr related + days-before-pr-stale: 60 + days-before-pr-close: 60 + stale-pr-message: ${{ env.STALE_PR_MESSAGE }} + close-pr-message: ${{ env.CLOSE_PR_MESSAGE }} + stale-pr-label: 'stale: 60d' + close-pr-label: 'stale: closed' + exempt-pr-labels: 'stale: never' + # issue related + days-before-issue-stale: 60 + days-before-issue-close: 30 + stale-issue-message: ${{ env.STALE_ISSUE_MESSAGE }} + close-issue-message: ${{ env.CLOSE_ISSUE_MESSAGE }} + stale-issue-label: 'stale: 30d' + close-issue-label: 'stale: closed' + exempt-issue-labels: 'stale: never' + # max requests it will send per run to the GitHub API before it deliberately exits to avoid hitting API rate limits + operations-per-run: 500 diff --git a/.github/workflows/gh_pr_auto_merger.yml b/.github/workflows/gh_pr_auto_merger.yml new file mode 100644 index 00000000000..2134bc70f12 --- /dev/null +++ b/.github/workflows/gh_pr_auto_merger.yml @@ -0,0 +1,206 @@ +name: '[gh] pull request auto merger' + +on: + workflow_run: + workflows: + - \[gh\] pull request review + types: [ completed ] + +env: + GREETINGS_MESSAGE: ':tada: It seems that this pull request has been approved by all required reviewers.' + AUTO_MERGE_MESSAGE: As it only contains one normal commit, I will rebase and merge it automatically via add `action(rebase-merge)` label. + MANUAL_MERGE_MESSAGE: But it has more than one normal commit, I will notify admin team member to merge it manually, please wait a moment. + MERGE_SHA_MESSAGE: | +
+ + * SHA: {0} + +
+ +jobs: + call_get_workflow_output: + if: github.repository == 'Tencent/Hippy' && github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success' + uses: ./.github/workflows/reuse_get_workflow_output.yml + with: + workflow_run: ${{ github.event.workflow_run.id }} + + get_decision: + needs: call_get_workflow_output + runs-on: ubuntu-latest + outputs: + review_decision: ${{ steps.decision.outputs.review_decision }} + pull_request_number: ${{ steps.parse_workflow_output.outputs.pull_request_number }} + pull_request_title: ${{ steps.parse_workflow_output.outputs.pull_request_title }} + pull_request_url: ${{ steps.parse_workflow_output.outputs.pull_request_url }} + pull_request_sha: ${{ steps.parse_workflow_output.outputs.pull_request_sha }} + steps: + - name: Parse + id: parse_workflow_output + env: + RAW: ${{ needs.call_get_workflow_output.outputs.raw }} + shell: python + run: | + import json + import os + + raw = os.getenv("RAW") + data = json.loads(raw) + with open(os.getenv("GITHUB_OUTPUT"), 'w', encoding='utf-8') as file: + file.write("review_state=%s\n" % data["review"]["state"]) + file.write("pull_request_number=%s\n" % data["pull_request"]["number"]) + file.write("pull_request_title=%s\n" % data["pull_request"]["title"]) + file.write("pull_request_url=%s\n" % data["pull_request"]["html_url"]) + file.write("pull_request_sha=%s\n" % data["pull_request"]["head"]["sha"]) + - name: Decision + id: decision + if: steps.parse_workflow_output.outputs.review_state == 'approved' + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + const os = require('os'); + + const query = `query($owner:String!, $repo:String!, $number:Int!) { + repository(name: $repo, owner: $owner) { + pullRequest(number: $number) { + reviewDecision + } + } + }`; + const variables = { + ...context.repo, + number: ${{ steps.parse_workflow_output.outputs.pull_request_number }} + }; + const { repository: { pullRequest: { reviewDecision } } } = await github.graphql(query, variables); + if (reviewDecision === 'APPROVED' || !reviewDecision) { + fs.appendFileSync(process.env.GITHUB_OUTPUT, `review_decision=APPROVED${os.EOL}`, { encoding: 'utf8' }); + } + + call_classify_commits: + needs: get_decision + if: needs.get_decision.outputs.review_decision == 'APPROVED' + uses: ./.github/workflows/reuse_classify_commits.yml + with: + pull_request_number: ${{ fromJSON(needs.get_decision.outputs.pull_request_number) }} + + auto_merge: + needs: [ get_decision, call_classify_commits ] + if: needs.call_classify_commits.outputs.normal_commits_count == 1 + runs-on: ubuntu-latest + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - name: Auto + uses: actions/github-script@v6 + env: + COMMENT_MESSAGE: ${{ env.GREETINGS_MESSAGE }} ${{ env.AUTO_MERGE_MESSAGE }} ${{ format(env.MERGE_SHA_MESSAGE, needs.get_decision.outputs.pull_request_sha) }} + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { issues } = github.rest; + + const comments = await github.paginate(issues.listComments, { + ...context.repo, + per_page: 100, + issue_number: ${{ needs.get_decision.outputs.pull_request_number }} + }); + if (comments.some((comment) => comment.body.includes(process.env.COMMENT_MESSAGE))) { + return; + } + + const p = []; + + p.push(issues.addLabels({ + ...context.repo, + issue_number: ${{ needs.get_decision.outputs.pull_request_number }}, + labels: [ 'action(rebase-merge)' ] + })); + + p.push(issues.createComment({ + ...context.repo, + issue_number: ${{ needs.get_decision.outputs.pull_request_number }}, + body: process.env.COMMENT_MESSAGE + })); + + await Promise.all(p); + + manual_merge: + needs: [ get_decision, call_classify_commits ] + if: needs.call_classify_commits.outputs.normal_commits_count > 1 || !needs.call_classify_commits.outputs.normal_commits_count + runs-on: ubuntu-latest + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - name: Manual + uses: actions/github-script@v6 + env: + WECHAT_WORK_MESSAGE: | + [#${{ needs.get_decision.outputs.pull_request_number }}](${{ needs.get_decision.outputs.pull_request_url }}) pull request is met merge requirements. + > ${{ needs.get_decision.outputs.pull_request_title }} + > %s normal commits ahead + COMMENT_MESSAGE: ${{ env.GREETINGS_MESSAGE }} ${{ env.MANUAL_MERGE_MESSAGE }} ${{ format(env.MERGE_SHA_MESSAGE, needs.get_decision.outputs.pull_request_sha) }} + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const util = require('util'); + const { issues } = github.rest; + + const comments = await github.paginate(issues.listComments, { + ...context.repo, + per_page: 100, + issue_number: ${{ needs.get_decision.outputs.pull_request_number }} + }); + if (comments.some((comment) => comment.body.includes(process.env.COMMENT_MESSAGE))) { + return; + } + + const p = []; + + p.push(issues.createComment({ + ...context.repo, + issue_number: ${{ needs.get_decision.outputs.pull_request_number }}, + body: process.env.COMMENT_MESSAGE + })); + + p.push(github.request("POST ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }}", { + headers: { + "content-type": "application/json" + }, + data: { + chatid: "${{ secrets.WECHAT_WORK_ADMIN_CHAT_ID }}", + msgtype: "markdown", + markdown: { + content: util.format(process.env.WECHAT_WORK_MESSAGE, (Number.parseInt("${{ needs.call_classify_commits.outputs.normal_commits_count }}") || Infinity).toLocaleString()), + attachments: [{ + callback_id: "merge", + actions: [{ + name: "merge_btn", + text: "Mark as Merged", + type: "button", + value: "Mark as Merged", + replace_text: "Already merged", + border_color: "2c974b", + text_color: "2c974b" + }, { + name: "ignore_btn", + text: "Mark as Ignored", + type: "button", + value: "Mark as Ignored", + replace_text: "Already ignored", + border_color: "6e7781", + text_color: "6e7781" + }] + }] + } + } + })); + + await Promise.all(p); diff --git a/.github/workflows/gh_pr_auto_updater.yml b/.github/workflows/gh_pr_auto_updater.yml new file mode 100644 index 00000000000..4b3da1afe61 --- /dev/null +++ b/.github/workflows/gh_pr_auto_updater.yml @@ -0,0 +1,64 @@ +name: '[gh] pull request auto updater' + +on: + pull_request_target: + types: + - auto_merge_enabled + push: + +jobs: + up_to_date: + if: github.repository == 'Tencent/Hippy' + runs-on: ubuntu-latest + steps: + - name: Updater + uses: actions/github-script@v6.3.3 + with: + # Because the Github App Token, Github Token, and Fine-grained PAT + # cannot obtain the permission to update the workflow files in the head branch, + # so use classic PAT to avoid failures caused by modification of workflow files. + # TODO: use Github App Token or Github Token if permission is granted in the future. + github-token: ${{ secrets.BOT_PAT }} + script: | + const { pulls, repos } = github.rest; + + let pull_requests; + switch (context.eventName) { + case 'push': { + pull_requests = (await github.paginate(pulls.list, { + per_page: 100, + state: 'open', + base: '${{ github.ref_name }}', + ...context.repo + })).filter(pull => pull.draft === false && pull.auto_merge); + break; + } + case 'pull_request_target': { + const { pull_request } = context.payload; + if (pull_request.draft === true) { + return; + } + pull_requests = [pull_request]; + break; + } + default: { + throw new Error(`Unsupported event name: ${context.eventName}`); + break; + } + } + + await Promise.all( + pull_requests.map(pull => + repos.compareCommitsWithBasehead({ + ...context.repo, + basehead: `${pull.base.label}...${pull.head.label}`, + }).then(({ data: comparison }) => { + if (comparison.behind_by > 0) { + return pulls.updateBranch({ + ...context.repo, + pull_number: pull.number + }).catch(error => console.error(error)); + } + }) + ) + ); diff --git a/.github/workflows/gh_pr_checks_approval.yml b/.github/workflows/gh_pr_checks_approval.yml new file mode 100644 index 00000000000..200f0186b27 --- /dev/null +++ b/.github/workflows/gh_pr_checks_approval.yml @@ -0,0 +1,123 @@ +name: '[gh] pull request checks approval' + +on: + pull_request_target: + branches: + - master + - main + - v3.0-dev + - v3.0 + types: [ opened, reopened ] + workflow_run: + workflows: + - \[gh\] pull request review + types: [ completed ] + +jobs: + pull_request_opened: + if: github.repository == 'Tencent/Hippy' && contains(github.event.action, 'opened') + outputs: + pull_request_number: ${{ github.event.pull_request.number }} + pull_request_head_sha: ${{ github.event.pull_request.head.sha }} + run: 'true' + runs-on: ubuntu-latest + steps: + - run: echo "Pull request opened" + + call_get_workflow_output: + if: github.repository == 'Tencent/Hippy' && github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success' + uses: ./.github/workflows/reuse_get_workflow_output.yml + with: + workflow_run: ${{ github.event.workflow_run.id }} + + pull_request_approved: + needs: call_get_workflow_output + if: needs.call_get_workflow_output.outputs.action == 'submitted' + outputs: + pull_request_number: ${{ steps.parse_workflow_output.outputs.pull_request_number }} + pull_request_head_sha: ${{ steps.parse_workflow_output.outputs.pull_request_head_sha }} + run: ${{ steps.parse_workflow_output.outputs.run }} + runs-on: ubuntu-latest + steps: + - name: Parse + id: parse_workflow_output + env: + RAW: ${{ needs.call_get_workflow_output.outputs.raw }} + shell: python + run: | + import json + import os + + raw = os.getenv("RAW") + data = json.loads(raw) + with open(os.getenv("GITHUB_OUTPUT"), 'w', encoding='utf-8') as file: + file.write('run=%s\n' % 'true' if data["review"]["state"] == 'approved' else 'false') + file.write("pull_request_number=%s\n" % data["pull_request"]["number"]) + file.write("pull_request_head_sha=%s\n" % data["pull_request"]["head"]["sha"]) + + call_approval_checks_run: + needs: [ pull_request_opened, pull_request_approved ] + if: always() && contains(needs.*.result, 'success') && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && contains(needs.*.outputs.run, 'true') + uses: ./.github/workflows/reuse_approve_checks_run.yml + with: + pull_request_number: ${{ fromJSON(needs.pull_request_opened.outputs.pull_request_number || needs.pull_request_approved.outputs.pull_request_number) }} + pull_request_head_sha: ${{ needs.pull_request_opened.outputs.pull_request_head_sha || needs.pull_request_approved.outputs.pull_request_head_sha }} + + checks_approval_comment: + needs: call_approval_checks_run + if: always() && needs.call_approval_checks_run.outputs.action_required == 'true' + runs-on: ubuntu-latest + env: + safety_changes_message: | + After a quick scan, I have approved workflow to run. + risky_changes_message: | + Sorry, due to risky changes, I can\'t approve workflow to run, our collaborators will handle it asap. + details_message: | +
+ + * SHA: ${{ needs.call_approval_checks_run.outputs.pull_request_head_sha }} + +
+ tips_message: | + :label: **New commits in this PR would not be tested automatically** until this pull request is reviewed by our collaborators. + :label: **No need to worry about the status of `merge_guard ` and `[gh] pull request merge guard / merge_guard (pull_request_target)` checks**, once this pull request is met merge requirements, it will be automatically converted to successful status. + steps: + - name: Message + id: generate_message + run: | + message="$${{ needs.call_approval_checks_run.outputs.included_risk_files == 'true' && 'risky_changes_message' || 'safety_changes_message' }}" + + echo "comment_message<> $GITHUB_OUTPUT + echo "$message" >> $GITHUB_OUTPUT + echo "$details_message" >> $GITHUB_OUTPUT + if [[ "${{ github.event.action }}" == *"opened"* ]]; then + echo >> $GITHUB_OUTPUT + echo "$tips_message" >> $GITHUB_OUTPUT + fi + echo "EOF" >> $GITHUB_OUTPUT + + echo "search_message<> $GITHUB_OUTPUT + echo "$message" >> $GITHUB_OUTPUT + echo "$details_message" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + - name: Find + uses: peter-evans/find-comment@v2.1.0 + id: find_comment + with: + issue-number: ${{ needs.call_approval_checks_run.outputs.pull_request_number }} + body-includes: ${{ steps.generate_message.outputs.search_message }} + direction: last + - name: Token + id: get-token + if: steps.find_comment.outputs.comment-id == '' + uses: navikt/github-app-token-generator@v1 + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - name: Comment + uses: peter-evans/create-or-update-comment@v2 + if: steps.get-token.outputs.token != '' + with: + token: ${{ steps.get-token.outputs.token }} + issue-number: ${{ needs.call_approval_checks_run.outputs.pull_request_number }} + body: ${{ steps.generate_message.outputs.comment_message }} diff --git a/.github/workflows/gh_pr_guide.yml b/.github/workflows/gh_pr_guide.yml new file mode 100644 index 00000000000..ed144105f3d --- /dev/null +++ b/.github/workflows/gh_pr_guide.yml @@ -0,0 +1,105 @@ +name: '[gh] pull request guide' + +on: + pull_request_target: + branches: + - master + - main + - v3.0-dev + - v3.0 + types: + - opened + issue_comment: + types: + - created + +jobs: + pull_request_greetings: + if: github.event.action == 'opened' && github.repository == 'Tencent/Hippy' + runs-on: ubuntu-latest + env: + MESSAGE: | + Hi, @${{ github.event.sender.login }}. Thanks for your PR! :clap: + + :label: You can leave a comment in this PR with **`#help`** tag when you need help (e.g. some status checks run failed due to internal issue), admin team members will help asap. + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - name: Greetings + uses: actions/github-script@v6.1.0 + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { owner, repo } = context.repo; + const { pull_request } = context.payload; + const { issues } = github.rest; + + await issues.createComment({ + owner, + repo, + issue_number: pull_request.number, + body: process.env.MESSAGE, + }); + + pull_request_help_needed: + if: github.event.sender.type == 'User' && github.event.issue.pull_request && contains(github.event.comment.body, '#help') && github.repository == 'Tencent/Hippy' + runs-on: ubuntu-latest + env: + MESSAGE: | + [${{ github.event.sender.login }}](https://github.com/${{ github.event.sender.login }}) needs help on [#${{ github.event.issue.number }}](${{ github.event.comment.html_url }}) pull request. + > [${{ github.event.comment.html_url }}](${{ github.event.comment.html_url }}) + > ${{ github.event.comment.body }} + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - name: Action + uses: actions/github-script@v6.3.3 + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { owner, repo } = context.repo; + const { issue } = context.payload; + const { issues } = github.rest; + + const p = []; + + p.push(issues.addLabels({ + issue_number: issue.number, + labels: [ 'need: help' ], + ...context.repo, + })); + + p.push(github.request("POST ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }}", { + headers: { + "content-type": "application/json" + }, + data: { + chatid: "${{ secrets.WECHAT_WORK_ADMIN_CHAT_ID }}", + msgtype: "markdown", + markdown: { + content: process.env.MESSAGE, + attachments: [{ + callback_id: "help_needed", + actions: [{ + name: "help_needed_btn", + text: "Mark as Resolved", + type: "button", + value: "Mark as Resolved", + replace_text: "Already resolved", + border_color: "2c974b", + text_color: "2c974b" + }] + }] + } + } + })); + + await Promise.all(p); diff --git a/.github/workflows/gh_pr_labeler.yml b/.github/workflows/gh_pr_labeler.yml new file mode 100644 index 00000000000..84af239cb84 --- /dev/null +++ b/.github/workflows/gh_pr_labeler.yml @@ -0,0 +1,34 @@ +name: '[gh] pull request labeler' + +on: + pull_request_target: + branches: + - master + - main + - v3.0-dev + - v3.0 + types: + - opened + - reopened + - synchronize + +permissions: + contents: read + pull-requests: write + +jobs: + basic_info_labeler: + if: github.repository == 'Tencent/Hippy' && contains(fromJSON('[''opened'', ''reopened'', ''synchronize'']'), github.event.action) + runs-on: ubuntu-latest + steps: + - name: Path + uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: ".github/workflows/config/pr-path-labeler.yml" + sync-labels: true + - name: Size + uses: julrocas/pr-size-labeler@v1.0 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: ".github/workflows/config/pr-size-labeler.yml" diff --git a/.github/workflows/gh_pr_merge_guard.yml b/.github/workflows/gh_pr_merge_guard.yml new file mode 100644 index 00000000000..da11b5eaa8e --- /dev/null +++ b/.github/workflows/gh_pr_merge_guard.yml @@ -0,0 +1,34 @@ +name: '[gh] pull request merge guard' + +on: + pull_request_target: + types: + - auto_merge_enabled + - auto_merge_disabled + - synchronize + +jobs: + merge_guard: + if: github.repository == 'Tencent/Hippy' + runs-on: ubuntu-latest + steps: + - name: Goalkeeper + env: + AUTO_MERGE_ENABLED: ${{ !!github.event.pull_request.auto_merge }} + AUTO_MERGE_USER: ${{ github.event.pull_request.auto_merge.enabled_by.login }} + AUTO_MERGE_TYPE: ${{ github.event.pull_request.auto_merge.enabled_by.type }} + run: | + if [[ "$AUTO_MERGE_ENABLED" == "false" ]]; then + echo "Auto-merge is disabled." + echo "> Blocking ..." + exit -1 + fi + + echo "Auto-merge is enabled by a $AUTO_MERGE_USER." + if [[ "$AUTO_MERGE_TYPE" == "Bot" ]]; then + echo "> Passing ..." + exit 0 + else + echo "> Blocking ..." + exit -1 + fi diff --git a/.github/workflows/gh_pr_review.yml b/.github/workflows/gh_pr_review.yml new file mode 100644 index 00000000000..beeddb67c8f --- /dev/null +++ b/.github/workflows/gh_pr_review.yml @@ -0,0 +1,21 @@ +name: '[gh] pull request review' + +on: + pull_request_review: + types: [ submitted, edit ] + +jobs: + pull_request_review: + if: github.repository == 'Tencent/Hippy' + runs-on: ubuntu-latest + steps: + - name: Commit + env: + DATA: ${{ toJSON(github.event) }} + run: | + echo $DATA > ./data + - name: Push + uses: actions/upload-artifact@v3 + with: + name: data + path: ./data diff --git a/.github/workflows/gh_pr_review_notification.yml b/.github/workflows/gh_pr_review_notification.yml new file mode 100644 index 00000000000..066965c6abc --- /dev/null +++ b/.github/workflows/gh_pr_review_notification.yml @@ -0,0 +1,196 @@ +name: '[gh] pull review notification' + +on: + pull_request_target: + types: [ review_requested ] + workflow_run: + workflows: + - \[gh\] pull request review + types: [ completed ] + workflow_dispatch: + schedule: + # Run every day at 23:30 UTC(07:30 UTC+08:00). + - cron: '30 23 * * *' + +jobs: + request_notification: + if: github.repository == 'Tencent/Hippy' && github.event.action == 'review_requested' && github.event.requested_reviewer.type == 'User' + runs-on: ubuntu-latest + steps: + - name: Notice + uses: actions/github-script@v6.3.3 + env: + MESSAGE: | + [${{ github.event.sender.login }}](https://github.com/${{ github.event.sender.login }}) requested your review on [#${{ github.event.pull_request.number }}](${{ github.event.pull_request.html_url }}) pull request. + > ${{ github.event.pull_request.title }} + > [${{ github.event.pull_request.html_url }}](${{ github.event.pull_request.html_url }}) + > [%s changed files](${{ github.event.pull_request.html_url }}/files) with %s additions and %s deletions + + <@%s> + WECHAT_WORK_USERS: ${{ secrets.WECHAT_WORK_USERS }} + with: + script: | + const { format } = require("util"); + + const userid = JSON.parse(process.env.WECHAT_WORK_USERS)["${{ github.event.requested_reviewer.login }}"]; + if (!userid) { + console.log("The reviewer ${{ github.event.requested_reviewer.login }} not found in secrets.WECHAT_WORK_USERS"); + return; + } + + await github.request("POST ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }}", { + headers: { + "content-type": "application/json" + }, + data: { + chatid: "${{ secrets.WECHAT_WORK_CHAT_ID }}", + visible_to_user: userid, + msgtype: "markdown", + markdown: { + content: format(process.env.MESSAGE, (${{ github.event.pull_request.changed_files }}).toLocaleString(), (${{ github.event.pull_request.additions }}).toLocaleString(), (${{ github.event.pull_request.deletions }}).toLocaleString(), userid), + attachments: [{ + callback_id: "review", + actions: [{ + name: "review_btn", + text: "Mark as Reviewed", + type: "button", + value: "Mark as Reviewed", + replace_text: "Already reviewed", + border_color: "2c974b", + text_color: "2c974b" + }, { + name: "ignore_btn", + text: "Mark as Ignored", + type: "button", + value: "Mark as Ignored", + replace_text: "Already ignored", + border_color: "6e7781", + text_color: "6e7781" + }] + }] + } + } + }); + + call_get_workflow_output: + if: github.repository == 'Tencent/Hippy' && github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success' + uses: ./.github/workflows/reuse_get_workflow_output.yml + with: + workflow_run: ${{ github.event.workflow_run.id }} + + changes_requested_comment: + needs: call_get_workflow_output + if: needs.call_get_workflow_output.outputs.action == 'submitted' + runs-on: ubuntu-latest + env: + MESSAGE: | + Hi, @{0}, I noticed that our reviewers requested changes to this pull request. + When you're done, **click the `Re-request review` button in the right sidebar(shown below)** to notify the reviewer. + ![Re-request review button in the right sidebar](https://docs.github.com/assets/cb-4714/images/help/pull_requests/request-re-review.png) + steps: + - name: Parse + id: parse_workflow_output + env: + RAW: ${{ needs.call_get_workflow_output.outputs.raw }} + shell: python + run: | + import json + import os + + raw = os.getenv("RAW") + data = json.loads(raw) + with open(os.getenv("GITHUB_OUTPUT"), 'w', encoding='utf-8') as file: + file.write("review_state=%s\n" % data["review"]["state"]) + file.write("pull_request_number=%s\n" % data["pull_request"]["number"]) + file.write("pull_request_user=%s\n" % data["pull_request"]["user"]["login"]) + - name: Find + id: find_comment + if: steps.parse_workflow_output.outputs.review_state == 'changes_requested' + uses: peter-evans/find-comment@v2.1.0 + with: + issue-number: ${{ steps.parse_workflow_output.outputs.pull_request_number }} + body-includes: ${{ format(env.MESSAGE, steps.parse_workflow_output.outputs.pull_request_user) }} + - name: Token + id: get-token + if: steps.find_comment.outputs.comment-id == '' && steps.parse_workflow_output.outputs.review_state == 'changes_requested' + uses: navikt/github-app-token-generator@v1 + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - name: Comment + uses: peter-evans/create-or-update-comment@v2 + if: steps.get-token.outputs.token != '' + with: + token: ${{ steps.get-token.outputs.token }} + issue-number: ${{ steps.parse_workflow_output.outputs.pull_request_number }} + body: ${{ format(env.MESSAGE, steps.parse_workflow_output.outputs.pull_request_user) }} + reactions: eyes + + requested_reviewers_notification: + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + steps: + - name: Notice + uses: actions/github-script@v6.3.3 + env: + WECHAT_WORK_USERS: ${{ secrets.WECHAT_WORK_USERS }} + with: + script: | + const { pulls } = github.rest; + const os = require('os'); + + const pull_requests = (await github.paginate(pulls.list, { + per_page: 100, + state: 'open', + ...context.repo + })).filter(pull => pull.draft === false); + + const requested_reviewers = await Promise.all( + pull_requests.map( + pull => pulls.listRequestedReviewers({ + per_page: 100, + pull_number: pull.number, + ...context.repo + }).then(({ data }) => data) + ) + ); + + if (pull_requests.length !== requested_reviewers.length) { + throw new Error("The length of pull_requests and requested_reviewers is not equal"); + } + + const wechat_work_users = JSON.parse(process.env.WECHAT_WORK_USERS); + const notification_users = {}; + + pull_requests.forEach((pull, index) => { + requested_reviewers[index].users.forEach(reviewer => { + if (reviewer.type === 'User') { + const user_id = wechat_work_users[reviewer.login]; + if (user_id) { + (notification_users[user_id] ||= []).push(pull); + } + } + }); + }); + + await Promise.all(Object.entries(notification_users).map(([user_id, pulls]) => { + const content = []; + content.push(`${pulls.length} pull requests are waiting on your review.`); + content.push(...pulls.map(pull => `> [#${pull.number}](${pull.html_url}) ${pull.title}`)); + content.push(''); + content.push(`<@${user_id}>`); + + return github.request("POST ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }}", { + headers: { + "content-type": "application/json" + }, + data: { + chatid: "${{ secrets.WECHAT_WORK_CHAT_ID }}", + visible_to_user: user_id, + msgtype: "markdown", + markdown: { + content: content.join(os.EOL) + } + } + }); + })); diff --git a/.github/workflows/gh_runners_monitor.yml b/.github/workflows/gh_runners_monitor.yml new file mode 100644 index 00000000000..291acd288ac --- /dev/null +++ b/.github/workflows/gh_runners_monitor.yml @@ -0,0 +1,95 @@ +name: '[gh] self-hosted runners monitor' + +on: + workflow_dispatch: + schedule: + # Run every 30th minute. + - cron: '*/30 * * * *' + +jobs: + runners_monitor: + if: github.repository == 'Tencent/Hippy' + runs-on: ubuntu-latest + env: + cache_file: /tmp/gh_runners_monitor.data + cache_key: gh_runners_monitor + steps: + - name: Token + uses: navikt/github-app-token-generator@v1 + id: get-token + with: + private-key: ${{ secrets.BOT_APP_KEY }} + app-id: ${{ secrets.BOT_APP_ID }} + - name: Check + id: check + uses: actions/github-script@v6.3.3 + with: + github-token: ${{ steps.get-token.outputs.token }} + script: | + const { actions } = github.rest; + const os = require('os'); + const fs = require('fs'); + + const runners = await github.paginate(actions.listSelfHostedRunnersForRepo, { + per_page: 100, + ...context.repo + }); + const offline_runners = runners.filter(runner => runner.status === 'offline'); + + if (offline_runners.length > 0) { + fs.appendFileSync(process.env.GITHUB_OUTPUT, `total_runners=${runners.length}${os.EOL}`, { encoding: 'utf8' }); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `offline_runners=${JSON.stringify(offline_runners)}${os.EOL}`, { encoding: 'utf8' }); + } + - name: Cache + if: steps.check.outputs.offline_runners + uses: actions/cache@v3 + env: + prefix: gh_runners_monitor + with: + path: ${{ env.cache_file }} + key: ${{ env.prefix }}-${{ github.run_id }} + restore-keys: ${{ env.prefix }} + - name: Notification + if: steps.check.outputs.offline_runners + uses: actions/github-script@v6.3.3 + env: + offline_runners: ${{ steps.check.outputs.offline_runners }} + with: + script: | + const fs = require('fs'); + const os = require('os'); + + const offline_runners = JSON.parse(process.env.offline_runners); + if (offline_runners.length === 0) { + throw new Error('offline_runners is empty'); + } + + const message = [ + `${offline_runners.length}/${{ steps.check.outputs.total_runners }} self-hosted runners are offline.`, + ...offline_runners.map(runner => `> ${runner.name}`) + ].join(os.EOL); + + try { + const stored_data = JSON.parse(fs.readFileSync(process.env.cache_file, { encoding: 'utf8'})); + if (stored_data.message === message && Date.now() - stored_data.timestamp < 6_60_60_000 /* every 6th hour */) { + return; + } + } catch(e) {} + + await github.request("POST ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }}", { + headers: { + "content-type": "application/json" + }, + data: { + chatid: "${{ secrets.WECHAT_WORK_ADMIN_CHAT_ID }}", + msgtype: "markdown", + markdown: { + content: message + } + } + }); + + fs.writeFileSync(process.env.cache_file, JSON.stringify({ + message, + timestamp: Date.now() + }), { encoding: 'utf8' }); diff --git a/.github/workflows/gh_webhook_retrier.yml b/.github/workflows/gh_webhook_retrier.yml new file mode 100644 index 00000000000..d7c2205f6da --- /dev/null +++ b/.github/workflows/gh_webhook_retrier.yml @@ -0,0 +1,74 @@ +name: '[gh] webhook retrier' + +on: + workflow_dispatch: + schedule: + # Run every 10th minute. + - cron: '*/10 * * * *' + +jobs: + webhook_retrier: + if: github.repository == 'Tencent/Hippy' + runs-on: ubuntu-latest + steps: + - name: Action + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.BOT_PAT }} + script: | + const { repos } = github.rest; + const os = require('os'); + const fs = require('fs'); + + const per_page = 100; + + const hooks = (await github.paginate(repos.listWebhooks, { + per_page, + ...context.repo + })).filter((hook) => hook.last_response && hook.active); + + const retriedDeliveries = (await Promise.all(hooks.map((hook) => repos.listWebhookDeliveries({ + per_page, + ...context.repo, + hook_id: hook.id + })))).map(({ data: deliveries }) => { + const indexed = {}; + const failedList = new Set(); + deliveries.forEach((delivery) => { + (indexed[delivery.guid] ||= []).push(delivery); + if (delivery.status != 'OK') { + failedList.add(delivery.guid); + } + }); + + return Array.from(failedList).filter((guid) => { + const failedGroup = indexed[guid]; + return failedGroup.every((delivery) => delivery.status != 'OK') && failedGroup.length <= 4; // maximum attempts(origin included) + }).map((guid) => indexed[guid][0]); + }); + + (await Promise.all(retriedDeliveries.map((deliveries, hooksIndex) => + Promise.allSettled(deliveries.map((delivery) => + repos.redeliverWebhookDelivery({ + ...context.repo, + hook_id: hooks[hooksIndex].id, + delivery_id: delivery.id + }) + )) + ))).forEach((results, hooksIndex) => { + if (results.length > 0) { + const summary = []; + + const hook = hooks[hooksIndex]; + summary.push(`## ${hook.config.url} (#${hook.id})`); + summary.push('| guid | event | action | redelivery |'); + summary.push('| ---- | ----- | ------ | ---------- |'); + results.forEach((result, deliveriesIndex) => { + const delivery = retriedDeliveries[hooksIndex][deliveriesIndex]; + summary.push(`| ${delivery.guid} | ${delivery.event} | ${delivery.action || ''} | ${result.status === 'fulfilled' ? ':white_check_mark:' : ':x:'} |`); + }); + summary.push(os.EOL); + + fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary.join(os.EOL), { encoding: 'utf8' }); + } + }); diff --git a/.github/workflows/git_commit_lint.yml b/.github/workflows/git_commit_lint.yml new file mode 100644 index 00000000000..6bccc142297 --- /dev/null +++ b/.github/workflows/git_commit_lint.yml @@ -0,0 +1,23 @@ +name: '[git] commit message format lint' + +on: [ pull_request ] + +jobs: + commitlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: setup-node + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: 'npm' + cache-dependency-path: package-lock.json + - name: Install + run: | + npm install commitlint-plugin-function-rules@1.6.0 @commitlint/cli@16.2.1 @commitlint/config-conventional@16.2.1 @commitlint/lint@16.2.1 @commitlint/prompt-cli@16.2.1 + - name: commitlint + run: | + npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose diff --git a/.github/workflows/hip_archive_artifact.yml b/.github/workflows/hip_archive_artifact.yml new file mode 100644 index 00000000000..4f36e1a0ed2 --- /dev/null +++ b/.github/workflows/hip_archive_artifact.yml @@ -0,0 +1,115 @@ +name: '[hip] archive artifact' + +on: + workflow_dispatch: + inputs: + source_type: + description: 'Type of source' + type: choice + options: + - Git + - URL + default: 'URL' + required: true + source_url: + description: 'URL or Git ' + type: string + required: true + git_revision: + description: 'Git ref(only Git source available)' + type: string + required: false + hip_domain: + description: 'HIP ' + type: choice + options: + - hippy + - test + default: 'hippy' + required: true + hip_artifact_path: + description: 'HIP artifact (without domain)' + type: string + required: true + hip_writing_mode: + description: 'HIP writing mode' + type: choice + options: + - preserve + - overwrite + default: 'preserve' + required: true + +jobs: + archive_artifact: + runs-on: ubuntu-latest + steps: + - name: Git clone + if: github.event.inputs.source_type == 'Git' + id: git-clone + shell: bash + run: | + name=$(basename ${{ github.event.inputs.hip_artifact_path }}) + if [[ $name != *.tgz ]]; then + echo 'In `Git` source type, must be end with |.tgz|' + exit -1 + fi + git clone ${{ github.event.inputs.source_url }} artifact + pushd artifact + git checkout ${{ github.event.inputs.git_revision }} + echo "git-head=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + rm -rf .git + popd + tar -zcvf $name -C artifact . + - name: URL fetch + if: github.event.inputs.source_type == 'URL' + shell: bash + run: | + wget ${{ github.event.inputs.source_url }} -O $(basename ${{ github.event.inputs.hip_artifact_path }}) + - name: Install Requirement + shell: bash + run: | + pip install -U cos-python-sdk-v5 + - name: Publish artifact + shell: python + run: | + from qcloud_cos import CosConfig + from qcloud_cos import CosS3Client + from urllib.parse import urlencode + import hashlib + import os + + artifact = os.path.basename("${{ github.event.inputs.hip_artifact_path }}") + + metadata = {} + metadata["ci-name"] = "Github Action" + metadata["ci-id"] = "${{ github.run_id }}" + metadata["source-type"] = "${{ github.event.inputs.source_type }}" + metadata["source-url"] = "${{ github.event.inputs.source_url }}" + metadata["artifact-publisher"] = "${{ github.event.sender.login }}" + with open(artifact, "rb") as artifact_file: + metadata["artifact-md5"] = hashlib.md5(artifact_file.read()).hexdigest() + if "${{ github.event.inputs.source_type }}" == "Git": + metadata["git-revision"] = "${{ github.event.inputs.git_revision }}" + metadata["git-head"] = "${{ steps.git-clone.outputs.git-head }}" + + config = CosConfig(Region="${{ secrets.COS_REGION }}", SecretId="${{ secrets.TC_SECRET_ID }}", SecretKey="${{ secrets.TC_SECRET_KEY }}") + client = CosS3Client(config) + + cos_key = "${{ github.event.inputs.hip_domain }}/${{ github.event.inputs.hip_artifact_path }}" + + if "${{ github.event.inputs.hip_writing_mode }}" == "preserve" and client.object_exists( + Bucket="${{ secrets.COS_BUCKET }}", + Key=cos_key + ): + raise Exception("Package already exists") + + response = client.upload_file( + Bucket="${{ secrets.COS_BUCKET }}", + Key=cos_key, + LocalFilePath=artifact, + EnableMD5=True, + ContentMD5=metadata["artifact-md5"], + Metadata={"x-cos-tagging": urlencode(metadata)} + ) + print("ETag: " + response["ETag"]) diff --git a/.github/workflows/hip_info_artifacts.yml b/.github/workflows/hip_info_artifacts.yml new file mode 100644 index 00000000000..21a7e41bd96 --- /dev/null +++ b/.github/workflows/hip_info_artifacts.yml @@ -0,0 +1,72 @@ +name: '[hip] info artifacts' + +on: + workflow_dispatch: + inputs: + hip_domain: + description: 'HIP ' + type: choice + options: + - hippy + - test + default: 'hippy' + required: true + hip_path: + description: 'HIP (without domain)' + type: string + required: false + +jobs: + info_artifacts: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Install Requirement + run: | + pip install -U cos-python-sdk-v5 + - name: Info artifact + shell: python + run: | + from qcloud_cos import CosConfig, CosS3Client + from os import getenv + + def sizeof_fmt(num): + if num == 0: + return "" + for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]: + if abs(num) < 1024.0: + return f"{num:3.1f}{unit}" + num /= 1024.0 + return f"{num:.1f}Yi" + + config = CosConfig(Region="${{ secrets.COS_REGION }}", SecretId="${{ secrets.TC_SECRET_ID }}", SecretKey="${{ secrets.TC_SECRET_KEY }}") + client = CosS3Client(config) + + path = "${{ github.event.inputs.hip_domain }}/${{ github.event.inputs.hip_path }}" + + if path.endswith("/") or path.endswith("\\"): + response = client.list_objects( + Bucket="${{ secrets.COS_BUCKET }}", + Prefix=path + ) + + with open(getenv("GITHUB_STEP_SUMMARY"), 'w', encoding='utf-8') as file: + file.write("Root Path: %s\n" % path) + file.write("| File | Size | LastModified |\n") + file.write("|------|------|------|\n") + for object in response["Contents"]: + file.write("| %s | %s | %s |\n" % (object["Key"], sizeof_fmt(int(object["Size"])), object["LastModified"])) + else: + response = client.get_object_tagging( + Bucket="${{ secrets.COS_BUCKET }}", + Key=path + ) + + with open(getenv("GITHUB_STEP_SUMMARY"), 'w', encoding='utf-8') as file: + file.write("File Path: %s\n" % path) + file.write("| TAG Key | TAG Value |\n") + file.write("|------|------|\n") + for tag in response["TagSet"]["Tag"]: + file.write("| %s | %s |\n" % (tag["Key"], tag["Value"])) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml deleted file mode 100644 index d535f73c6ff..00000000000 --- a/.github/workflows/ios.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: '[iOS] build iOS native example' - -on: - push: - paths: - - 'ios/**' - branches: - # Push events on main branch - - main - # Push events on master branch - - master - tags-ignore: - - '**' - pull_request: - paths: - - 'ios/**' - branches: - # Pull request events to main branch - - main - # Pull request events to master branch - - master - tags-ignore: - - '**' - -jobs: - buildios: - runs-on: macOS-11 - steps: - - uses: actions/checkout@v2 - - name: buildexample - run: | - # https://github.com/actions/virtual-environments/issues/4180 - # Xcode_13 will be selected on October, 18, so we need to set to xcode13 manually before that day. - sudo xcode-select --switch '/Applications/Xcode_13.0.app/' - pushd examples/ios-demo && xcodebuild build -destination 'name=iPhone 11' -scheme 'HippyDemo' && popd diff --git a/.github/workflows/ios_build_tests.yml b/.github/workflows/ios_build_tests.yml new file mode 100644 index 00000000000..d5c2f7fa5c5 --- /dev/null +++ b/.github/workflows/ios_build_tests.yml @@ -0,0 +1,45 @@ +name: '[ios] build tests' + +on: + pull_request: + branches: + - master + - main + - v3.0-dev + - v3.0 + paths: + - 'framework/ios/**' + - 'framework/examples/ios-demo/**' + - 'driver/js/src/**' + - 'driver/js/include/**' + - 'dom/include/**' + - 'dom/src/**' + - 'layout/engine/**' + - 'modules/ios/**' + - 'modules/footstone/**' + - 'modules/vfs/ios/**' + - 'modules/vfs/native/**' + - 'renderer/native/ios/**' + - 'devtools/devtools-backend/**' + - 'hippy.podspec' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + ios_build_tests: + runs-on: macos-latest + strategy: + matrix: + type: [Debug, Release] + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + lfs: true + - name: Demo + working-directory: framework/examples/ios-demo + run: | + pod install + xcodebuild build -destination "generic/platform=iOS" -workspace "HippyDemo.xcworkspace" -scheme "HippyDemo" -configuration ${{matrix.type}} CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO diff --git a/.github/workflows/ios_build_tests_bypass.yml b/.github/workflows/ios_build_tests_bypass.yml new file mode 100644 index 00000000000..d3b0cc355dc --- /dev/null +++ b/.github/workflows/ios_build_tests_bypass.yml @@ -0,0 +1,39 @@ +name: '[ios] build tests' + +on: + pull_request: + branches: + - master + - main + - v3.0-dev + - v3.0 + paths-ignore: + - 'framework/ios/**' + - 'framework/examples/ios-demo/**' + - 'driver/js/src/**' + - 'driver/js/include/**' + - 'dom/include/**' + - 'dom/src/**' + - 'layout/engine/**' + - 'modules/ios/**' + - 'modules/footstone/**' + - 'modules/vfs/ios/**' + - 'modules/vfs/native/**' + - 'renderer/native/ios/**' + - 'devtools/devtools-backend/**' + - 'hippy.podspec' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + ios_build_tests: + runs-on: ubuntu-latest # use ubuntu to replace macos in order to save macos resources and improve efficiency + strategy: + matrix: + type: [Debug, Release] + steps: + - name: Build Test Bypass + run: | + echo "No build test required" diff --git a/.github/workflows/project_artifact_compare.yml b/.github/workflows/project_artifact_compare.yml new file mode 100644 index 00000000000..bdb37c8c999 --- /dev/null +++ b/.github/workflows/project_artifact_compare.yml @@ -0,0 +1,158 @@ +name: "[project] artifact compare" + +on: + workflow_dispatch: + inputs: + git_ref_a: + description: 'Git Ref A' + type: string + required: true + git_ref_b: + description: 'Git Ref B(contrast)' + type: string + required: false + is_compare_for_android: + description: 'Compare for Android artifact' + type: boolean + default: true + required: true + is_compare_for_ios: + description: 'Compare for iOS artifact' + type: boolean + default: true + required: true + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + android: + if: ${{ github.event.inputs.is_compare_for_android == 'true' }} + runs-on: ${{ github.repository == 'Tencent/Hippy' && fromJson('[''self-hosted'', ''linux'', ''shared'']') || 'ubuntu-latest' }} + container: + image: ghcr.io/tencent/android-release:latest # repository name must be lowercase(${{ github.repository_owner }}) + strategy: + matrix: + ref: ${{ fromJSON(format('[''{0}'', ''{1}'']', github.event.inputs.git_ref_a, github.event.inputs.git_ref_b)) }} + include: + - ref: ${{ github.event.inputs.git_ref_a }} + source: ref_a + - ref: ${{ github.event.inputs.git_ref_b }} + source: ref_b + defaults: + run: + shell: bash + outputs: + ref_a: ${{ steps.get_size.outputs.ref_a }} + ref_b: ${{ steps.get_size.outputs.ref_b }} + artifact: Android(android-sdk.aar) + steps: + - name: Checkout + if: ${{ matrix.ref }} + uses: actions/checkout@v3 + with: + ref: ${{ matrix.ref }} + lfs: true + - name: Build + if: ${{ matrix.ref }} + run: | + ./gradlew assembleRelease -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + - name: Size + id: get_size + run: | + if [[ "${{ matrix.ref }}" ]]; then + echo "${{ matrix.source }}=$(ls -l ./framework/android/build/outputs/aar/android-sdk.aar | awk '{print $5}')" >> $GITHUB_OUTPUT + else + echo "${{ matrix.source }}=-1" >> $GITHUB_OUTPUT + fi + + ios: + if: ${{ github.event.inputs.is_compare_for_ios == 'true' }} + runs-on: macos-latest + strategy: + matrix: + ref: ${{ fromJSON(format('[''{0}'', ''{1}'']', github.event.inputs.git_ref_a, github.event.inputs.git_ref_b)) }} + include: + - ref: ${{ github.event.inputs.git_ref_a }} + source: ref_a + - ref: ${{ github.event.inputs.git_ref_b }} + source: ref_b + outputs: + ref_a: ${{ steps.get_size.outputs.ref_a }} + ref_b: ${{ steps.get_size.outputs.ref_b }} + artifact: iOS(libhippy.a) + steps: + - name: Checkout + if: ${{ matrix.ref }} + uses: actions/checkout@v3 + with: + ref: ${{ matrix.ref }} + lfs: true + - name: Build + if: ${{ matrix.ref }} + run: | + pushd framework/examples/ios-demo + pod install + xcodebuild build \ + -destination 'generic/platform=iOS' \ + -project 'Pods/hippy.xcodeproj' \ + -scheme 'hippy' \ + -configuration 'Release' \ + CODE_SIGN_IDENTITY="" + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + - name: Size + id: get_size + run: | + pushd framework/examples/ios-demo + if [[ "${{ matrix.ref }}" ]]; then + echo "${{ matrix.source }}=$(ls -l $(xcodebuild -project 'Pods/hippy.xcodeproj' -showBuildSettings | grep -m 1 TARGET_BUILD_DIR | grep -oEi "\/.*")/libhippy.a | awk '{print $5}')" >> $GITHUB_OUTPUT + else + echo "${{ matrix.source }}=-1" >> $GITHUB_OUTPUT + fi + + collector: + needs: [ android, ios ] + if: ${{ always() && contains(needs.*.result, 'success') && !(contains(needs.*.result, 'failure')) }} + runs-on: ubuntu-latest + steps: + - name: Summary + shell: python + run: | + from os import getenv + from json import loads + + def sizeof_fmt(num): + if num == 0: + return "0" + for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]: + if abs(num) < 1024.0: + return f"{num:3.2f}{unit}" + num /= 1024.0 + return f"{num:.1f}Yi" + + def delta(a, b): + num = a - b + return "$$\color{%s}{%s%s (%s)}$$" % ("red" if num > 0 else "green", "+" if num > 0 else "", sizeof_fmt(num), "%.2f\\\\%%" % abs(num / a * 100)) + + json = loads("""${{ toJSON(needs.*.outputs) }}""") + with open(getenv("GITHUB_STEP_SUMMARY"), 'w', encoding='utf-8') as file: + for result in json: + if "artifact" in result: + ref_a = int(result["ref_a"]) + ref_b = int(result["ref_b"]) + if ref_a > 0 and ref_b > 0: + file.write("## %s Artifact Compare\n" % result["artifact"]) + file.write("| Ref | Size | Delta |\n") + file.write("|------|------|-------|\n") + file.write("| %s | %s | %s |\n" % ("${{ github.event.inputs.git_ref_a }}", sizeof_fmt(ref_a), delta(ref_a, ref_b))) + file.write("| %s | %s | %s |\n" % ("${{ github.event.inputs.git_ref_b }}", sizeof_fmt(ref_b), delta(ref_b, ref_a))) + file.write("\n") + elif ref_a > 0: + ref_a = int(result["ref_a"]) + file.write("## %s Artifact\n" % result["artifact"]) + file.write("| Ref | Size |\n") + file.write("|------|------|\n") + file.write("| %s | %s |\n" % ("${{ github.event.inputs.git_ref_a }}", sizeof_fmt(ref_a))) + file.write("\n") diff --git a/.github/workflows/project_artifact_release.yml b/.github/workflows/project_artifact_release.yml new file mode 100644 index 00000000000..990e47747a1 --- /dev/null +++ b/.github/workflows/project_artifact_release.yml @@ -0,0 +1,213 @@ +name: '[project] artifact release' + +on: + workflow_dispatch: + inputs: + git_ref: + description: 'Git Ref' + type: string + required: true + version_name: + description: 'Version name' + type: string + required: true + registry_choice: + description: 'Registry choice' + type: choice + required: true + default: 'Both' + options: + - Default + - Github + - Both + is_release_for_android: + description: 'Release for Android' + type: boolean + default: true + required: false + is_release_for_ios: + description: 'Release for iOS' + type: boolean + default: true + required: false + is_release_for_js: + description: 'Release for JS' + type: boolean + default: true + required: false + js_npm_dist_tag_name: + description: 'NPM dist tag name to release' + type: string + required: false + is_npm_version_to_latest_tag: + description: 'Set current version to npm latest tag' + type: boolean + default: true + required: false + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + context_in_lowercase: + if: github.event.inputs.is_release_for_android == 'true' + runs-on: ubuntu-latest + outputs: + repository_owner: ${{ steps.get_owner.outputs.lowercase }} + steps: + - name: Get repo owner(in lowercase) + id: get_owner + uses: ASzc/change-string-case-action@v2 + with: + string: ${{ github.repository_owner }} + + android_release: + if: github.event.inputs.is_release_for_android == 'true' + needs: context_in_lowercase + runs-on: ubuntu-latest + strategy: + matrix: + build_type: [Debug, Release] + include: + - build_type: Debug + artifact_id: hippy-debug + - build_type: Release + artifact_id: hippy-release + container: + image: ghcr.io/${{ needs.context_in_lowercase.outputs.repository_owner }}/android-release:latest + steps: + - name: Checkout (${{ github.event.inputs.git_ref }}) + uses: actions/checkout@v3 + with: + ref: ${{ github.event.inputs.git_ref }} + lfs: true + - name: ${{ matrix.build_type }} build + env: + SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }} + SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }} + run: | + ./gradlew assemble${{ matrix.build_type }} -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + ./gradlew signMavenAarPublication + - name: Pre Archive artifacts + shell: bash + run: | + pip3 install -U cos-python-sdk-v5 + - name: Archive artifacts + working-directory: ./framework/android/build + shell: python3 {0} + run: | + from qcloud_cos import CosConfig + from qcloud_cos import CosS3Client + from urllib.parse import urlencode + import os + import tempfile + import zipfile + + artifacts = [("outputs/aar/android-sdk.aar", "hippy/android/${{ matrix.artifact_id }}/${{ github.event.inputs.version_name }}/android-sdk.aar")] + for path, dirs, files in os.walk("intermediates/merged_native_libs/%s/out/lib" % "${{ matrix.build_type }}".lower()): + if files: + with zipfile.ZipFile(tempfile.mkstemp()[1], "w", zipfile.ZIP_DEFLATED) as zip_file: + for file in files: + zip_file.write(os.path.join(path, file), file) + artifacts.append((zip_file.filename, "hippy/android/${{ matrix.artifact_id }}/${{ github.event.inputs.version_name }}/symbols/%s.zip" % os.path.basename(path))) + + metadata = {} + metadata["ci-name"] = "Github Action" + metadata["ci-id"] = "${{ github.run_id }}" + metadata["ci-url"] = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + metadata["artifact-author"] = "${{ github.event.sender.login }}" + metadata["git-ref"] = "${{ github.event.inputs.git_ref }}" + + config = CosConfig(Region="${{ secrets.COS_REGION }}", SecretId="${{ secrets.TC_SECRET_ID }}", SecretKey="${{ secrets.TC_SECRET_KEY }}") + client = CosS3Client(config) + for artifact in artifacts: + print("Uploading %s" % artifact[0]) + response = client.upload_file( + Bucket="${{ secrets.COS_BUCKET_ARTIFACTS_STORE }}", + Key=artifact[1], + LocalFilePath=artifact[0], + Metadata={"x-cos-tagging": urlencode(metadata)} + ) + print("Archived %s" % artifact[1]) + - name: Publish to Github Packages + if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Github' + env: + SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }} + SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }} + MAVEN_USERNAME: ${{ secrets.GITHUB_ACTOR }} + MAVEN_PASSWORD: ${{ secrets.GITHUB_TOKEN }} + MAVEN_URL: https://maven.pkg.github.com/${{ github.repository }} + run: | + ./gradlew publish -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + - name: Publish to OSSRH + if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Default' + env: + SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }} + SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }} + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + run: | + ./gradlew publish -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + + ios_release: + if: github.event.inputs.is_release_for_ios == 'true' + runs-on: macos-latest + steps: + - name: Checkout (${{ github.event.inputs.git_ref }}) + uses: actions/checkout@v3 + with: + ref: ${{ github.event.inputs.git_ref }} + lfs: true + - name: Publish to Cocoapods + if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Default' + env: + COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} + run: | + pod trunk push hippy.podspec --allow-warnings --use-libraries --verbose --skip-import-validation + + js_release: + if: github.event.inputs.is_release_for_js == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout (${{ github.event.inputs.git_ref }}) + uses: actions/checkout@v3 + with: + ref: ${{ github.event.inputs.git_ref }} + lfs: true + - name: setup-node + uses: actions/setup-node@v3 + with: + node-version: 18 + registry-url: https://npm.pkg.github.com + cache: 'npm' + cache-dependency-path: driver/js/package-lock.json + - name: Install && Build + run: | + pushd driver/js + npm install && npx lerna bootstrap --no-ci + npm run build + - uses: actions/setup-node@v3 + with: + node-version: 18 + registry-url: 'https://registry.npmjs.org' + - name: Publish to NPM + if: github.event.inputs.js_npm_dist_tag_name != null && (github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Default') + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + pushd driver/js + echo "released js_npm_dist_tag_name is '${{ github.event.inputs.js_npm_dist_tag_name }}'" + npx lerna publish from-package --ignore-scripts --yes --dist-tag ${{ github.event.inputs.js_npm_dist_tag_name }} + - name: Change tag to latest + if: github.event.inputs.is_npm_version_to_latest_tag == 'true' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + pushd driver/js + npm run release:tag-to-latest ${{ github.event.inputs.version_name }} + + diff --git a/.github/workflows/project_artifact_snapshot.yml b/.github/workflows/project_artifact_snapshot.yml new file mode 100644 index 00000000000..cf92eb0a3c8 --- /dev/null +++ b/.github/workflows/project_artifact_snapshot.yml @@ -0,0 +1,134 @@ +name: '[project] artifact snapshot' + +on: + workflow_dispatch: + inputs: + git_ref: + description: 'Git Ref' + type: string + required: true + version_name: + description: 'Version name' + type: string + required: true + registry_choice: + description: 'Registry choice' + type: choice + required: true + default: 'Both' + options: + - Default + - Github + - Both + is_release_for_android: + description: 'Release for Android' + type: boolean + default: true + required: false + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + context_in_lowercase: + if: github.event.inputs.is_release_for_android == 'true' + runs-on: ubuntu-latest + outputs: + repository_owner: ${{ steps.get_owner.outputs.lowercase }} + steps: + - name: Get repo owner(in lowercase) + id: get_owner + uses: ASzc/change-string-case-action@v2 + with: + string: ${{ github.repository_owner }} + + android_release: + if: github.event.inputs.is_release_for_android == 'true' + needs: context_in_lowercase + runs-on: ubuntu-latest + strategy: + matrix: + build_type: [Release] + include: + - build_type: Release + artifact_id: hippy-snapshot + container: + image: ghcr.io/${{ needs.context_in_lowercase.outputs.repository_owner }}/android-release:latest + steps: + - name: Checkout (${{ github.event.inputs.git_ref }}) + uses: actions/checkout@v3 + with: + ref: ${{ github.event.inputs.git_ref }} + lfs: true + - name: ${{ matrix.build_type }} build + env: + SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }} + SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }} + run: | + ./gradlew assemble${{ matrix.build_type }} -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + ./gradlew signMavenAarPublication + - name: Pre Archive artifacts + shell: bash + run: | + pip3 install -U cos-python-sdk-v5 + - name: Archive artifacts + working-directory: ./framework/android/build + shell: python3 {0} + run: | + from qcloud_cos import CosConfig + from qcloud_cos import CosS3Client + from urllib.parse import urlencode + import os + import tempfile + import zipfile + + artifacts = [("outputs/aar/android-sdk.aar", "hippy/android/${{ matrix.artifact_id }}/${{ github.event.inputs.version_name }}/android-sdk.aar")] + for path, dirs, files in os.walk("intermediates/merged_native_libs/%s/out/lib" % "${{ matrix.build_type }}".lower()): + if files: + with zipfile.ZipFile(tempfile.mkstemp()[1], "w", zipfile.ZIP_DEFLATED) as zip_file: + for file in files: + zip_file.write(os.path.join(path, file), file) + artifacts.append((zip_file.filename, "hippy/android/${{ matrix.artifact_id }}/${{ github.event.inputs.version_name }}/symbols/%s.zip" % os.path.basename(path))) + + metadata = {} + metadata["ci-name"] = "Github Action" + metadata["ci-id"] = "${{ github.run_id }}" + metadata["ci-url"] = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + metadata["artifact-author"] = "${{ github.event.sender.login }}" + metadata["git-ref"] = "${{ github.event.inputs.git_ref }}" + + config = CosConfig(Region="${{ secrets.COS_REGION }}", SecretId="${{ secrets.TC_SECRET_ID }}", SecretKey="${{ secrets.TC_SECRET_KEY }}") + client = CosS3Client(config) + for artifact in artifacts: + print("Uploading %s" % artifact[0]) + response = client.upload_file( + Bucket="${{ secrets.COS_BUCKET_ARTIFACTS_STORE }}", + Key=artifact[1], + LocalFilePath=artifact[0], + Metadata={"x-cos-tagging": urlencode(metadata)} + ) + print("Archived %s" % artifact[1]) + - name: Publish to Github Packages + if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Github' + env: + SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }} + SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }} + MAVEN_USERNAME: ${{ secrets.GITHUB_ACTOR }} + MAVEN_PASSWORD: ${{ secrets.GITHUB_TOKEN }} + MAVEN_URL: https://maven.pkg.github.com/${{ github.repository }} + run: | + ./gradlew publish -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + - name: Publish to OSSRH + if: github.event.inputs.registry_choice == 'Both' || github.event.inputs.registry_choice == 'Default' + env: + SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEY_ID }} + SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }} + SIGNING_SECRET_KEY: ${{ secrets.ANDROID_SIGNING_SECRET_KEY }} + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + run: | + ./gradlew publish -PVERSION_NAME=${{ github.event.inputs.version_name }} -PPUBLISH_ARTIFACT_ID=${{ matrix.artifact_id }} -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + diff --git a/.github/workflows/project_dependency_review.yml b/.github/workflows/project_dependency_review.yml new file mode 100644 index 00000000000..409b82f8d5e --- /dev/null +++ b/.github/workflows/project_dependency_review.yml @@ -0,0 +1,22 @@ +name: "[project] dependency review" + +on: + pull_request: + branches: + - v3.0-dev + - v3.0 + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Dependency Review + uses: actions/dependency-review-action@v3 + with: + deny-licenses: | + GPL-1.0-only, GPL-1.0-or-later, GPL-2.0-only, GPL-2.0-or-later, GPL-3.0-only, GPL-3.0-or-later, AGPL-1.0, AGPL-3.0, AGPL-1.0-only, AGPL-1.0-or-later, AGPL-3.0-only, AGPL-3.0-or-later, MPL-1.0, MPL-1.1, MPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+, LGPL-3.0, LGPL-3.0+, LGPL-2.0-only, LGPL-2.0-or-later, LGPL-2.1-only, LGPL-2.1-or-later, LGPL-3.0-only, LGPL-3.0-or-later diff --git a/.github/workflows/reuse_approve_checks_run.yml b/.github/workflows/reuse_approve_checks_run.yml new file mode 100644 index 00000000000..72f359eec3e --- /dev/null +++ b/.github/workflows/reuse_approve_checks_run.yml @@ -0,0 +1,104 @@ +name: '[reuse] approve checks run' + +on: + workflow_call: + inputs: + pull_request_number: + description: 'Pull request number' + required: true + type: number + pull_request_head_sha: + description: 'Pull request head sha' + required: true + type: string + requied_privilege_escalation: + description: 'Privilege escalation required' + required: false + default: false + type: boolean + outputs: + pull_request_number: + description: 'Pull request number' + value: ${{ inputs.pull_request_number }} + pull_request_head_sha: + description: 'Pull request head sha' + value: ${{ inputs.pull_request_head_sha }} + action_required: + description: "Checks require approve" + value: ${{ jobs.approve_checks_run.outputs.action_required }} + included_risk_files: + description: "Contains risk files" + value: ${{ jobs.approve_checks_run.outputs.included_risk_files }} + +jobs: + approve_checks_run: + runs-on: ubuntu-latest + outputs: + included_risk_files: ${{ steps.action.outputs.included_risk_files }} + action_required: ${{ steps.action.outputs.action_required }} + workflow_runs: ${{ steps.action.outputs.workflow_runs }} + steps: + - name: Action + id: action + uses: actions/github-script@v6.3.3 + with: + script: | + const { actions, pulls } = github.rest; + const fs = require('fs'); + const os = require('os'); + + const per_page = 100; + + let workflow_runs = (await github.paginate(actions.listWorkflowRunsForRepo, { + per_page, + event: 'pull_request', + status: 'action_required', + ...context.repo + })).filter(workflow_run => workflow_run.head_sha === '${{ inputs.pull_request_head_sha }}').map(workflow_run => workflow_run.id); + if (workflow_runs.length === 0) { + fs.appendFileSync(process.env.GITHUB_OUTPUT, `action_required=false${os.EOL}`, { encoding: 'utf8' }); + return; + } + fs.appendFileSync(process.env.GITHUB_OUTPUT, `action_required=true${os.EOL}`, { encoding: 'utf8' }); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `workflow_runs=${JSON.stringify(workflow_runs)}${os.EOL}`, { encoding: 'utf8' }); + + const [includedRiskFiles] = await github.paginate(pulls.listFiles, { + per_page, + pull_number: ${{ inputs.pull_request_number }}, + ...context.repo + }, ({ data: files }, done) => { + if (files.some(file => file.filename.startsWith('.github/workflows'))) { + done(); + return [true]; + } + return []; + }); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `included_risk_files=${includedRiskFiles}${os.EOL}`, { encoding: 'utf8' }); + + if (!includedRiskFiles) { + await Promise.all(workflow_runs.map(workflow_run => actions.approveWorkflowRun({ + run_id: workflow_run, + ...context.repo + }))); + } + + approve_checks_run_privileged: + needs: approve_checks_run + if: needs.approve_checks_run.outputs.included_risk_files == 'true' && inputs.requied_privilege_escalation == true + environment: github-actions-privileged + runs-on: ubuntu-latest + steps: + - name: Action + id: action + env: + workflow_runs: ${{ needs.approve_checks_run.outputs.workflow_runs }} + uses: actions/github-script@v6.1.0 + with: + script: | + const { actions } = github.rest; + + const workflow_runs = JSON.parse(process.env.workflow_runs); + await Promise.all(workflow_runs.map(workflow_run => actions.approveWorkflowRun({ + run_id: workflow_run, + ...context.repo + }))); diff --git a/.github/workflows/reuse_classify_commits.yml b/.github/workflows/reuse_classify_commits.yml new file mode 100644 index 00000000000..d5f17538106 --- /dev/null +++ b/.github/workflows/reuse_classify_commits.yml @@ -0,0 +1,59 @@ +name: '[reuse] classify commits' + +on: + workflow_call: + inputs: + pull_request_number: + description: 'Pull request number' + required: true + type: number + outputs: + merge_commits_sha: + description: 'Merge commits sha' + value: ${{ jobs.classify_commits.outputs.merge_commits_sha }} + merge_commits_count: + description: 'Merge commits count' + value: ${{ jobs.classify_commits.outputs.merge_commits_count }} + normal_commits_sha: + description: 'Normal commits sha' + value: ${{ jobs.classify_commits.outputs.normal_commits_sha }} + normal_commits_count: + description: 'Normal commits count' + value: ${{ jobs.classify_commits.outputs.normal_commits_count }} + +jobs: + classify_commits: + runs-on: ubuntu-latest + outputs: + merge_commits_sha: ${{ steps.action.outputs.merge_commits_sha }} + merge_commits_count: ${{ steps.action.outputs.merge_commits_count }} + normal_commits_sha: ${{ steps.action.outputs.normal_commits_sha }} + normal_commits_count: ${{ steps.action.outputs.normal_commits_count }} + steps: + - name: Action + id: action + uses: actions/github-script@v6.3.3 + with: + script: | + const { pulls } = github.rest; + const fs = require('fs'); + const os = require('os'); + + const commits = (await github.paginate(pulls.listCommits, { + per_page: 100, + pull_number: ${{ inputs.pull_request_number }}, + ...context.repo + })); + + if (commits.length >= 250) { // exceeded maximum of 250 commits per pull request + return; + } + + const merge_commits = []; + const normal_commits = []; + commits.forEach(commit => commit.parents.length > 1 ? merge_commits.push(commit.sha) : normal_commits.push(commit.sha)); + + fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge_commits_sha=${JSON.stringify(merge_commits)}${os.EOL}`, { encoding: 'utf8' }); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `merge_commits_count=${merge_commits.length}${os.EOL}`, { encoding: 'utf8' }); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `normal_commits_sha=${JSON.stringify(normal_commits)}${os.EOL}`, { encoding: 'utf8' }); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `normal_commits_count=${normal_commits.length}${os.EOL}`, { encoding: 'utf8' }); diff --git a/.github/workflows/reuse_get_workflow_output.yml b/.github/workflows/reuse_get_workflow_output.yml new file mode 100644 index 00000000000..e130b0a2f71 --- /dev/null +++ b/.github/workflows/reuse_get_workflow_output.yml @@ -0,0 +1,67 @@ +name: '[reuse] get workflow output' + +on: + workflow_call: + inputs: + workflow_run: + description: 'A workflow run id' + required: true + type: number + outputs: + action: + description: "A workflow run action field" + value: ${{ jobs.get_workflow_output.outputs.action }} + sender: + description: "A workflow run sender.login field" + value: ${{ jobs.get_workflow_output.outputs.sender }} + raw: + description: "A workflow run raw output" + value: ${{ jobs.get_workflow_output.outputs.raw }} + +jobs: + get_workflow_output: + runs-on: ubuntu-latest + outputs: + action: ${{ steps.parse.outputs.action }} + sender: ${{ steps.parse.outputs.sender }} + raw: ${{ steps.parse.outputs.raw }} + steps: + - name: Pull + uses: actions/github-script@v6.3.3 + with: + script: | + const { actions } = github.rest; + const fs = require('fs'); + + const { data: { artifacts } } = await actions.listWorkflowRunArtifacts({ + run_id: ${{ inputs.workflow_run }}, + ...context.repo + }); + const [ artifact ] = artifacts.filter((artifact) => { + return artifact.name == "data" + }); + if (!artifact) { + throw new Error("Missing data artifact generated in parent workflow(${{ inputs.workflow_run }})"); + } + + const download = await actions.downloadArtifact({ + artifact_id: artifact.id, + archive_format: 'zip', + ...context.repo + }); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/data.zip`, Buffer.from(download.data)); + - name: Parse + id: parse + shell: python + run: | + import zipfile + import json + import os + + with zipfile.ZipFile("data.zip", "r") as zip_ref: + buf = zip_ref.read("data") + data = json.loads(buf) + with open(os.getenv("GITHUB_OUTPUT"), 'w', encoding='utf-8') as file: + file.write("action=%s\n" % data["action"]) + file.write("sender=%s\n" % data["sender"]["login"]) + file.write("raw=%s\n" % json.dumps(data)) diff --git a/.github/workflows/security_codeql_analyses.yml b/.github/workflows/security_codeql_analyses.yml new file mode 100644 index 00000000000..f4078a06af7 --- /dev/null +++ b/.github/workflows/security_codeql_analyses.yml @@ -0,0 +1,156 @@ +name: "[security] codeql analyses" + +on: + push: + branches: + - v3.0-dev + - v3.0 + pull_request: + branches: + - v3.0-dev + - v3.0 + schedule: + # Run every day at 20:00 UTC(04:00 UTC+08:00). + - cron: '0 20 * * *' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + actions: read + contents: read + security-events: write + +jobs: + triage: + runs-on: ubuntu-latest + outputs: + languages: ${{ steps.action.outputs.languages }} + group: ${{ steps.action.outputs.group }} + steps: + - name: Action + id: action + uses: actions/github-script@v6.3.3 + with: + script: | + const { pull_request } = context.payload; + const { pulls } = github.rest; + const path = require('path'); + const fs = require('fs'); + const os = require('os'); + + // Ref: https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/#languages-and-compilers + const mappings = { + "cpp": [".cpp", ".c++", ".cxx", ".hpp", ".hh", ".h++", ".hxx", ".c", ".cc", ".h"], + // Use only 'java' to analyze code written in Java, Kotlin or both + "java": [".java", ".kt"], // written in Java, Kotlin or both + // Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + "javascript": [".ts", ".tsx", ".js", ".jsx", ".mjs", ".es", ".es6", ".htm", ".html", ".xhtm", ".xhtml", ".vue", ".hbs", ".ejs", ".njk", ".json", ".yaml", ".yml", ".raml", ".xml"] + }; + + const languages = new Set(); + + if (pull_request) { + try { + const files = await github.paginate(pulls.listFiles, { + ...context.repo, + per_page: 100, + pull_number: pull_request.number + }); + + if (files.length > 3_000) { // The paginated response include a maximum of 3000 files + Object.keys(mappings).forEach(languages.add, languages); + } else { + files.forEach(({ filename }) => { + const ext = path.extname(filename); + Object.keys(mappings).some((name) => { + if (mappings[name].includes(ext)) { + languages.add(name); + return true; + } + return false; + }); + }); + } + } catch (e) { + console.error(e); + Object.keys(mappings).forEach(languages.add, languages); + } + } else { + Object.keys(mappings).forEach(languages.add, languages); + } + + if (languages.size > 0) { + fs.appendFileSync(process.env.GITHUB_OUTPUT, `languages=${JSON.stringify(Array.from(languages))}${os.EOL}`, { encoding: 'utf8' }); + } + + analyze: + needs: triage + if: needs.triage.outputs.languages + runs-on: ${{ github.repository == 'Tencent/Hippy' && fromJson('[''self-hosted'', ''linux'', ''codeql'']') || 'ubuntu-latest' }} + container: + image: ghcr.io/tencent/android-release:latest + options: --user root + strategy: + fail-fast: false + matrix: + language: ${{ fromJSON(needs.triage.outputs.languages) }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + lfs: true + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + - name: Setup Node.js + if: matrix.language == 'javascript' + uses: actions/setup-node@v3 + with: + node-version: latest + - name: Build Java + if: matrix.language == 'java' + env: + skipCmakeAndNinja: 1 + run: | + ./gradlew assembleDebug + - name: Build C++ + if: matrix.language == 'cpp' + run: | + ./gradlew buildCMakeDebug -PINCLUDE_ABI_X86=true -PINCLUDE_ABI_X86_64=true + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + + fallback: + needs: triage + if: ${{ !needs.triage.outputs.languages }} + runs-on: ubuntu-latest + steps: + - name: Generate Fake SARIF + run: + echo '{"version":"2.1.0","runs":[{"tool":{"driver":{"name":"CodeQL"}},"results":[]}]}' > ./fake.sarif + # The following step will output a lot of errors(like `The process '/usr/bin/git' failed with exit code 128`), + # don't worry it's NORMAL because we don't checkout repository. + - name: Upload Fake SARIF + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: ./fake.sarif + category: fake_results_do_not_care + + codeql_finalize: + needs: [ analyze, fallback ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Success + if: contains(needs.*.result, 'success') + run: | + echo "CodeQL analysis completed successfully!" + - name: Failure + if: ${{ !contains(needs.*.result, 'success') }} + run: | + echo "CodeQL analysis completed with errors!" + exit -1 diff --git a/.github/workflows/tools/v8_7_7_229_build.patch b/.github/workflows/tools/v8_7_7_229_build.patch new file mode 100644 index 00000000000..265207157e5 --- /dev/null +++ b/.github/workflows/tools/v8_7_7_229_build.patch @@ -0,0 +1,68 @@ +diff --git a/config/android/BUILD.gn b/config/android/BUILD.gn +index 233e8b0e7..d2286cd77 100644 +--- a/config/android/BUILD.gn ++++ b/config/android/BUILD.gn +@@ -105,9 +105,7 @@ config("runtime_library") { + # arm-linux-androideabi-4.4.3 toolchain (circa Gingerbread) will exhibit + # strange errors. The include ordering here is important; change with + # caution. +- cflags_cc = [ "-isystem" + +- rebase_path("$android_ndk_root/sources/android/support/include", +- root_build_dir) ] ++ cflags_cc = [] + + defines = [ + "__GNU_SOURCE=1", # Necessary for clone(). +@@ -117,20 +115,31 @@ config("runtime_library") { + lib_dirs = [ android_libcpp_lib_dir ] + + libs = [] +- libs += [ "android_support" ] ++ if (!use_custom_libcxx) { ++ # The libc++ runtime library (must come first). ++ # ASan needs to dynamically link to libc++ even in static builds so ++ # that it can interpose operator new. ++ if (is_component_build || is_asan) { ++ libs += [ "c++_shared" ] ++ } else { ++ libs += [ "c++_static" ] ++ } ++ libs += [ "c++abi" ] ++ } ++ # On 64-bit platforms, the only symbols provided by libandroid_support.a are ++ # strto{d,f,l,ul}_l. These symbols are not used by our libc++, and newer NDKs ++ # don't provide a libandroid_support.a on 64-bit platforms, so we only depend ++ # on this library on 32-bit platforms. ++ if (current_cpu == "arm" || current_cpu == "x86") { ++ libs += [ "android_support" ] ++ } ++ + + # arm builds of libc++ starting in NDK r12 depend on unwind. + if (current_cpu == "arm") { + libs += [ "unwind" ] + } + +- # Manually link the libgcc.a that the cross compiler uses. This is +- # absolute because the linker will look inside the sysroot if it's not. +- libs += [ +- rebase_path(android_libgcc_file), +- "c", +- ] +- + if (current_cpu == "arm" && arm_version == 6) { + libs += [ "atomic" ] + } +diff --git a/config/sysroot.gni b/config/sysroot.gni +index 701c66082..bc33b7cd1 100644 +--- a/config/sysroot.gni ++++ b/config/sysroot.gni +@@ -27,7 +27,7 @@ if (current_os == target_os && current_cpu == target_cpu && + import("//build/config/android/config.gni") + + # Android uses unified headers, and thus a single compile time sysroot +- sysroot = "$android_ndk_root/sysroot" ++ sysroot = "$android_ndk_root/toolchains/llvm/prebuilt/linux-x86_64/sysroot" + } else if (is_linux && use_sysroot) { + # By default build against a sysroot image downloaded from Cloud Storage + # during gclient runhooks. diff --git a/.github/workflows/tools/v8_build.patch b/.github/workflows/tools/v8_build.patch deleted file mode 100644 index ae94974f0a0..00000000000 --- a/.github/workflows/tools/v8_build.patch +++ /dev/null @@ -1,55 +0,0 @@ -diff --git a/config/android/BUILD.gn b/config/android/BUILD.gn -index 233e8b0e7..d78a09e0b 100644 ---- a/config/android/BUILD.gn -+++ b/config/android/BUILD.gn -@@ -105,9 +105,7 @@ config("runtime_library") { - # arm-linux-androideabi-4.4.3 toolchain (circa Gingerbread) will exhibit - # strange errors. The include ordering here is important; change with - # caution. -- cflags_cc = [ "-isystem" + -- rebase_path("$android_ndk_root/sources/android/support/include", -- root_build_dir) ] -+ cflags_cc = [] - - defines = [ - "__GNU_SOURCE=1", # Necessary for clone(). -@@ -117,7 +115,25 @@ config("runtime_library") { - lib_dirs = [ android_libcpp_lib_dir ] - - libs = [] -- libs += [ "android_support" ] -+ if (!use_custom_libcxx) { -+ # The libc++ runtime library (must come first). -+ # ASan needs to dynamically link to libc++ even in static builds so -+ # that it can interpose operator new. -+ if (is_component_build || is_asan) { -+ libs += [ "c++_shared" ] -+ } else { -+ libs += [ "c++_static" ] -+ } -+ libs += [ "c++abi" ] -+ } -+ # On 64-bit platforms, the only symbols provided by libandroid_support.a are -+ # strto{d,f,l,ul}_l. These symbols are not used by our libc++, and newer NDKs -+ # don't provide a libandroid_support.a on 64-bit platforms, so we only depend -+ # on this library on 32-bit platforms. -+ if (current_cpu == "arm" || current_cpu == "x86") { -+ libs += [ "android_support" ] -+ } -+ - - # arm builds of libc++ starting in NDK r12 depend on unwind. - if (current_cpu == "arm") { -diff --git a/config/sysroot.gni b/config/sysroot.gni -index 701c66082..bc33b7cd1 100644 ---- a/config/sysroot.gni -+++ b/config/sysroot.gni -@@ -27,7 +27,7 @@ if (current_os == target_os && current_cpu == target_cpu && - import("//build/config/android/config.gni") - - # Android uses unified headers, and thus a single compile time sysroot -- sysroot = "$android_ndk_root/sysroot" -+ sysroot = "$android_ndk_root/toolchains/llvm/prebuilt/linux-x86_64/sysroot" - } else if (is_linux && use_sysroot) { - # By default build against a sysroot image downloaded from Cloud Storage - # during gclient runhooks. diff --git a/.github/workflows/tools/v8_support_16k_pages_for_android.patch b/.github/workflows/tools/v8_support_16k_pages_for_android.patch new file mode 100644 index 00000000000..0c458368507 --- /dev/null +++ b/.github/workflows/tools/v8_support_16k_pages_for_android.patch @@ -0,0 +1,15 @@ +diff --git a/src/base/build_config.h b/src/base/build_config.h +index 40719073377..6be42c877f0 100644 +--- a/src/base/build_config.h ++++ b/src/base/build_config.h +@@ -70,7 +70,9 @@ constexpr int kPageSizeBits = 18; + // The minimal supported page size by the operation system. Any region aligned + // to that size needs to be individually protectable via + // {base::OS::SetPermission} and friends. +-#if defined(V8_OS_MACOS) && defined(V8_HOST_ARCH_ARM64) ++#if (defined(V8_OS_MACOS) && defined(V8_HOST_ARCH_ARM64)) || \ ++ (defined(V8_OS_ANDROID) && (defined(V8_HOST_ARCH_ARM64) || defined(V8_HOST_ARCH_X64))) ++// Android 64 bit has experimental support for 16kB pages. + // MacOS on arm64 uses 16kB pages. + constexpr int kMinimumOSPageSize = 16 * 1024; + #elif defined(V8_OS_LINUX) && !defined(V8_OS_ANDROID) && \ diff --git a/.github/workflows/update_v8.yml b/.github/workflows/update_v8.yml deleted file mode 100644 index 00630318e33..00000000000 --- a/.github/workflows/update_v8.yml +++ /dev/null @@ -1,214 +0,0 @@ -name: '[android] [third_party] update v8' - -on: - workflow_dispatch: - inputs: - v8_revision: - description: 'V8 TAG(Branch) to build' - default: '9.5-lkgr' - required: true - release_tag: - description: 'Release tag' - default: 'latest' - required: true - build_args: - description: 'Build args' - default: 'is_component_build=false is_debug=false v8_use_external_startup_data=false is_official_build=true v8_enable_i18n_support=false treat_warnings_as_errors=false symbol_level=0 use_custom_libcxx=false clang_use_chrome_plugins=false use_thin_lto=false v8_enable_webassembly=false v8_monolithic=true' - required: true - build_target: - description: 'Build target' - default: 'v8_monolith' - required: true - -jobs: - build: - runs-on: [self-hosted, linux, trusted] - container: - image: ghcr.io/tencent/android-release:latest # repository name must be lowercase(${{ github.repository_owner }}) - credentials: - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - strategy: - matrix: - cpu: [arm, arm64, x86, x64] - include: - - cpu: arm - arch: armeabi-v7a - host-tag: arm-linux-androideabi - - cpu: arm64 - arch: arm64-v8a - host-tag: aarch64-linux-android - - cpu: x86 - arch: x86 - host-tag: i686-linux-android - - cpu: x64 - arch: x86_64 - host-tag: x86_64-linux-android - steps: - - name: Clean up before - run: | - shopt -s dotglob - rm -rf * - shopt -u dotglob - - name: Fetch v8 - run: | - fetch v8 - cd v8 - git checkout ${{ github.event.inputs.v8_revision }} - - name: Sync third_party - working-directory: ./v8 - run: | - echo "target_os = ['android']" >> ../.gclient - gclient sync -D - - name: Prepare android_ndk - working-directory: ./v8 - run: | - if [ -d third_party/android_tools ]; then - rm -rf third_party/android_tools - mkdir third_party/android_tools - ln -s $ANDROID_NDK_HOME third_party/android_tools/ndk - fi - if [ -f third_party/android_ndk/BUILD.gn ]; then - cp third_party/android_ndk/BUILD.gn $ANDROID_NDK_HOME - fi - if [ -d third_party/android_tools -o -f third_party/android_ndk/BUILD.gn ]; then - rm -rf third_party/android_ndk - ln -s $ANDROID_NDK_HOME third_party/android_ndk - fi - - name: Fetch patch - uses: actions/checkout@v2 - with: - path: ${{ github.repository }} - lfs: true - - name: Apply patch - working-directory: ./v8/build - continue-on-error: true - run: | - git apply ../../${{ github.repository }}/.github/workflows/tools/v8_build.patch - - name: Generate ${{ matrix.arch }} - working-directory: ./v8 - run: | - gn gen out/${{ matrix.arch }} --args="target_os=\"android\" target_cpu=\"${{ matrix.cpu }}\" v8_target_cpu=\"${{ matrix.cpu }}\" android_ndk_root=\"${ANDROID_NDK_HOME}\" ${{ github.event.inputs.build_args }}" - - name: Compile ${{ matrix.arch }} - working-directory: ./v8 - run: | - \cp -f build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu/libstdc++.so.6 /lib64 - \cp -f build/linux/debian_sid_i386-sysroot/usr/lib/i386-linux-gnu/libstdc++.so.6 /lib - ninja -C out/${{ matrix.arch }} ${{ github.event.inputs.build_target }} - - name: Release artifact - working-directory: ./v8/out/${{ matrix.arch }} - run: | - mkdir -p artifact/include/v8 artifact/libs/${{ matrix.arch }} - cp obj/libv8_monolith.a artifact/libs/${{ matrix.arch }} - cp -r ../../include/* artifact/include/v8/ - cp -r gen/include/* artifact/include/v8/ - find artifact/include/v8/. ! -name "*.h" -type f -delete - - name: Upload ${{ matrix.arch }} - uses: actions/upload-artifact@v2 - with: - name: ${{ matrix.arch }} - path: ./v8/out/${{ matrix.arch }}/artifact - if-no-files-found: error - - name: Clean up after - if: ${{ always() }} - run: | - shopt -s dotglob - rm -rf * - shopt -u dotglob - pull-request: - needs: build - runs-on: [self-hosted, linux, trusted] - container: - image: ghcr.io/tencent/android-release:latest # repository name must be lowercase(${{ github.repository_owner }}) - credentials: - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - env: - v8-dist: ./android/sdk/src/main/jni/third_party/v8/${{ github.event.inputs.release_tag }} - steps: - - name: Clean up before - run: | - shopt -s dotglob - rm -rf * - shopt -u dotglob - - name: Checkout repo - uses: actions/checkout@v2 - with: - lfs: true - - name: Construct directory structure - working-directory: ${{ env.v8-dist }}/official-release - run: | - shopt -s dotglob - shopt -s extglob - rm -rf -- !(CMakeLists.txt) - shopt -u extglob - shopt -u dotglob - - name: Fetch artifact - uses: actions/download-artifact@v2 - with: - path: ${{ env.v8-dist }}/official-release - - name: Merge all artifact - working-directory: ${{ env.v8-dist }}/official-release - run: | - for d in */ ; do - cp -r $d/* ./ - rm -rf $d - done - - name: Generate Readme - uses: DamianReeves/write-file-action@v1.0 - with: - path: ${{ env.v8-dist }}/official-release/README.md - contents: | - This v8 release is auto generated by Github Action([${{ github.run_id }}][2]). - - _Do NOT modify this release manually._ - - Refs: [${{ github.event.inputs.v8_revision }}][1] - - [1]: https://github.com/v8/v8/tree/${{ github.event.inputs.v8_revision }} - [2]: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - write-mode: overwrite - - name: Create Pull Request - uses: peter-evans/create-pull-request@v3 - with: - commit-message: | - chore(v8): update V8 to ${{ github.event.inputs.v8_revision }} - - Ref-URL: https://github.com/v8/v8/tree/${{ github.event.inputs.v8_revision }} - Action-Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - branch: chore/update-v8-to-${{ github.event.inputs.v8_revision }} - delete-branch: true - title: 'chore(v8): update V8 to ${{ github.event.inputs.v8_revision }}' - body: | - Refs: [${{ github.event.inputs.v8_revision }}][1] - Release TAG: ${{ github.event.inputs.release_tag }} - Action Run: [${{ github.run_id }}][2] - - [1]: https://github.com/v8/v8/tree/${{ github.event.inputs.v8_revision }} - [2]: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - labels: | - dependencies - android - - name: Clean up after - if: ${{ always() }} - run: | - shopt -s dotglob - rm -rf * - shopt -u dotglob - notification: - if: ${{ always() }} - needs: [build, pull-request] - runs-on: [self-hosted, linux, trusted] - continue-on-error: true - env: - WECHAT_WORK_BOT_WEBHOOK: ${{ secrets.WECHAT_WORK_BOT_WEBHOOK }} - steps: - - name: Wechat Work notification - uses: chf007/action-wechat-work@1.0.5 - with: - msgtype: markdown - content: "Github [Action] Notification\n - > repository: ${{ github.repository }}\n - > workflow: ${{ github.workflow }}\n - > result: ${{ needs.pull-request.result == 'success' && 'success' || 'failure'}}\n - > run: [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" diff --git a/.github/workflows/voltron_build_tests.yml b/.github/workflows/voltron_build_tests.yml new file mode 100644 index 00000000000..3a7d28fb876 --- /dev/null +++ b/.github/workflows/voltron_build_tests.yml @@ -0,0 +1,107 @@ +name: '[voltron] build tests' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths: + - 'renderer/voltron/**' + - 'framework/voltron/**' + - 'devtools/**' + - 'dom/**' + - 'driver/js/include/**' + - 'driver/js/src/**' + +defaults: + run: + working-directory: framework/voltron/example + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + voltron_framework_flutter_analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.3.8' + channel: 'stable' + - name: framework flutter pub get + run: flutter pub get + - name: framework flutter analyze + run: flutter analyze + working-directory: framework/voltron + + voltron_renderer_flutter_analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.3.8' + channel: 'stable' + - name: renderer flutter pub get + run: flutter pub get + - name: renderer flutter analyze + run: flutter analyze + working-directory: renderer/voltron + + voltron_renderer_flutter_test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.3.8' + channel: 'stable' + - name: renderer flutter pub get + run: flutter pub get + - name: renderer flutter test + run: flutter test + working-directory: renderer/voltron + + voltron_android_flutter_build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.3.8' + channel: 'stable' + - name: flutter pub get + run: flutter pub get + - name: Build for Android + run: flutter build apk + + voltron_ios_xcframework_build: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Build framework for iOS + run: python3 script/build.py -os ios -arch arm64 -rebuild + working-directory: framework/voltron + + voltron_ios_flutter_build: + runs-on: macos-13 + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + flutter-version: '3.3.8' + channel: 'stable' + architecture: x64 + - name: flutter pub get + run: flutter pub get + - name: Build for iOS + run: flutter build ios --release --no-codesign + env: + DEVELOPER_DIR: /Applications/Xcode_14.3.1.app/Contents/Developer diff --git a/.github/workflows/voltron_build_tests_bypass.yml b/.github/workflows/voltron_build_tests_bypass.yml new file mode 100644 index 00000000000..2b4afa12387 --- /dev/null +++ b/.github/workflows/voltron_build_tests_bypass.yml @@ -0,0 +1,56 @@ +name: '[voltron] build tests' + +on: + pull_request: + branches: + - main + - master + - v3.0-dev + - v3.0 + paths-ignore: + - 'renderer/voltron/**' + - 'framework/voltron/**' + - 'devtools/**' + - 'dom/**' + - 'driver/js/include/**' + - 'driver/js/src/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + voltron_framework_flutter_analyze: + runs-on: ubuntu-latest + steps: + - name: Build Test Bypass + run: | + echo "No build test required" + + voltron_renderer_flutter_analyze: + runs-on: ubuntu-latest + steps: + - name: Build Test Bypass + run: | + echo "No build test required" + + voltron_renderer_flutter_test: + runs-on: ubuntu-latest + steps: + - name: Build Test Bypass + run: | + echo "No build test required" + + voltron_android_flutter_build: + runs-on: ubuntu-latest + steps: + - name: Build Test Bypass + run: | + echo "No build test required" + + voltron_ios_flutter_build: + runs-on: ubuntu-latest # use ubuntu to replace macos in order to save macos resources and improve efficiency + steps: + - name: Build Test Bypass + run: | + echo "No build test required" diff --git a/.gitignore b/.gitignore index d993f9505ec..5bc12fba21c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,41 +1,118 @@ -*.log .DS_Store .nyc_output .vscode +.vs +.idea +.gradle +.externalNativeBuild +.cxx + +build coverage dist node_modules +xcuserdata +v8forios +hermesforios + +*.log +*.iml +local.properties +maven-auth.properties + layout/out -layout/build layout/cproject layout/.project layout/.settings -examples/*/res/vendor-manifest.json -android/sdk/src/main/jni/.vs -android/sdk/maven-auth.properties -android/sdk/local.properties -android/sdk/.cxx/* -android/sdk/libs/armeabi-v7a/libhippybridge.so -android/sdk/libs/arm64-v8a/libhippybridge.so -android/sdk/libs/x86/libhippybridge.so -android/sdk/libs/x86_64/libhippybridge.so -examples/android-demo/example/src/main/assets/ -examples/android-demo/example/libs/* -examples/ios-demo/HippyDemo.xcodeproj/project.xcworkspace/xcuserdata/* -examples/ios-demo/HippyDemo.xcodeproj/xcuserdata/* -examples/hippy-react-demo/package-lock.json -examples/hippy-vue-demo/package-lock.json -examples/android-demo/maven-auth.properties -examples/android-demo/example/.cxx/ - -# android -*.iml -local.properties -.idea/ -.gradle/ -build/ -.externalNativeBuild -# core -core/ARM -.vs/ +framework/android/maven-auth.properties +framework/android/local.properties +framework/android/.cxx/* +framework/android/libs/armeabi-v7a/libhippybridge.so +framework/android/libs/arm64-v8a/libhippybridge.so +framework/android/libs/x86/libhippybridge.so +framework/android/libs/x86_64/libhippybridge.so +framework/android/cmake-build-debug/* +framework/android/src/main/jni/.vs +framework/android/src/main/jni/cmake-build-debug/* + +framework/examples/*/res/vendor-manifest.json +framework/examples/android-demo/src/main/assets/ +framework/examples/android-demo/libs/* +framework/examples/android-demo/maven-auth.properties +framework/examples/android-demo/.cxx/ +framework/examples/ios-demo/HippyDemo.xcworkspace +framework/examples/ios-demo/Pods/* +framework/examples/ios-demo/Podfile.lock + +framework/examples/voltron-demo/IOSProj/IOSProj.xcworkspace +framework/examples/voltron-demo/IOSProj/Pods/* +framework/examples/voltron-demo/IOSProj/Podfile.lock + +driver/js/packages/hippy-vue-loader/remote-debug-profile/* + +docs/assets/*.png +docs/assets/*.jpg +docs/assets/*.gif +docs/assets/*.ico +docs/assets/*.js +docs/assets/*.css + +renderer/flutter/core/lib/* +renderer/flutter/example/ios/.symlinks/* +renderer/native/android/src/main/jni/lib/* + +dom/lib/* +dom/dom_project/* + +devtools/devtools-backend/lib/* +devtools/devtools-backend/test/build/* +devtools/devtools-integration/ios/DevtoolsBackend/* + +# Flutter/Dart/Pub related +framework/voltron/**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +/captures +.flutter-plugins-dependencies +pubspec.lock +generated_plugin_registrant.dart +GeneratedPluginRegistrant.java +framework/voltron/**/.generated/ + +framework/voltron/android/libs + +framework/voltron/example/ios/Flutter/App.framework +framework/voltron/example/ios/Flutter/Flutter.framework +framework/voltron/example/ios/Flutter/Flutter.podspec +framework/voltron/example/ios/Flutter/Generated.xcconfig +framework/voltron/example/ios/Flutter/app.flx +framework/voltron/example/ios/Flutter/app.zip +framework/voltron/example/ios/Flutter/flutter_assets/ +framework/voltron/example/ios/Flutter/flutter_export_environment.sh +framework/voltron/example/ios/Runner.xcodeproj/xcuserdata/* +framework/voltron/example/ios/Runner.xcodeproj/xcshareddata/* +framework/voltron/example/ios/Runner.xcworkspace/ +framework/voltron/example/ios/Runner.xcodeproj/project.xcworkspace/ +framework/voltron/example/ios/Runner/GeneratedPluginRegistrant.* +framework/voltron/example/ios/ServiceDefinitions.json +framework/voltron/example/ios/**/Pods/ +framework/voltron/example/ios/**/.symlinks/ +framework/voltron/ios/voltron_core.xcframework +framework/voltron/ios/Flutter/ +framework/voltron/VoltronCore/VoltronCore.xcodeproj/project.xcworkspace +framework/voltron/VoltronCore/VoltronCore.xcodeproj/xcuserdata/ + +renderer/voltron/core/lib/ + +.hvigor/ +oh_modules/* +oh-package-lock.json5 +.clang-format +.clang-tidy +.clangd +BuildProfile.ets +log.txt diff --git a/.husky/post-checkout b/.husky/post-checkout index cab40f26495..ca7fcb40088 100755 --- a/.husky/post-checkout +++ b/.husky/post-checkout @@ -1,3 +1,3 @@ #!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-checkout.\n"; exit 2; } +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-checkout' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } git lfs post-checkout "$@" diff --git a/.husky/post-commit b/.husky/post-commit index 9443f4161ac..52b339cb3f4 100755 --- a/.husky/post-commit +++ b/.husky/post-commit @@ -1,3 +1,3 @@ #!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-commit.\n"; exit 2; } +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-commit' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } git lfs post-commit "$@" diff --git a/.husky/post-merge b/.husky/post-merge index 828b70891ed..a912e667aa3 100755 --- a/.husky/post-merge +++ b/.husky/post-merge @@ -1,3 +1,3 @@ #!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-merge.\n"; exit 2; } +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'post-merge' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } git lfs post-merge "$@" diff --git a/.husky/pre-commit b/.husky/pre-commit index 77409daa30e..1d3d8b443d4 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,4 +2,4 @@ . "$(dirname "$0")/_/husky.sh" PATH=$PATH:/usr/local/bin:/usr/local/sbin -npx lint-staged && npm run markdownlint +npm run markdownlint diff --git a/.husky/pre-push b/.husky/pre-push index 81a9cc6398a..0f0089bc25d 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,3 +1,3 @@ #!/bin/sh -command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/pre-push.\n"; exit 2; } +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting the 'pre-push' file in the hooks directory (set by 'core.hookspath'; usually '.git/hooks').\n"; exit 2; } git lfs pre-push "$@" diff --git a/.markdownlintrc.json b/.markdownlintrc.json index b9a3a8338b7..44c2035e21d 100644 --- a/.markdownlintrc.json +++ b/.markdownlintrc.json @@ -6,5 +6,6 @@ "no-multiple-blanks": false, "no-trailing-spaces": false, "no-inline-html" : false, - "no-bare-urls": false + "no-bare-urls": false, + "no-duplicate-header": false } diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 06721a60591..00000000000 --- a/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -src -.rpt2_cache diff --git a/AppScope/app.json5 b/AppScope/app.json5 new file mode 100644 index 00000000000..e0605ec6682 --- /dev/null +++ b/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.tencent.hippydemo", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/AppScope/resources/base/element/string.json b/AppScope/resources/base/element/string.json new file mode 100644 index 00000000000..5d806813dd8 --- /dev/null +++ b/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "HippyDemo" + } + ] +} diff --git a/AppScope/resources/base/media/app_icon.png b/AppScope/resources/base/media/app_icon.png new file mode 100644 index 00000000000..cd45accb1df Binary files /dev/null and b/AppScope/resources/base/media/app_icon.png differ diff --git a/CHANGELOG.md b/CHANGELOG.md index 384d35d5a22..4a3b6f0fdbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,5 +3,5 @@ All notable changes to this project will be documented in different release branch. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -# [v2.x](//github.com/Tencent/Hippy/blob/v2.x/CHANGELOG.md) +# [Release Notes](//github.com/Tencent/Hippy/releases) diff --git a/PUBLISH.md b/PUBLISH.md new file mode 100644 index 00000000000..6939d8002a6 --- /dev/null +++ b/PUBLISH.md @@ -0,0 +1,171 @@ +# Hippy publish document + +Hippy version management follows principle that all modules use same version. + +## 1. Update Version Number + +The front-end Uses [lerna](https://lerna.js.org/) for versioning and CHANGELOG generation, but cannot use its publishing functionality because it needs to update the terminal package. + +Update version and CHANGELOG usage: + +```bash +npx lerna version [VERSION] --force-publish --conventional-commits --tag-version-prefix='' --no-push +``` + +* `[version]` - The version number to be released, such as 2.1.0. +* `--conventional-commits` - Generates a CHANGELOG based on the conventional commit specification. +* `--tag-version-prefix` - it is changed to a null character, so that the generated version number tag is not preceded by the default `v` +* `--no-push` - it does not push tags to remote. + +## 2. Rollback commit and delete auto-generated tag + +After Lerna generates the version number and CHANGELOG, it needs to roll back the version, and all the published changes need to be merged into a commit. + +```bash +git reset --soft HEAD^ +``` + +Delete the tag at the same time, after a while update need to regenerate the tag + +```bash +git tag -d [VERSION] +``` + +## 3. Update native version number + +The native version number is mainly located in the following files, which need to be updated to the version number to be released + +iOS + +* [hippy.podspec](https://github.com/Tencent/Hippy/blob/master/hippy.podspec#L11) +* [HippyBridge.mm](https://github.com/Tencent/Hippy/blob/master/ios/sdk/base/HippyBridge.mm#L45) + +Android + +* [gradle.properties](https://github.com/Tencent/Hippy/blob/master/android/sdk/gradle.properties#L25) + +修改安卓的abi配置,支持armeabi-v7a和arm64-v8a +``` +INCLUDE_ABI_ARMEABI_V7A=true +INCLUDE_ABI_ARM64_V8A=true +``` + +Ohos + +* [oh-package.json5](https://github.com/Tencent/Hippy/blob/main/framework/ohos/oh-package.json5#L9) +* [oh-package.json5](https://github.com/Tencent/Hippy/blob/main/framework/ohos/CHANGELOG.md) + +## 4. Update built-in packages and verify functionality + +The new front-end SDK is then compiled with + +```bash +npm run build +``` + +If some code updated under `core/js`, you need to compile the core code with + +```bash +npm run buildcore +``` + +Then update the dependencies under the target `examples` and update the built-in packages of the native. Generally speaking, the built-in hippy-react-demo is the default, but be sure to check that hippy-vue-demo functions properly. + +```bash +npm run buildexample hippy-react-demo +``` + +## 5. Resubmit when everything is ready + +Check again that all files have been modified correctly + +```bash +git status +``` + +Submit document modification + +```bash +git add [FILES] +``` + +Enter a commit message that conforms to [Convention Commit](https://conventionalcommits.org/) specifications + +```bash +git commit -m 'chore(release): released [VERSION]' +``` + +tag (如果是大版本, 在主干打tag, 如果是hotfix,在hotfix分支打tag,然后把changelog合回主干) + +```bash +git tag -a [VERSION] -m "version release xxx" +``` + +Commit the code and prepare to publish the PR merge into the master branch. + +```bash +git push origin branch # 提交代码 +git push origin tag # 提交 tag +``` + +## 6. Publish + +* Front End Publishing to npmjs.com + + ```bash + npx lerna exec "npm publish" + ``` + + > If npm secondary authentication is active, you will be asked to input a one-time password. + +* iOS published to CocoaPods.org + + * If you do not have a CocoaPod account, register first + + ```bash + pod trunk register [EMAIL] [NAME] + ``` + + * Then publish + + ```bash + pod trunk push hippy.podspec + ``` + + > If the parameter check fails when publishing, you can prefix the `pod` command `COCOAPODS_VALIDATOR_SKIP_XCODEBUILD=1` parameter + +* Android released to Maven Central, the original jCenter repository has been abandoned [version query](https://search.maven.org/search?q=com.tencent.hippy). + + * Follow [the steps for publishing Maven Central](https://zhuanlan.zhihu.com/p/362205023) and sign up for [sonatype](https://oss.sonatype.org). + * Increase the system environment variable configuration + + ```bash + SIGNING_KEY_ID=gpg公钥key后8位 + SIGNING_PASSWORD=gpg密钥对密码 + SIGNING_SECRET_KEY_RING_FILE=gpg文件存放路径, 如/Users/user/.gnupg/secring.gpg + OSSRH_USERNAME=sonatype账号 + OSSRH_PASSWORD=sonatype密码 + ``` + + * Run build `Clean Project` + * `Android gradle.properties` turns on the `#PUBLISH_ARTIFACT_ID=hippy-debug` comment, and the Gradle Task executes `other` => `assembleDebug` before `publishing` => `publish` + * `Android gradle.properties` turns on the `#PUBLISH_ARTIFACT_ID=hippy-common` comment, and the Gradle Task executes `other` => `assembleRelease` before `publishing` => `publish` + * After the success of the release of the SDK will be in the `staging` state of Sonatype, in the left side `Staging Repositories` of the Sonatype Staging Repositories to find just released repository, if you want to test before Release, can be under the `Content` will `aar` download, replace `examples` => `android-demo` => `example` => `libs` under the aar(name to `android-sdk-release.aar`) + + ```bash + // annotation local reference in `setting.gradle` + // include 'android-sdk' + // project(':android-sdk').projectDir = new File('../../ android/sdk') + + -------------- + + // `android-demo` => `example` => `build.gradle` dependencies can be changed as follow to use local aar file + if (1) { + api (name: 'android-sdk-release', ext: 'aar') + } else { + api project(path: ':android-sdk') + } + ``` + + * After successful verification, Close the repository of `Staging Repositories``Close` and click `Release`. + * After the success of the Release can be searched in the Repository to the corresponding version of aar, Maven home page need to wait for more than 2 hours to synchronize diff --git a/PUBLISH.zh_CN.md b/PUBLISH.zh_CN.md deleted file mode 100644 index ad6922ec949..00000000000 --- a/PUBLISH.zh_CN.md +++ /dev/null @@ -1,161 +0,0 @@ -# Hippy 发布文档 - -Hippy版本管理遵循所有模块使用同一版本原则 - -## 1. 更新版本号 - -前端使用 [lerna](https://lerna.js.org/) 进行版本管理和 CHANGELOG 生成,但因为需要更新终端包所以不能使用它的发布功能。 - -更新版本和 CHANGELOG 使用: - -```bash -lerna version [VERSION] --conventional-commits --tag-version-prefix='' --no-push -``` - -* `[VERSION]` - 要发布的版本号,如2.1.0。 -* `--conventional-commits` - 生成基于 conventional 提交规范的 CHANGELOG。 -* `--tag-version-prefix` - 改为空字符,这样生成的版本号 tag 前面就不会带上默认的 `v`。 -* `--no-push` - 不会将tag推动到远程。 - -## 2. 回退 commit 并删除自动生成的 tag - -lerna 生成版本号和 CHANGELOG 后,需要回退一下版本,所有发布改动需要合并到一个 commit 中。 - -```bash -git reset --soft HEAD^ -``` - -同时删除 tag,一会儿更新后需要重新生成 tag - -```bash -git tag -d [VERSION] -``` - -## 3. 更新终端版本号 - -终端版本号主要位于以下几个文件,都需要更新到即将发布的版本号 - -iOS - -* [hippy.podspec](https://github.com/Tencent/Hippy/blob/master/hippy.podspec#L11) -* [HippyBridge.mm](https://github.com/Tencent/Hippy/blob/master/ios/sdk/base/HippyBridge.mm#L45) - -Android - -* [gradle.properties](https://github.com/Tencent/Hippy/blob/master/android/sdk/gradle.properties#L25) - -## 4. 更新内置包并校验功能正常 - -随后编译新的前端 SDK - -```bash -npm run build -``` - -如果有 `core/js` 下的代码更新,则需要编译一下 core 代码 - -```bash -npm run buildcore -``` - -随后更新目标 `examples` 下的依赖并更新终端内置包,一般而言默认内置 hippy-react-demo,但务必检查一下 hippy-vue-demo 的功能正常。 - -```bash -npm run buildexample -- hippy-react-demo -``` - -> 注意:buildexample 可能会使用旧版本的前端 SDK,需要手工更新 node_modules 下的文件后再更新内置包,buildexample 也需要将 npm install 那一步暂时注释掉。 - -## 5. 一切准备完毕后重新提交 - -再一次检查所有文件都正确修改 - -```bash -git status -``` - -提交文件修改 - -```bash -git add [FILES] -``` - -输入符合 [Convention Commit](https://conventionalcommits.org/) 规范的 commit message - -```bash -git commit -m 'chore(release): released [VERSION]' -``` - -打上 tag - -```bash -git tag [VERSION] -``` - -提交代码,并准备发布 PR 合并到 master 分支。 - -```bash -git push # 提交代码 -git push --tags # 提交 tag -``` - -## 6. 发布 - -* 前端发布到 npmjs.com - - ```bash - lerna exec "npm publish" - ``` - - > 如果开启了 npm 二次验证会一直问你一次性密码,正常输入即可。 - -* iOS 发布到 cocoapods.org - - * 如果没有cocoapod账户,先进行注册 - - ```bash - pod trunk register [EMAIL] [NAME] - ``` - - * 然后发布 - - ```bash - pod trunk push hippy.podspec - ``` - - > 如果发布时参数检查失败,可以在`pod`命令前面加上 `COCOAPODS_VALIDATOR_SKIP_XCODEBUILD=1` 参数 - -* Android 发布到 Maven Central,原有jCenter仓库已经废弃 [版本查询](https://search.maven.org/search?q=com.tencent.hippy)。 - - * 参照 [发布 Maven Central](https://zhuanlan.zhihu.com/p/362205023) 的步骤,并注册 [sonatype](https://oss.sonatype.org) 的账号。 - * 增加系统环境变量配置 - - ```bash - SIGNING_KEY_ID=gpg公钥key后8位 - SIGNING_PASSWORD=gpg密钥对密码 - SIGNING_SECRET_KEY_RING_FILE=gpg文件存放路径, 如/Users/user/.gnupg/secring.gpg - OSSRH_USERNAME=sonatype账号 - OSSRH_PASSWORD=sonatype密码 - ``` - - * Gradle Task 先执行 `other` => `assembleRelease`, 再执行 `publishing` => `publish`, 发布成功后SDK会在 sonatype 的 `staging`状态 - * 在 sonatype 左边 `Staging Repositories` 里找到刚发布的 repository,如果想Release前进行测试,可以在 `Content` 下将 `aar` 下载,替换`examples` => `android-demo` => `example` => `libs` 下的 aar(名字改成 `android-sdk-release.aar`) - - ```bash - // 注释 `setting.gradle` 本地 SDK 的引用 - // include 'android-sdk' - // project(':android-sdk').projectDir = new File('../../android/sdk') - - -------------- - - // `android-demo` => `example` => `build.gradle` 的 dependencies 修改如下,这样就会默认采用本地 aar - if (1) { - api (name: 'android-sdk-release', ext: 'aar') - } else { - api project(path: ':android-sdk') - } - ``` - - * 验证成功后, 将 `Staging Repositories` 的 repository `Close`,再点击 `Release`。 - * Release 成功后就可以在 Repository 里 搜索到对应版本的aar,Maven主页需要等待2个小时以上才会同步 - \ No newline at end of file diff --git a/PrivacyInfo.xcprivacy b/PrivacyInfo.xcprivacy new file mode 100644 index 00000000000..8fe86d36970 --- /dev/null +++ b/PrivacyInfo.xcprivacy @@ -0,0 +1,31 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyCollectedDataTypes + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/README.md b/README.md index dde677e6d26..b7f82f06a49 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ ![Hippy Group](https://img.shields.io/badge/group-Hippy-blue.svg) [![license](https://img.shields.io/badge/license-Apache%202-blue)](https://github.com/Tencent/Hippy/blob/master/LICENSE) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/Hippy/pulls) ![node](https://img.shields.io/badge/node-%3E%3D10.0.0-green.svg) [![Actions Status](https://github.com/Tencent/Hippy/workflows/build/badge.svg?branch=master)](https://github.com/Tencent/Hippy/actions) [![Codecov](https://img.shields.io/codecov/c/github/Tencent/Hippy)](https://codecov.io/gh/Tencent/Hippy) [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/Tencent/Hippy)](https://github.com/Tencent/Hippy/releases) -English | [简体中文](./README.zh_CN.md) | [Homepage](//tencent.github.io/Hippy/) +[Homepage](https://framework.tds.qq.com) ## 💡 Introduction -Hippy is a cross-platform development framework, aiming to help developers write once, run on three platforms(iOS, Android and Web). Hippy is quite friendly to Web developers, especially who are familiar with React or Vue. With Hippy, developers are able to create the cross platform app easily. +Hippy is a cross-platform development framework, that aims to help developers write once, and run on multiple platforms(iOS, Android, Web, and so on). Hippy is quite friendly to Web developers, especially those who are familiar with React or Vue. With Hippy, developers can create the cross-platform app easily. -Hippy is now applied in 27+ [Tencent](http://www.tencent.com/) apps such as Mobile QQ, Mobile QQ Browser, Tencent Video App, QQ Music App, Tencent News, reaching hundreds of millions of ordinary users. +Hippy is now applied in [Tencent](http://www.tencent.com/) major apps such as Mobile QQ, Mobile QQ Browser, Tencent Video App, QQ Music App, and Tencent News, reaching hundreds of millions of ordinary users. ## 💯 Advantages @@ -17,16 +17,17 @@ Hippy is now applied in 27+ [Tencent](http://www.tencent.com/) apps such as Mobi * Excellent performance with JS engine binding communication. * Build-in recyclable component with better performance. * Smoothly and gracefully migrate to Web browser. -* Fully supported Flex [Layout engine](./layout). +* Fully supported Flex [Layout engine](https://github.com/Tencent/taitank). ## 🔨 Getting started ### Preparing environment -Run `git clone https://github.com/Tencent/Hippy.git` +Make sure you have [git](https://git-scm.com/) and [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) installed locally. -> Hippy repository applies [git-lfs](https://git-lfs.github.com/) to manage so,gz,otf,png,jpg files, make sure you have installed [git-lfs](https://git-lfs.github.com/) first. +Run `git clone https://github.com/Tencent/Hippy.git` and `npm install` at project root directory. +> The Hippy repository applies [git-lfs](https://git-lfs.github.com/) to manage so,gz,otf files, make sure you have installed [git-lfs](https://git-lfs.github.com/) first. For macOS developers: @@ -47,16 +48,27 @@ For Windows developers: For iOS, we recommend to use iOS simulator when first try. However, you can change the Xcode configuration to install the app to iPhone if you are an iOS expert. -1. Install the project build scripts dependencies at root directory with `npm install`. -2. Install dependencies of each npm package at root directory with `lerna bootstrap`. - (Hippy uses [Lerna](https://lerna.js.org/) to manage multi js packages, if `lerna` command is not found, execute `npm install lerna -g` first.) -3. Build each front-end sdk package at root directory with `npm run build`. -4. Choose a demo to build with `npm run buildexample -- [hippy-react-demo|hippy-vue-demo]` at root directory. -5. Start the Xcode and build the iOS app with `open examples/ios-demo/HippyDemo.xcodeproj`. +1. `cd` to `driver/js/`. -> If `Step 4` throw error, you can `cd` to `examples` hippy-react-demo or hippy-vue-demo, and run `npm install --legacy-peer-deps` to install demo dependencies first. +2. Run `npm run init`. + + > This command is combined with `npm install && npx lerna bootstrap && npm run build`. + > + > `npm install`: Install the project build scripts dependencies. + > + > `npx lerna bootstrap`: Install dependencies of each npm package.(Hippy uses [Lerna](https://lerna.js.org/) to manage multi js packages, if `lerna` command is not found, execute `npm install lerna -g` first.) + > + > `npm run build`: Build each front-end sdk package. + +3. Choose a demo to build with `npm run buildexample [hippy-react-demo|hippy-vue-demo|hippy-vue-next-demo]`. + +4. Install CocoaPods with `brew install cocoapods`, install cmake with `brew install cmake`, then execute `pod install` command at `framework/examples/ios-demo` directory, which will create `HippyDemo.xcworkspace` files and install Cocoapods dependencies. + +5. Start the Xcode and build the iOS app with opening `framework/examples/ios-demo/HippyDemo.xcworkspace`. + +> If `Step 2` throw error, you can `cd` to `driver/js/examples` hippy-react-demo or hippy-vue-demo, and run `npm install` to install demo dependencies first. > -> More details for [iOS SDK integration](https://hippyjs.org/#/ios/integration?id=ios-%e9%9b%86%e6%88%90). +> More details for [iOS SDK integration](https://doc.openhippy.com/#/development/ios-3.0-integration-guidelines). ### Build the Android app with js demo @@ -64,35 +76,54 @@ For Android, we recommend using the real cellphone for better develop experience Before build the android app, please make sure the SDK and NDK is installed, And *DO NOT* update the build toolchain. -1. Install the whole project dependencies at root directory with `npm install`. -2. Install dependencies of each npm package at root directory with `lerna bootstrap`. - (Hippy uses [Lerna](https://lerna.js.org/) to manage multi js packages, if `lerna` command is not found, execute `npm install lerna -g` first.) -3. Build each front-end sdk package at root directory with `npm run build`. -4. Choose a demo to build with `npm run buildexample -- [hippy-react-demo|hippy-vue-demo]` at root directory. -5. Open the `examples/android-demo` with Android Studio. -6. Connect Android phone with USB cable and make sure USB debugging mode is enabled(Run `adb devices` on the computer terminal to check cellphone connection status). -7. Open the project with Android Studio, run and install the apk. +1. `cd` to `driver/js/`. + +2. Run `npm run init`. + + > This command is combined with `npm install && npx lerna bootstrap && npm run build`. + > + > `npm install`: Install the project build scripts dependencies. + > + > `npx lerna bootstrap`: Install dependencies of each npm package.(Hippy uses [Lerna](https://lerna.js.org/) to manage multi js packages, if `lerna` command is not found, execute `npm install lerna -g` first.) + > + > `npm run build`: Build each front-end sdk package. + +3. Choose a demo to build with `npm run buildexample [hippy-react-demo|hippy-vue-demo|hippy-vue-next-demo]`. +4. Open the `Hippy Project` at root directory with Android Studio. +5. Connect Android phone with USB cable and make sure USB debugging mode is enabled(Run `adb devices` on the computer terminal to check cellphone connection status). +6. Open the project with Android Studio, run and install the apk. -> If `Step 4` throw error, you can `cd` to `examples` hippy-react-demo or hippy-vue-demo, and run `npm install --legacy-peer-deps` to install demo dependencies first. +> If `Step 2` throw error, you can `cd` to `driver/js/examples` hippy-react-demo, hippy-vue-demo or hippy-vue-next-demo, and run `npm install` to install demo dependencies first. > > If you encounter the issue of `No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android`, here is the [solution](https://github.com/google/filament/issues/15#issuecomment-415423557). > -> More details for [Android SDK integration](https://hippyjs.org/#/android/integration?id=android-%e9%9b%86%e6%88%90). +> More details for [Android SDK integration](https://doc.openhippy.com/#/development/android-3.0-integration-guidelines). ### Debug the js demo 1. Follow [Build the iOS simulator with js demo](https://github.com/Tencent/Hippy#build-the-ios-simulator-with-js-demo) or [Build the Android app with js demo](https://github.com/Tencent/Hippy#build-the-android-app-with-js-demo) first to build the App. -2. `cd` to `examples` hippy-react-demo or hippy-vue-demo. -3. Run `npm install` to install demo js dependencies. -4. Run `npm run hippy:dev` and `npm run hippy:debug` (`npm run hippy:local-debug` will link to source code in packages) respectively to start the live debug mode. +2. `cd` to `driver/js/`. +3. Run `npm run init:example [hippy-react-demo|hippy-vue-demo|hippy-vue-next-demo]`. +4. Run `npm run debugexample [hippy-react-demo|hippy-vue-demo|hippy-vue-next-demo] dev`. -> On example debug mode, npm packages such as @hippy/react, @hippy/vue are linked to `packages` > `[different package]` > `dist`(not node_modules), so if you have changed js package source code and want to make it take effect in target example, please call `npm run build` at root directory again. +> Or you can `cd` to `driver/js/examples/hippy-react-demo`, `driver/js/examples/hippy-vue-demo` or `driver/js/examples/hippy-vue-next-demo` directory to run `npm run hippy:dev` instead. +> +> On example debug mode, npm packages such as @hippy/react, @hippy/vue, @hippy/vue-next are linked to `driver/js/packages` > `[different package]` > `dist`(not node_modules), so if you have changed js package source code and want to make it take effect in target example, please call `npm run build` again. > -> More details for debugging can be read in [Hippy Debug Document](https://hippyjs.org/#/guide/debug). +> More details for debugging can be read in [Hippy Debug Document](https://doc.openhippy.com/#/development/debug). + +### Build the js production demo + +1. Follow [Build the iOS simulator with js demo](https://github.com/Tencent/Hippy#build-the-ios-simulator-with-js-demo) or [Build the Android app with js demo](https://github.com/Tencent/Hippy#build-the-android-app-with-js-demo) first to build the App. +2. `cd` to `driver/js/examples/hippy-react-demo`, `driver/js/examples/hippy-vue-demo` or `driver/js/examples/hippy-vue-next-demo`. +3. Run `npm install` to install demo js dependencies. +4. Run `npm run hippy:vendor` and `npm run hippy:build` in sequence to build the production `vendor.[android|ios].js` and `index.[android|ios].js`. + +> Hippy demo uses DllPlugin to split the common chunk and app chunk. ## 📁 Documentation -To check out [hippy examples](https://github.com/Tencent/Hippy/tree/master/examples) and visit [hippyjs.org](https://hippyjs.org). +To check out [hippy examples](https://github.com/Tencent/Hippy/tree/master/examples) and visit [framework.tds.qq.com](https://framework.tds.qq.com/). ## 📅 Changelog @@ -102,29 +133,37 @@ Detailed changes for each release version are documented in the [project release ```text Hippy -├── examples # Demo code for frontend or native developer. -│   ├── hippy-react-demo # hippy-react js demo code. -│   ├── hippy-vue-demo # hippy-vue js demo code. -│   ├── ios-demo # iOS native demo code. -│   └── android-demo # Android native demo code. -├── packages # npm packages. -│   ├── hippy-debug-server # Debug the Hippy with native. -│   ├── hippy-react # React binding for Hippy. -│   ├── hippy-react-web # Web adapter for hippy-react. -│   ├── hippy-vue # Vue binding for Hippy. -│   ├── hippy-vue-css-loader # Webpack loader for convert CSS text to JS AST. -│   ├── hippy-vue-native-components # Native components extensions for hippy-vue. -│   ├── hippy-vue-router # Vue router for hippy-vue. -│   └── types # Global type definition. -├── ios -│   └── sdk # iOS SDK -├── android -│   ├── support_ui # Android native components. -│   └── sdk # Android SDK. -├── core # JS modules implemented by C++, binding to JS engine. -├── docker # Native release docker image and build scripts. -├── layout # Hippy layout engine. -└── scripts # Project build script. +├── devtools # Devtools for Hippy. +├── dom # DOM Layer for Hippy. +├── driver # Different UI Driver Layers for Hippy. +│   └── js # JS Driver Layer for Hippy. +│   ├── examples # Related examples for JS Driver. +│   ├── include +│   ├── packages # Related JS Packages for JS Driver. +│   │   ├── hippy-react +│   │   ├── hippy-react-web +│   │   ├── hippy-vue +│   │   ├── hippy-vue-css-loader +│   │   ├── hippy-vue-loader +│   │   ├── hippy-vue-native-components +│   │   └── hippy-vue-router +│   └── src +├── framework +│   ├── android +│   ├── examples +│   │   ├── android-demo +│   │   └── ios-demo +│   └── ios +├── layout # Layout engine for Hippy. +├── modules +│   ├── android +│   └── footstone +├── renderer # Different Renderers for Hippy. +│   ├── flutter +│   └── native +│   ├── android +│   └── ios +└── static ``` ## 🤝 Contribution @@ -146,4 +185,3 @@ Hippy is [Apache-2.0 licensed](./LICENSE). [Hippy Eco-System](https://github.com/hippy-contrib) [Taitank Layout Engine](https://github.com/Tencent/Taitank) - diff --git a/README.zh_CN.md b/README.zh_CN.md deleted file mode 100644 index cb1f1590f6e..00000000000 --- a/README.zh_CN.md +++ /dev/null @@ -1,147 +0,0 @@ -# Hippy 跨端开发框架 - -![Hippy Group](https://img.shields.io/badge/group-Hippy-blue.svg) [![license](https://img.shields.io/badge/license-Apache%202-blue)](https://github.com/Tencent/Hippy/blob/master/LICENSE) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/Hippy/pulls) ![node](https://img.shields.io/badge/node-%3E%3D10.0.0-green.svg) [![Actions Status](https://github.com/Tencent/Hippy/workflows/build/badge.svg?branch=master)](https://github.com/Tencent/Hippy/actions) [![Codecov](https://img.shields.io/codecov/c/github/Tencent/Hippy)](https://codecov.io/gh/Tencent/Hippy) [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/Tencent/Hippy)](https://github.com/Tencent/Hippy/releases) - -[English](./README.md) | 简体中文 | [官网](//tencent.github.io/Hippy/) | [文章专栏](https://cloud.tencent.com/developer/column/84006) | [QQ群:784894901](//shang.qq.com/wpa/qunwpa?idkey=7bff52aca3aac75a4f1ba96c1844a5e3b62000351890182eb60311542d75fa1a) - -## 💡 介绍 - -Hippy 是一个新生的跨端开发框架,目标是使开发者可以只写一套代码就直接运行于三个平台(iOS、Android 和 Web)。Hippy 的设计是面向传统 Web 开发者的,特别是之前有过 React 和 Vue 开发经验的开发者用起来会更为顺手,Hippy 致力于让前端开发跨端 App 更加容易。 - -到目前为止,[腾讯](http://www.tencent.com/)公司内已经有 27+ 款主流 App 在使用 Hippy 框架,包括手机QQ、QQ浏览器、腾讯视频、QQ音乐、腾讯新闻等,每日触达数亿用户。 - - - -## 💯 特征 - -* 为传统 Web 前端开发者设计,官方支持 `React` 和 `Vue` 两种主流前端框架。 -* 不同的平台保持了相同的接口。 -* 通过 JS 引擎 binding 模式实现的前端-终端通讯,具备超强性能。 -* 提供了高性能的可复用列表。 -* 皆可平滑迁移到 Web 浏览器。 -* 完整支持 Flex 的[布局引擎](./layout)。 - -## 🔨 开始 - -### 准备环境 - -运行 `git clone https://github.com/Tencent/Hippy.git` - -> Hippy 仓库使用 [git-lfs](https://git-lfs.github.com/) 来管理 so,gz,otf,png,jpg 文件, 请确保你已经安装 [git-lfs](https://git-lfs.github.com/)。 - -macOS 用户需要以下软件: - -* [Xcode](https://developer.apple.com/xcode/) 和 iOS SDK: 用以编译 iOS 终端 app。 -* [Android Studio](https://developer.android.com/studio) 和 NDK: 用以编译 Android app。 -* [Node.JS](http://nodejs.cn/): 用以运行前端编译脚本。 - -我们推荐使用 [homebrew](https://brew.sh/) 来安装依赖。 - -Windows 用户者需要以下软件: - -* [Android Studio](https://developer.android.com/studio) 和 NDK: 用以编译 Android app。 -* [Node.JS](http://nodejs.cn/): 用以运行前端编译脚本。 - -> Windows 用户受条件所限,暂时无法进行 iOS app 开发。 - -### 使用 JS 范例来构建 iOS App - -我们推荐 iOS 开发者使用模拟器来进行开发和调试工作。当然如果你是一个 iOS 开发高手,也可以通过修改配置将 Hippy app 安装到 iPhone 手机上。 - -1. 在根目录运行命令 `npm install` 安装项目构建脚本的依赖。 -2. 在根目录运行命令 `lerna bootstrap` 安装前端每一个 package 依赖。(Hippy 采用 [Lerna](https://lerna.js.org/) 管理多 JS SDK 包仓库,如果出现 `lerna command is not found`, 先执行 `npm install lerna -g` 全局安装 `Lerna`。) -3. 在根目录运行命令 `npm run build` 编译每一个 JS SDK 包。 -4. 选择一个前端范例项目来进行编译,在项目根目录运行 `npm run buildexample -- [hippy-react-demo|hippy-vue-demo]`。 -5. 启动 Xcode 并且开始编译终端 App:`open examples/ios-demo/HippyDemo.xcodeproj`。 - -> 如果步骤4出现错误,可以先 `cd` 到 `examples` hippy-react-demo 或者 hippy-vue-demo 目录下,执行 `npm install --legacy-peer-deps`,提前将 demo 的 NPM 包依赖先安装好。 -> -> 更多信息请参考 [iOS SDK 集成](https://hippyjs.org/#/ios/integration?id=ios-%e9%9b%86%e6%88%90)。 - -### 使用 JS 范例来构建 Android App - -我们推荐 Android 开发者使用真机,因为 Hippy 使用的 [X5](https://x5.tencent.com/) JS 引擎没有提供 x86 的库以至于无法支持 x86 模拟器,同时使用 ARM 模拟器也比较慢。 - -在开始前请确认好 SDK 和 NDK 都安装了范例的指定版本,并且**请勿**更新编译工具链。 - -1. 在根目录运行命令 `npm install` 安装项目构建脚本的依赖。 -2. 在根目录运行命令 `lerna bootstrap` 安装前端每一个 package 依赖。(Hippy 采用 [Lerna](https://lerna.js.org/) 管理多 JS SDK 包仓库,如果出现 `lerna command is not found`, 先执行 `npm install lerna -g` 全局安装 `Lerna`。) -3. 在根目录运行命令 `npm run build` 编译每一个 JS SDK 包。 -4. 选择一个前端范例项目来进行编译,在项目根目录运行 `npm run buildexample -- [hippy-react-demo|hippy-vue-demo]`。 -5. 用 Android Studio 来打开终端范例工程 `examples/android-demo`。 -6. 用 USB 数据线插上你的 Android 手机,需要确认手机已经打开 USB 调试模式(可通过在电脑 Terminal 执行 `adb devices` 判断手机是否已经连上了电脑)。 -7. 运行工程,并安装 APK。 - -> 如果步骤4出现错误,可以先 `cd` 到 `examples` hippy-react-demo 或者 hippy-vue-demo 目录下,执行 `npm install --legacy-peer-deps`,提前将 demo 的 NPM 包依赖先安装好。 -> -> 如果 Android Studio 报了这个错误 `No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android`,这里有[解决办法](https://github.com/google/filament/issues/15#issuecomment-415423557)。 -> -> 更多信息请参考 [Android SDK 集成](https://hippyjs.org/#/android/integration?id=android-%e9%9b%86%e6%88%90)。 - -### 调试前端 Demo - -1. 先按照 **[使用 JS 范例来构建 iOS App]** 和 **[使用 JS 范例来构建 Android App]** 步骤执行。 -2. `cd` 到 `examples` hippy-react-demo 或者 hippy-vue-demo 目录。 -3. 执行 `npm install` 安装相应 js demo 的依赖包。 -4. 分别执行 `npm run hippy:dev` 和 `npm run hippy:debug`(`npm run hippy:local-debug` 会调用 packages 下的源码) 来开启实时 Debug 模式。 - -> 在 example 调试模式下,@hippy/react、@hippy/vue 等 npm 模块会直接链接到 `packages` > `[different package]` > `dist` 目录下面的 js 文件(非 node_modules),所以如果你修改了 packages 下的 JS 源代码并且想让其在 example 中生效,请重新在根目录执行 `npm run build`。 -> -> 更多关于调试的说明请浏览 [Hippy Debug Document](https://hippyjs.org/#/guide/debug)。 - -## 📁 文档 - -参考 [hippy examples](https://github.com/Tencent/Hippy/tree/master/examples) 下的代码和浏览官网 [hippyjs.org](https://hippyjs.org)。 - -## 📅 更新日志 - -每个发布版本的详细更新日志会记录在 [project release notes](https://github.com/Tencent/Hippy/releases)。 - -## 🧱 项目结构 - -```text -Hippy -├── examples # 前终端范例代码。 -│   ├── hippy-react-demo # hippy-react 前端范例代码。 -│   ├── hippy-vue-demo # hippy-vue 前端范例代码。 -│   ├── ios-demo # iOS 终端范例代码。 -│   └── android-demo # Android 终端范例代码。 -├── packages # 前端 npm 包。 -│   ├── hippy-debug-server # Hippy 的前终端调试服务。 -│   ├── hippy-react # Hippy 的 React 语法绑定。 -│   ├── hippy-react-web # hippy-react 转 Web 的库。 -│   ├── hippy-vue # Hippy 的 Vue 语法绑定。 -│   ├── hippy-vue-css-loader # 用来将 CSS 文本转换为 JS 语法树以供解析的 Webpack loader。 -│   ├── hippy-vue-native-components # hippy-vue 中浏览器中所没有的,额外的,终端定制组件。 -│   ├── hippy-vue-router # 在 hippy-vue 中运行的 vue-router。 -│   └── types # 全局 Typescript 类型 -├── ios -│   └── sdk # iOS SDK。 -├── android -│   ├── support_ui # Android 终端实现的组件。 -│   └── sdk # Android SDK。 -├── core # C++ 实现的 JS 模块,通过 Binding 方式运行在 JS 引擎中。 -├── docker # 发布 Native 的 Docker 镜像和构建脚本 -├── layout # Hippy 布局引擎。 -└── scripts # 项目编译脚本。 -``` - -## 🤝 贡献 - -欢迎开发人员为腾讯的开源做出贡献,我们将持续激励他们并感谢他们。我们提供了腾讯对开源贡献的说明,每个项目的具体贡献规则由项目团队制定。开发人员可以选择适当的项目并根据相应的规则参与。腾讯项目管理委员会将定期汇报合格的贡献者,奖项将由官方联络人颁发。在发起 Pull Request 或者 issue 前, 请确保你已经阅读 [Contributing Guide](https://github.com/Tencent/Hippy/blob/master/.github/CONTRIBUTING.md)。 - -所有曾经参与 Hippy 项目贡献的开发者都会记录在 [Contributors](https://github.com/Tencent/Hippy/graphs/contributors) 和 [Authors File](https://github.com/Tencent/Hippy/blob/master/AUTHORS) 。 - -## ❤️ 追星数 - -[![Stargazers over time](https://starchart.cc/Tencent/Hippy.svg)](https://starchart.cc/Tencent/Hippy) - -## 📄 许可协议 - -Hippy 遵守 [Apache-2.0 licensed](./LICENSE) 协议。 - -## 🔗 链接 - -[Hippy 生态](https://github.com/hippy-contrib) - -[Taitank 布局引擎](https://github.com/Tencent/Taitank) diff --git a/android/sdk/build.gradle b/android/sdk/build.gradle deleted file mode 100644 index e30336d8d5f..00000000000 --- a/android/sdk/build.gradle +++ /dev/null @@ -1,285 +0,0 @@ -apply plugin: 'com.android.library' -apply from: './mavencentral.gradle' - -ext { - CMAKE_PATH = "$projectDir.absolutePath/src/main/jni/CMakeLists.txt" - OUTPUT_PATH = "$buildDir/outputs/aar" - THIRD_PARTY_LIBRARY_PATH = "$projectDir.absolutePath/src/main/jni/third_party" - skipCmakeAndNinja = System.getenv('skipCmakeAndNinja') != null -} - -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - ext { - MAVEN_USER = System.getenv('maven_username') - MAVEN_PWD = System.getenv('maven_password') - MAVEN_URL = System.getenv('maven_url') - - println("MAVEN_USER=" + MAVEN_USER + ", MAVEN_PWD=" + MAVEN_PWD) - } - - repositories { - if (MAVEN_URL != null) { - maven { - url MAVEN_URL - credentials { - username MAVEN_USER - password MAVEN_PWD - } - } - } - google() - mavenCentral() - } -} - -android { - archivesBaseName = ARCHIVES_BASE_NAME - compileSdkVersion COMPILE_SDK_VERSION as int - ndkVersion = NDK_VERSION - defaultConfig { - minSdkVersion MIN_SDK_VERSION as int - targetSdkVersion TARGET_SDK_VERSION as int - versionCode VERSION_CODE as int - versionName VERSION_NAME - - // 保证app使用aar时,会自动将该proguard文件添加到本身的proguard规则中 - consumerProguardFiles 'proguard-rules.pro' - - buildConfigField("boolean", "ENABLE_SO_DOWNLOAD", ENABLE_SO_DOWNLOAD) - buildConfigField("boolean", "INCLUDE_SUPPORT_UI", INCLUDE_SUPPORT_UI) - - packagingOptions { - if (!INCLUDE_ABI_ARMEABI.toBoolean()) { - exclude 'lib/armeabi/*' - } - if (!INCLUDE_ABI_ARMEABI_V7A.toBoolean()) { - exclude 'lib/armeabi-v7a/*' - } - if (!INCLUDE_ABI_ARM64_V8A.toBoolean()) { - exclude 'lib/arm64-v8a/*' - } - if (!INCLUDE_ABI_X86.toBoolean()) { - exclude 'lib/x86/*' - } - if (!INCLUDE_ABI_X86_64.toBoolean()) { - exclude 'lib/x86_64/*' - } - } - } - - def V8_COMPONENT_DEBUG - def V8_COMPONENT_RELEASE - if (V8_COMPONENT == 'auto') { - V8_COMPONENT_DEBUG = 'third_party/v8/stable/official-release' - V8_COMPONENT_RELEASE = 'third_party/v8/stable/x5-lite' - } else { - V8_COMPONENT_DEBUG = V8_COMPONENT - V8_COMPONENT_RELEASE = V8_COMPONENT - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - externalNativeBuild { - cmake { - arguments "-DJS_ENGINE=V8", - "-DANDROID_CPP_FEATURES=rtti exceptions", - "-DANDROID_PLATFORM=android-21", - "-DCMAKE_BUILD_TYPE=Release", - "-DANDROID_STL=$ANDROID_STL", - "-DV8_COMPONENT=$V8_COMPONENT_RELEASE", - "-DHIDDEN_LIBRARY_SYMBOL=$HIDDEN_LIBRARY_SYMBOL" - - if (INCLUDE_ABI_ARMEABI_V7A.toBoolean() || INCLUDE_ABI_ARMEABI.toBoolean()) { - abiFilters 'armeabi-v7a' - } - if (INCLUDE_ABI_ARM64_V8A.toBoolean()) { - abiFilters 'arm64-v8a' - } - if (INCLUDE_ABI_X86.toBoolean()) { - abiFilters 'x86' - } - if (INCLUDE_ABI_X86_64.toBoolean()) { - abiFilters 'x86_64' - } - } - } - } - debug { - minifyEnabled false - externalNativeBuild { - cmake { - arguments "-DJS_ENGINE=V8", - "-DANDROID_CPP_FEATURES=rtti exceptions", - "-DANDROID_PLATFORM=android-21", - "-DCMAKE_BUILD_TYPE=Debug", - "-DANDROID_STL=$ANDROID_STL", - "-DV8_COMPONENT=$V8_COMPONENT_DEBUG", - "-DHIDDEN_LIBRARY_SYMBOL=$HIDDEN_LIBRARY_SYMBOL" - - if (INCLUDE_ABI_ARMEABI_V7A.toBoolean() || INCLUDE_ABI_ARMEABI.toBoolean()) { - abiFilters 'armeabi-v7a' - } - if (INCLUDE_ABI_ARM64_V8A.toBoolean()) { - abiFilters 'arm64-v8a' - } - if (INCLUDE_ABI_X86.toBoolean()) { - abiFilters 'x86' - } - if (INCLUDE_ABI_X86_64.toBoolean()) { - abiFilters 'x86_64' - } - } - } - } - } - - if (!SKIP_CMAKE_AND_NINJA.toBoolean() || !skipCmakeAndNinja) { - externalNativeBuild { - cmake { - path CMAKE_PATH - } - } - } - - tasks.withType(JavaCompile) { - options.encoding = "UTF-8" - } - - sourceSets{ - main { - if (INCLUDE_SUPPORT_UI.toBoolean() == false) { - java.exclude("com/tencent/mtt/supportui/**") - } - - jniLibs.srcDirs = ["${THIRD_PARTY_LIBRARY_PATH}/layout"] - } - } -} - -dependencies { - api fileTree(dir: 'libs', include: ['*.jar']) - //noinspection GradleDependency - implementation 'androidx.annotation:annotation:1.0.0' - //noinspection GradleDependency - implementation 'androidx.recyclerview:recyclerview:1.1.0' - if (!INCLUDE_SUPPORT_UI.toBoolean()) { - compileOnly('com.tencent.mtt:support-ui:99.2.3') - } - - testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:2.8.9" - testImplementation "org.mockito:mockito-android:2.8.9" - testImplementation "org.powermock:powermock-module-junit4:2.0.7" - testImplementation "org.powermock:powermock-api-mockito2:2.0.7" - testImplementation 'org.powermock:powermock-core:2.0.7' - testImplementation "org.powermock:powermock-module-junit4-rule:2.0.7" - testImplementation "org.powermock:powermock-classloading-xstream:2.0.7" - testImplementation "org.robolectric:robolectric:4.4" -} - -project.tasks.whenTaskAdded { task -> - if (task.name == 'assembleRelease') { - task.finalizedBy dealAfterAssembleRelease - } - - if (task.name == 'assembleDebug') { - task.finalizedBy dealAfterAssembleDebug - } - - if (task.name == 'mergeReleaseNativeLibs') { - task.finalizedBy dealAfterMergeReleaseNativeLibs - } - - if (task.name == 'mergeDebugNativeLibs') { - task.finalizedBy dealAfterMergeDebugNativeLibs - } -} - -def dealAfterMergeNativeLibs(mergedNativeLibsPath) { - EXCLUDE_LIBRARY_FILES.tokenize(";").each{filename -> - if (INCLUDE_ABI_ARMEABI_V7A.toBoolean() || INCLUDE_ABI_ARMEABI.toBoolean()) { - delete "$mergedNativeLibsPath/armeabi-v7a/$filename" - } - if (INCLUDE_ABI_ARM64_V8A.toBoolean()) { - delete "$mergedNativeLibsPath/arm64-v8a/$filename" - } - if (INCLUDE_ABI_X86.toBoolean()) { - delete "$mergedNativeLibsPath/x86/$filename" - } - if (INCLUDE_ABI_X86_64.toBoolean()) { - delete "$mergedNativeLibsPath/x86_64/$filename" - } - } - delete "$mergedNativeLibsPath/armeabi" - if (INCLUDE_ABI_ARMEABI.toBoolean()) { - copy { - from "$mergedNativeLibsPath/armeabi-v7a" - into "$mergedNativeLibsPath/armeabi" - } - if (!INCLUDE_ABI_ARMEABI_V7A.toBoolean()) { - delete "$mergedNativeLibsPath/armeabi-v7a" - } - } -} - -def MERGED_NATIVE_LIBS_PATH = "$buildDir/intermediates/merged_native_libs" -task dealAfterMergeReleaseNativeLibs() { - doLast { - dealAfterMergeNativeLibs("$MERGED_NATIVE_LIBS_PATH/release/out/lib") - } -} - -task dealAfterMergeDebugNativeLibs() { - doLast { - dealAfterMergeNativeLibs("$MERGED_NATIVE_LIBS_PATH/debug/out/lib") - } -} - -def dealAfterAssemble(buildType) { - file("$OUTPUT_PATH/$buildType").deleteDir() - - file(OUTPUT_PATH).list().each{fileName -> - if (fileName.contains(buildType + ".aar")) { - copy { - from zipTree("$OUTPUT_PATH/$fileName") - into "$OUTPUT_PATH/$buildType" - } - copy { - from "$OUTPUT_PATH/$buildType" - into OUTPUT_PATH - include 'classes.jar' - rename 'classes.jar', 'hippy.jar' - } - } - } -} - -task dealAfterAssembleDebug() { - doLast { - dealAfterAssemble("debug") - } -} - -task dealAfterAssembleRelease() { - doLast { - dealAfterAssemble("release") - copy { - from "$OUTPUT_PATH/$ARCHIVES_BASE_NAME-release.aar" - into "$projectDir.absolutePath/../../examples/android-demo/example/libs" - } - } -} diff --git a/android/sdk/gradle.properties b/android/sdk/gradle.properties deleted file mode 100644 index aac8735ef62..00000000000 --- a/android/sdk/gradle.properties +++ /dev/null @@ -1,130 +0,0 @@ -# Tencent is pleased to support the open source community by making -# Hippy available. -# -# Copyright (C) 2019 THL A29 Limited, a Tencent company. -# All rights reserved. -# -# 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. - -android.enableD8=true -android.enableR8=false -android.enableJetifier=true -android.useAndroidX=true - -# -# Specifies Android archives base name -# -# Equals to setting android.archivesBaseName property in the build.gradle file. -# Default is android-sdk -# -ARCHIVES_BASE_NAME=android-sdk - -# -# Specifies Android SDK version -# -COMPILE_SDK_VERSION=29 -MIN_SDK_VERSION=19 -TARGET_SDK_VERSION=29 - -# -# Specifies Android NDK version -# -# Equals to setting android.ndkVersion property in the build.gradle file. -# Default is 21.4.7075529 -# -NDK_VERSION=21.4.7075529 - -# -# Specifies Maven Central SDK version -# -# Equals to setting android.defaultConfig.versionCode and versionName property -# in the build.gradle file. -# -VERSION_NAME=1.0.0 -VERSION_CODE=1 - -# -# Whether to skip build C/C++ code -# -# The default is false, -# if you want to build C/C++ code in the other build system, set to true. -# -SKIP_CMAKE_AND_NINJA=false - -# -# ABI Filters -# -# Use specific ABIs to build C/C++ code, affect both debug and release build types. -# -# Please note that armeabi(legacy) will be built using the armeabi_v7a architecture, -# and the artifacts will be copied to the armeabi directory. -# -INCLUDE_ABI_ARMEABI=false -INCLUDE_ABI_ARMEABI_V7A=true -INCLUDE_ABI_ARM64_V8A=true -INCLUDE_ABI_X86=false -INCLUDE_ABI_X86_64=false - -# -# V8 Component Directory -# -# The following built-in V8 component directories are available: -# * third_party/v8/stable/x5-lite -# * third_party/v8/stable/official-release -# * third_party/v8/latest/official-release -# -# You can also specify the external V8 component directory to be used, -# by the way, if set to 'auto'(default), it will be automatic selection of -# v8 component directory based on the current build type. -# -V8_COMPONENT=auto - -# -# Whether to hide Hippy library symbols -# -# * true(recommend): hide non-export symbols from library: -# it can very substantially improve load times of libraries, -# produce more optimized code, reduce size of libraries -# and prevent symbol clashes. -# * false: export all symbols from library: -# it can expose all internal symbols to 3rd libraries, -# will be increase the size of library. -# -HIDDEN_LIBRARY_SYMBOL=true - -# -# Specifies which STL to use for this SDK -# -# Equals to setting -DANDROID_STL macro in the cmake.arguments property, -# recommend STL is c++_static. -# -ANDROID_STL=c++_static - -# -# Exclude library files from artifacts -# -# When you want to obtain these library files manually, -# you can set the name (separated by semicolons) of the library files -# to be excluded from the artifacts. -# -EXCLUDE_LIBRARY_FILES= - -#features -ENABLE_SO_DOWNLOAD=false -INCLUDE_SUPPORT_UI=true - -#maven central publish params -PUBLISH_ARTIFACT_ID=hippy-common -PUBLISH_GROUP_ID=com.tencent.hippy -PUBLISH_GIT_URL=https://github.com/Tencent/Hippy -PUBLISH_VERSION_DESC=Hippy library for Android diff --git a/android/sdk/gradle/wrapper/gradle-wrapper.properties b/android/sdk/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 2539a6e96aa..00000000000 --- a/android/sdk/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Thu Dec 19 10:43:01 CST 2019 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip diff --git a/android/sdk/mavencentral.gradle b/android/sdk/mavencentral.gradle deleted file mode 100644 index 99b8994c353..00000000000 --- a/android/sdk/mavencentral.gradle +++ /dev/null @@ -1,66 +0,0 @@ -apply plugin: 'maven-publish' -apply plugin: 'signing' - -ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID') -ext["signing.password"] = System.getenv('SIGNING_PASSWORD') -ext["signing.secretKeyRingFile"] = System.getenv('SIGNING_SECRET_KEY_RING_FILE') -ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME') -ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD') - -println("signing.keyId=" + ext["signing.keyId"]) -println("signing.password=" + ext["signing.password"]) -println("signing.secretKeyRingFile=" + ext["signing.secretKeyRingFile"]) -println("ossrhUsername=" + ossrhUsername) -println("ossrhPassword=" + ossrhPassword) - -publishing { - publications { - mavenAar(MavenPublication) { - artifact("$buildDir/outputs/aar/android-sdk-release.aar") - groupId PUBLISH_GROUP_ID - artifactId PUBLISH_ARTIFACT_ID - version VERSION_NAME - pom { - name = PUBLISH_ARTIFACT_ID - description = PUBLISH_VERSION_DESC - url = PUBLISH_GIT_URL - licenses { - license { - name = 'The Apache Software License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - developers { - developer { - id = PUBLISH_ARTIFACT_ID - name = 'Tencent Hippy' - email = 'maxli@tencent.com' - } - } - scm { - connection = "scm:git@github.com:Tencent/Hippy.git" - developerConnection = "scm:git@github.com:Tencent/Hippy.git" - url = PUBLISH_GIT_URL - } - } - } - } - repositories { - maven { - def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2" - def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots" - url = VERSION_NAME.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl - - credentials { - username ossrhUsername - password ossrhPassword - } - } - } -} - -signing { - sign publishing.publications.mavenAar -} - - diff --git a/android/sdk/proguard-rules.pro b/android/sdk/proguard-rules.pro deleted file mode 100644 index 02c889acaef..00000000000 --- a/android/sdk/proguard-rules.pro +++ /dev/null @@ -1,219 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in D:\Users\xiandongluo\AppData\Local\Android\sdk1/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile -#-optimizationpasses 7 -#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* --dontoptimize --dontusemixedcaseclassnames --verbose --dontskipnonpubliclibraryclasses --dontskipnonpubliclibraryclassmembers -#noinspection ShrinkerUnresolvedReference -#-overloadaggressively - --dontwarn **HoneycombMR2 --dontwarn **CompatICS --dontwarn **Honeycomb --dontwarn **CompatIcs* --dontwarn **CompatFroyo --dontwarn **CompatGingerbread --dontwarn android.support.** --dontwarn com.alipay.sdk.** --dontwarn com.tencent.mm.opensdk.** --dontwarn android.telephony.** --dontwarn android.graphics.** --dontwarn android.view.** --dontwarn com.tencent.mtt.weapp.** --dontwarn **ConcurrentHashMap** --dontwarn **KeySetView - -# - --keep public class * extends android.app.Activity { - public ; - public ; -} --keep public class * extends android.app.Application { - public ; - public ; -} - --keep public class * extends android.app.Service --keep public class * extends android.content.BroadcastReceiver --keep public class * extends android.content.ContentProvider --keep public class * extends android.app.backup.BackupAgentHelper --keep public class * extends android.preference.Preference - --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} - --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet); -} - --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet, int); -} - --keepattributes *Annotation*,Signature,InnerClasses - -# - --keepclasseswithmembers class * { - native ; -} - --keep class * implements android.os.Parcelable { - public static final android.os.Parcelable$Creator *; -} - -# -# -# - --keep class **JNI* {*;} - --keep class com.tencent.mtt.hippy.*{*;} - - --keep class com.tencent.mtt.hippy.common.* {*;} - --keep class com.tencent.mtt.hippy.annotation.* {*;} - --keep class com.tencent.mtt.hippy.adapter.** {*;} - --keep class com.tencent.mtt.hippy.modules.* {*;} - - --keep class * extends com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase{ public *;} - --keep class com.tencent.mtt.hippy.modules.nativemodules.* {*;} - --keep class com.tencent.mtt.hippy.modules.javascriptmodules.* {*;} - --keep class com.tencent.mtt.hippy.bridge.bundleloader.* {*;} - -#-keep class com.tencent.mtt.hippy.uimanager.* {*;} --keep class com.tencent.mtt.hippy.uimanager.DiffUtils {*;} --keep class com.tencent.mtt.hippy.uimanager.DiffUtils$* {*;} --keep class com.tencent.mtt.hippy.uimanager.HippyCustomViewCreator {*;} --keep class com.tencent.mtt.hippy.uimanager.HippyViewController {*;} --keep class com.tencent.mtt.hippy.uimanager.HippyViewBase {*;} --keep class com.tencent.mtt.hippy.uimanager.HippyGroupController {*;} --keep class com.tencent.mtt.hippy.uimanager.HippyViewEvent {*;} --keep class com.tencent.mtt.hippy.uimanager.RenderNode {*;} --keepclasseswithmembers class com.tencent.mtt.hippy.uimanager.RenderManager { -public com.tencent.mtt.hippy.uimanager.RenderNode getRenderNode(int); -public com.tencent.mtt.hippy.uimanager.ControllerManager getControllerManager(); -public void addUpdateNodeIfNeeded(com.tencent.mtt.hippy.uimanager.RenderNode); -} --keep class com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher {*;} --keep class com.tencent.mtt.hippy.uimanager.ListItemRenderNode{ -public boolean shouldSticky(); -} --keepclasseswithmembers class com.tencent.mtt.hippy.uimanager.ControllerManager { -public android.view.View findView(int); -public void deleteChild(int ,int ); -} --keepclasseswithmembers class com.tencent.mtt.hippy.dom.DomManager { -public void updateNodeSize(int,int,int); -public void forceUpdateNode(int); -public void addActionInterceptor(com.tencent.mtt.hippy.dom.node.DomActionInterceptor); -public void removeActionInterceptor(com.tencent.mtt.hippy.dom.node.DomActionInterceptor); - -} --keepclasseswithmembers class com.tencent.mtt.hippy.bridge.HippyBridgeImpl { -*; -} - --keepclasseswithmembers class com.tencent.mtt.hippy.bridge.NativeCallback { -*; -} - --keep public interface com.tencent.mtt.hippy.modules.nativemodules.deviceevent.DeviceEventModule$InvokeDefaultBackPress {*;} - --keep class com.tencent.mtt.hippy.utils.* {*;} --keep class com.tencent.mtt.hippy.dom.node.NodeProps {*;} --keep class com.tencent.mtt.hippy.dom.node.TextExtra {*;} --keep class * extends com.tencent.mtt.hippy.dom.node.DomNode {*;} - --keep class com.tencent.mtt.hippy.views.** {*;} --keep interface com.tencent.mtt.hippy.bridge.HippyBridge {*;} - --keep class com.tencent.mtt.supportui.views.** {*;} --keep class com.tencent.mtt.hippy.utils.** {*;} --keep class com.tencent.mtt.hippy.dom.node.TypeFaceUtil {*;} --keep class com.tencent.mtt.hippy.adapter.image.HippyImageLoader {*;} --keep class com.tencent.mtt.hippy.dom.node.DomActionInterceptor {*;} - --keepclasseswithmembers class com.tencent.mtt.supportui.** { -public ; -} - --keepclasseswithmembers class com.tencent.mtt.supportui.** { -protected ; -} - --keepclasseswithmembers class com.tencent.mtt.supportui.** { -public ; -} - --keepclasseswithmembers class com.tencent.mtt.supportui.** { -protected ; -} - --keepclasseswithmembers class androidx.recyclerview.widget.** { -public ; -} - --keepclasseswithmembers class androidx.recyclerview.widget.** { -protected ; -} - --keepclasseswithmembers class androidx.recyclerview.widget.** { -public ; -} - --keepclasseswithmembers class androidx.recyclerview.widget.** { -protected ; -} - -# turbo --keep class com.tencent.mtt.hippy.annotation.HippyTurboObj - --keep @com.tencent.mtt.hippy.annotation.HippyTurboObj class * {*;} - --keep class com.tencent.mtt.hippy.annotation.HippyTurboProp - --keepclasseswithmembers class * { - @com.tencent.mtt.hippy.annotation.HippyTurboProp ; -} - --keep public class com.tencent.mtt.hippy.bridge.jsi.TurboModuleManager { -public ; -public ; -} diff --git a/android/sdk/src/main/AndroidManifest.xml b/android/sdk/src/main/AndroidManifest.xml deleted file mode 100644 index 9bcf06a8719..00000000000 --- a/android/sdk/src/main/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/EasyLinearLayoutManager.java b/android/sdk/src/main/java/androidx/recyclerview/widget/EasyLinearLayoutManager.java deleted file mode 100644 index fdfdc00ba1d..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/EasyLinearLayoutManager.java +++ /dev/null @@ -1,161 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView.Adapter; -import androidx.recyclerview.widget.RecyclerView.LayoutParams; -import androidx.recyclerview.widget.RecyclerView.State; -import android.util.AttributeSet; -import android.view.View; -import java.util.HashMap; - -public class EasyLinearLayoutManager extends LinearLayoutManager { - - /** - * 无效的高度 - */ - public static final int INVALID_HEIGHT = -1; - private static final LayoutParams ITEM_LAYOUT_PARAMS = new LayoutParams(0, 0); - /** - * 由于排版后才知道对应item的高度,topMargin和bottomMargin,所以这里缓存一下这些值 - */ - protected HashMap itemHeightMaps = new HashMap<>(); - protected HashMap itemTopMarginMaps = new HashMap<>(); - protected HashMap itemBottomMarginMaps = new HashMap<>(); - - public EasyLinearLayoutManager(Context context) { - super(context); - } - - public EasyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { - super(context, orientation, reverseLayout); - } - - public EasyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - /** - * 排版完成后,缓存view的排版信息 - */ - @Override - public void layoutDecoratedWithMargins(@NonNull View child, int left, int top, int right, - int bottom) { - super.layoutDecoratedWithMargins(child, left, top, right, bottom); - cacheItemLayoutParams(bottom - top, (LayoutParams) child.getLayoutParams(), getPosition(child)); - } - - /** - * 缓存Item排版信息,缓存信息有两种来源 一种是排版过程中的得到实际上屏的排版信息 {@link #layoutDecoratedWithMargins(View, int, int, - * int, int)} 一种是从adapter获取的item的预排版信息 {@link #getItemHeightFromAdapter(int)} - * - * @param height item的高度 - * @param layoutParams 排版参数 - * @param position 位置 - */ - private void cacheItemLayoutParams(int height, LayoutParams layoutParams, int position) { - itemBottomMarginMaps.put(position, layoutParams.bottomMargin); - itemTopMarginMaps.put(position, layoutParams.topMargin); - itemHeightMaps.put(position, height); - } - - /** - * 从adapter 获取position对应的排版信息,这里不需要排版,是item预先指定的高度 - */ - int getItemHeightFromAdapter(int position) { - Adapter adapter = mRecyclerView.getAdapter(); - if (adapter instanceof IItemLayoutParams) { - IItemLayoutParams layoutInfo = (IItemLayoutParams) adapter; - resetLayoutParams(); - layoutInfo.getItemLayoutParams(position, ITEM_LAYOUT_PARAMS); - if (ITEM_LAYOUT_PARAMS.height >= 0) { - cacheItemLayoutParams(ITEM_LAYOUT_PARAMS.height, ITEM_LAYOUT_PARAMS, position); - return ITEM_LAYOUT_PARAMS.height + ITEM_LAYOUT_PARAMS.bottomMargin - + ITEM_LAYOUT_PARAMS.topMargin; - } - } - return INVALID_HEIGHT; - } - - /** - * 清除之前的缓存数据,ITEM_LAYOUT_PARAMS 不是最终用来排版的,只是一个参数的载体 - */ - private static void resetLayoutParams() { - ITEM_LAYOUT_PARAMS.height = 0; - ITEM_LAYOUT_PARAMS.topMargin = 0; - ITEM_LAYOUT_PARAMS.rightMargin = 0; - ITEM_LAYOUT_PARAMS.leftMargin = 0; - ITEM_LAYOUT_PARAMS.bottomMargin = 0; - } - - /** - * 计算position以前(包含position)的高度,如果发现其中有一个没有缓存,那么得出来的值是无效的 - */ - int getHeightUntilPosition(int position) { - int totalHeight = 0; - for (int i = 0; i <= position; i++) { - Integer height = itemHeightMaps.get(i); - if (height == null) { - height = getItemHeightFromAdapter(i); - } - if (height != null && height != INVALID_HEIGHT) { - totalHeight += height; - } else { - return INVALID_HEIGHT; - } - } - return totalHeight; - } - - /** - * 由于父类的computeVerticalScrollOffset是基于平均值计算高度。对于Item类型和高度不一样的情况,计算是有误差的。 - * 用第一个可见view的前面总的内容高度减去第一个可见view的底部位置 - * - * @return 当前的内容偏移,也就是被推出顶部以外的内容高度。 - */ - @Override - public int computeVerticalScrollOffset(State state) { - if (getChildCount() <= 0 || getItemCount() <= 0) { - return 0; - } - int firstVisiblePosition = findFirstVisibleItemPosition(); - View firstVisibleView = findViewByPosition(firstVisiblePosition); - int heightUntilPosition = getHeightUntilPosition(firstVisiblePosition); - if (firstVisibleView != null && heightUntilPosition != INVALID_HEIGHT) { - return heightUntilPosition - mOrientationHelper.getDecoratedEnd(firstVisibleView); - } - return super.computeVerticalScrollOffset(state); - } - - - /** - * 由于父类的computeVerticalScrollRange是基于平均值计算高度。对于Item类型和高度不一样的情况,计算是有误差的。 - * - * @return 内容的总高度 - **/ - @Override - public int computeVerticalScrollRange(State state) { - int heightUntilPosition = getHeightUntilPosition(getItemCount() - 1); - if (heightUntilPosition != INVALID_HEIGHT) { - return heightUntilPosition; - } - return super.computeVerticalScrollRange(state); - } -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/EasyRecyclerView.java b/android/sdk/src/main/java/androidx/recyclerview/widget/EasyRecyclerView.java deleted file mode 100644 index 776c2a11444..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/EasyRecyclerView.java +++ /dev/null @@ -1,233 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - - -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.RecycledViewPool.ScrapData; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import java.lang.reflect.Field; -import java.util.ArrayList; - -public class EasyRecyclerView extends RecyclerView { - - protected OverPullHelper overPullHelper; - protected OverPullListener overPullListener; - protected VelocityTracker velocityTracker; - - public EasyRecyclerView(@NonNull Context context) { - super(context); - init(); - } - - public EasyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(); - } - - public EasyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - protected void init() { - } - - public int getOverPullState() { - if (overPullHelper != null) { - return overPullHelper.getOverPullState(); - } - return OverPullHelper.OVER_PULL_NONE; - } - - public boolean isOverPulling() { - int pullState = getOverPullState(); - return pullState == OverPullHelper.OVER_PULL_DOWN_ING - || pullState == OverPullHelper.OVER_PULL_UP_ING - || pullState == OverPullHelper.OVER_PULL_SETTLING; - } - - /** - * 下拉的时候,返回值<0,表示顶部被下拉了一部分距离,顶部有空白 - */ - public int getOverPullUpOffset() { - if (overPullHelper != null) { - return overPullHelper.getOverPullUpOffset(); - } - return 0; - } - - /** - * 上拉的时候,返回值>0,表示底部被上拉了一部分距离,底部有空白 - */ - public int getOverPullDownOffset() { - if (overPullHelper != null) { - return overPullHelper.getOverPullDownOffset(); - } - return 0; - } - - public void setOverPullListener(OverPullListener listener) { - overPullListener = listener; - if (overPullHelper != null) { - overPullHelper.setOverPullListener(listener); - } - } - - public void setEnableOverPull(boolean enableOverDrag) { - if (enableOverDrag) { - if (overPullHelper == null) { - overPullHelper = new OverPullHelper(this); - } - overPullHelper.setOverPullListener(overPullListener); - } else { - overPullHelper = null; - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (overPullHelper != null && overPullHelper.onTouchEvent(event)) { - return true; - } - boolean handled = super.onTouchEvent(event); - if (overPullHelper != null) { - overPullHelper.handleEventUp(event); - } - return handled; - } - - @Override - public void requestLayout() { - super.requestLayout(); - } - - public void recycleAndClearCachedViews() { - mRecycler.recycleAndClearCachedViews(); - } - - public int getChildCountWithCaches() { - return getCachedViewHolderCount() + getChildCount(); - } - - public View getChildAtWithCaches(int index) { - ArrayList viewHolders = getCachedViewHolders(); - if (index < viewHolders.size()) { - return viewHolders.get(index).itemView; - } else { - return getChildAt(index - viewHolders.size()); - } - } - - private int getCachedViewHolderCount() { - int count = mRecycler.mAttachedScrap.size() + mRecycler.mCachedViews.size(); - for (int i = 0; i < mRecycler.getRecycledViewPool().mScrap.size(); i++) { - ScrapData scrapData = mRecycler.getRecycledViewPool().mScrap.valueAt(i); - count += scrapData.mScrapHeap.size(); - } - return count; - } - - public ArrayList getCachedViewHolders() { - ArrayList listViewHolder = new ArrayList<>(); - listViewHolder.addAll(mRecycler.mAttachedScrap); - listViewHolder.addAll(mRecycler.mCachedViews); - for (int i = 0; i < mRecycler.getRecycledViewPool().mScrap.size(); i++) { - ScrapData scrapData = mRecycler.getRecycledViewPool().mScrap.valueAt(i); - listViewHolder.addAll(scrapData.mScrapHeap); - } - return listViewHolder; - } - - public boolean didStructureChange() { - return mState.didStructureChange(); - } - - - public int getFirstChildPosition() { - return getChildLayoutPosition(getChildCount() > 0 ? getChildAt(0) : null); - } - - public int getLashChildPosition() { - return getChildLayoutPosition(getChildCount() > 0 ? getChildAt(getChildCount() - 1) : null); - } - - /** - * 通过位置获取一个ViewHolder,目前暂时提供给header使用 - */ - public ViewHolder getViewHolderForPosition(int position) { - View view = mRecycler.getViewForPosition(position); - if (view.getLayoutParams() instanceof LayoutParams) { - return ((LayoutParams) view.getLayoutParams()).mViewHolder; - } - return null; - } - - public ViewHolder getFistChildViewHolder() { - View view = getChildAt(0); - if (view != null && view.getLayoutParams() instanceof LayoutParams) { - return ((LayoutParams) view.getLayoutParams()).mViewHolder; - } - return null; - } - - /** - * 改成public接口,主要用于hippy业务的特殊需求 - */ - @Override - public void dispatchLayout() { - super.dispatchLayout(); - } - - @Override - public void invalidateGlows() { - super.invalidateGlows(); - } - - /** - * 反射获取滚动的VelocityTracker - */ - public VelocityTracker getVelocityTracker() { - if (velocityTracker == null) { - try { - Field velocityTrackerField = RecyclerView.class.getDeclaredField("mVelocityTracker"); - velocityTrackerField.setAccessible(true); - velocityTracker = (VelocityTracker) velocityTrackerField.get(this); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - return velocityTracker; - } - - /** - * recyclerView的adapter状态已经变化,但是没有进行notify,导致state和adapter 的itemCount对不齐,比如hippy场景,直接把recyclerView的renderNode删除了,adapter的itemCount直接变为0, - * 由于没有notifyDatSetChange,state的itemCount不为0,这样就会出现validateViewHolderForOffsetPosition报 - * IndexOutOfBoundsException - */ - public boolean isDataChangedWithoutNotify() { - return getAdapter().getItemCount() != mState.getItemCount(); - } -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyItemTypeHelper.java b/android/sdk/src/main/java/androidx/recyclerview/widget/HippyItemTypeHelper.java deleted file mode 100644 index be032212389..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyItemTypeHelper.java +++ /dev/null @@ -1,119 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - -import androidx.recyclerview.widget.RecyclerView.RecycledViewPool.ScrapData; -import androidx.recyclerview.widget.RecyclerView.Recycler; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import android.util.SparseArray; -import com.tencent.mtt.hippy.uimanager.ListItemRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewHolder; -import java.util.ArrayList; - -public class HippyItemTypeHelper { - - HippyRecyclerViewBase recyclerView; - private Recycler recycler; - - public HippyItemTypeHelper(HippyRecyclerViewBase recyclerView) { - this.recyclerView = recyclerView; - this.recycler = recyclerView.mRecycler; - } - - /** - * 更新3层缓存的ViewHolder - * - * @param oldType 老的type - * @param newType 新的type - * @param listItemRenderNode 前端变化type的RenderNode - */ - public void updateItemType(int oldType, int newType, ListItemRenderNode listItemRenderNode) { - int count = recyclerView.getChildCount(); - for (int i = 0; i < count; i++) { - final ViewHolder holder = recyclerView - .getChildViewHolder(recyclerView.getChildAt(i)); - if (changeTypeIfNeed(oldType, newType, listItemRenderNode, holder)) { - return; - } - } - - if (updateItemType(oldType, newType, listItemRenderNode, recycler.mAttachedScrap)) { - return; - } - - if (updateItemType(oldType, newType, listItemRenderNode, recyclerView.mRecycler.mCachedViews)) { - return; - } - - updateTypeForRecyclerPool(oldType, newType, listItemRenderNode); - } - - private void updateTypeForRecyclerPool(int oldType, int newType, ListItemRenderNode renderNode) { - if (recycler.getRecycledViewPool() != null) { - SparseArray scrap = recycler.getRecycledViewPool().mScrap; - ScrapData scrapData = scrap.get(oldType); - if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) { - for (ViewHolder holder : scrapData.mScrapHeap) { - if (changeTypeIfNeed(oldType, newType, renderNode, holder)) { - scrapData.mScrapHeap.remove(holder); - addNewType(newType, holder); - return; - } - } - } - } - } - - /** - * 重新将viewHolder加入缓存池 - */ - private void addNewType(int newType, ViewHolder holder) { - holder.mItemViewType = newType; - SparseArray scrap = recycler.getRecycledViewPool().mScrap; - ScrapData newScrapData = scrap.get(newType); - if (newScrapData == null) { - newScrapData = new ScrapData(); - scrap.append(newType, newScrapData); - } - newScrapData.mScrapHeap.add(holder); - } - - private boolean updateItemType(int oldType, int newType, ListItemRenderNode listItemRenderNode, - ArrayList viewHolders) { - final int cacheSize = viewHolders.size(); - for (int i = 0; i < cacheSize; i++) { - final ViewHolder holder = viewHolders.get(i); - if (changeTypeIfNeed(oldType, newType, listItemRenderNode, holder)) { - return true; - } - } - return false; - } - - private boolean changeTypeIfNeed(int oldType, int newType, ListItemRenderNode listItemRenderNode, - ViewHolder holder) { - if (holder.getItemViewType() == oldType && holder instanceof HippyRecyclerViewHolder) { - RenderNode holderNode = ((HippyRecyclerViewHolder) holder).bindNode; - if (holderNode == listItemRenderNode) { - holder.mItemViewType = newType; - return true; - } - } - return false; - } -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerExtension.java b/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerExtension.java deleted file mode 100644 index 24d738cf215..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerExtension.java +++ /dev/null @@ -1,115 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - -import androidx.recyclerview.widget.RecyclerView.Recycler; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import android.view.View; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.uimanager.ListItemRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewHolder; -import com.tencent.mtt.hippy.views.hippylist.NodePositionHelper; -import java.util.ArrayList; - -public class HippyRecyclerExtension extends RecyclerView.ViewCacheExtension { - - private final HippyEngineContext hpContext; - private final NodePositionHelper nodePositionHelper; - private HippyRecyclerViewBase recyclerView; - private int currentPosition; - - public HippyRecyclerExtension(HippyRecyclerViewBase recyclerView, HippyEngineContext hpContext, - NodePositionHelper nodePositionHelper) { - this.nodePositionHelper = nodePositionHelper; - this.recyclerView = recyclerView; - this.hpContext = hpContext; - } - - public int getCurrentPosition() { - return currentPosition; - } - - @Override - public View getViewForPositionAndType(Recycler recycler, int position, int type) { - currentPosition = position; - View bestView = findInAttachedScrap(recycler, position, type); - if (bestView == null) { - bestView = findInCachedScrap(recycler, position, type); - } - return bestView; - } - - private View findInCachedScrap(Recycler recycler, int position, int type) { - ViewHolder bestHolder = findBestHolder(recycler.mCachedViews, position, type); - if (bestHolder != null) { - recycler.mCachedViews.remove(bestHolder); - return bestHolder.itemView; - } - return null; - } - - protected View findInAttachedScrap(Recycler recycler, int position, int type) { - ViewHolder bestHolder = findBestHolder(recycler.mAttachedScrap, position, type); - if (bestHolder != null) { - bestHolder.unScrap(); - return bestHolder.itemView; - } - return null; - } - - private ViewHolder findBestHolder(ArrayList viewHolders, int position, - int type) { - int scrapCount = viewHolders.size(); - for (int i = 0; i < scrapCount; i++) { - final ViewHolder holder = viewHolders.get(i); - if (isTheBestHolder(position, type, holder)) { - return holder; - } - } - return null; - } - - /** - * 找到对应的bindNode,比对缓存池的holder是否正好是当前position位置对应的Holder - * - * @param position 要获取Holder的position - * @param type 节点类型 - * @param scrapHolder 缓存池的Holder - * @return - */ - protected boolean isTheBestHolder(int position, int type, ViewHolder scrapHolder) { - if (scrapHolder.getAdapterPosition() != position || scrapHolder.isInvalid() || scrapHolder - .isRemoved()) { - return false; - } - if (scrapHolder.getItemViewType() == type && scrapHolder instanceof HippyRecyclerViewHolder) { - RenderNode nodeOfPosition = hpContext.getRenderManager().getRenderNode(recyclerView.getId()) - .getChildAt(nodePositionHelper.getRenderNodePosition(position)); - return isNodeEquals(((HippyRecyclerViewHolder) scrapHolder).bindNode, - (ListItemRenderNode) nodeOfPosition); - } - return false; - } - - public static boolean isNodeEquals(ListItemRenderNode node1, ListItemRenderNode node2) { - if (node1 == null || node2 == null) { - return false; - } - return node1.equals(node2); - } -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerPool.java b/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerPool.java deleted file mode 100644 index db0d53dbf3c..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerPool.java +++ /dev/null @@ -1,113 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import android.view.View; -import android.view.ViewGroup; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewHolder; -import com.tencent.mtt.hippy.views.hippylist.NodePositionHelper; - -public class HippyRecyclerPool extends RecyclerView.RecycledViewPool { - - private final View recyclerView; - private final HippyRecyclerExtension viewCacheExtension; - private final HippyEngineContext hpContext; - private final NodePositionHelper nodePositionHelper; - private IHippyViewAboundListener viewAboundListener; - - public HippyRecyclerPool(HippyEngineContext hpContext, View recyclerView, - HippyRecyclerExtension viewCacheExtension, NodePositionHelper nodePositionHelper) { - this.nodePositionHelper = nodePositionHelper; - this.hpContext = hpContext; - this.recyclerView = recyclerView; - this.viewCacheExtension = viewCacheExtension; - } - - public void setViewAboundListener(IHippyViewAboundListener viewAboundListener) { - this.viewAboundListener = viewAboundListener; - } - - /** - * 从缓存池里面获取ViewHolder进行复用 1、精确命中相同的renderNode 2、命中相同Type的ViewHolder,并且对应的RenderNode是没有被前端删除的 - * 如果renderNode.isDelete为true,说明前端删除了RenderNode, 此时会调用 RenderManager框架的deleteChild, 所以view也不会存在了。 - * 即使找到了相同type的Holder,也不能复用了。 - */ - @Override - public ViewHolder getRecycledView(int viewType) { - ScrapData scrapData = mScrap.get(viewType); - if (scrapData == null) { - return null; - } - ViewHolder delegateHolder = null; - for (ViewHolder holder : scrapData.mScrapHeap) { - if (isTheSameRenderNode((HippyRecyclerViewHolder) holder)) { - scrapData.mScrapHeap.remove(holder); - delegateHolder = holder; - break; - } - } - //没有精确命中,再看看缓存池里面有没有相同类型的viewType - if (delegateHolder == null) { - delegateHolder = super.getRecycledView(viewType); - } - //检测对应的节点是否被删除 - if (delegateHolder instanceof HippyRecyclerViewHolder - && ((HippyRecyclerViewHolder) delegateHolder).isRenderDeleted()) { - return null; - } - return delegateHolder; - } - - /** - * putRecycledView 可能出现缓存已经超过最大值,会发生ViewHolder被抛弃, 抛弃需要后,需要同步修改 renderManager内部创建对应的view,这样 {@link - * com.tencent.mtt.hippy.views.hippylist.HippyRecyclerListAdapter#onCreateViewHolder(ViewGroup, - * int)},才能通过 {@link RenderNode#createViewRecursive()} 创建新的view, 否则createViewRecursive会返回null。 - * - * @param scrap - */ - @Override - public void putRecycledView(ViewHolder scrap) { - notifyAboundIfNeed(scrap); - super.putRecycledView(scrap); - } - - private void notifyAboundIfNeed(ViewHolder scrap) { - int viewType = scrap.getItemViewType(); - ScrapData scrapData = this.mScrap.get(viewType); - if (scrapData != null && scrapData.mScrapHeap.size() >= scrapData.mMaxScrap) { - viewAboundListener.onViewAbound((HippyRecyclerViewHolder) scrap); - } - } - - /** - * 是否是节点完全相等 - * - * @param scrapHolder 缓存池里面的Holder - */ - private boolean isTheSameRenderNode(HippyRecyclerViewHolder scrapHolder) { - if (scrapHolder.bindNode == null) { - return false; - } - RenderNode nodeForCurrent = hpContext.getRenderManager().getRenderNode(recyclerView.getId()) - .getChildAt( - nodePositionHelper.getRenderNodePosition(viewCacheExtension.getCurrentPosition())); - return scrapHolder.bindNode.equals(nodeForCurrent); - } -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerViewBase.java b/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerViewBase.java deleted file mode 100644 index f68b9477781..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/HippyRecyclerViewBase.java +++ /dev/null @@ -1,75 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - - -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.util.AttributeSet; -import androidx.recyclerview.widget.LinearLayoutManager; - -public class HippyRecyclerViewBase extends EasyRecyclerView { - - public HippyRecyclerViewBase(@NonNull Context context) { - super(context); - } - - public HippyRecyclerViewBase(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public HippyRecyclerViewBase(@NonNull Context context, @Nullable AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - } - - /** - * @param position 从哪一个数据位置开始排版,将position的item置顶 - * @param offset 相对于RecyclerView底部的offset,offset>0:内容下移,offset<0:内容上移 - */ - public void scrollToPositionWithOffset(int position, int offset) { - if (mLayoutSuppressed) { - return; - } - stopScroll(); - if (this.mLayout == null) { - android.util.Log.e("RecyclerView", - "Cannot scroll to position a LayoutManager set. Call setLayoutManager with a non-null argument."); - } else { - LayoutManager layoutManager = getLayoutManager(); - if (layoutManager instanceof LinearLayoutManager) { - ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, offset); - } else { - this.mLayout.scrollToPosition(position); - } - this.awakenScrollBars(); - } - } - - @Override - String exceptionLabel() { - return super.exceptionLabel() + ",state:" + getStateInfo(); - } - - public String getStateInfo() { - if (mState != null) { - return mState.toString(); - } - return null; - } -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/IHippyViewAboundListener.java b/android/sdk/src/main/java/androidx/recyclerview/widget/IHippyViewAboundListener.java deleted file mode 100644 index 0516c1488ff..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/IHippyViewAboundListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package androidx.recyclerview.widget; - -import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewHolder; - -public interface IHippyViewAboundListener { - - void onViewAbound(HippyRecyclerViewHolder viewHolder); -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/IItemLayoutParams.java b/android/sdk/src/main/java/androidx/recyclerview/widget/IItemLayoutParams.java deleted file mode 100644 index 7193f98210a..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/IItemLayoutParams.java +++ /dev/null @@ -1,8 +0,0 @@ -package androidx.recyclerview.widget; - -import androidx.recyclerview.widget.RecyclerView.LayoutParams; - -public interface IItemLayoutParams { - - void getItemLayoutParams(int position, LayoutParams lp); -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/OverPullHelper.java b/android/sdk/src/main/java/androidx/recyclerview/widget/OverPullHelper.java deleted file mode 100644 index 654f8ce3ec7..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/OverPullHelper.java +++ /dev/null @@ -1,342 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - -import static android.view.View.OVER_SCROLL_NEVER; - -import android.animation.Animator; -import android.animation.ValueAnimator; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView.OnScrollListener; -import android.view.MotionEvent; -import android.view.ViewConfiguration; -import android.view.animation.DecelerateInterpolator; -import com.tencent.mtt.nxeasy.recyclerview.helper.AnimatorListenerBase; - -public class OverPullHelper { - - private static final int DURATION = 150; - protected float lastRawY = -1; - protected float downRawY = -1; - - private int overPullState = OVER_PULL_NONE; - public static final int OVER_PULL_NONE = 0; - public static final int OVER_PULL_DOWN_ING = 1; - public static final int OVER_PULL_UP_ING = 2; - public static final int OVER_PULL_NORMAL = 3; - public static final int OVER_PULL_SETTLING = 4; - - private ValueAnimator animator; - private boolean enableOverDrag = true; - private int lastOverScrollMode = -1; - private boolean isRollBacking = false; - private OverPullListener overPullListener = null; - private EasyRecyclerView recyclerView; - - public OverPullHelper(EasyRecyclerView recyclerView) { - this.recyclerView = recyclerView; - lastOverScrollMode = recyclerView.getOverScrollMode(); - recyclerView.addOnScrollListener(new OnScrollListener() { - @Override - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - if (newState == RecyclerView.SCROLL_STATE_IDLE) { - rollbackToBottomOrTop(); - } - } - }); - } - - private int getTouchSlop() { - final ViewConfiguration vc = ViewConfiguration.get(recyclerView.getContext()); - return vc.getScaledTouchSlop(); - } - - public void setOverPullListener(OverPullListener overPullListener) { - this.overPullListener = overPullListener; - } - - private boolean isMoving(MotionEvent event) { - return lastRawY > 0 && Math.abs(event.getRawY() - downRawY) > getTouchSlop(); - } - - public boolean onTouchEvent(MotionEvent event) { - if (isRollBacking) { - return true; - } - if (checkOverDrag(event)) { - return true; - } - return false; - } - - /** - * 检测是否处于顶部过界拉取,或者顶部过界拉取 - */ - private boolean checkOverDrag(MotionEvent event) { - if (!enableOverDrag) { - return false; - } - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - lastRawY = event.getRawY(); - downRawY = event.getRawY(); - break; - case MotionEvent.ACTION_MOVE: - boolean overPullDown = isOverPullDown(event); - boolean overScrollUp = isOverPullUp(event); - if ((overPullDown || overScrollUp)) { - recyclerView.setOverScrollMode(OVER_SCROLL_NEVER); - recyclerView.invalidateGlows(); - if (overPullDown) { - setOverPullState(OVER_PULL_DOWN_ING); - } else { - setOverPullState(OVER_PULL_UP_ING); - } - int deltaY = (int) (event.getRawY() - lastRawY) / 2; -// if (deltaY > 0) { -// //下拉的时候除以2,放慢拉动的速度,调节拉动的手感 -// deltaY = deltaY / 2; -// } - recyclerView.offsetChildrenVertical(deltaY); - if (overPullListener != null) { - overPullListener - .onOverPullStateChanged(overPullState, overPullState, getOverPullOffset()); - } - } else { - setOverPullState(OVER_PULL_NORMAL); - } - lastRawY = event.getRawY(); - break; - default: - reset(); - } - if (overPullState == OVER_PULL_DOWN_ING || overPullState == OVER_PULL_UP_ING) { - return true; - } - return false; - } - - /** - * 在松开手后, 1、如果当前处于fling状态,scrollState的值是SCROLL_STATE_SETTLING,先不做rollbackToBottomOrTop - * 等到onScrollStateChanged 变成 IDLE的时候,再做rollbackToBottomOrTop 2、如果当前处于非fling状态,scrollState的值不是SCROLL_STATE_SETTLING,就立即做rollbackToBottomOrTop - */ - public void handleEventUp(MotionEvent event) { - if (isActionUpOrCancel(event)) { - revertOverScrollMode(); - if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_SETTLING) { - rollbackToBottomOrTop(); - } - } - } - - private void revertOverScrollMode() { - if (lastOverScrollMode != -1) { - recyclerView.setOverScrollMode(lastOverScrollMode); - } - } - - private int getOverPullOffset() { - if (overPullState == OVER_PULL_DOWN_ING) { - return getOverPullDownOffset(); - } else if (overPullState == OVER_PULL_UP_ING) { - return getOverPullUpOffset(); - } - return 0; - } - - void setOverPullState(int newOverPullState) { - if (overPullListener != null) { - overPullListener.onOverPullStateChanged(overPullState, newOverPullState, getOverPullOffset()); - } - overPullState = newOverPullState; - } - - /** - * 因为可能出现越界拉取,松手后需要回退到原来的位置,要么回到顶部,要么回到底部 - */ - void rollbackToBottomOrTop() { - int distanceToTop = recyclerView.computeVerticalScrollOffset(); - if (distanceToTop < 0) { - //顶部空出了一部分,需要回滚上去 - rollbackTo(distanceToTop, 0); - } else { - //底部空出一部分,需要混滚下去 - int overPullUpOffset = getOverPullUpOffset(); - if (overPullUpOffset != 0) { - rollbackTo(overPullUpOffset, 0); - } - } - } - - /** - * 计算底部被overPull的偏移,需要向下回滚的距离 要么出现底部内容顶满distanceToBottom,要么出现顶部内容顶满distanceToTop,取最小的那一个 - * - * @return - */ - public int getOverPullUpOffset() { - int contentOffset = recyclerView.computeVerticalScrollOffset(); - int verticalScrollRange = recyclerView.computeVerticalScrollRange(); - int blankHeightToBottom = contentOffset + recyclerView.getHeight() - verticalScrollRange; - if (blankHeightToBottom > 0 && contentOffset > 0) { - return Math.min(blankHeightToBottom, contentOffset); - } - return 0; - } - - private boolean isActionUpOrCancel(MotionEvent event) { - return event.getAction() == MotionEvent.ACTION_UP - || event.getAction() == MotionEvent.ACTION_CANCEL; - } - - private void endAnimation() { - if (animator != null) { - animator.removeAllListeners(); - animator.removeAllUpdateListeners(); - animator.end(); - animator = null; - } - isRollBacking = false; - } - - /** - * 回弹动画的接口 - */ - private void rollbackTo(int from, int to) { - endAnimation(); - animator = ValueAnimator.ofInt(from, to); - animator.setInterpolator(new DecelerateInterpolator()); - animator.addUpdateListener(new RollbackUpdateListener(from)); - animator.addListener(new AnimatorListenerBase() { - @Override - public void onAnimationEnd(Animator animation) { - setOverPullState(OVER_PULL_NONE); - isRollBacking = false; - } - }); - isRollBacking = true; - animator.setDuration(DURATION).start(); - } - - private void reset() { - revertOverScrollMode(); - lastRawY = -1; - downRawY = -1; - setOverPullState(OVER_PULL_NONE); - } - - /** - * 顶部是否可以越界下拉,拉出一段空白区域,越界的部分最多不能超过RecyclerView高度+1 - */ - private boolean isOverPullDown(MotionEvent event) { - //常规情况,内容在顶部offset为0,异常情况,内容被完全拉到最底部,看不见内容的时候,offset也为0 - int offset = recyclerView.computeVerticalScrollOffset(); - int dy = Math.abs((int) (event.getRawY() - lastRawY)) + 1; - //不能把内容完全拉得看不见 - if (Math.abs(offset) + dy < recyclerView.getHeight()) { - return isMoving(event) && isPullDownAction(event) && !canOverPullDown(); - } - return false; - } - - /** - * 底部是否可以越界上拉,拉出一段空白区域,越界的部分最多不能超过RecyclerView高度的一般 - */ - private boolean isOverPullUp(MotionEvent event) { - int dy = Math.abs((int) (event.getRawY() - lastRawY)) + 1; - //不能让内容完全被滚出屏幕,否则computeVerticalScrollOffset为0是一个无效的值 - int distanceToBottom = - recyclerView.computeVerticalScrollOffset() + recyclerView.getHeight() - recyclerView - .computeVerticalScrollRange(); - if (distanceToBottom + dy < recyclerView.getHeight()) { - return isMoving(event) && isPullUpAction(event) && !canOverPullUp(); - } - return false; - } - - boolean isPullDownAction(MotionEvent event) { - return event.getRawY() - lastRawY > 0; - } - - boolean isPullUpAction(MotionEvent event) { - return event.getRawY() - lastRawY <= 0; - } - - /** - * 顶部还有内容,还可以向下拉到 - */ - boolean canOverPullDown() { - return recyclerView.canScrollVertically(-1); - } - - /** - * 底部还有内容,还可以向上拉动 - */ - boolean canOverPullUp() { - return recyclerView.canScrollVertically(1); - } - - public int getOverPullState() { - return overPullState; - } - - /** - * 下拉的时候,返回值<0,表示顶部被下拉了一部分距离 - */ - public int getOverPullDownOffset() { - if (overPullState == OVER_PULL_DOWN_ING) { - return recyclerView.computeVerticalScrollOffset(); - } - return 0; - } - - private class RollbackUpdateListener implements ValueAnimator.AnimatorUpdateListener { - - int currentValue; - int totalConsumedY; - - RollbackUpdateListener(int fromValue) { - currentValue = fromValue; - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (recyclerView.isDataChangedWithoutNotify()) { - //由于动画是一个异步操作,做动画的时候,recyclerView的adapter状态已经变化,但是没有进行notify,导致state和adapter - //的itemCount对不齐,比如hippy场景,直接把recyclerView的renderNode删除了,adapter的itemCount直接变为0, - //由于没有notifyDatSetChange,state的itemCount不为0,这样就会出现validateViewHolderForOffsetPosition报 - //IndexOutOfBoundsException - return; - } - int value = (int) animation.getAnimatedValue(); - int[] consumed = new int[2]; - int dy = value - currentValue; - //dy>0 上回弹,列表内容向上滚动,慢慢显示底部的内容;dy<0 下回弹,列表内容向下滚动,慢慢显示顶部的内容 - recyclerView.scrollStep(0, dy, consumed); - int consumedY = consumed[1]; - totalConsumedY += consumedY; - - //consumedY是排版view消耗的Y的距离,没有内容填充,即consumedY为0,需要强行offsetChildrenVertical - int leftOffset = consumedY - dy; - if (leftOffset != 0) { - //leftOffset<0 向上回弹,leftOffset>0 向下回弹 - recyclerView.offsetChildrenVertical(leftOffset); - } - setOverPullState(OVER_PULL_SETTLING); - currentValue = value; - } - } -} diff --git a/android/sdk/src/main/java/androidx/recyclerview/widget/OverPullListener.java b/android/sdk/src/main/java/androidx/recyclerview/widget/OverPullListener.java deleted file mode 100644 index ad7eb67f3e2..00000000000 --- a/android/sdk/src/main/java/androidx/recyclerview/widget/OverPullListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 androidx.recyclerview.widget; - -public interface OverPullListener { - - /** - * @param newState {@link OverPullHelper#OVER_PULL_DOWN_ING} - * @param offset - */ - - void onOverPullStateChanged(int oldState, int newState, int offset); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngine.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngine.java deleted file mode 100644 index c9efbeabfde..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngine.java +++ /dev/null @@ -1,456 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy; - -import android.content.Context; -import android.text.TextUtils; - -import com.tencent.mtt.hippy.adapter.DefaultLogAdapter; -import com.tencent.mtt.hippy.adapter.HippyLogAdapter; -import com.tencent.mtt.hippy.adapter.device.DefaultDeviceAdapter; -import com.tencent.mtt.hippy.adapter.device.HippyDeviceAdapter; -import com.tencent.mtt.hippy.adapter.exception.DefaultExceptionHandler; -import com.tencent.mtt.hippy.adapter.exception.HippyExceptionHandlerAdapter; -import com.tencent.mtt.hippy.adapter.executor.DefaultExecutorSupplierAdapter; -import com.tencent.mtt.hippy.adapter.executor.HippyExecutorSupplierAdapter; -import com.tencent.mtt.hippy.adapter.font.DefaultFontScaleAdapter; -import com.tencent.mtt.hippy.adapter.font.HippyFontScaleAdapter; -import com.tencent.mtt.hippy.adapter.http.DefaultHttpAdapter; -import com.tencent.mtt.hippy.adapter.http.HippyHttpAdapter; -import com.tencent.mtt.hippy.adapter.image.HippyImageLoader; -import com.tencent.mtt.hippy.adapter.monitor.DefaultEngineMonitorAdapter; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorAdapter; -import com.tencent.mtt.hippy.adapter.sharedpreferences.DefaultSharedPreferencesAdapter; -import com.tencent.mtt.hippy.adapter.sharedpreferences.HippySharedPreferencesAdapter; -import com.tencent.mtt.hippy.adapter.soloader.DefaultSoLoaderAdapter; -import com.tencent.mtt.hippy.adapter.soloader.HippySoLoaderAdapter; -import com.tencent.mtt.hippy.adapter.storage.DefaultStorageAdapter; -import com.tencent.mtt.hippy.adapter.storage.HippyStorageAdapter; -import com.tencent.mtt.hippy.bridge.HippyCoreAPI; -import com.tencent.mtt.hippy.bridge.bundleloader.HippyBundleLoader; -import com.tencent.mtt.hippy.bridge.libraryloader.LibraryLoader; -import com.tencent.mtt.hippy.common.HippyJsException; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.UIThreadUtils; -import com.tencent.mtt.hippy.adapter.thirdparty.HippyThirdPartyAdapter; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicInteger; - -@SuppressWarnings({"deprecation", "unused", "rawtypes"}) -public abstract class HippyEngine { - - private static final AtomicInteger sIdCounter = new AtomicInteger(); - @SuppressWarnings("unchecked") - final CopyOnWriteArrayList mEventListeners = new CopyOnWriteArrayList(); - volatile EngineState mCurrentState = EngineState.UNINIT; - // Engine的ID,唯一 - private final int mID = sIdCounter.getAndIncrement(); - // Engine所属的分组ID,同一个组共享线程和isolate,不同context - protected int mGroupId; - ModuleListener mModuleListener; - - static { - LibraryLoader.loadLibraryIfNeed(); - } - - public static void setNativeLogHandler(IHippyNativeLogHandler handler) { - if (handler != null) { - initNativeLogHandler(handler); - } - } - - @SuppressWarnings("JavaJniMissingFunction") - private static native void initNativeLogHandler(IHippyNativeLogHandler handler); - - /** - * @param params 创建实例需要的参数 创建一个HippyEngine实例 - */ - public static HippyEngine create(EngineInitParams params) { - if (params == null) { - throw new RuntimeException("Hippy: initParams must no be null"); - } - params.check(); - LogUtils.enableDebugLog(params.enableLog); - ContextHolder.initAppContext(params.context); - - HippyEngine hippyEngine; - if (params.groupId == -1) { - hippyEngine = new HippyNormalEngineManager(params, null); - } else { - hippyEngine = new HippySingleThreadEngineManager(params, null); - } - - return hippyEngine; - } - - /** - * listen engine state. no need to make this method public - */ - protected void listen(EngineListener listener) { - // 通知listener都要在UI线程 - if (UIThreadUtils.isOnUiThread()) { - listenInUIThread(listener); - } else { - final EngineListener listenerFinal = listener; - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - listenInUIThread(listenerFinal); - } - }); - } - } - - /** - * listen engine state in UI thread - */ - private void listenInUIThread(EngineListener listener) { - // 1. 若mCurrentState是结束态,无论成功还是失败,要直接通知结果并返回。 - // 2. 若mCurrentState是初始化过程中的状态,则把listener添加到mEventListeners后返回 - if (mCurrentState == EngineState.INITED) { - listener.onInitialized(EngineInitStatus.STATUS_OK, null); - } else if (mCurrentState == EngineState.INITERRORED || mCurrentState == EngineState.DESTROYED) { - listener.onInitialized(EngineInitStatus.STATUS_WRONG_STATE, "engine state=" + mCurrentState); - } else // 说明mCurrentState是初始化过程中的状态 - { - mEventListeners.add(listener); - } - } - - @SuppressWarnings("unused") - public EngineState getEngineState() { - return mCurrentState; - } - - /** - * get group id - */ - public int getGroupId() { - return mGroupId; - } - - /** - * get engine id - */ - public int getId() { - return mID; - } - - public abstract void initEngine(EngineListener listener); - - // 是否调试模式 - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - public abstract boolean isDebugMode(); - - /** - * destroy the hippy engine All hippy instance will be destroyed - */ - @SuppressWarnings("EmptyMethod") - public abstract void destroyEngine(); - - /** - * 加载hippy业务模块 ,函数组 - * - * @param loadParams 加载hippy业务模块时需要的参数 - */ - public abstract HippyRootView loadModule(ModuleLoadParams loadParams); - - public abstract HippyRootView loadModule(ModuleLoadParams loadParams, ModuleListener listener); - - @SuppressWarnings("unused") - public abstract HippyRootView loadModule(ModuleLoadParams loadParams, ModuleListener listener, - HippyRootView.OnLoadCompleteListener onLoadCompleteListener); - - public abstract void destroyModule(HippyRootView moduleView); - - /** - * resume hippy engine - */ - public abstract void onEngineResume(); - - /** - * pause hippy engine - */ - public abstract void onEnginePause(); - - public abstract void sendEvent(String event, Object params); - - public abstract void sendEvent(String event, Object params, BridgeTransferType transferType); - - public abstract void preloadModule(HippyBundleLoader loader); - - public abstract boolean onBackPressed(BackPressHandler handler); - - public abstract HippyEngineContext getEngineContext(); - - public interface BackPressHandler { - - void handleBackPress(); - } - - public enum EngineState { - UNINIT, - INITING, - ONRESTART, - INITERRORED, - INITED, - DESTROYED - } - - // Hippy 引擎初始化时的参数设置 - @SuppressWarnings("deprecation") - public static class EngineInitParams { - - // 必须 宿主(Hippy的使用者)的Context - public Context context; - // 必须 图片加载器:需要实现异步的图片加载接口fetchImage(),和同步的图片加载接口getImage()。 - public HippyImageLoader imageLoader; - - // 可选参数 核心的jsbundle的assets路径(assets路径和文件路径二选一,优先使用assets路径),debugMode = false时有效 - public String coreJSAssetsPath; - // 可选参数 核心的jsbundle的文件路径(assets路径和文件路径二选一,优先使用assets路径),debugMode = false时有效 - public String coreJSFilePath; - // 可选参数 指定需要预加载的业务模块bundle assets路径 - public HippyBundleLoader jsPreloadAssetsPath; - // 可选参数 指定需要预加载的业务模块bundle 文件路径 - public HippyBundleLoader jsPreloadFilePath; - public boolean debugMode = false; - // 可选参数 是否开启调试模式,默认为false,不开启 - // 可选参数 Hippy Server的jsbundle名字,默认为"index.bundle"。debugMode = true时有效 - public final String debugBundleName = "index.bundle"; - // 可选参数 Hippy Server的Host。默认为"localhost:38989"。debugMode = true时有效 - public String debugServerHost = "localhost:38989"; - // 可选参数 自定义的,用来提供Native modules、JavaScript modules、View controllers的管理器。1个或多个 - public List providers; - //Optional is use V8 serialization or json - public boolean enableV8Serialization = true; - // 可选参数 是否打印引擎的完整的log。默认为false - public boolean enableLog = false; - // 可选参数 code cache的名字,如果设置为空,则不启用code cache,默认为 "" - public String codeCacheTag = ""; - - //可选参数 接收RuntimeId - public HippyThirdPartyAdapter thirdPartyAdapter; - - // 可选参数 接收异常 - public HippyExceptionHandlerAdapter exceptionHandler; - // 可选参数 设置相关 - public HippySharedPreferencesAdapter sharedPreferencesAdapter; - // 可选参数 Http request adapter - public HippyHttpAdapter httpAdapter; - // 可选参数 Storage adapter 设置相关 - public HippyStorageAdapter storageAdapter; - // 可选参数 Executor Supplier adapter - public HippyExecutorSupplierAdapter executorSupplier; - // 可选参数 Engine Monitor adapter - public HippyEngineMonitorAdapter engineMonitor; - // 可选参数 font scale adapter - public HippyFontScaleAdapter fontScaleAdapter; - // 可选参数 so加载位置 - public HippySoLoaderAdapter soLoader; - // 可选参数 device adapter - public HippyDeviceAdapter deviceAdapter; - // 设置Hippy引擎的组,同一组的HippyEngine,会共享C层的v8 引擎实例。 默认值为-1(无效组,即不属于任何group组) - public int groupId = -1; - // 可选参数 日志输出 - @SuppressWarnings("DeprecatedIsStillUsed") - @Deprecated - public HippyLogAdapter logAdapter; - public boolean enableTurbo; - - protected void check() { - if (context == null) { - throw new IllegalArgumentException( - EngineInitParams.class.getName() + " context must not be null!"); - } - if (imageLoader == null) { - throw new IllegalArgumentException( - EngineInitParams.class.getName() + " imageLoader must not be null!"); - } - if (sharedPreferencesAdapter == null) { - sharedPreferencesAdapter = new DefaultSharedPreferencesAdapter(context); - } - if (exceptionHandler == null) { - exceptionHandler = new DefaultExceptionHandler(); - } - if (httpAdapter == null) { - httpAdapter = new DefaultHttpAdapter(); - } - if (executorSupplier == null) { - executorSupplier = new DefaultExecutorSupplierAdapter(); - } - if (storageAdapter == null) { - storageAdapter = new DefaultStorageAdapter(context, executorSupplier.getDBExecutor()); - } - if (engineMonitor == null) { - engineMonitor = new DefaultEngineMonitorAdapter(); - } - if (fontScaleAdapter == null) { - fontScaleAdapter = new DefaultFontScaleAdapter(); - } - if (soLoader == null) { - soLoader = new DefaultSoLoaderAdapter(); - } - if (deviceAdapter == null) { - deviceAdapter = new DefaultDeviceAdapter(); - } - if (logAdapter == null) { - logAdapter = new DefaultLogAdapter(); - } - if (providers == null) { - providers = new ArrayList<>(); - } - providers.add(0, new HippyCoreAPI()); - if (!debugMode) { - if (TextUtils.isEmpty(coreJSAssetsPath) && TextUtils.isEmpty(coreJSFilePath)) { - throw new RuntimeException( - "Hippy: debugMode=true, initParams.coreJSAssetsPath and coreJSFilePath both null!"); - } - } - } - } - - // Hippy 业务模块jsbundle加载时的参数设置 - @SuppressWarnings("deprecation") - public static class ModuleLoadParams { - - // 必须参数 挂载HippyRootView的Activity or Dialog的Context。注意,只有Context为当前Activity时,调试模式才能使用 - public Context context; - /** - * 必须参数 业务模块jsbundle中定义的组件名称。componentName对应的是js文件中的"appName",比如: var hippy = new Hippy({ - * appName: "Demo", entryPage: App }); - */ - public String componentName; - - // 可选参数 二选一设置 自己开发的业务模块的jsbundle的assets路径(assets路径和文件路径二选一,优先使用assets路径) - public String jsAssetsPath; - // 可选参数 二选一设置 自己开发的业务模块的文件路径(assets路径和文件路径二选一,优先使用assets路径) - public String jsFilePath; - // 可选参数 传递给前端的rootview:比如:Hippy.entryPage: class App extends Component - public HippyMap jsParams; - // 可选参数 目前只有一个用处:映射:"CustomViewCreator" <==> 宿主自定义的一个HippyCustomViewCreator(这个creator还得通过ModuleParams.Builder.setCustomViewCreator来指定才行) - public Map nativeParams; - // 可选参数 方便对将本View和hippyContext进行绑定。对于这种场景时有用:某些View组件的创建先于业务模块初始化的时机(也就是View组件的预先创建、预加载)。 - public HippyInstanceContext hippyContext; - // 可选参数 Bundle加载器,老式用法,不建议使用(若一定要使用,则会覆盖jsAssetsPath,jsFilePath的值)。参见jsAssetsPath,jsFilePath - // 可选参数 code cache的名字,如果设置为空,则不启用code cache,默认为 "" - public String codeCacheTag = ""; - @SuppressWarnings("DeprecatedIsStillUsed") - @Deprecated - public HippyBundleLoader bundleLoader; - - public ModuleLoadParams() { - } - - public ModuleLoadParams(ModuleLoadParams params) { - context = params.context; - jsAssetsPath = params.jsAssetsPath; - jsFilePath = params.jsFilePath; - componentName = params.componentName; - jsParams = params.jsParams; - nativeParams = params.nativeParams; - hippyContext = params.hippyContext; - codeCacheTag = params.codeCacheTag; - bundleLoader = params.bundleLoader; - } - } - - /** - * 引擎初始化过程中的错误码,对于hippy sdk开发者调查hippy sdk的使用者在使用过程中遇到的问题,很必须。 - */ - - public enum EngineInitStatus { - STATUS_OK(0), // 初始化成功 - STATUS_ERR_BRIDGE(-101), // 初始化过程,initBridge错误 - STATUS_ERR_DEVSERVER(-102), // 初始化过程,devServer错误 - STATUS_WRONG_STATE(-103), // 状态错误。调用init函数时,引擎不在未初始化的状态 - STATUS_INIT_EXCEPTION(-104); // 初始化过程,抛出了未知的异常,详情需要查看传回的Throwable - - private final int iValue; - - EngineInitStatus(int value) { - iValue = value; - } - - @SuppressWarnings("unused") - public int value() { - return iValue; - } - } - - public enum ModuleLoadStatus { - STATUS_OK(0), // 加载正常 - STATUS_ENGINE_UNINIT(-201), // 引擎未完成初始化就加载JSBundle - STATUS_VARIABLE_NULL(-202), // check变量(bundleUniKey, loader, rootView)引用为空 - STATUS_ERR_RUN_BUNDLE(-203), // 业务JSBundle执行错误 - STATUS_REPEAT_LOAD(-204); // 重复加载同一JSBundle - - private final int iValue; - - ModuleLoadStatus(int value) { - iValue = value; - } - - @SuppressWarnings("unused") - public int value() { - return iValue; - } - } - - public enum BridgeTransferType { - BRIDGE_TRANSFER_TYPE_NORMAL(0), - BRIDGE_TRANSFER_TYPE_NIO(1); - - private final int iValue; - - BridgeTransferType(int value) { - iValue = value; - } - - public int value() { - return iValue; - } - } - - /** - * Hippy引擎初始化结果listener - */ - public interface EngineListener { - - /** - * callback after initialization - * - * @param statusCode status code from initializing procedure - * @param msg Message from initializing procedure - */ - void onInitialized(EngineInitStatus statusCode, String msg); - } - - @SuppressWarnings("unused") - public interface ModuleListener { - - void onLoadCompleted(ModuleLoadStatus statusCode, String msg, HippyRootView hippyRootView); - - @SuppressWarnings("SameReturnValue") - boolean onJsException(HippyJsException exception); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngineContext.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngineContext.java deleted file mode 100644 index 9931eae0ae3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngineContext.java +++ /dev/null @@ -1,58 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy; - -import com.tencent.mtt.hippy.bridge.HippyBridgeManager; -import com.tencent.mtt.hippy.common.ThreadExecutor; -import com.tencent.mtt.hippy.devsupport.DevSupportManager; -import com.tencent.mtt.hippy.dom.DomManager; -import com.tencent.mtt.hippy.modules.HippyModuleManager; -import com.tencent.mtt.hippy.uimanager.RenderManager; -import com.tencent.mtt.hippy.utils.TimeMonitor; - -@SuppressWarnings("unused") -public interface HippyEngineContext { - - HippyGlobalConfigs getGlobalConfigs(); - - HippyModuleManager getModuleManager(); - - HippyBridgeManager getBridgeManager(); - - DevSupportManager getDevSupportManager(); - - ThreadExecutor getThreadExecutor(); - - DomManager getDomManager(); - - RenderManager getRenderManager(); - - HippyRootView getInstance(int id); - - void addInstanceLifecycleEventListener(HippyInstanceLifecycleEventListener listener); - - void removeInstanceLifecycleEventListener(HippyInstanceLifecycleEventListener listener); - - void addEngineLifecycleEventListener(HippyEngineLifecycleEventListener listener); - - void removeEngineLifecycleEventListener(HippyEngineLifecycleEventListener listener); - - void handleException(Throwable throwable); - - TimeMonitor getStartTimeMonitor(); - - int getEngineId(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java deleted file mode 100644 index 8c88313dcf5..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java +++ /dev/null @@ -1,866 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Hippy - * available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * 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 com.tencent.mtt.hippy; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.text.TextUtils; - -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorAdapter; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorEvent; -import com.tencent.mtt.hippy.adapter.thirdparty.HippyThirdPartyAdapter; -import com.tencent.mtt.hippy.bridge.HippyBridgeManager; -import com.tencent.mtt.hippy.bridge.HippyBridgeManagerImpl; -import com.tencent.mtt.hippy.bridge.bundleloader.HippyAssetBundleLoader; -import com.tencent.mtt.hippy.bridge.bundleloader.HippyBundleLoader; -import com.tencent.mtt.hippy.bridge.bundleloader.HippyFileBundleLoader; -import com.tencent.mtt.hippy.bridge.bundleloader.HippyRemoteBundleLoader; -import com.tencent.mtt.hippy.common.Callback; -import com.tencent.mtt.hippy.common.HippyJsException; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.common.ThreadExecutor; -import com.tencent.mtt.hippy.devsupport.DevServerCallBack; -import com.tencent.mtt.hippy.devsupport.DevSupportManager; -import com.tencent.mtt.hippy.dom.DomManager; -import com.tencent.mtt.hippy.modules.HippyModuleManager; -import com.tencent.mtt.hippy.modules.HippyModuleManagerImpl; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.modules.nativemodules.deviceevent.DeviceEventModule; -import com.tencent.mtt.hippy.uimanager.RenderManager; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.TimeMonitor; -import com.tencent.mtt.hippy.utils.UIThreadUtils; -import java.io.InputStream; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -@SuppressWarnings({"deprecation", "unused"}) -public abstract class HippyEngineManagerImpl extends HippyEngineManager implements - DevServerCallBack, HippyRootView.OnSizeChangedListener, - HippyRootView.OnResumeAndPauseListener, ThreadExecutor.UncaughtExceptionHandler { - - static final String TAG = "HippyEngineManagerImpl"; - - static final int MSG_ENGINE_INIT_TIMEOUT = 100; - /** - * All HippyCompoundView Instance collections,multi-thread read and write - */ - final CopyOnWriteArrayList mInstances = new CopyOnWriteArrayList<>(); - /** - * global configuration - */ - final HippyGlobalConfigs mGlobalConfigs; - /** - * core bundle loader - */ - HippyBundleLoader mCoreBundleLoader; - /** - * preload bundle loader - */ - final HippyBundleLoader mPreloadBundleLoader; - /** - * providers - */ - final List mAPIProviders; - /** - * Dev support manager - */ - DevSupportManager mDevSupportManager; - HippyEngineContextImpl mEngineContext; - // 从网络上加载jsbundle - final boolean mDebugMode; - // Hippy Server的jsbundle名字,调试模式下有效 - final String mServerBundleName; - // Hippy Server的host,调试模式下有效 - private final String mServerHost; - - final boolean enableV8Serialization; - - boolean mDevManagerInited = false; - final TimeMonitor mStartTimeMonitor; - boolean mHasReportEngineLoadResult = false; - private final HippyThirdPartyAdapter mThirdPartyAdapter; - - final Handler mHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - if (msg.what - == MSG_ENGINE_INIT_TIMEOUT) { - reportEngineLoadResult( - HippyEngineMonitorAdapter.ENGINE_LOAD_RESULE_TIMEOUT, - null); - } - super.handleMessage(msg); - } - }; - - HippyEngineManagerImpl(EngineInitParams params, HippyBundleLoader preloadBundleLoader) { - super(); - - // create core bundle loader - HippyBundleLoader coreBundleLoader = null; - if (!TextUtils.isEmpty(params.coreJSAssetsPath)) { - coreBundleLoader = new HippyAssetBundleLoader(params.context, params.coreJSAssetsPath, - !TextUtils.isEmpty(params.codeCacheTag), params.codeCacheTag); - } else if (!TextUtils.isEmpty(params.coreJSFilePath)) { - coreBundleLoader = new HippyFileBundleLoader(params.coreJSFilePath, - !TextUtils.isEmpty(params.codeCacheTag), params.codeCacheTag); - } - - this.mGlobalConfigs = new HippyGlobalConfigs(params); - this.mCoreBundleLoader = coreBundleLoader; - this.mPreloadBundleLoader = preloadBundleLoader; - this.mAPIProviders = params.providers; - this.mDebugMode = params.debugMode; - this.mServerBundleName = params.debugMode ? params.debugBundleName : ""; - this.mStartTimeMonitor = new TimeMonitor(!params.debugMode); - this.enableV8Serialization = params.enableV8Serialization; - this.mServerHost = params.debugServerHost; - this.mGroupId = params.groupId; - this.mThirdPartyAdapter = params.thirdPartyAdapter; - } - - /** - * 初始化引擎。这个method,可重入。也就是允许重复调用,而不会导致异常 - */ - @Override - public void initEngine(EngineListener listener) { - if (mCurrentState != EngineState.UNINIT) { - if (listener != null) { - listen(listener); - } - return; - } - - mCurrentState = EngineState.INITING; - if (listener != null) { - mEventListeners.add(listener); - } - - mGlobalConfigs.getEngineMonitorAdapter().reportEngineLoadStart(); - mHandler.removeMessages(MSG_ENGINE_INIT_TIMEOUT); - - try { - mDevSupportManager = new DevSupportManager(mGlobalConfigs, mDebugMode, mServerHost, - mServerBundleName); - mDevSupportManager.setDevCallback(this); - - if (mDebugMode) { - String url = mDevSupportManager.createResourceUrl(mServerBundleName); - mCoreBundleLoader = new HippyRemoteBundleLoader(url); - ((HippyRemoteBundleLoader) mCoreBundleLoader).setIsDebugMode(true); - } - - LogUtils.d(TAG, "start restartEngineInBackground..."); - restartEngineInBackground(); - } catch (Throwable e) { - mCurrentState = EngineState.INITERRORED; - notifyEngineInitialized(EngineInitStatus.STATUS_INIT_EXCEPTION, e); - } - } - - @Override - public void destroyEngine() { - if (mEngineContext == null) { - return; - } - - mEngineContext.destroyBridge(new Callback() { - @Override - public void callback(Boolean param, Throwable e) { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - onDestroy(); - } - }); - } - }); - } - - protected void onDestroy() { - mCurrentState = EngineState.DESTROYED; - for (HippyRootView rootView : mInstances) { - destroyInstance(rootView); - } - - mEventListeners.clear(); - resetEngine(); - - if (mGlobalConfigs != null) { - mGlobalConfigs.destroyIfNeed(); - } - mExtendDatas.clear(); - } - - @Override - public HippyInstanceContext preCreateInstanceContext(Context context) { - return new HippyInstanceContext(context); - } - - @Override - public HippyRootView loadModule(ModuleLoadParams loadParams) { - return loadModule(loadParams, null, null); - } - - @Override - public HippyRootView loadModule(ModuleLoadParams loadParams, ModuleListener listener) { - return loadModule(loadParams, listener, null); - } - - @Override - public HippyRootView loadModule(ModuleLoadParams loadParams, ModuleListener listener, - HippyRootView.OnLoadCompleteListener onLoadCompleteListener) { - if (loadParams == null) { - throw new RuntimeException("Hippy: loadModule loadParams must no be null"); - } - if (loadParams.context == null) { - throw new RuntimeException("Hippy: loadModule loadParams.context must no be null"); - } - if (!mDebugMode && TextUtils.isEmpty(loadParams.jsAssetsPath) && TextUtils - .isEmpty(loadParams.jsFilePath)) { - throw new RuntimeException( - "Hippy: loadModule debugMode=true, loadParams.jsAssetsPath and jsFilePath both null!"); - } - - if (loadParams.jsParams == null) { - loadParams.jsParams = new HippyMap(); - } - if (loadParams.hippyContext != null) { - loadParams.hippyContext.setModuleParams(loadParams); - } - if (!TextUtils.isEmpty(loadParams.jsAssetsPath)) { - loadParams.jsParams.pushString("sourcePath", loadParams.jsAssetsPath); - } else { - loadParams.jsParams.pushString("sourcePath", loadParams.jsFilePath); - } - mModuleListener = listener; - - HippyRootView view = new HippyRootView(loadParams); - - if (mCurrentState == EngineState.DESTROYED) { - notifyModuleLoaded(ModuleLoadStatus.STATUS_ENGINE_UNINIT, - "load module error wrong state, Engine destroyed", view); - return view; - } - if (onLoadCompleteListener != null) { - view.setOnLoadCompleteListener(onLoadCompleteListener); - } - view.setTimeMonitor(new TimeMonitor(!mDebugMode)); - view.getTimeMonitor().begine(); - view.getTimeMonitor().startEvent(HippyEngineMonitorEvent.MODULE_LOAD_EVENT_WAIT_ENGINE); - view.setOnResumeAndPauseListener(this); - view.setOnSizeChangedListener(this); - view.attachEngineManager(this); - mInstances.add(view); - mDevSupportManager.attachToHost(view); - if (!mDevManagerInited && mDebugMode) { - mDevManagerInited = true; - } - - LogUtils.d(TAG, "internalLoadInstance start..."); - if (mCurrentState == EngineState.INITED) { - internalLoadInstance(view); - } else { - notifyModuleLoaded(ModuleLoadStatus.STATUS_ENGINE_UNINIT, - "error wrong state, Engine state not INITED, state:" + mCurrentState, view); - } - - return view; - } - - @Deprecated - @Override - public HippyRootView loadInstance(HippyRootViewParams params) { - return loadInstance(params, null, null); - } - - @Deprecated - @Override - public HippyRootView loadInstance(HippyRootViewParams params, ModuleListener listener) { - return loadInstance(params, listener, null); - } - - @Deprecated - @Override - public HippyRootView loadInstance(HippyRootViewParams params, ModuleListener listener, - HippyRootView.OnLoadCompleteListener onLoadCompleteListener) { - ModuleLoadParams loadParams = new ModuleLoadParams(); - loadParams.context = params.getActivity(); - loadParams.componentName = params.getName(); - // getBundleLoader可能为空,debugMode = false的时候 - HippyBundleLoader loader = params.getBundleLoader(); - if (loader instanceof HippyAssetBundleLoader) { - loadParams.jsAssetsPath = params.getBundleLoader().getRawPath(); - } else if (loader instanceof HippyFileBundleLoader) { - loadParams.jsFilePath = params.getBundleLoader().getRawPath(); - } - loadParams.jsParams = params.getLaunchParams(); - loadParams.nativeParams = params.getNativeParams(); - loadParams.hippyContext = params.getInstanceContext(); - loadParams.bundleLoader = params.getBundleLoader(); - return loadModule(loadParams, listener, onLoadCompleteListener); - } - - @Override - public void destroyModule(HippyRootView moduleView) { - if (moduleView == null || !mInstances.contains(moduleView)) { - return; - } - moduleView.setOnResumeAndPauseListener(null); - moduleView.setOnSizeChangedListener(null); - if (mDevSupportManager != null) { - mDevSupportManager.detachFromHost(moduleView); - } - - if (mEngineContext != null && mEngineContext.getBridgeManager() != null) { - mEngineContext.getBridgeManager().destroyInstance(moduleView.getId()); - } - if (mEngineContext != null && mEngineContext.mInstanceLifecycleEventListeners != null) { - for (HippyInstanceLifecycleEventListener hippyInstanceLifecycleEventListener : mEngineContext.mInstanceLifecycleEventListeners) { - hippyInstanceLifecycleEventListener.onInstanceDestroy(moduleView.getId()); - } - } - moduleView.destroy(); - mInstances.remove(moduleView); - } - - @Deprecated - public HippyEngineContextImpl getCurrentEngineContext() { - return getEngineContext(); - } - - public HippyEngineContextImpl getEngineContext() { - return mEngineContext; - } - - @Override - public void onEngineResume() { - if (mEngineContext != null && mEngineContext.mEngineLifecycleEventListeners != null) { - for (HippyRootView rootView : mInstances) { - rootView.onResume(); - } - - Iterator iterator = mEngineContext.mEngineLifecycleEventListeners - .iterator(); - HippyEngineLifecycleEventListener listener; - while (iterator.hasNext()) { - listener = iterator.next(); - if (listener instanceof DomManager) { - continue; - } - listener.onEngineResume(); - } - - // dom要最后恢复执行,才能保证UI状态 - DomManager domManager = mEngineContext.getDomManager(); - if (domManager != null) { - domManager.onEngineResume(); - } - } - } - - @Override - public void onEnginePause() { - if (mEngineContext != null && mEngineContext.mEngineLifecycleEventListeners != null) { - for (HippyRootView rootView : mInstances) { - rootView.onPause(); - } - - // dom要最先暂停执行,才能保证UI状态 - DomManager domManager = mEngineContext.getDomManager(); - if (domManager != null) { - domManager.onEnginePause(); - } - - Iterator iterator = mEngineContext.mEngineLifecycleEventListeners - .iterator(); - HippyEngineLifecycleEventListener listener; - while (iterator.hasNext()) { - listener = iterator.next(); - if (listener instanceof DomManager) { - continue; - } - listener.onEnginePause(); - } - } - } - - @Override - public void sendEvent(String event, Object params, BridgeTransferType transferType) { - if (mEngineContext != null && mEngineContext.getModuleManager() != null) { - mEngineContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeEvent(event, params, transferType); - } - } - - @Override - public void sendEvent(String event, Object params) { - sendEvent(event, params, BridgeTransferType.BRIDGE_TRANSFER_TYPE_NORMAL); - } - - @Override - public void preloadModule(HippyBundleLoader loader) { - if (mEngineContext != null && mEngineContext.getBridgeManager() != null) { - mEngineContext.getBridgeManager().runBundle(-1, loader, null, null); - } - } - - @Override - public boolean onBackPressed(BackPressHandler handler) { - if (mEngineContext != null - && mEngineContext.getModuleManager().getNativeModule(DeviceEventModule.class) != null) { - return mEngineContext.getModuleManager().getNativeModule(DeviceEventModule.class) - .onBackPressed(handler); - } else { - return false; - } - } - - @Override - public boolean onBackPress(final DeviceEventModule.InvokeDefaultBackPress invokeImp) { - BackPressHandler handler = new BackPressHandler() { - @Override - public void handleBackPress() { - if (invokeImp != null) { - invokeImp.callSuperOnBackPress(); - } - } - }; - return onBackPressed(handler); - } - - @Override - public boolean isDebugMode() { - return mDebugMode; - } - - private void notifyModuleLoaded(final ModuleLoadStatus statusCode, final String msg, - final HippyRootView hippyRootView) { - if (mModuleListener != null) { - if (UIThreadUtils.isOnUiThread()) { - if (mModuleListener != null) { - mModuleListener.onLoadCompleted(statusCode, msg, hippyRootView); - mModuleListener = null; - } - } else { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - if (mModuleListener != null) { - mModuleListener.onLoadCompleted(statusCode, msg, hippyRootView); - mModuleListener = null; - } - } - }); - } - } - } - - void notifyEngineInitialized(EngineInitStatus statusCode, Throwable e) { - mHandler.removeMessages(MSG_ENGINE_INIT_TIMEOUT); - if (mPreloadBundleLoader != null) { - LogUtils.d(TAG, "preload bundle loader"); - preloadModule(mPreloadBundleLoader); - } - - if (UIThreadUtils.isOnUiThread()) { - mStartTimeMonitor.end(); - reportEngineLoadResult( - mCurrentState == EngineState.INITED ? HippyEngineMonitorAdapter.ENGINE_LOAD_RESULT_SUCCESS - : HippyEngineMonitorAdapter.ENGINE_LOAD_RESULT_ERROR, e); - for (EngineListener listener : mEventListeners) { - listener.onInitialized(statusCode, e == null ? null : e.toString()); - } - mEventListeners.clear(); - } else { - final EngineInitStatus code = statusCode; - final Throwable error = e; - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - if (mCurrentState != EngineState.DESTROYED) { - mStartTimeMonitor.end(); - reportEngineLoadResult(mCurrentState == EngineState.INITED - ? HippyEngineMonitorAdapter.ENGINE_LOAD_RESULT_SUCCESS - : HippyEngineMonitorAdapter.ENGINE_LOAD_RESULT_ERROR, error); - } - - for (EngineListener listener : mEventListeners) { - listener.onInitialized(code, error == null ? null : error.toString()); - } - mEventListeners.clear(); - } - }); - } - } - - private void reportEngineLoadResult(int code, Throwable e) { - mHandler.removeMessages(MSG_ENGINE_INIT_TIMEOUT); - if (!mDebugMode && !mHasReportEngineLoadResult) { - mHasReportEngineLoadResult = true; - mGlobalConfigs.getEngineMonitorAdapter() - .reportEngineLoadResult(code, mStartTimeMonitor.getTotalTime(), - mStartTimeMonitor.getEvents(), e); - } - } - - private synchronized void restartEngineInBackground() { - if (mCurrentState == EngineState.DESTROYED) { - String errorMsg = - "restartEngineInBackground... error STATUS_WRONG_STATE, state=" + mCurrentState; - LogUtils.e(TAG, errorMsg); - notifyEngineInitialized(EngineInitStatus.STATUS_WRONG_STATE, new Throwable(errorMsg)); - return; - } - mStartTimeMonitor.begine(); - mStartTimeMonitor.startEvent(HippyEngineMonitorEvent.ENGINE_LOAD_EVENT_INIT_INSTANCE); - if (mCurrentState != EngineState.INITING) { - mCurrentState = EngineState.ONRESTART; - } - resetEngine(); - - mEngineContext = new HippyEngineContextImpl(mDebugMode, mServerHost); - mEngineContext.getBridgeManager().initBridge(new Callback() { - @Override - public void callback(Boolean param, Throwable e) { - if (mCurrentState != EngineState.INITING && mCurrentState != EngineState.ONRESTART) { - LogUtils.e(TAG, "initBridge callback error STATUS_WRONG_STATE, state=" + mCurrentState); - notifyEngineInitialized(EngineInitStatus.STATUS_WRONG_STATE, e); - return; - } - mStartTimeMonitor - .startEvent(HippyEngineMonitorEvent.ENGINE_LOAD_EVENT_NOTIFY_ENGINE_INITED); - for (HippyRootView rootView : mInstances) { - internalLoadInstance(rootView); - } - - EngineState state = mCurrentState; - mCurrentState = param ? EngineState.INITED : EngineState.INITERRORED; - if (state != EngineState.ONRESTART) { - notifyEngineInitialized( - param ? EngineInitStatus.STATUS_OK : EngineInitStatus.STATUS_ERR_BRIDGE, e); - } else { - LogUtils.e(TAG, "initBridge callback error STATUS_WRONG_STATE, state=" + mCurrentState); - notifyEngineInitialized(EngineInitStatus.STATUS_WRONG_STATE, e); - mStartTimeMonitor.end(); - } - } - }); - } - - private void resetEngine() { - if (mEngineContext != null) { - mEngineContext.destroy(); - } - } - - private void internalLoadInstance(HippyRootView instance) { - if (mEngineContext == null || instance == null) { - notifyModuleLoaded(ModuleLoadStatus.STATUS_VARIABLE_NULL, - "load module error. mEngineContext=" + mEngineContext + ", HippyRootView instance=" - + instance, instance); - return; - } - LogUtils.d(TAG, "in internalLoadInstance"); - if (mEngineContext.mInstanceLifecycleEventListeners != null) { - for (HippyInstanceLifecycleEventListener listener : mEngineContext.mInstanceLifecycleEventListeners) { - listener.onInstanceLoad(instance.getId()); - } - } - instance.attachToEngine(mEngineContext); - HippyMap launchParams = instance.getLaunchParams(); - HippyBundleLoader loader = ((HippyInstanceContext) instance.getContext()).getBundleLoader(); - if (!mDebugMode) { - if (loader != null) { - instance.getTimeMonitor() - .startEvent(HippyEngineMonitorEvent.MODULE_LOAD_EVENT_WAIT_LOAD_BUNDLE); - mEngineContext.getBridgeManager() - .runBundle(instance.getId(), loader, mModuleListener, instance); - } else { - notifyModuleLoaded(ModuleLoadStatus.STATUS_VARIABLE_NULL, "load module error. loader==null", - instance); - return; - } - } - LogUtils.d(TAG, "in internalLoadInstance before loadInstance"); - mEngineContext.getBridgeManager() - .loadInstance(instance.getName(), instance.getId(), launchParams); - if (mDebugMode) { - notifyModuleLoaded(ModuleLoadStatus.STATUS_OK, null, instance); - } - } - - @Override - public void onInstanceResume(int id) { - if (mEngineContext == null) { - return; - } - if (mEngineContext.mInstanceLifecycleEventListeners != null) { - for (HippyInstanceLifecycleEventListener hippyInstanceLifecycleEventListener : mEngineContext.mInstanceLifecycleEventListeners) { - hippyInstanceLifecycleEventListener.onInstanceResume(id); - } - } - - if (mEngineContext.getBridgeManager() != null) { - mEngineContext.getBridgeManager().resumeInstance(id); - } - } - - @Override - public void onInstancePause(int id) { - if (mEngineContext == null) { - return; - } - if (mEngineContext.mInstanceLifecycleEventListeners != null) { - for (HippyInstanceLifecycleEventListener hippyInstanceLifecycleEventListener : mEngineContext.mInstanceLifecycleEventListeners) { - hippyInstanceLifecycleEventListener.onInstancePause(id); - } - } - - if (mEngineContext.getBridgeManager() != null) { - mEngineContext.getBridgeManager().pauseInstance(id); - } - } - - @Override - public void onDevBundleLoadReady(InputStream inputStream) { - - } - - @Override - public void onDevBundleReLoad() { - mEngineContext.destroyBridge(new Callback() { - @Override - public void callback(Boolean param, Throwable e) { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - restartEngineInBackground(); - } - }); - } - }); - } - - @Override - public void onInitDevError(Throwable e) { - mCurrentState = EngineState.INITED; - mDevManagerInited = false; - notifyEngineInitialized(EngineInitStatus.STATUS_ERR_DEVSERVER, e); - } - - @Override - public void onSizeChanged(final HippyRootView rootView, final int width, final int height, - int oldWidth, int oldHeight) { - getThreadExecutor().postOnDomThread(new Runnable() { - @Override - public void run() { - if (mEngineContext != null && mEngineContext.getDomManager() != null) { - mEngineContext.getDomManager().updateNodeSize(rootView.getId(), width, height); - } - } - }); - } - - - public abstract ThreadExecutor getThreadExecutor(); - - public abstract int getBridgeType(); - - @Override - public void handleThreadUncaughtException(Thread t, Throwable e, Integer groupId) { - if (mDebugMode && mDevSupportManager != null) { - mDevSupportManager.handleException(e); - } else { - mGlobalConfigs.getExceptionHandler().handleNativeException(new RuntimeException(e), false); - } - } - - public class HippyEngineContextImpl implements HippyEngineContext { - - /** - * UI Manager - */ - final RenderManager mRenderManager; - - volatile CopyOnWriteArrayList mEngineLifecycleEventListeners; - - /** - * All HippyCompoundView Instance Status Listener collections,multi-thread read and write - */ - volatile CopyOnWriteArrayList mInstanceLifecycleEventListeners; - - /** - * Module Manager - */ - private final HippyModuleManager mModuleManager; - /** - * Bridge Manager - */ - private final HippyBridgeManager mBridgeManager; - /** - * Dom Manager - */ - private final DomManager mDomManager; - - public HippyEngineContextImpl(boolean isDevModule, String debugServerHost) { - mModuleManager = new HippyModuleManagerImpl(this, mAPIProviders); - mBridgeManager = new HippyBridgeManagerImpl(this, mCoreBundleLoader, - HippyEngineManagerImpl.this.getBridgeType(), - enableV8Serialization, isDevModule, debugServerHost, mGroupId, mThirdPartyAdapter); - mRenderManager = new RenderManager(this, mAPIProviders); - mDomManager = new DomManager(this); - } - - @Override - public HippyGlobalConfigs getGlobalConfigs() { - return mGlobalConfigs; - } - - @Override - public HippyModuleManager getModuleManager() { - return mModuleManager; - } - - @Override - public DevSupportManager getDevSupportManager() { - return mDevSupportManager; - } - - @Override - public ThreadExecutor getThreadExecutor() { - return HippyEngineManagerImpl.this.getThreadExecutor(); - } - - @Override - public HippyBridgeManager getBridgeManager() { - return mBridgeManager; - } - - @Override - public DomManager getDomManager() { - return mDomManager; - } - - @Override - public RenderManager getRenderManager() { - return mRenderManager; - } - - @Override - public HippyRootView getInstance(int id) { - for (HippyRootView rootView : mInstances) { - if (rootView.getId() == id) { - return rootView; - } - } - return null; - } - - @Override - public void addInstanceLifecycleEventListener(HippyInstanceLifecycleEventListener listener) { - if (mInstanceLifecycleEventListeners == null) { - synchronized (HippyEngineContextImpl.class) { - if (mInstanceLifecycleEventListeners == null) { - mInstanceLifecycleEventListeners = new CopyOnWriteArrayList<>(); - } - } - } - mInstanceLifecycleEventListeners.add(listener); - } - - @Override - public void removeInstanceLifecycleEventListener(HippyInstanceLifecycleEventListener listener) { - if (mInstanceLifecycleEventListeners != null) { - mInstanceLifecycleEventListeners.remove(listener); - } - } - - @Override - public void addEngineLifecycleEventListener(HippyEngineLifecycleEventListener listener) { - if (mEngineLifecycleEventListeners == null) { - synchronized (HippyEngineContextImpl.class) { - if (mEngineLifecycleEventListeners == null) { - mEngineLifecycleEventListeners = new CopyOnWriteArrayList<>(); - } - } - } - mEngineLifecycleEventListeners.add(listener); - } - - @Override - public void removeEngineLifecycleEventListener(HippyEngineLifecycleEventListener listener) { - if (mEngineLifecycleEventListeners != null) { - mEngineLifecycleEventListeners.remove(listener); - } - } - - @Override - public void handleException(Throwable throwable) { - if (mDebugMode && mDevSupportManager != null) { - mDevSupportManager.handleException(throwable); - } else { - if (throwable instanceof HippyJsException) { - mGlobalConfigs.getExceptionHandler().handleJsException((HippyJsException) throwable); - mEngineContext.getBridgeManager().notifyModuleJsException((HippyJsException) throwable); - } else { - mGlobalConfigs.getExceptionHandler() - .handleNativeException(new RuntimeException(throwable), true); - } - - } - } - - @Override - public TimeMonitor getStartTimeMonitor() { - return HippyEngineManagerImpl.this.mStartTimeMonitor; - } - - @Override - public int getEngineId() { - return HippyEngineManagerImpl.this.getId(); - } - - public void destroyBridge(Callback callback) { - mBridgeManager.destroyBridge(callback); - } - - public void destroy() { - if (mBridgeManager != null) { - mBridgeManager.destroy(); - } - if (mModuleManager != null) { - mModuleManager.destroy(); - } - if (mDomManager != null) { - mDomManager.destroy(); - } - if (mRenderManager != null) { - mRenderManager.destroy(); - } - if (mInstanceLifecycleEventListeners != null) { - mInstanceLifecycleEventListeners.clear(); - } - if (mEngineLifecycleEventListeners != null) { - mEngineLifecycleEventListeners.clear(); - } - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyGlobalConfigs.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyGlobalConfigs.java deleted file mode 100644 index 507a43da575..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyGlobalConfigs.java +++ /dev/null @@ -1,375 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy; - -import android.content.Context; - -import com.tencent.mtt.hippy.adapter.DefaultLogAdapter; -import com.tencent.mtt.hippy.adapter.HippyLogAdapter; -import com.tencent.mtt.hippy.adapter.device.DefaultDeviceAdapter; -import com.tencent.mtt.hippy.adapter.device.HippyDeviceAdapter; -import com.tencent.mtt.hippy.adapter.exception.DefaultExceptionHandler; -import com.tencent.mtt.hippy.adapter.exception.HippyExceptionHandlerAdapter; -import com.tencent.mtt.hippy.adapter.executor.DefaultExecutorSupplierAdapter; -import com.tencent.mtt.hippy.adapter.executor.HippyExecutorSupplierAdapter; -import com.tencent.mtt.hippy.adapter.font.DefaultFontScaleAdapter; -import com.tencent.mtt.hippy.adapter.font.HippyFontScaleAdapter; -import com.tencent.mtt.hippy.adapter.http.DefaultHttpAdapter; -import com.tencent.mtt.hippy.adapter.http.HippyHttpAdapter; -import com.tencent.mtt.hippy.adapter.image.HippyImageLoader; -import com.tencent.mtt.hippy.adapter.monitor.DefaultEngineMonitorAdapter; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorAdapter; -import com.tencent.mtt.hippy.adapter.sharedpreferences.DefaultSharedPreferencesAdapter; -import com.tencent.mtt.hippy.adapter.sharedpreferences.HippySharedPreferencesAdapter; -import com.tencent.mtt.hippy.adapter.soloader.DefaultSoLoaderAdapter; -import com.tencent.mtt.hippy.adapter.soloader.HippySoLoaderAdapter; -import com.tencent.mtt.hippy.adapter.storage.DefaultStorageAdapter; -import com.tencent.mtt.hippy.adapter.storage.HippyStorageAdapter; -import com.tencent.mtt.hippy.utils.LogUtils; - -@SuppressWarnings({"deprecation", "unused"}) -public class HippyGlobalConfigs { - - /** - * SharedPreferences - */ - private final HippySharedPreferencesAdapter mSharedPreferencesAdapter; - - private final Context mContext; - - /** - * Crash Handler - */ - private final HippyExceptionHandlerAdapter mExceptionHandler; - - /** - * Http request adapter - */ - private final HippyHttpAdapter mHttpAdapter; - - /** - * Image loader adapter - */ - private final HippyImageLoader mImageLoaderAdapter; - - /** - * Storage adapter - */ - private final HippyStorageAdapter mStorageAdapter; - - /** - * Executor Supplier adapter - */ - private final HippyExecutorSupplierAdapter mExecutorSupplierAdapter; - - /** - * Engine Monitor adapter - */ - private final HippyEngineMonitorAdapter mEngineMonitorAdapter; - - - /** - * font scale adapter - */ - private final HippyFontScaleAdapter mFontScaleAdapter; - - - private final HippySoLoaderAdapter mSoLoaderAdapter; - - /** - * device adapter - */ - private final HippyDeviceAdapter mDeviceAdapter; - - - private final HippyLogAdapter mLogAdapter; - - private boolean mEnableTurbo; - - public HippyGlobalConfigs(HippyEngine.EngineInitParams params) { - this.mContext = params.context; - this.mSharedPreferencesAdapter = params.sharedPreferencesAdapter; - this.mExceptionHandler = params.exceptionHandler; - this.mHttpAdapter = params.httpAdapter; - this.mImageLoaderAdapter = params.imageLoader; - this.mStorageAdapter = params.storageAdapter; - this.mExecutorSupplierAdapter = params.executorSupplier; - this.mEngineMonitorAdapter = params.engineMonitor; - this.mFontScaleAdapter = params.fontScaleAdapter; - this.mSoLoaderAdapter = params.soLoader; - this.mDeviceAdapter = params.deviceAdapter; - this.mLogAdapter = params.logAdapter; - this.mEnableTurbo = params.enableTurbo; - } - - private HippyGlobalConfigs(Context context, - HippySharedPreferencesAdapter sharedPreferencesAdapter, - HippyExceptionHandlerAdapter exceptionHandler, HippyHttpAdapter httpAdapter, - HippyImageLoader imageLoaderAdapter, - HippyExecutorSupplierAdapter executorSupplierAdapter, HippyStorageAdapter storageAdapter, - HippyEngineMonitorAdapter engineMonitorAdapter, - HippyFontScaleAdapter hippyFontScaleAdapter, HippySoLoaderAdapter hippySoLoaderAdapter, - HippyDeviceAdapter hippyDeviceAdapter, - HippyLogAdapter hippyLogAdapter) { - this.mContext = context; - this.mSharedPreferencesAdapter = sharedPreferencesAdapter; - this.mExceptionHandler = exceptionHandler; - this.mHttpAdapter = httpAdapter; - this.mImageLoaderAdapter = imageLoaderAdapter; - this.mStorageAdapter = storageAdapter; - this.mExecutorSupplierAdapter = executorSupplierAdapter; - this.mEngineMonitorAdapter = engineMonitorAdapter; - this.mFontScaleAdapter = hippyFontScaleAdapter; - this.mSoLoaderAdapter = hippySoLoaderAdapter; - this.mDeviceAdapter = hippyDeviceAdapter; - this.mLogAdapter = hippyLogAdapter; - } - - public void destroyIfNeed() { - try { - if (mHttpAdapter != null) { - mHttpAdapter.destroyIfNeed(); - } - - if (mStorageAdapter != null) { - mStorageAdapter.destroyIfNeed(); - } - - if (mExecutorSupplierAdapter != null) { - mExecutorSupplierAdapter.destroyIfNeed(); - } - if (mImageLoaderAdapter != null) { - mImageLoaderAdapter.destroyIfNeed(); - } - } catch (Throwable e) { - LogUtils.d("HippyGlobalConfigs", "destroyIfNeed: " + e.getMessage()); - } - } - - public HippyLogAdapter getLogAdapter() { - return mLogAdapter; - } - - public HippySoLoaderAdapter getSoLoaderAdapter() { - return mSoLoaderAdapter; - } - - public HippySharedPreferencesAdapter getSharedPreferencesAdapter() { - return mSharedPreferencesAdapter; - } - - public HippyExceptionHandlerAdapter getExceptionHandler() { - return mExceptionHandler; - } - - public HippyFontScaleAdapter getFontScaleAdapter() { - return mFontScaleAdapter; - } - - public HippyDeviceAdapter getDeviceAdapter() { - return mDeviceAdapter; - } - - public HippyHttpAdapter getHttpAdapter() { - return mHttpAdapter; - } - - public Context getContext() { - return mContext; - } - - public HippyImageLoader getImageLoaderAdapter() { - return mImageLoaderAdapter; - } - - public HippyStorageAdapter getStorageAdapter() { - return mStorageAdapter; - } - - public HippyExecutorSupplierAdapter getExecutorSupplierAdapter() { - return mExecutorSupplierAdapter; - } - - public HippyEngineMonitorAdapter getEngineMonitorAdapter() { - return mEngineMonitorAdapter; - } - - @Deprecated - public void toDebug(HippyEngine.EngineInitParams params) { - params.context = mContext; - params.sharedPreferencesAdapter = mSharedPreferencesAdapter; - params.exceptionHandler = mExceptionHandler; - params.httpAdapter = mHttpAdapter; - params.imageLoader = mImageLoaderAdapter; - params.storageAdapter = mStorageAdapter; - params.executorSupplier = mExecutorSupplierAdapter; - params.engineMonitor = mEngineMonitorAdapter; - params.fontScaleAdapter = mFontScaleAdapter; - params.soLoader = mSoLoaderAdapter; - params.deviceAdapter = mDeviceAdapter; - params.logAdapter = mLogAdapter; - params.enableTurbo = true; - } - - @SuppressWarnings({"unused"}) - public static class Builder { - - private HippySharedPreferencesAdapter mSharedPreferencesAdapter; - - private Context mContext; - - private HippyExceptionHandlerAdapter mExceptionHandler; - - private HippyHttpAdapter mHttpAdapter; - - private HippyImageLoader mImageLoaderAdapter; - - private HippyStorageAdapter mStorageAdapter; - - private HippyExecutorSupplierAdapter mExecutorSupplierAdapter; - - private HippyEngineMonitorAdapter mEngineMonitorAdapter; - - - private HippyFontScaleAdapter mFontScaleAdapter; - - private HippySoLoaderAdapter mSoLoaderAdapter; - - private HippyDeviceAdapter mDeviceAdapter; - - private HippyLogAdapter mLogAdapter; - - - public HippyLogAdapter getLogAdapter() { - return mLogAdapter; - } - - public Builder setLogAdapter(HippyLogAdapter mLogAdapter) { - this.mLogAdapter = mLogAdapter; - return this; - } - - public Builder setSharedPreferencesAdapter(HippySharedPreferencesAdapter adapter) { - this.mSharedPreferencesAdapter = adapter; - return this; - } - - public Builder setSoLoaderAdapter(HippySoLoaderAdapter mSoLoaderAdapter) { - this.mSoLoaderAdapter = mSoLoaderAdapter; - return this; - } - - public Builder setDeviceAdapter(HippyDeviceAdapter mDeviceAdapter) { - this.mDeviceAdapter = mDeviceAdapter; - return this; - } - - public Builder setContext(Context context) { - this.mContext = context; - return this; - } - - - public Builder setExceptionHandler(HippyExceptionHandlerAdapter exceptionHandler) { - this.mExceptionHandler = exceptionHandler; - return this; - } - - public Builder setFontScaleAdapter(HippyFontScaleAdapter hippyFontScaleAdapter) { - this.mFontScaleAdapter = hippyFontScaleAdapter; - return this; - } - - public Builder setHttpAdapter(HippyHttpAdapter httpAdapter) { - this.mHttpAdapter = httpAdapter; - return this; - } - - public Builder setImageLoaderAdapter(HippyImageLoader adapter) { - this.mImageLoaderAdapter = adapter; - return this; - } - - public Builder setStorageAdapter(HippyStorageAdapter adapter) { - this.mStorageAdapter = adapter; - return this; - } - - public Builder setExecutorSupplierAdapter(HippyExecutorSupplierAdapter adapter) { - this.mExecutorSupplierAdapter = adapter; - return this; - } - - public Builder setEngineMonitorAdapter(HippyEngineMonitorAdapter adapter) { - this.mEngineMonitorAdapter = adapter; - return this; - } - - @Deprecated - public HippyGlobalConfigs build() { - if (mContext == null) { - throw new IllegalArgumentException("HippyGlobalConfigs Context must is not null!"); - } - if (mSharedPreferencesAdapter == null) { - mSharedPreferencesAdapter = new DefaultSharedPreferencesAdapter(mContext); - } - if (mExceptionHandler == null) { - mExceptionHandler = new DefaultExceptionHandler(); - } - if (mHttpAdapter == null) { - mHttpAdapter = new DefaultHttpAdapter(); - } - if (mExecutorSupplierAdapter == null) { - mExecutorSupplierAdapter = new DefaultExecutorSupplierAdapter(); - } - if (mStorageAdapter == null) { - mStorageAdapter = new DefaultStorageAdapter(mContext, - mExecutorSupplierAdapter.getDBExecutor()); - } - if (mEngineMonitorAdapter == null) { - mEngineMonitorAdapter = new DefaultEngineMonitorAdapter(); - } - - if (mFontScaleAdapter == null) { - mFontScaleAdapter = new DefaultFontScaleAdapter(); - } - if (mSoLoaderAdapter == null) { - mSoLoaderAdapter = new DefaultSoLoaderAdapter(); - } - if (mDeviceAdapter == null) { - mDeviceAdapter = new DefaultDeviceAdapter(); - } - if (mLogAdapter == null) { - mLogAdapter = new DefaultLogAdapter(); - } - if (mImageLoaderAdapter == null) { - throw new IllegalArgumentException( - "HippyGlobalConfigs ImageLoaderAdapter must is not null!"); - } - - @SuppressWarnings("UnnecessaryLocalVariable") HippyGlobalConfigs configs = new HippyGlobalConfigs( - mContext, mSharedPreferencesAdapter, mExceptionHandler, - mHttpAdapter, mImageLoaderAdapter, mExecutorSupplierAdapter, mStorageAdapter, - mEngineMonitorAdapter, mFontScaleAdapter, - mSoLoaderAdapter, mDeviceAdapter, mLogAdapter); - return configs; - } - } - - public boolean enableTurbo() { - return mEnableTurbo; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyRootView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyRootView.java deleted file mode 100644 index cfc3eef37cc..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/HippyRootView.java +++ /dev/null @@ -1,363 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy; - -import android.content.Context; -import android.os.Build; -import android.os.Parcelable; -import android.util.DisplayMetrics; -import android.util.SparseArray; -import android.view.Display; -import android.view.View; -import android.view.ViewTreeObserver; -import android.view.WindowManager; -import android.widget.FrameLayout; - -import com.tencent.mtt.hippy.adapter.device.HippyDeviceAdapter; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorEvent; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.common.HippyTag; -import com.tencent.mtt.hippy.devsupport.DevFloatButton; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.modules.HippyModuleManager; -import com.tencent.mtt.hippy.modules.javascriptmodules.Dimensions; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.utils.DimensionsUtil; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.utils.TimeMonitor; - -import java.lang.reflect.Method; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import static android.content.res.Configuration.ORIENTATION_UNDEFINED; - -@SuppressWarnings({"deprecation", "unused"}) -public class HippyRootView extends FrameLayout { - - private static final int ROOT_VIEW_TAG_INCREMENT = 10; - - private static final AtomicInteger ID_COUNTER = new AtomicInteger(0); - - OnSizeChangedListener mSizeChangListener; - - private final int mInstanceId; - - private final HippyEngine.ModuleLoadParams mLoadParams; - - private HippyEngineContext mEngineContext; - - private GlobalLayoutListener mGlobalLayoutListener; - - private OnResumeAndPauseListener mOnResumeAndPauseListener; - - private OnLoadCompleteListener mOnLoadCompleteListener; - - private TimeMonitor mTimeMonitor; - - protected boolean mLoadCompleted = false; - - public HippyRootView(HippyEngine.ModuleLoadParams loadParams) { - super(loadParams.hippyContext != null ? loadParams.hippyContext - : new HippyInstanceContext(loadParams.context, loadParams)); - - mLoadParams = loadParams; - mInstanceId = ID_COUNTER.addAndGet(ROOT_VIEW_TAG_INCREMENT); - - setId(mInstanceId); - //setTag(NodeProps.ROOT_NODE); - HippyMap tagMap = HippyTag.createTagMap(NodeProps.ROOT_NODE, null); - setTag(tagMap); - getViewTreeObserver().addOnGlobalLayoutListener(getGlobalLayoutListener()); - setOnSystemUiVisibilityChangeListener(getGlobalLayoutListener()); - } - - public void attachEngineManager(HippyEngine hippyEngineManager) { - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) getContext(); - hippyInstanceContext.attachEngineManager(hippyEngineManager); - - } - - // HippyRootView上添加View了,说明jsbundle正常工作了 - @Override - public void onViewAdded(View child) { - // 若HippyRootView所依赖的Context不是Activity,则调试模式下的那个按钮会先添加到HippyRootView上,从而触发此处的onViewAdded - if (!mLoadCompleted && !(child instanceof DevFloatButton)) { - mLoadCompleted = true; - if (mTimeMonitor != null) { - mTimeMonitor.end(); - if (mOnLoadCompleteListener != null) { - mOnLoadCompleteListener - .onLoadComplete(mTimeMonitor.getTotalTime(), mTimeMonitor.getEvents()); - } - mEngineContext.getGlobalConfigs().getEngineMonitorAdapter() - .reportModuleLoadComplete(this, mTimeMonitor.getTotalTime(), mTimeMonitor.getEvents()); - } - } - } - - public String getName() { - return mLoadParams.componentName; - } - - public int getId() { - return mInstanceId; - } - - public Context getHost() { - return mLoadParams.context; - } - - public HippyMap getLaunchParams() { - return mLoadParams.jsParams; - } - - public HippyEngineContext getEngineContext() { - return mEngineContext; - } - - public void setOnSizeChangedListener(OnSizeChangedListener listener) { - this.mSizeChangListener = listener; - } - - public void setOnResumeAndPauseListener(OnResumeAndPauseListener listener) { - this.mOnResumeAndPauseListener = listener; - } - - public void setOnLoadCompleteListener(OnLoadCompleteListener listener) { - this.mOnLoadCompleteListener = listener; - } - - @Override - protected void dispatchRestoreInstanceState(SparseArray container) { - // No-op do not onRestoreInstanceState for sub views - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - // No-op since UIManagerModule handles actually laying out children. - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), - MeasureSpec.getSize(heightMeasureSpec)); - // super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - if (w != oldw || h != oldh) { - getGlobalLayoutListener().checkUpdateDimension(w, h, false, false); - if (mEngineContext != null) { - HippyModuleManager manager = mEngineContext.getModuleManager(); - if (manager != null) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushDouble("width", PixelUtil.px2dp(w)); - hippyMap.pushDouble("height", PixelUtil.px2dp(h)); - hippyMap.pushDouble("oldWidth", PixelUtil.px2dp(oldw)); - hippyMap.pushDouble("oldHeight", PixelUtil.px2dp(oldh)); - manager.getJavaScriptModule(EventDispatcher.class) - .receiveNativeEvent("onSizeChanged", hippyMap); - } - } - if (mSizeChangListener != null) { - mSizeChangListener.onSizeChanged(this, w, h, oldw, oldh); - } - } - } - - public void attachToEngine(HippyEngineContext context) { - mEngineContext = context; - ((HippyInstanceContext) getContext()).setEngineContext(context); - getGlobalLayoutListener().checkUpdateDimension(false, false); - } - - public void onResume() { - if (mOnResumeAndPauseListener != null) { - mOnResumeAndPauseListener.onInstanceResume(getId()); - } - } - - public void onPause() { - if (mOnResumeAndPauseListener != null) { - mOnResumeAndPauseListener.onInstancePause(getId()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - try { - getViewTreeObserver().removeGlobalOnLayoutListener(getGlobalLayoutListener()); - - //java.lang.ArrayIndexOutOfBoundsException - } catch (Throwable e) { - e.printStackTrace(); - } - getViewTreeObserver().addOnGlobalLayoutListener(getGlobalLayoutListener()); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - try { - getViewTreeObserver().removeGlobalOnLayoutListener(getGlobalLayoutListener()); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - void destroy() { - if (getContext() instanceof HippyInstanceContext) { - ((HippyInstanceContext) getContext()).notifyInstanceDestroy(); - } - } - - private GlobalLayoutListener getGlobalLayoutListener() { - if (mGlobalLayoutListener == null) { - mGlobalLayoutListener = new GlobalLayoutListener(); - } - return mGlobalLayoutListener; - } - - public void startMonitorEvent(String eventName) { - if (mTimeMonitor != null) { - mTimeMonitor.startEvent(eventName); - } - } - - public TimeMonitor getTimeMonitor() { - return mTimeMonitor; - } - - public void setTimeMonitor(TimeMonitor timeMonitor) { - this.mTimeMonitor = timeMonitor; - } - - public interface OnSizeChangedListener { - - void onSizeChanged(HippyRootView rootView, int width, int height, int oldWidth, int oldHeight); - } - - public interface OnResumeAndPauseListener { - - void onInstanceResume(int id); - - void onInstancePause(int id); - } - - public interface OnLoadCompleteListener { - - void onLoadComplete(int loadTime, List loadEvents); - } - - private class GlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener, - OnSystemUiVisibilityChangeListener { - - private int mOrientation = ORIENTATION_UNDEFINED; - - @SuppressWarnings("RedundantIfStatement") - @Override - public void onSystemUiVisibilityChange(int visibility) { - if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { - checkUpdateDimension(false, true); - } else { - checkUpdateDimension(true, true); - } - } - - @Override - public void onGlobalLayout() { - if (getContext() != null) { - int orientation = getContext().getResources().getConfiguration().orientation; - if (orientation != mOrientation) { - mOrientation = orientation; - sendOrientationChangeEvent(mOrientation); - checkUpdateDimension(false, false); - } - } - } - - private void sendOrientationChangeEvent(int orientation) { - LogUtils.d("HippyRootView", "sendOrientationChangeEvent: orientation=" + orientation); - } - - private void checkUpdateDimension(boolean shouldUseScreenDisplay, - boolean systemUiVisibilityChanged) { - checkUpdateDimension(-1, -1, false, false); - } - - @SuppressWarnings("SameParameterValue") - private void checkUpdateDimension(int windowWidth, int windowHeight, - boolean shouldUseScreenDisplay, boolean systemUiVisibilityChanged) { - if (mEngineContext == null) { - return; - } - DisplayMetrics windowDisplayMetrics = getContext().getResources().getDisplayMetrics(); - DisplayMetrics screenDisplayMetrics = new DisplayMetrics(); - screenDisplayMetrics.setTo(windowDisplayMetrics); - WindowManager windowManager = (WindowManager) getContext() - .getSystemService(Context.WINDOW_SERVICE); - Display defaultDisplay = windowManager.getDefaultDisplay(); - try { - if (Build.VERSION.SDK_INT >= 17) { - defaultDisplay.getRealMetrics(screenDisplayMetrics); - } else { - //noinspection JavaReflectionMemberAccess - Method mGetRawH = Display.class.getMethod("getRawHeight"); - //noinspection JavaReflectionMemberAccess - Method mGetRawW = Display.class.getMethod("getRawWidth"); - - Object width = mGetRawW.invoke(defaultDisplay); - screenDisplayMetrics.widthPixels = width != null ? (Integer) width : 0; - - Object height = mGetRawH.invoke(defaultDisplay); - screenDisplayMetrics.heightPixels = height != null ? (Integer) height : 0; - } - - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - - HippyMap dimensionMap = DimensionsUtil - .getDimensions(windowWidth, windowHeight, mEngineContext.getGlobalConfigs().getContext(), - shouldUseScreenDisplay); - int dimensionW = 0; - int dimensionH = 0; - if (dimensionMap != null) { - HippyMap windowMap = dimensionMap.getMap("windowPhysicalPixels"); - dimensionW = windowMap.getInt("width"); - dimensionH = windowMap.getInt("height"); - } - // 如果windowHeight是无效值,则允许客户端定制 - if ((windowHeight < 0 || dimensionW == dimensionH) - && mEngineContext.getGlobalConfigs() != null) { - HippyDeviceAdapter deviceAdapter = mEngineContext.getGlobalConfigs().getDeviceAdapter(); - if (deviceAdapter != null) { - deviceAdapter.reviseDimensionIfNeed(getContext(), dimensionMap, shouldUseScreenDisplay, - systemUiVisibilityChanged); - } - } - if (mEngineContext.getModuleManager() != null) { - mEngineContext.getModuleManager().getJavaScriptModule(Dimensions.class).set(dimensionMap); - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/IHippyNativeLogHandler.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/IHippyNativeLogHandler.java deleted file mode 100644 index cc36ba890f8..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/IHippyNativeLogHandler.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.tencent.mtt.hippy; - -@SuppressWarnings({"unused"}) -public interface IHippyNativeLogHandler { - - void onReceiveNativeLogMessage(String msg); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/NativeAccess.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/NativeAccess.java deleted file mode 100644 index 67add697860..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/NativeAccess.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.tencent.mtt.hippy; - -import com.tencent.mtt.hippy.runtime.builtins.JSSharedArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.wasm.WasmModule; - -@SuppressWarnings("JavaJniMissingFunction") -public class NativeAccess { - - private NativeAccess() { - - } - - // region bridge.serialization.delegate - public static native JSSharedArrayBuffer getSharedArrayBufferFromId(int clone_id); - - public static native WasmModule getWasmModuleFromId(int transfer_id); - // endregion -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/DefaultLogAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/DefaultLogAdapter.java deleted file mode 100644 index 7caaa4d811c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/DefaultLogAdapter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter; - -@SuppressWarnings({"unused"}) -public class DefaultLogAdapter implements HippyLogAdapter { - - @Override - public void log(String tag, String msg) { - - } - - @Override - public void init(int rootId, String module) { - - } - - @Override - public void upload(callBack callBack) { - callBack.onSuccess(); - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/font/DefaultFontScaleAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/font/DefaultFontScaleAdapter.java deleted file mode 100644 index fcbcff1d81f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/font/DefaultFontScaleAdapter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.font; - -import com.tencent.mtt.hippy.utils.LogUtils; - -@SuppressWarnings({"unused"}) -public class DefaultFontScaleAdapter implements HippyFontScaleAdapter { - - @Override - public float getFontScale() { - return 1; - } - - @Override - public CharSequence getEmoticonText(CharSequence text, int fontSize) { - return text; - } - - @Override - public String getCustomFontFilePath(String fontFamilyName, int style) { - LogUtils.d("DefaultFontScaleAdapter", - "getCustomFontFilePath fontFamilyName=" + fontFamilyName + ", style=" + style); - return null; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/font/HippyFontScaleAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/font/HippyFontScaleAdapter.java deleted file mode 100644 index d063ecf5f53..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/font/HippyFontScaleAdapter.java +++ /dev/null @@ -1,27 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.font; - -@SuppressWarnings("SameReturnValue") -public interface HippyFontScaleAdapter { - - float getFontScale(); - - @SuppressWarnings("unused") - CharSequence getEmoticonText(CharSequence text, int fontSize); - - String getCustomFontFilePath(String fontFamilyName, int style); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/DefaultHttpAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/DefaultHttpAdapter.java deleted file mode 100644 index 4c29501be34..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/DefaultHttpAdapter.java +++ /dev/null @@ -1,223 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.http; - -import android.text.TextUtils; - -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.modules.nativemodules.network.NetworkModule; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -public class DefaultHttpAdapter implements HippyHttpAdapter { - - private ExecutorService mExecutorService; - - private static URL toURL(String url) throws MalformedURLException { - URL _URL = new URL(url); - - // 有个别 URL 在 path 和 querystring 之间缺少 / 符号,需补上 - if (_URL.getPath() == null || "".equals(_URL.getPath())) { - if (_URL.getFile() != null && _URL.getFile().startsWith("?")) { - // 补斜杠符号 - int idx = url.indexOf('?'); - if (idx != -1) { - String sb = url.substring(0, idx) - + '/' - + url.substring(idx); - _URL = new URL(sb); - - // System.out.println("toURL : " + _URL.toString()); - } - } - - // 分支走到这里,没有path也没有file,证明为一个没有/的host,例如: - // http://m.cnbeta.com(注意:后面没有/) - if (_URL.getFile() == null || "".equals(_URL.getFile())) { - String sb = url - + "/"; - _URL = new URL(sb); - } - - } - return _URL; - } - - private void execute(Runnable runnable) { - if (mExecutorService == null) { - mExecutorService = Executors.newFixedThreadPool(3); - } - mExecutorService.execute(runnable); - } - - @Override - public void sendRequest(final HippyHttpRequest request, final HttpTaskCallback callback) { - execute(new Runnable() { - @Override - public void run() { - if (callback == null) { - return; - } - HippyHttpResponse response = null; - HttpURLConnection connection = null; - try { - connection = createConnection(request); - fillHeader(connection, request); - fillPostBody(connection, request); - response = createResponse(connection); - - callback.onTaskSuccess(request, response); - } catch (Throwable e) { - callback.onTaskFailed(request, e); - } finally { - if (response != null) { - response.close(); - } - if (connection != null) { - connection.disconnect(); - } - } - } - }); - } - - HippyHttpResponse createResponse(HttpURLConnection urlConnection) throws Exception { - HippyHttpResponse response = new HippyHttpResponse(); - parseResponseHeaders(urlConnection, response); - boolean isException = false; - InputStream inputStream = null; - try { - inputStream = urlConnection.getInputStream(); - } catch (IOException ie) { - ie.printStackTrace(); - isException = true; - } - - InputStream errorStream = null; - if (isException || urlConnection.getResponseCode() >= 400) { - try { - errorStream = urlConnection.getErrorStream(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (isException) { - inputStream = errorStream; - } - response.setInputStream(inputStream); - response.setErrorStream(errorStream); - response.setResponseMessage(urlConnection.getResponseMessage()); - - return response; - } - - HttpURLConnection createConnection(HippyHttpRequest request) throws Exception { - if (TextUtils.isEmpty(request.getUrl())) { - throw new RuntimeException("url is null"); - } - URL url = toURL(request.getUrl()); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - - if (TextUtils.isEmpty(request.getMethod())) { - request.setMethod("GET"); - } - connection.setRequestMethod(request.getMethod()); - connection.setUseCaches(request.isUseCaches()); - connection.setInstanceFollowRedirects(request.isInstanceFollowRedirects()); - - connection.setConnectTimeout(request.getConnectTimeout()); - connection.setReadTimeout(request.getReadTimeout()); - - if (request.getMethod().equalsIgnoreCase("POST") || request.getMethod().equalsIgnoreCase("PUT") - || request.getMethod().equalsIgnoreCase("PATCH")) { - - connection.setDoOutput(true); - } - - return connection; - } - - void fillHeader(URLConnection urlConnection, HippyHttpRequest request) { - Map headerMap = request.getHeaders(); - if (headerMap != null && !headerMap.isEmpty()) { - Set keySets = headerMap.keySet(); - for (String key : keySets) { - Object obj = headerMap.get(key); - if (obj instanceof String) { - urlConnection.setRequestProperty(key, (String) obj); - } else if (obj instanceof List) { - @SuppressWarnings("unchecked") List requestProperties = (List) obj; - if (!requestProperties.isEmpty()) { - for (String oneReqProp : requestProperties) { - if (!TextUtils.isEmpty(oneReqProp)) { - urlConnection.addRequestProperty(key, oneReqProp); - } - } - } - } - - } - } - } - - void fillPostBody(HttpURLConnection connection, HippyHttpRequest request) throws IOException { - if (TextUtils.isEmpty(request.getBody())) { - return; - } - connection.setRequestProperty("Content-Length", request.getBody().getBytes().length + ""); - DataOutputStream out = new DataOutputStream(connection.getOutputStream()); - //TODO big stream will cause OOM; Progress callback is meaningless - out.write(request.getBody().getBytes()); - out.flush(); - out.close(); - } - - void parseResponseHeaders(HttpURLConnection httpConn, HippyHttpResponse response) - throws Exception { - if (httpConn == null) { - return; - } - - response.setStatusCode(httpConn.getResponseCode()); - response.setRspHeaderMap(httpConn.getHeaderFields()); - } - - public void destroyIfNeed() { - if (mExecutorService != null && !mExecutorService.isShutdown()) { - mExecutorService.shutdown(); - mExecutorService = null; - } - } - - public void handleRequestCookie(String url, HippyArray requestCookies, HippyHttpRequest httpRequest) { - NetworkModule.saveCookie2Manager(url, requestCookies); - String cookie = NetworkModule.getCookieManager().getCookie(url); - if (!TextUtils.isEmpty(cookie)) { - httpRequest.addHeader(HttpHeader.REQ.COOKIE, cookie); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/HippyHttpAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/HippyHttpAdapter.java deleted file mode 100644 index 974c4e45672..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/HippyHttpAdapter.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.http; - -import com.tencent.mtt.hippy.common.HippyArray; - -public interface HippyHttpAdapter { - - void sendRequest(HippyHttpRequest request, HttpTaskCallback callback); - - void destroyIfNeed(); - - void handleRequestCookie(String url, HippyArray requestCookies, HippyHttpRequest httpRequest); - - interface HttpTaskCallback { - - void onTaskSuccess(HippyHttpRequest request, HippyHttpResponse response) throws Exception; - - @SuppressWarnings("unused") - void onTaskFailed(HippyHttpRequest request, Throwable error); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/HippyHttpRequest.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/HippyHttpRequest.java deleted file mode 100644 index 0f0c3e5ec5e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/http/HippyHttpRequest.java +++ /dev/null @@ -1,158 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.http; - -import android.os.Build; - -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -@SuppressWarnings({"unused"}) -public class HippyHttpRequest { - - public static final int DEFAULT_TIMEOUT_MS = 3000; - - private static String USER_AGENT = null; - private int mConnectTimeout = DEFAULT_TIMEOUT_MS; - private int mReadTimeout = DEFAULT_TIMEOUT_MS; - private final Map mHeaderMap; - private String mUrl; - private boolean mUseCaches = true; - private String mMethod = "GET"; - private boolean mInstanceFollowRedirects = false; - private String mBody; - - public HippyHttpRequest() { - //noinspection unchecked,rawtypes - mHeaderMap = new HashMap(); - initUserAgent(); - - if (USER_AGENT != null) { - addHeader(HttpHeader.REQ.USER_AGENT, USER_AGENT); - } else { - System.err.println("user_agent is null!"); - } - } - - public String getUrl() { - return mUrl; - } - - public void setUrl(String url) { - this.mUrl = url; - } - - public void addHeader(String name, String value) { - mHeaderMap.put(name, value); - } - - public void addHeader(String name, List value) { - mHeaderMap.put(name, value); - } - - public Map getHeaders() { - return mHeaderMap; - } - - public int getConnectTimeout() { - return mConnectTimeout; - } - - public void setConnectTimeout(int time) { - mConnectTimeout = time; - } - - public int getReadTimeout() { - return mReadTimeout; - } - - public void setReadTimeout(int time) { - mReadTimeout = time; - } - - public boolean isUseCaches() { - return mUseCaches; - } - - public void setUseCaches(boolean useCaches) { - this.mUseCaches = useCaches; - } - - public String getMethod() { - return mMethod; - } - - public void setMethod(String method) { - this.mMethod = method; - } - - public boolean isInstanceFollowRedirects() { - return mInstanceFollowRedirects; - } - - public void setInstanceFollowRedirects(boolean instanceFollowRedirects) { - this.mInstanceFollowRedirects = instanceFollowRedirects; - } - - public String getBody() { - return mBody; - } - - public void setBody(String body) { - this.mBody = body; - } - - private void initUserAgent() { - if (USER_AGENT == null) { - Locale locale = Locale.getDefault(); - StringBuffer buffer = new StringBuffer(); - // Add version - final String version = Build.VERSION.RELEASE; - if (version.length() > 0) { - buffer.append(version); - } else { - // default to "1.0" - buffer.append("1.0"); - } - buffer.append("; "); - final String language = locale.getLanguage(); - buffer.append(language.toLowerCase()); - final String country = locale.getCountry(); - buffer.append("-"); - buffer.append(country.toLowerCase()); - // add the model for the release build - if (android.os.Build.VERSION.SDK_INT > 3 && "REL".equals(Build.VERSION.CODENAME)) { - final String model = Build.MODEL; - if (model.length() > 0) { - buffer.append("; "); - buffer.append(model); - } - } - final String id = Build.ID; - if (id.length() > 0) { - buffer.append(" Build/"); - buffer.append(id); - } - - final String base = "Mozilla/5.0 (Linux; U; Android %s) AppleWebKit/533.1 (KHTML, like Gecko) Mobile Safari/533.1"; - - USER_AGENT = String.format(base, buffer); - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/ByteBufferInputStream.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/ByteBufferInputStream.java deleted file mode 100644 index 37e0af451e6..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/ByteBufferInputStream.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.tencent.mtt.hippy.adapter.image; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; - -/** - * Copyright (C) 2015-2025 TENCENT Inc.All Rights Reserved. FileName: ByteBufferInputStream - * Description: History: 2.0 harryguo on 2019/4/26 - */ - -public class ByteBufferInputStream extends InputStream { - - private final ByteBuffer byteBuffer; - private int markPos = -1; - - @SuppressWarnings("unused") - ByteBufferInputStream(ByteBuffer byteBuffer) { - this.byteBuffer = byteBuffer; - byteBuffer.flip(); - } - - public int available() { - return this.byteBuffer.remaining(); - } - - public int read() { - return !this.byteBuffer.hasRemaining() ? -1 : this.byteBuffer.get(); - } - - public synchronized void mark(int readLimit) { - this.markPos = this.byteBuffer.position(); - } - - public boolean markSupported() { - return true; - } - - public int read(byte[] buffer, int byteOffset, int byteCount) { - if (!this.byteBuffer.hasRemaining()) { - return -1; - } else { - int toRead = Math.min(byteCount, this.available()); - this.byteBuffer.get(buffer, byteOffset, toRead); - return toRead; - } - } - - public synchronized void reset() throws IOException { - if (this.markPos == -1) { - throw new IOException("Cannot reset to unset mark position"); - } else { - this.byteBuffer.position(this.markPos); - } - } - - public long skip(long byteCount) { - if (!this.byteBuffer.hasRemaining()) { - return -1L; - } else { - long toSkip = Math.min(byteCount, this.available()); - this.byteBuffer.position((int) ((long) this.byteBuffer.position() + toSkip)); - return toSkip; - } - } -} \ No newline at end of file diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/HippyDrawable.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/HippyDrawable.java deleted file mode 100644 index 86b61b29311..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/HippyDrawable.java +++ /dev/null @@ -1,261 +0,0 @@ -package com.tencent.mtt.hippy.adapter.image; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.supportui.adapters.image.IDrawableTarget; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.ImageDecoder; -import android.graphics.Movie; -import android.graphics.drawable.Drawable; -import android.util.Base64; - -@SuppressWarnings({"unused"}) -public class HippyDrawable implements IDrawableTarget { - - // 原始数据的来源:base64 / assets / file - protected String mSource; - - protected Drawable mDrawable; - - // GIF动画 - private Movie mGifMovie; - - // 静态图片 - private Bitmap mBitmap; - - private String imageType; - - public void setImageType(String type) { - imageType = type; - } - - @Override - public String getImageType() { - return imageType; - } - - public void setDrawable(Drawable drawable) { - mDrawable = drawable; - } - - /** - * 设置原始数据。预期这个原始数据是GIF,或Bitmap的原始数据 - * - * @param rawData byte array raw data - */ - public void setData(byte[] rawData) { - try { - mGifMovie = Movie.decodeByteArray(rawData, 0, rawData.length); - if (mGifMovie == null) { - mBitmap = BitmapFactory.decodeByteArray(rawData, 0, rawData.length); - } else { - mBitmap = null; - } - } catch (OutOfMemoryError | Exception e) { - e.printStackTrace(); - } - } - - /** - * 设置原始数据的文件地址。预期这个原始数据是GIF,或Bitmap的原始数据 - * - * @param path file path of the image - */ - public void setData(File path) { - FileInputStream is = null; - try { - is = new FileInputStream(path); - byte[] rawData = new byte[is.available()]; - int total = is.read(rawData); - LogUtils.d("HippyDrawable", "setData path: read total=" + total); - setData(rawData); - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (is != null) { - try { - is.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - - public void setData(File path, boolean isGif) { - FileInputStream is = null; - try { - is = new FileInputStream(path); - if (isGif) { - mGifMovie = Movie.decodeStream(is); - mBitmap = null; - } else { - mBitmap = BitmapFactory.decodeStream(is); - mGifMovie = null; - } - } catch (OutOfMemoryError | Exception e) { - e.printStackTrace(); - } finally { - if (is != null) { - try { - is.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - - public void setDataForTarge28Assets(String assetsFile) { - ImageDecoder.Source source; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { - try { - source = ImageDecoder.createSource(ContextHolder.getAppContext().getAssets(), - assetsFile.substring("assets://".length())); - mBitmap = ImageDecoder.decodeBitmap(source); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - /** - * 设置图片数据。Bitmap - * - * @param bmp Bitmap - */ - public void setData(Bitmap bmp) { - mBitmap = bmp; - mGifMovie = null; - } - - /** - * 设置原始数据来源。 - * - * @param source 不是原始数据,而是原始数据的来源:base64 / assets / file - */ - public void setData(String source) { - mSource = source; - if (mSource.startsWith("data:")) { - try { - // base64 image - int base64Index = mSource.indexOf(";base64,"); - if (base64Index >= 0) { - base64Index += ";base64,".length(); - String base64String = mSource.substring(base64Index); - byte[] decode = Base64.decode(base64String, Base64.DEFAULT); - if (decode != null) { - setData(decode); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } else if (mSource.startsWith("file://")) { - // local file image - String filePath = mSource.substring("file://".length()); - setData(new File(filePath)); - } else if (mSource.startsWith("assets://")) { - InputStream is = null; - try { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { - setDataForTarge28Assets(mSource); - } else { - is = ContextHolder.getAppContext().getAssets() - .open(mSource.substring("assets://".length())); - byte[] rawData = new byte[is.available()]; - int total = is.read(rawData); - LogUtils.d("HippyDrawable", "setData source: read total=" + total); - setData(rawData); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (is != null) { - try { - is.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - } - - /** - * 获取GIF数据 - */ - public Movie getGIF() { - return mGifMovie; - } - - /** - * 是否是动画图片 - */ - public boolean isAnimated() { - return mGifMovie != null; - } - - public int getWidth() { - if (mBitmap != null) { - return mBitmap.getWidth(); - } - - if (mGifMovie != null) { - return mGifMovie.width(); - } - - return 0; - } - - public int getHeight() { - if (mBitmap != null) { - return mBitmap.getHeight(); - } - - if (mGifMovie != null) { - return mGifMovie.height(); - } - - return 0; - } - - /** - * 获取Bitmap - */ - @Override - public Bitmap getBitmap() { - return mBitmap; - } - - /** - * 实现空的interface 获取数据源 - */ - @Override - public String getSource() { - return mSource; - } - - @Override - public Drawable getDrawable() { - return mDrawable; - } - - @Override - public Object getExtraData() { - return null; - } - - @Override - public void onDrawableAttached() { - } - - @Override - public void onDrawableDetached() { - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/HippyImageLoader.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/HippyImageLoader.java deleted file mode 100644 index 183963dcec6..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/image/HippyImageLoader.java +++ /dev/null @@ -1,87 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.image; - -import android.util.SparseArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.devsupport.DebugWebSocketClient.JSDebuggerCallback; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.supportui.adapters.image.IImageLoaderAdapter; -import com.tencent.mtt.supportui.adapters.image.IImageRequestListener; - -import java.lang.ref.WeakReference; -import java.util.concurrent.ConcurrentHashMap; - -public abstract class HippyImageLoader implements IImageLoaderAdapter { - private final ConcurrentHashMap> mWeakImageCache = new ConcurrentHashMap<>(); - // 本地图片加载,同步获取 - @Override - public HippyDrawable getImage(String source, Object param) { - //base64图片和APK内置图片增加弱引用缓存,避免每次在主线程加载和解码图片 - boolean canCacheImage = source.startsWith("data:") || source.startsWith("assets://"); - Integer imageCacheCode = source.hashCode(); - if (canCacheImage) { - WeakReference weakReferenceHippyDrawable = mWeakImageCache.get(imageCacheCode); - if (weakReferenceHippyDrawable != null) { - HippyDrawable hippyDrawable = weakReferenceHippyDrawable.get(); - if (hippyDrawable == null) { - mWeakImageCache.remove(imageCacheCode); - } else { - return hippyDrawable; - } - } - } - HippyDrawable drawable = new HippyDrawable(); - drawable.setData(source); - if (canCacheImage) { - mWeakImageCache.put(imageCacheCode, new WeakReference<>(drawable)); - } - return drawable; - } - - public void getSize(final String url, final Promise promise) { - fetchImage(url, new HippyImageLoader.Callback() { - @Override - public void onRequestStart(HippyDrawable hippyDrawable) { - } - - @Override - public void onRequestSuccess(HippyDrawable hippyDrawable) { - if (hippyDrawable != null) { - HippyMap resultMap = new HippyMap(); - resultMap.pushInt("width", hippyDrawable.getWidth()); - resultMap.pushInt("height", hippyDrawable.getHeight()); - promise.resolve(resultMap); - hippyDrawable.onDrawableDetached(); - } else { - promise.reject("fetch image fail " + url); - } - } - - @Override - public void onRequestFail(Throwable throwable, String source) { - promise.reject("fetch image fail " + source); - } - }, null); - } - - public void destroyIfNeed() { - } - - public interface Callback extends IImageRequestListener { - - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/DefaultEngineMonitorAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/DefaultEngineMonitorAdapter.java deleted file mode 100644 index aacf1a6a3d3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/DefaultEngineMonitorAdapter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.monitor; - -import com.tencent.mtt.hippy.HippyRootView; - -import java.util.List; - -@SuppressWarnings({"unused"}) -public class DefaultEngineMonitorAdapter implements HippyEngineMonitorAdapter { - - @Override - public void reportEngineLoadStart() { - - } - - @Override - public void reportEngineLoadResult(int code, int loadTime, - List loadEvents, Throwable e) { - - } - - @Override - public void reportModuleLoadComplete(HippyRootView rootView, int loadTime, - List loadEvents) { - - } - - @Override - public boolean needReportBridgeANR() { - return false; - } - - @Override - public void reportBridgeANR(String message) { - - } - - @Override - public void reportDoCallNatives(String moduleName, String moduleFunc) { - - } - - @Override - public void reportGestureEventCallStack(String funcName, String msg) { - - } - - @Override - public void reportClickEvent(Object object, boolean isCustomEvent) { - - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorAdapter.java deleted file mode 100644 index 53ff44613e1..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorAdapter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.monitor; - -import com.tencent.mtt.hippy.HippyRootView; - -import java.util.List; - -@SuppressWarnings({"EmptyMethod", "unused"}) -public interface HippyEngineMonitorAdapter { - - int ENGINE_LOAD_RESULT_SUCCESS = 0; - int ENGINE_LOAD_RESULT_ERROR = 1; - int ENGINE_LOAD_RESULE_TIMEOUT = 2; - - void reportEngineLoadStart(); - - void reportEngineLoadResult(int code, int loadTime, List loadEvents, - Throwable e); - - void reportModuleLoadComplete(HippyRootView rootView, int loadTime, - List loadEvents); - - @SuppressWarnings("SameReturnValue") - boolean needReportBridgeANR(); - - void reportBridgeANR(String message); - - void reportDoCallNatives(String moduleName, String moduleFunc); - - void reportGestureEventCallStack(String funcName, String msg); - - void reportClickEvent(Object object, boolean isCustomEvent); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorEvent.java deleted file mode 100644 index 247b9ca411b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/monitor/HippyEngineMonitorEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.adapter.monitor; - -@SuppressWarnings("unused") -public class HippyEngineMonitorEvent { - - public static final String ENGINE_LOAD_EVENT_INIT_INSTANCE = "initInstance"; - public static final String ENGINE_LOAD_EVENT_INIT_BRIDGE = "initBridge"; - public static final String ENGINE_LOAD_EVENT_LOAD_COMMONJS = "loadCommonJS"; - public static final String ENGINE_LOAD_EVENT_NOTIFY_ENGINE_INITED = "notifyEngineInited"; - public static final String MODULE_LOAD_EVENT_WAIT_ENGINE = "waitEngine"; - public static final String MODULE_LOAD_EVENT_WAIT_LOAD_BUNDLE = "waitLoadBundle"; - public static final String MODULE_LOAD_EVENT_LOAD_BUNDLE = "loadBundle"; - public static final String MODULE_LOAD_EVENT_RUN_BUNDLE = "runBundle"; - public static final String MODULE_LOAD_EVENT_CREATE_VIEW = "createView"; - public String eventName; - public long startTime; - public long endTime; -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/thirdparty/HippyThirdPartyAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/thirdparty/HippyThirdPartyAdapter.java deleted file mode 100644 index f09586d7391..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/adapter/thirdparty/HippyThirdPartyAdapter.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.tencent.mtt.hippy.adapter.thirdparty; - -import org.json.JSONObject; - -@SuppressWarnings({"unused"}) -public abstract class HippyThirdPartyAdapter { - - public abstract void onRuntimeInit(long runtimeId); - - public abstract void onRuntimeDestroy(); - - public abstract String getPackageName(); - - public abstract String getAppVersion(); - - public abstract void setPageUrl(String url); - - public abstract String getPageUrl(); - - public abstract void setExtraData(JSONObject extraData); - - public abstract JSONObject getExtraData(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridge.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridge.java deleted file mode 100644 index 6eb929afd3e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridge.java +++ /dev/null @@ -1,53 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.bridge; - -import android.content.res.AssetManager; - -import com.tencent.mtt.hippy.common.HippyArray; -import java.nio.ByteBuffer; - -public interface HippyBridge { - - String URI_SCHEME_ASSETS = "asset:"; - String URI_SCHEME_FILE = "file:"; - - void initJSBridge(String gobalConfig, NativeCallback callback, int groupId); - - boolean runScriptFromUri(String uri, AssetManager assetManager, boolean canUseCodeCache, - String codeCacheTag, NativeCallback callback); - - void onDestroy(); - - void destroy(NativeCallback callback); - - void callFunction(String action, NativeCallback callback, ByteBuffer buffer); - - void callFunction(String action, NativeCallback callback, byte[] buffer); - - void callFunction(String action, NativeCallback callback, byte[] buffer, int offset, int length); - - long getV8RuntimeId(); - - interface BridgeCallback { - - void callNatives(String moduleName, String moduleFunc, String callId, HippyArray params); - - void reportException(String message, String stackTrace); - - void reportException(Throwable e); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeImpl.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeImpl.java deleted file mode 100644 index 21c1f3e7ffc..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeImpl.java +++ /dev/null @@ -1,415 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.bridge; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.devsupport.DevServerCallBack; -import com.tencent.mtt.hippy.devsupport.DevSupportManager; -import com.tencent.mtt.hippy.serialization.compatible.Deserializer; -import com.tencent.mtt.hippy.serialization.nio.reader.BinaryReader; -import com.tencent.mtt.hippy.serialization.nio.reader.SafeDirectReader; -import com.tencent.mtt.hippy.serialization.nio.reader.SafeHeapReader; -import com.tencent.mtt.hippy.serialization.string.InternalizedStringTable; -import com.tencent.mtt.hippy.devsupport.inspector.Inspector; -import com.tencent.mtt.hippy.utils.UIThreadUtils; -import com.tencent.mtt.hippy.utils.UrlUtils; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Locale; - -import android.content.Context; -import android.content.res.AssetManager; -import android.text.TextUtils; - -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.devsupport.DebugWebSocketClient; -import com.tencent.mtt.hippy.devsupport.DevRemoteDebugProxy; -import com.tencent.mtt.hippy.utils.ArgumentUtils; -import com.tencent.mtt.hippy.utils.FileUtils; -import com.tencent.mtt.hippy.utils.LogUtils; -import java.nio.ByteOrder; - -@SuppressWarnings({"unused", "JavaJniMissingFunction"}) -public class HippyBridgeImpl implements HippyBridge, DevRemoteDebugProxy.OnReceiveDataListener { - - private static final Object sBridgeSyncLock; - - static { - sBridgeSyncLock = new Object(); - } - - private static volatile String mCodeCacheRootDir; - private long mV8RuntimeId = 0; - private BridgeCallback mBridgeCallback; - private boolean mInit = false; - private final boolean mIsDevModule; - private String mDebugServerHost; - private final boolean mSingleThreadMode; - private final boolean enableV8Serialization; - private DebugWebSocketClient mDebugWebSocketClient; - private String mDebugGlobalConfig; - private NativeCallback mDebugInitJSFrameworkCallback; - private final HippyEngineContext mContext; - private Deserializer deserializer; - private BinaryReader safeHeapReader; - private BinaryReader safeDirectReader; - - public HippyBridgeImpl(HippyEngineContext engineContext, BridgeCallback callback, - boolean singleThreadMode, - boolean enableV8Serialization, boolean isDevModule, String debugServerHost) { - this.mBridgeCallback = callback; - this.mSingleThreadMode = singleThreadMode; - this.enableV8Serialization = enableV8Serialization; - this.mIsDevModule = isDevModule; - this.mDebugServerHost = debugServerHost; - this.mContext = engineContext; - - synchronized (sBridgeSyncLock) { - if (mCodeCacheRootDir == null) { - Context context = mContext.getGlobalConfigs().getContext(); - File hippyFile = FileUtils.getHippyFile(context); - if (hippyFile != null) { - mCodeCacheRootDir = - hippyFile.getAbsolutePath() + File.separator + "codecache" + File.separator; - } - } - } - - if (enableV8Serialization) { - deserializer = new Deserializer(null, new InternalizedStringTable()); - } - } - - @Override - public void initJSBridge(String globalConfig, NativeCallback callback, final int groupId) { - mDebugGlobalConfig = globalConfig; - mDebugInitJSFrameworkCallback = callback; - - if (this.mIsDevModule) { - mDebugWebSocketClient = new DebugWebSocketClient(); - mDebugWebSocketClient.setOnReceiveDataCallback(this); - if (TextUtils.isEmpty(mDebugServerHost)) { - mDebugServerHost = "localhost:38989"; - } - String clientId = mContext.getDevSupportManager().getDevInstanceUUID(); // 方便区分不同的 Hippy 调试页面 - mDebugWebSocketClient.connect( - String.format(Locale.US, "ws://%s/debugger-proxy?role=android_client&clientId=%s", mDebugServerHost, clientId), - new DebugWebSocketClient.JSDebuggerCallback() { - @SuppressWarnings("unused") - @Override - public void onSuccess(String response) { - LogUtils.d("hippyCore", "js debug socket connect success"); - initJSEngine(groupId); - } - - @SuppressWarnings("unused") - @Override - public void onFailure(final Throwable cause) { - LogUtils.e("hippyCore", "js debug socket connect failed"); - initJSEngine(groupId); - } - }); - } else { - initJSEngine(groupId); - } - } - - private void initJSEngine(int groupId) { - synchronized (HippyBridgeImpl.class) { - try { - byte[] globalConfig = mDebugGlobalConfig.getBytes(StandardCharsets.UTF_16LE); - mV8RuntimeId = initJSFramework(globalConfig, mSingleThreadMode, enableV8Serialization, mIsDevModule, mDebugInitJSFrameworkCallback, groupId); - mInit = true; - } catch (Throwable e) { - if (mBridgeCallback != null) { - mBridgeCallback.reportException(e); - } - } - } - } - - @Override - public long getV8RuntimeId() { - return mV8RuntimeId; - } - - @Override - public boolean runScriptFromUri(String uri, AssetManager assetManager, boolean canUseCodeCache, - String codeCacheTag, NativeCallback callback) { - if (!mInit) { - return false; - } - - if (!TextUtils.isEmpty(codeCacheTag) && !TextUtils.isEmpty(mCodeCacheRootDir)) { - String codeCacheDir = mCodeCacheRootDir + codeCacheTag + File.separator; - File codeCacheFile = new File(codeCacheDir); - if (!codeCacheFile.exists()) { - boolean ret = codeCacheFile.mkdirs(); - if (!ret) { - canUseCodeCache = false; - codeCacheDir = ""; - } - } - - return runScriptFromUri(uri, assetManager, canUseCodeCache, codeCacheDir, mV8RuntimeId, - callback); - } else { - boolean ret = false; - LogUtils.d("HippyEngineMonitor", "runScriptFromAssets codeCacheTag is null"); - try { - ret = runScriptFromUri(uri, assetManager, false, "" + codeCacheTag + File.separator, - mV8RuntimeId, callback); - } catch (Throwable e) { - if (mBridgeCallback != null) { - mBridgeCallback.reportException(e); - } - } - return ret; - } - } - - @Override - public void callFunction(String action, NativeCallback callback, ByteBuffer buffer) { - if (!mInit || TextUtils.isEmpty(action) || buffer == null || buffer.limit() == 0) { - return; - } - - int offset = buffer.position(); - int length = buffer.limit() - buffer.position(); - if (buffer.isDirect()) { - callFunction(action, mV8RuntimeId, callback, buffer, offset, length); - } else { - /* - * In Android's DirectByteBuffer implementation. - * - * {@link DirectByteBuffer#hb backing array} will be used to store buffer data, - * {@link DirectByteBuffer#offset} will be used to handle the alignment, - * it's already add to {@link DirectByteBuffer#address}, - * so the {@link DirectByteBuffer} has backing array and offset. - * - * In the other side, JNI method |void* GetDirectBufferAddress(JNIEnv*, jobject)| - * will be directly return {@link DirectByteBuffer#address} as the starting buffer address. - * - * So in this situation if, and only if, buffer is direct, - * {@link ByteBuffer#arrayOffset} will be ignored, treated as 0. - */ - offset += buffer.arrayOffset(); - callFunction(action, mV8RuntimeId, callback, buffer.array(), offset, length); - } - } - - @Override - public void callFunction(String action, NativeCallback callback, byte[] buffer) { - callFunction(action, callback, buffer, 0, buffer.length); - } - - @Override - public void callFunction(String action, NativeCallback callback, byte[] buffer, int offset, - int length) { - if (!mInit || TextUtils.isEmpty(action) || buffer == null || offset < 0 || length < 0 - || offset + length > buffer.length) { - return; - } - - callFunction(action, mV8RuntimeId, callback, buffer, offset, length); - } - - @Override - public void onDestroy() { - if (mDebugWebSocketClient != null) { - mDebugWebSocketClient.closeQuietly(); - mDebugWebSocketClient = null; - } - - if (!mInit) { - return; - } - - mInit = false; - if (enableV8Serialization) { - deserializer.getStringTable().release(); - } - - mV8RuntimeId = 0; - mBridgeCallback = null; - } - - @Override - public void destroy(NativeCallback callback) { - destroy(mV8RuntimeId, mSingleThreadMode, callback); - } - - public native long initJSFramework(byte[] gobalConfig, boolean useLowMemoryMode, - boolean enableV8Serialization, boolean isDevModule, NativeCallback callback, long groupId); - - public native boolean runScriptFromUri(String uri, AssetManager assetManager, - boolean canUseCodeCache, String codeCacheDir, long V8RuntimId, NativeCallback callback); - - public native void destroy(long runtimeId, boolean useLowMemoryMode, NativeCallback callback); - - public native void callFunction(String action, long V8RuntimId, NativeCallback callback, - ByteBuffer buffer, int offset, int length); - - public native void callFunction(String action, long V8RuntimId, NativeCallback callback, - byte[] buffer, int offset, int length); - - public native void onResourceReady(ByteBuffer output, long runtimeId, long resId); - - public void callNatives(String moduleName, String moduleFunc, String callId, byte[] buffer) { - callNatives(moduleName, moduleFunc, callId, ByteBuffer.wrap(buffer)); - } - - public void callNatives(String moduleName, String moduleFunc, String callId, ByteBuffer buffer) { - LogUtils.d("jni_callback", - "callNatives [moduleName:" + moduleName + " , moduleFunc: " + moduleFunc + "]"); - - if (mBridgeCallback != null) { - HippyArray hippyParam = bytesToArgument(buffer); - mBridgeCallback.callNatives(moduleName, moduleFunc, callId, hippyParam); - } - } - - public void InspectorChannel(byte[] params) { - String encoding = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? "UTF-16BE" : "UTF-16LE"; - String msg = new String(params, Charset.forName(encoding)); - if (mDebugWebSocketClient != null) { - mDebugWebSocketClient.sendMessage(msg); - } - } - - @SuppressWarnings("unused") - public void fetchResourceWithUri(final String uri, final long resId) { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - DevSupportManager devManager = mContext.getDevSupportManager(); - if (TextUtils.isEmpty(uri) || !UrlUtils.isWebUrl(uri) || devManager == null) { - LogUtils.e("HippyBridgeImpl", - "fetchResourceWithUri: can not call loadRemoteResource with " + uri); - return; - } - - devManager.loadRemoteResource(uri, new DevServerCallBack() { - @Override - public void onDevBundleReLoad() { - } - - @Override - public void onDevBundleLoadReady(InputStream inputStream) { - try { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - - byte[] b = new byte[2048]; - int size; - while ((size = inputStream.read(b)) > 0) { - output.write(b, 0, size); - } - - byte[] resBytes = output.toByteArray(); - final ByteBuffer buffer = ByteBuffer.allocateDirect(resBytes.length); - buffer.put(resBytes); - onResourceReady(buffer, mV8RuntimeId, resId); - } catch (Throwable e) { - if (mBridgeCallback != null) { - mBridgeCallback.reportException(e); - } - onResourceReady(null, mV8RuntimeId, resId); - } - } - - @Override - public void onInitDevError(Throwable e) { - LogUtils.e("hippy", "requireSubResource: " + e.getMessage()); - onResourceReady(null, mV8RuntimeId, resId); - } - }); - } - }); - } - - private HippyArray bytesToArgument(ByteBuffer buffer) { - HippyArray hippyParam = null; - if (enableV8Serialization) { - LogUtils.d("hippy_bridge", "bytesToArgument using Buffer"); - Object paramObj; - try { - final BinaryReader binaryReader; - if (buffer.isDirect()) { - if (safeDirectReader == null) { - safeDirectReader = new SafeDirectReader(); - } - binaryReader = safeDirectReader; - } else { - if (safeHeapReader == null) { - safeHeapReader = new SafeHeapReader(); - } - binaryReader = safeHeapReader; - } - binaryReader.reset(buffer); - deserializer.setReader(binaryReader); - deserializer.reset(); - deserializer.readHeader(); - paramObj = deserializer.readValue(); - } catch (Throwable e) { - e.printStackTrace(); - LogUtils.e("compatible.Deserializer", "Error Parsing Buffer", e); - return new HippyArray(); - } - if (paramObj instanceof HippyArray) { - hippyParam = (HippyArray) paramObj; - } - } else { - LogUtils.d("hippy_bridge", "bytesToArgument using JSON"); - byte[] bytes; - if (buffer.isDirect()) { - bytes = new byte[buffer.limit()]; - buffer.get(bytes); - } else { - bytes = buffer.array(); - } - hippyParam = ArgumentUtils.parseToArray(new String(bytes)); - } - - return hippyParam == null ? new HippyArray() : hippyParam; - } - - public void reportException(String message, String stackTrace) { - LogUtils.e("reportException", "!!!!!!!!!!!!!!!!!!!"); - - LogUtils.e("reportException", message); - LogUtils.e("reportException", stackTrace); - - if (mBridgeCallback != null) { - mBridgeCallback.reportException(message, stackTrace); - } - } - - @Override - public void onReceiveData(String msg) { - if (this.mIsDevModule) { - boolean isInspectMsg = Inspector.getInstance(mContext) - .setWebSocketClient(mDebugWebSocketClient).dispatchReqFromFrontend(mContext, msg); - if (!isInspectMsg) { - callFunction("onWebsocketMsg", null, msg.getBytes(StandardCharsets.UTF_16LE)); - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeManagerImpl.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeManagerImpl.java deleted file mode 100644 index 3a739b5318a..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyBridgeManagerImpl.java +++ /dev/null @@ -1,663 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Hippy - * available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * 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 com.tencent.mtt.hippy.bridge; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.os.Build; -import android.os.Handler; -import android.os.Message; -import android.text.TextUtils; - -import com.tencent.mtt.hippy.HippyEngine; -import com.tencent.mtt.hippy.HippyEngine.BridgeTransferType; -import com.tencent.mtt.hippy.HippyEngine.ModuleLoadStatus; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorEvent; -import com.tencent.mtt.hippy.adapter.thirdparty.HippyThirdPartyAdapter; -import com.tencent.mtt.hippy.bridge.bundleloader.HippyBundleLoader; -import com.tencent.mtt.hippy.bridge.jsi.TurboModuleManager; -import com.tencent.mtt.hippy.common.Callback; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyJsException; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.modules.HippyModuleManager; -import com.tencent.mtt.hippy.runtime.builtins.JSValue; -import com.tencent.mtt.hippy.serialization.PrimitiveValueSerializer; -import com.tencent.mtt.hippy.serialization.compatible.Serializer; -import com.tencent.mtt.hippy.serialization.nio.writer.SafeDirectWriter; -import com.tencent.mtt.hippy.serialization.nio.writer.SafeHeapWriter; -import com.tencent.mtt.hippy.utils.ArgumentUtils; -import com.tencent.mtt.hippy.utils.DimensionsUtil; -import com.tencent.mtt.hippy.utils.I18nUtil; -import com.tencent.mtt.hippy.utils.UIThreadUtils; - -import org.json.JSONObject; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; - -@SuppressWarnings({"unused", "deprecation"}) -public class HippyBridgeManagerImpl implements HippyBridgeManager, HippyBridge.BridgeCallback, - Handler.Callback { - - static final int MSG_CODE_INIT_BRIDGE = 10; - static final int MSG_CODE_RUN_BUNDLE = 11; - static final int MSG_CODE_CALL_FUNCTION = 12; - static final int MSG_CODE_DESTROY_BRIDGE = 13; - - static final int FUNCTION_ACTION_LOAD_INSTANCE = 1; - static final int FUNCTION_ACTION_RESUME_INSTANCE = 2; - static final int FUNCTION_ACTION_PAUSE_INSTANCE = 3; - static final int FUNCTION_ACTION_DESTROY_INSTANCE = 4; - static final int FUNCTION_ACTION_CALLBACK = 5; - static final int FUNCTION_ACTION_CALL_JSMODULE = 6; - - public static final int BRIDGE_TYPE_SINGLE_THREAD = 2; - public static final int BRIDGE_TYPE_NORMAL = 1; - - final HippyEngineContext mContext; - final HippyBundleLoader mCoreBundleLoader; - HippyBridge mHippyBridge; - volatile boolean mIsInit = false; - Handler mHandler; - final int mBridgeType; - final boolean enableV8Serialization; - ArrayList mLoadedBundleInfo = null; - private final boolean mIsDevModule; - private final String mDebugServerHost; - private final int mGroupId; - private final HippyThirdPartyAdapter mThirdPartyAdapter; - private StringBuilder mStringBuilder; - private SafeHeapWriter safeHeapWriter; - private SafeDirectWriter safeDirectWriter; - private Serializer compatibleSerializer; - private com.tencent.mtt.hippy.serialization.recommend.Serializer recommendSerializer; - - - HippyEngine.ModuleListener mLoadModuleListener; - - private TurboModuleManager mTurboModuleManager; - - public HippyBridgeManagerImpl(HippyEngineContext context, HippyBundleLoader coreBundleLoader, - int bridgeType, - boolean enableV8Serialization, boolean isDevModule, String debugServerHost, int groupId, - HippyThirdPartyAdapter thirdPartyAdapter) { - mContext = context; - mCoreBundleLoader = coreBundleLoader; - mBridgeType = bridgeType; - mIsDevModule = isDevModule; - mDebugServerHost = debugServerHost; - mGroupId = groupId; - mThirdPartyAdapter = thirdPartyAdapter; - this.enableV8Serialization = enableV8Serialization; - - if (enableV8Serialization) { - compatibleSerializer = new Serializer(); - recommendSerializer = new com.tencent.mtt.hippy.serialization.recommend.Serializer(); - } else { - mStringBuilder = new StringBuilder(1024); - } - } - - private void handleCallFunction(Message msg) { - String action = null; - int instanceId = 0; - switch (msg.arg2) { - case FUNCTION_ACTION_LOAD_INSTANCE: { - if (msg.obj instanceof HippyMap) { - instanceId = ((HippyMap)msg.obj).getInt("id"); - HippyRootView rootView = mContext.getInstance(instanceId); - if (rootView != null) { - rootView.startMonitorEvent(HippyEngineMonitorEvent.MODULE_LOAD_EVENT_RUN_BUNDLE); - } - } - action = "loadInstance"; - break; - } - case FUNCTION_ACTION_RESUME_INSTANCE: { - action = "resumeInstance"; - break; - } - case FUNCTION_ACTION_PAUSE_INSTANCE: { - action = "pauseInstance"; - break; - } - case FUNCTION_ACTION_DESTROY_INSTANCE: { - action = "destroyInstance"; - break; - } - case FUNCTION_ACTION_CALLBACK: { - action = "callBack"; - break; - } - case FUNCTION_ACTION_CALL_JSMODULE: { - action = "callJsModule"; - break; - } - } - - final int actinCode = msg.arg2; - final int rootViewId = instanceId; - NativeCallback callback = new NativeCallback(mHandler) { - @Override - public void Call(long result, Message message, String action, String reason) { - if (result != 0) { - String info = "CallFunction error: actinCode=" + actinCode - + ", result=" + result + ", reason=" + reason; - reportException(new Throwable(info)); - } else if (actinCode == FUNCTION_ACTION_LOAD_INSTANCE) { - HippyRootView rootView = mContext.getInstance(rootViewId); - if (rootView != null) { - rootView.startMonitorEvent(HippyEngineMonitorEvent.MODULE_LOAD_EVENT_CREATE_VIEW); - } - } - } - }; - - PrimitiveValueSerializer serializer = (msg.obj instanceof JSValue) ? - recommendSerializer : compatibleSerializer; - - if (msg.arg1 == BridgeTransferType.BRIDGE_TRANSFER_TYPE_NIO.value()) { - ByteBuffer buffer; - if (enableV8Serialization) { - if (safeDirectWriter == null) { - safeDirectWriter = new SafeDirectWriter(SafeDirectWriter.INITIAL_CAPACITY, 0); - } else { - safeDirectWriter.reset(); - } - serializer.setWriter(safeDirectWriter); - serializer.reset(); - serializer.writeHeader(); - serializer.writeValue(msg.obj); - buffer = safeDirectWriter.chunked(); - } else { - mStringBuilder.setLength(0); - byte[] bytes = ArgumentUtils.objectToJsonOpt(msg.obj, mStringBuilder).getBytes( - StandardCharsets.UTF_16LE); - buffer = ByteBuffer.allocateDirect(bytes.length); - buffer.put(bytes); - } - - mHippyBridge.callFunction(action, callback, buffer); - } else { - if (enableV8Serialization) { - if (safeHeapWriter == null) { - safeHeapWriter = new SafeHeapWriter(); - } else { - safeHeapWriter.reset(); - } - serializer.setWriter(safeHeapWriter); - serializer.reset(); - serializer.writeHeader(); - serializer.writeValue(msg.obj); - ByteBuffer buffer = safeHeapWriter.chunked(); - int offset = buffer.arrayOffset() + buffer.position(); - int length = buffer.limit() - buffer.position(); - mHippyBridge.callFunction(action, callback, buffer.array(), offset, length); - } else { - mStringBuilder.setLength(0); - byte[] bytes = ArgumentUtils.objectToJsonOpt(msg.obj, mStringBuilder).getBytes( - StandardCharsets.UTF_16LE); - mHippyBridge.callFunction(action, callback, bytes); - } - } - } - - private void handleDestroyBridge(Message msg) { - if (mThirdPartyAdapter != null) { - mThirdPartyAdapter.onRuntimeDestroy(); - } - - if (enableTurbo() && mTurboModuleManager != null) { - mTurboModuleManager.uninstall(mHippyBridge.getV8RuntimeId()); - } - - @SuppressWarnings("unchecked") final com.tencent.mtt.hippy.common.Callback destroyCallback = (com.tencent.mtt.hippy.common.Callback) msg.obj; - mHippyBridge.destroy(new NativeCallback(mHandler) { - @Override - public void Call(long result, Message message, String action, String reason) { - boolean success = result == 0; - mHippyBridge.onDestroy(); - if (destroyCallback != null) { - RuntimeException exception = null; - if (!success) { - exception = new RuntimeException("destroy error: result=" + result + ", reason=" + reason); - } - - destroyCallback.callback(success, exception); - } - } - }); - } - - @Override - public boolean handleMessage(@SuppressWarnings("NullableProblems") Message msg) { - try { - switch (msg.what) { - case MSG_CODE_INIT_BRIDGE: { - mContext.getStartTimeMonitor() - .startEvent(HippyEngineMonitorEvent.ENGINE_LOAD_EVENT_INIT_BRIDGE); - @SuppressWarnings("unchecked") final com.tencent.mtt.hippy.common.Callback callback = (com.tencent.mtt.hippy.common.Callback) msg.obj; - try { - mHippyBridge = new HippyBridgeImpl(mContext, HippyBridgeManagerImpl.this, - mBridgeType == BRIDGE_TYPE_SINGLE_THREAD, enableV8Serialization, this.mIsDevModule, - this.mDebugServerHost); - - mHippyBridge.initJSBridge(getGlobalConfigs(), new NativeCallback(mHandler) { - @Override - public void Call(long result, Message message, String action, String reason) { - if (result != 0) { - String info = "initJSBridge error: result=" + result + ", reason=" + reason; - reportException(new Throwable(info)); - } - - if (enableTurbo()) { - mTurboModuleManager = new TurboModuleManager(mContext); - mTurboModuleManager.install(mHippyBridge.getV8RuntimeId()); - } - - if (mThirdPartyAdapter != null) { - mThirdPartyAdapter.onRuntimeInit(mHippyBridge.getV8RuntimeId()); - } - mContext.getStartTimeMonitor() - .startEvent(HippyEngineMonitorEvent.ENGINE_LOAD_EVENT_LOAD_COMMONJS); - - if (mCoreBundleLoader != null) { - mCoreBundleLoader.load(mHippyBridge, new NativeCallback(mHandler) { - @Override - public void Call(long result, Message message, String action, String reason) { - mIsInit = result == 0; - RuntimeException exception = null; - if (!mIsInit) { - exception = new RuntimeException( - "load coreJsBundle failed, check your core jsBundle:" + reason); - } - callback.callback(mIsInit, exception); - } - }); - } else { - mIsInit = true; - callback.callback(mIsInit, null); - } - } - }, mGroupId); - } catch (Throwable e) { - mIsInit = false; - callback.callback(false, e); - } - return true; - } - case MSG_CODE_RUN_BUNDLE: { - HippyRootView rootView = null; - if (msg.arg2 > 0) { - rootView = mContext.getInstance(msg.arg2); - if (rootView != null && rootView.getTimeMonitor() != null) { - rootView.getTimeMonitor() - .startEvent(HippyEngineMonitorEvent.MODULE_LOAD_EVENT_LOAD_BUNDLE); - } - } - HippyBundleLoader loader = (HippyBundleLoader) msg.obj; - - if (!mIsInit) { - notifyModuleLoaded(ModuleLoadStatus.STATUS_ENGINE_UNINIT, - "load module error. HippyBridge mIsInit:" + mIsInit, null); - return true; - } - if (loader == null) { - notifyModuleLoaded(ModuleLoadStatus.STATUS_VARIABLE_NULL, - "load module error. loader:" + null, null); - return true; - } - - final String bundleUniKey = loader.getBundleUniKey(); - final HippyRootView localRootView = rootView; - - if (mLoadedBundleInfo != null && !TextUtils.isEmpty(bundleUniKey) && mLoadedBundleInfo - .contains(bundleUniKey)) { - notifyModuleLoaded(ModuleLoadStatus.STATUS_REPEAT_LOAD, - "repeat load module. loader.getBundleUniKey=" + bundleUniKey, localRootView); - return true; - } - - if (!TextUtils.isEmpty(bundleUniKey)) { - if (mLoadedBundleInfo == null) { - mLoadedBundleInfo = new ArrayList<>(); - } - mLoadedBundleInfo.add(bundleUniKey); - - loader.load(mHippyBridge, new NativeCallback(mHandler) { - @Override - public void Call(long result, Message message, String action, String reason) { - if (result == 0) { - notifyModuleLoaded(ModuleLoadStatus.STATUS_OK, null, localRootView); - } else { - notifyModuleLoaded(ModuleLoadStatus.STATUS_ERR_RUN_BUNDLE, - "load module error. loader.load failed. check the file!!", null); - } - } - }); - } else { - notifyModuleLoaded(ModuleLoadStatus.STATUS_VARIABLE_NULL, - "can not load module. loader.getBundleUniKey=null", null); - } - - return true; - } - case MSG_CODE_CALL_FUNCTION: { - if (mIsInit) { - handleCallFunction(msg); - } - - return true; - } - case MSG_CODE_DESTROY_BRIDGE: { - handleDestroyBridge(msg); - return true; - } - } - } catch (Throwable e) { - reportException(e); - } - - return false; - } - - @Override - public void initBridge(Callback callback) { - mHandler = new Handler(mContext.getThreadExecutor().getJsThread().getLooper(), this); - Message message = mHandler.obtainMessage(MSG_CODE_INIT_BRIDGE, callback); - mHandler.sendMessage(message); - } - - @Override - public void runBundle(int id, HippyBundleLoader loader, HippyEngine.ModuleListener listener, - HippyRootView hippyRootView) { - if (!mIsInit) { - mLoadModuleListener = listener; - notifyModuleLoaded(ModuleLoadStatus.STATUS_ENGINE_UNINIT, - "load module error. HippyBridge not initialized", hippyRootView); - return; - } - - mLoadModuleListener = listener; - Message message = mHandler.obtainMessage(MSG_CODE_RUN_BUNDLE, 0, id, loader); - mHandler.sendMessage(message); - } - - public void notifyModuleJsException(final HippyJsException exception) { - if (UIThreadUtils.isOnUiThread()) { - if (mLoadModuleListener != null && mLoadModuleListener.onJsException(exception)) { - mLoadModuleListener = null; - } - } else { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - if (mLoadModuleListener != null && mLoadModuleListener.onJsException(exception)) { - mLoadModuleListener = null; - } - } - }); - } - } - - private void notifyModuleLoaded(final ModuleLoadStatus statusCode, final String msg, - final HippyRootView hippyRootView) { - if (UIThreadUtils.isOnUiThread()) { - if (mLoadModuleListener != null) { - mLoadModuleListener.onLoadCompleted(statusCode, msg, hippyRootView); - //mLoadModuleListener = null; - } - } else { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - if (mLoadModuleListener != null) { - mLoadModuleListener.onLoadCompleted(statusCode, msg, hippyRootView); - //mLoadModuleListener = null; - } - } - }); - } - } - - @Override - public void loadInstance(String name, int id, HippyMap params) { - if (!mIsInit) { - return; - } - - HippyMap map = new HippyMap(); - map.pushString("name", name); - map.pushInt("id", id); - map.pushMap("params", params); - Message message = mHandler - .obtainMessage(MSG_CODE_CALL_FUNCTION, 0, FUNCTION_ACTION_LOAD_INSTANCE, map); - mHandler.sendMessage(message); - } - - @Override - public void resumeInstance(int id) { - if (!mIsInit) { - return; - } - - Message message = mHandler - .obtainMessage(MSG_CODE_CALL_FUNCTION, 0, FUNCTION_ACTION_RESUME_INSTANCE, id); - mHandler.sendMessage(message); - } - - @Override - public void pauseInstance(int id) { - if (!mIsInit) { - return; - } - - Message message = mHandler - .obtainMessage(MSG_CODE_CALL_FUNCTION, 0, FUNCTION_ACTION_PAUSE_INSTANCE, id); - mHandler.sendMessage(message); - } - - @Override - public void destroyInstance(int id) { - if (!mIsInit) { - return; - } - - Message message = mHandler - .obtainMessage(MSG_CODE_CALL_FUNCTION, 0, FUNCTION_ACTION_DESTROY_INSTANCE, id); - mHandler.sendMessage(message); - } - - @Override - public void execCallback(Object params, BridgeTransferType transferType) { - Message message = mHandler - .obtainMessage(MSG_CODE_CALL_FUNCTION, transferType.value(), FUNCTION_ACTION_CALLBACK, - params); - mHandler.sendMessage(message); - } - - @Override - public void destroyBridge(Callback callback) { - assert (mHandler != null); - //noinspection ConstantConditions - if (mHandler == null) { - return; - } - - Message message = mHandler.obtainMessage(MSG_CODE_DESTROY_BRIDGE, callback); - mHandler.sendMessage(message); - } - - @Override - public void destroy() { - mIsInit = false; - mLoadModuleListener = null; - if (mHandler != null) { - mHandler.removeMessages(MSG_CODE_INIT_BRIDGE); - mHandler.removeMessages(MSG_CODE_RUN_BUNDLE); - mHandler.removeMessages(MSG_CODE_CALL_FUNCTION); - } - } - - @Override - public void callJavaScriptModule(String moduleName, String methodName, Object param, - BridgeTransferType transferType) { - if (!mIsInit) { - return; - } - - HippyMap map = new HippyMap(); - map.pushString("moduleName", moduleName); - map.pushString("methodName", methodName); - map.pushObject("params", param); - - Message message = mHandler - .obtainMessage(MSG_CODE_CALL_FUNCTION, transferType.value(), FUNCTION_ACTION_CALL_JSMODULE, - map); - mHandler.sendMessage(message); - } - - @Override - public void callNatives(String moduleName, String moduleFunc, String callId, HippyArray params) { - if (mContext != null && mContext.getModuleManager() != null) { - HippyModuleManager manager = mContext.getModuleManager(); - if (manager != null) { - HippyCallNativeParams callNativeParams = HippyCallNativeParams - .obtain(moduleName, moduleFunc, callId, params); - manager.callNatives(callNativeParams); - } - } - } - - @Override - public void reportException(Throwable e) { - if (mContext == null || e == null) { - return; - } - - mContext.handleException(e); - } - - @Override - public void reportException(String message, String stackTrace) { - if (mContext == null) { - return; - } - - mContext.handleException(new HippyJsException(message, stackTrace)); - } - - String getGlobalConfigs() { - Context context = mContext.getGlobalConfigs().getContext(); - assert (context != null); - - HippyMap globalParams = new HippyMap(); - HippyMap dimensionMap = DimensionsUtil.getDimensions(-1, -1, context, false); - - if (mContext.getGlobalConfigs() != null - && mContext.getGlobalConfigs().getDeviceAdapter() != null) { - mContext.getGlobalConfigs().getDeviceAdapter() - .reviseDimensionIfNeed(context, dimensionMap, false, - false); - } - globalParams.pushMap("Dimensions", dimensionMap); - - String packageName = ""; - String versionName = ""; - String pageUrl = ""; - - HippyMap extraDataMap = new HippyMap(); - if (mThirdPartyAdapter != null) { - packageName = mThirdPartyAdapter.getPackageName(); - versionName = mThirdPartyAdapter.getAppVersion(); - pageUrl = mThirdPartyAdapter.getPageUrl(); - JSONObject jObject = mThirdPartyAdapter.getExtraData(); - extraDataMap.pushJSONObject(jObject); - } - - try { - PackageManager packageManager = context.getPackageManager(); - PackageInfo packageInfo = packageManager.getPackageInfo( - context.getPackageName(), 0); - if (TextUtils.isEmpty(packageName)) { - packageName = packageInfo.packageName; - } - - if (TextUtils.isEmpty(versionName)) { - versionName = packageInfo.versionName; - } - } catch (Exception e) { - e.printStackTrace(); - } - - HippyMap platformParams = new HippyMap(); - platformParams.pushString("OS", "android"); - platformParams.pushString("PackageName", (packageName == null) ? "" : packageName); - platformParams.pushString("VersionName", (versionName == null) ? "" : versionName); - platformParams.pushInt("APILevel", Build.VERSION.SDK_INT); - platformParams.pushBoolean("NightMode", getNightMode()); - - HippyMap Localization = new HippyMap(); - Localization.pushString("language", I18nUtil.getLanguage()); - Localization.pushString("country", I18nUtil.getCountry()); - Localization.pushInt("direction", I18nUtil.getLayoutDirection()); - platformParams.pushMap("Localization", Localization); - - globalParams.pushMap("Platform", platformParams); - - HippyMap tkd = new HippyMap(); - tkd.pushString("url", (pageUrl == null) ? "" : pageUrl); - tkd.pushString("appName", (packageName == null) ? "" : packageName); - tkd.pushString("appVersion", (versionName == null) ? "" : versionName); - tkd.pushMap("extra", extraDataMap); - globalParams.pushMap("tkd", tkd); - - return ArgumentUtils.objectToJson(globalParams); - } - - private boolean getNightMode() { - int currentNightMode = - mContext.getGlobalConfigs().getContext().getResources().getConfiguration().uiMode - & Configuration.UI_MODE_NIGHT_MASK; - switch (currentNightMode) { - case Configuration.UI_MODE_NIGHT_UNDEFINED: - // We don't know what mode we're in, assume notnight - return false; - case Configuration.UI_MODE_NIGHT_NO: - // Night mode is not active, we're in day time - return false; - case Configuration.UI_MODE_NIGHT_YES: - // Night mode is active, we're at night! - return true; - default: - return false; - } - } - - @Override - public HippyThirdPartyAdapter getThirdPartyAdapter() { - return mThirdPartyAdapter; - } - - private boolean enableTurbo() { - return mContext.getGlobalConfigs() != null && mContext.getGlobalConfigs().enableTurbo(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyCallNativeParams.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyCallNativeParams.java deleted file mode 100644 index 03fea3aef04..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyCallNativeParams.java +++ /dev/null @@ -1,54 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.bridge; - -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.supportui.utils.struct.Pools; - -@SuppressWarnings({"unused"}) -public class HippyCallNativeParams { - - private static final int POOL_SIZE = 20; - private static final Pools.SynchronizedPool INSTANCE_POOL = new Pools.SynchronizedPool<>( - POOL_SIZE); - - public String mModuleName; - public String mModuleFunc; - public String mCallId; - public HippyArray mParams; - - public static HippyCallNativeParams obtain(String moduleName, String moduleFunc, String callId, - HippyArray params) { - HippyCallNativeParams instance = INSTANCE_POOL.acquire(); - if (instance == null) { - instance = new HippyCallNativeParams(); - } - instance.init(moduleName, moduleFunc, callId, params); - return instance; - } - - private void init(String moduleName, String moduleFunc, String callId, HippyArray params) { - this.mModuleName = moduleName; - this.mModuleFunc = moduleFunc; - this.mCallId = callId; - this.mParams = params; - } - - public void onDispose() { - mParams = null; - INSTANCE_POOL.release(this); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyCoreAPI.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyCoreAPI.java deleted file mode 100644 index 0f1af9d6d78..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/HippyCoreAPI.java +++ /dev/null @@ -1,221 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.bridge; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyAPIProvider; -import com.tencent.mtt.hippy.common.Provider; -import com.tencent.mtt.hippy.modules.javascriptmodules.Dimensions; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.modules.javascriptmodules.HippyJavaScriptModule; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import com.tencent.mtt.hippy.modules.nativemodules.animation.AnimationFrameModule; -import com.tencent.mtt.hippy.modules.nativemodules.animation.AnimationModule; -import com.tencent.mtt.hippy.modules.nativemodules.audio.AudioPlayerModule; -import com.tencent.mtt.hippy.modules.nativemodules.clipboard.ClipboardModule; -import com.tencent.mtt.hippy.modules.nativemodules.debug.DevMenu; -import com.tencent.mtt.hippy.modules.nativemodules.console.ConsoleModule; -import com.tencent.mtt.hippy.modules.nativemodules.deviceevent.DeviceEventModule; -import com.tencent.mtt.hippy.modules.nativemodules.exception.ExceptionModule; -import com.tencent.mtt.hippy.modules.nativemodules.image.ImageLoaderModule; -import com.tencent.mtt.hippy.modules.nativemodules.netinfo.NetInfoModule; -import com.tencent.mtt.hippy.modules.nativemodules.network.NetworkModule; -import com.tencent.mtt.hippy.modules.nativemodules.network.WebSocketModule; -import com.tencent.mtt.hippy.modules.nativemodules.storage.StorageModule; -import com.tencent.mtt.hippy.modules.nativemodules.timer.TimerModule; -import com.tencent.mtt.hippy.modules.nativemodules.uimanager.UIManagerModule; -import com.tencent.mtt.hippy.modules.nativemodules.utils.UtilsModule; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.views.custom.HippyCustomPropsController; -import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerViewController; -import com.tencent.mtt.hippy.views.image.HippyImageViewController; -import com.tencent.mtt.hippy.views.list.HippyListItemViewController; -import com.tencent.mtt.hippy.views.list.HippyListViewController; -import com.tencent.mtt.hippy.views.modal.HippyModalHostManager; -import com.tencent.mtt.hippy.views.navigator.NavigatorController; -import com.tencent.mtt.hippy.views.refresh.HippyPullFooterViewController; -import com.tencent.mtt.hippy.views.refresh.HippyPullHeaderViewController; -import com.tencent.mtt.hippy.views.refresh.RefreshWrapperController; -import com.tencent.mtt.hippy.views.refresh.RefreshWrapperItemController; -import com.tencent.mtt.hippy.views.scroll.HippyScrollViewController; -import com.tencent.mtt.hippy.views.text.HippyTextViewController; -import com.tencent.mtt.hippy.views.textinput.HippyTextInputController; -import com.tencent.mtt.hippy.views.view.HippyViewGroupController; -import com.tencent.mtt.hippy.views.viewpager.HippyViewPagerController; -import com.tencent.mtt.hippy.views.viewpager.HippyViewPagerItemController; -import com.tencent.mtt.hippy.views.waterfalllist.HippyWaterfallItemViewController; -import com.tencent.mtt.hippy.views.waterfalllist.HippyWaterfallViewController; -import com.tencent.mtt.hippy.views.webview.HippyWebViewController; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@SuppressWarnings({"unused", "rawtypes"}) -public class HippyCoreAPI implements HippyAPIProvider { - - @Override - public Map, Provider> getNativeModules( - final HippyEngineContext context) { - Map, Provider> modules = new HashMap<>(); - modules.put(TimerModule.class, new Provider() { - @Override - public TimerModule get() { - return new TimerModule(context); - } - }); - modules.put(ConsoleModule.class, new Provider() { - @Override - public ConsoleModule get() { - return new ConsoleModule(context); - } - }); - modules.put(ExceptionModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new ExceptionModule(context); - } - }); - modules.put(UIManagerModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new UIManagerModule(context); - } - }); - modules.put(AnimationModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new AnimationModule(context); - } - }); - modules.put(StorageModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new StorageModule(context); - } - }); - modules.put(NetInfoModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new NetInfoModule(context); - } - }); - modules.put(AnimationFrameModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new AnimationFrameModule(context); - } - }); - modules.put(ImageLoaderModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new ImageLoaderModule(context); - } - }); - modules.put(NetworkModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new NetworkModule(context); - } - }); - modules.put(DeviceEventModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new DeviceEventModule(context); - } - }); - modules.put(WebSocketModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new WebSocketModule(context); - } - }); - modules.put(UtilsModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new UtilsModule(context); - } - }); - modules.put(ClipboardModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new ClipboardModule(context); - } - }); - modules.put(DevMenu.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new DevMenu(context); - } - }); - modules.put(AudioPlayerModule.class, new Provider() { - @Override - public HippyNativeModuleBase get() { - return new AudioPlayerModule(context); - } - }); - return modules; - } - - @Override - public List> getJavaScriptModules() { - List> jsModules = new ArrayList<>(); - jsModules.add(EventDispatcher.class); - jsModules.add(Dimensions.class); - return jsModules; - } - - @Override - public List> getControllers() { - List> components = new ArrayList<>(); - components.add(HippyTextViewController.class); - components.add(HippyViewGroupController.class); - components.add(HippyImageViewController.class); - components.add(HippyListViewController.class); - components.add(HippyRecyclerViewController.class); - components.add(HippyListItemViewController.class); - components.add(HippyTextInputController.class); - components.add(HippyScrollViewController.class); - components.add(HippyViewPagerController.class); - components.add(HippyViewPagerItemController.class); - components.add(HippyModalHostManager.class); - components.add(RefreshWrapperController.class); - components.add(RefreshWrapperItemController.class); - components.add(HippyPullHeaderViewController.class); - components.add(HippyPullFooterViewController.class); - components.add(NavigatorController.class); - components.add(HippyWebViewController.class); - components.add(HippyCustomPropsController.class); - components.add(HippyWaterfallViewController.class); - components.add(HippyWaterfallItemViewController.class); - - return components; - } - - @SuppressWarnings("SameParameterValue") - private void addControllerWithClassName(String className, - List> components) { - try { - Class videoControllerClass = Class.forName(className); - //noinspection unchecked - components.add(videoControllerClass); - } catch (ClassNotFoundException ignore) { - LogUtils.d("HippyCoreAPI", "not contain video component, make sure current project config!"); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/NativeCallback.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/NativeCallback.java deleted file mode 100644 index 90f1bb06c17..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/NativeCallback.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.tencent.mtt.hippy.bridge; - -import android.os.Handler; -import android.os.Message; - -@SuppressWarnings({"unused"}) -public abstract class NativeCallback { - - public NativeCallback(Handler handler) { - mHandler = handler; - } - - public NativeCallback(Handler handler, Message msg, String action) { - mHandler = handler; - mMsg = msg; - mAction = action; - } - - public void Callback(long result, String reason) { - if (mHandler != null) { - NativeRunnable runnable = new NativeRunnable(this, result, mMsg, mAction, reason); - mHandler.post(runnable); - } - } - - public abstract void Call(long result, Message message, String action, String reason); - - private final Handler mHandler; - private Message mMsg = null; - private String mAction = null; - - public static class NativeRunnable implements Runnable { - - private final long result; - private final NativeCallback callback; - private final Message message; - private final String action; - private final String reason; - - public NativeRunnable(NativeCallback callback, long result, Message message, - String action, String reason) { - this.result = result; - this.callback = callback; - this.message = message; - this.action = action; - this.reason = reason; - } - - @Override - public void run() { - callback.Call(result, message, action, reason); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/libraryloader/LibraryLoader.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/libraryloader/LibraryLoader.java deleted file mode 100644 index a42fc7a5e1a..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/libraryloader/LibraryLoader.java +++ /dev/null @@ -1,42 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.bridge.libraryloader; - -import com.tencent.mtt.hippy.BuildConfig; - -public class LibraryLoader { - - private static boolean hasLoaded = false; - private final static String[] SO_NAME_LIST = new String[]{ - "hippy", "flexbox" - }; - - public static synchronized void loadLibraryIfNeed() { - if (hasLoaded || BuildConfig.ENABLE_SO_DOWNLOAD) { - return; - } - - try { - for (String name : SO_NAME_LIST) { - System.loadLibrary(name); - } - hasLoaded = true; - } catch (Throwable e) { - e.printStackTrace(); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/DeserializerDelegate.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/DeserializerDelegate.java deleted file mode 100644 index c3a4c6e72e7..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/DeserializerDelegate.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.tencent.mtt.hippy.bridge.serialization.delegate; - -import com.tencent.mtt.hippy.NativeAccess; -import com.tencent.mtt.hippy.runtime.builtins.JSSharedArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.wasm.WasmModule; -import com.tencent.mtt.hippy.serialization.exception.DataCloneDeserializationException; -import com.tencent.mtt.hippy.serialization.recommend.Deserializer; - -@SuppressWarnings("unused") -public class DeserializerDelegate implements Deserializer.Delegate { - - private static final DeserializerDelegate instance = new DeserializerDelegate(); - - public static DeserializerDelegate getInstance() { - return instance; - } - - private DeserializerDelegate() { - - } - - @Override - public Object readHostObject(Deserializer deserializer) { - throw new DataCloneDeserializationException(); - } - - @Override - public JSSharedArrayBuffer getSharedArrayBufferFromId(Deserializer deserializer, int clone_id) { - return NativeAccess.getSharedArrayBufferFromId(clone_id); - } - - @Override - public WasmModule getWasmModuleFromId(Deserializer deserializer, int transfer_id) { - return NativeAccess.getWasmModuleFromId(transfer_id); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/SerializerDelegate.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/SerializerDelegate.java deleted file mode 100644 index e4707ee6cfd..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/SerializerDelegate.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.tencent.mtt.hippy.bridge.serialization.delegate; - -import com.tencent.mtt.hippy.exception.UnexpectedTypeException; -import com.tencent.mtt.hippy.runtime.builtins.JSSharedArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.JSValue; -import com.tencent.mtt.hippy.runtime.builtins.wasm.WasmModule; -import com.tencent.mtt.hippy.serialization.recommend.Serializer; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; - -@SuppressWarnings({"unused"}) -public class SerializerDelegate implements Serializer.Delegate, SerializerDelegateHost { - - private static final Map objectMap = new ConcurrentHashMap<>(); - private static final AtomicInteger nextId = new AtomicInteger(0); - private static final SerializerDelegate instance = new SerializerDelegate(); - - private SerializerDelegate() { - - } - - public static SerializerDelegate getInstance() { - return instance; - } - - @Override - public boolean writeHostObject(Serializer serializer, Object object) { - return false; - } - - // region set & set - private int getObjectId(T object) { - int id = nextId.incrementAndGet(); - objectMap.put(id, object); - return id; - } - - private T getObjectFromId(int id, Class type) { - Object object = objectMap.get(id); - if (type.isInstance(object)) { - objectMap.remove(id); - return type.cast(object); - } else if (object == null) { - return null; - } - throw new UnexpectedTypeException(type, object); - } - // endregion - - // region SharedArrayBuffer - @Override - public int getSharedArrayBufferId(Serializer serializer, JSSharedArrayBuffer sharedArrayBuffer) { - return getObjectId(sharedArrayBuffer); - } - - @Override - public JSSharedArrayBuffer getSharedArrayBufferFromId(int clone_id) { - return getObjectFromId(clone_id, JSSharedArrayBuffer.class); - } - // endregion - - // region WasmModule - @Override - public int getWasmModuleTransferId(Serializer serializer, WasmModule module) { - return getObjectId(module); - } - - @Override - public WasmModule getWasmModuleFromId(int transfer_id) { - return getObjectFromId(transfer_id, WasmModule.class); - } - // endregion -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/SerializerDelegateHost.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/SerializerDelegateHost.java deleted file mode 100644 index 1e7e5eb375c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/bridge/serialization/delegate/SerializerDelegateHost.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.tencent.mtt.hippy.bridge.serialization.delegate; - -import com.tencent.mtt.hippy.runtime.builtins.JSSharedArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.wasm.WasmModule; -import com.tencent.mtt.hippy.serialization.recommend.Serializer; - -@SuppressWarnings({"unused"}) -public interface SerializerDelegateHost { - - /** - * Get a {@link JSSharedArrayBuffer} given a clone_id previously provided by {@link - * SerializerDelegate#getSharedArrayBufferId(Serializer, JSSharedArrayBuffer)}
- * This method will be called from C++ side. - * - * @param clone_id clone id - * @return JSSharedArrayBuffer - */ - JSSharedArrayBuffer getSharedArrayBufferFromId(int clone_id); - - /** - * Get a {@link WasmModule} given a transfer_id previously provided by {@link - * SerializerDelegate#getWasmModuleTransferId(Serializer, WasmModule)}
- * This method will be called from C++ side. - * - * @param transfer_id clone id - * @return webAssembly module - */ - WasmModule getWasmModuleFromId(int transfer_id); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyArray.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyArray.java deleted file mode 100644 index 8ee431a8c2f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyArray.java +++ /dev/null @@ -1,237 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.common; - -import com.tencent.mtt.hippy.utils.ArgumentUtils; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Iterator; - -@SuppressWarnings({"deprecation", "unchecked", "rawtypes"}) -public class HippyArray { - - private final ArrayList mDatas; - - public HippyArray() { - mDatas = new ArrayList(); - } - - public int size() { - return mDatas.size(); - } - - public Object get(int index) { - return mDatas.get(index); - } - - public void pushObject(Object obj) { - mDatas.add(obj); - } - - public void setObject(int index, Object obj) { - mDatas.set(index, obj); - } - - public int getInt(int index) { - if (mDatas.size() > index) { - Object value = mDatas.get(index); - return value instanceof Number ? ((Number) value).intValue() : 0; - } - return 0; - } - - public long getLong(int index) { - if (mDatas.size() > index) { - Object value = mDatas.get(index); - return value instanceof Number ? ((Number) value).longValue() : 0; - } - return 0; - } - - public double getDouble(int index) { - if (mDatas.size() > index) { - Object value = mDatas.get(index); - return value instanceof Number ? ((Number) value).doubleValue() : 0; - } - return 0; - } - - public String getString(int index) { - if (mDatas.size() > index) { - return String.valueOf(mDatas.get(index)); - } - return null; - } - - public boolean getBoolean(int index) { - if (mDatas.size() > index) { - Object value = mDatas.get(index); - return (value instanceof Boolean) && (boolean) value; - } - return false; - } - - public HippyArray getArray(int index) { - if (mDatas.size() > index) { - Object value = mDatas.get(index); - return value instanceof HippyArray ? (HippyArray) value : null; - } - return null; - } - - public HippyMap getMap(int index) { - if (mDatas.size() > index) { - Object value = mDatas.get(index); - return value instanceof HippyMap ? (HippyMap) value : null; - } - return null; - } - - public Object getObject(int index) { - if (mDatas.size() > index) { - return mDatas.get(index); - } - return null; - } - - public void pushInt(int value) { - mDatas.add(value); - } - - public void pushLong(long value) { - mDatas.add(value); - } - - public void pushDouble(double value) { - mDatas.add(value); - } - - public void pushBoolean(boolean value) { - mDatas.add(value); - } - - public void pushString(String value) { - mDatas.add(value); - } - - public void pushArray(HippyArray array) { - mDatas.add(array); - } - - public void pushMap(HippyMap map) { - mDatas.add(map); - } - - public void pushNull() { - mDatas.add(null); - } - - @SuppressWarnings("unused") - public void clear() { - mDatas.clear(); - } - - public HippyArray copy() { - HippyArray newArray = new HippyArray(); - Iterator it = mDatas.iterator(); - Object value; - Object newValue; - while (it.hasNext()) { - value = it.next(); - if (value instanceof HippyMap) { - newValue = ((HippyMap) value).copy(); - } else if (value instanceof HippyArray) { - newValue = ((HippyArray) value).copy(); - } else { - newValue = value; - } - newArray.pushObject(newValue); - } - - return newArray; - } - - @Override - public String toString() { - return mDatas.toString(); - } - - public void pushJSONArray(JSONArray jArray) { - if (jArray == null || jArray.length() <= 0) { - return; - } - - try { - for (int i = 0; i < jArray.length(); i++) { - Object obj = jArray.opt(i); - if (obj == null) { - pushNull(); - } else if (obj instanceof JSONObject) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushJSONObject((JSONObject) obj); - pushMap(hippyMap); - } else if (obj instanceof JSONArray) { - HippyArray hippyArray = new HippyArray(); - hippyArray.pushJSONArray((JSONArray) obj); - pushArray(hippyArray); - } else { - pushObject(obj); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - public JSONArray toJSONArray() { - JSONArray jArray = new JSONArray(); - if (size() <= 0) { - return jArray; - } - - try { - Iterator it = mDatas.iterator(); - Object value; - while (it.hasNext()) { - value = it.next(); - if (value instanceof HippyMap) { - JSONObject jObjectMap = ((HippyMap) value).toJSONObject(); - jArray.put(jObjectMap); - } else if (value instanceof HippyArray) { - JSONArray jObjectArray = ((HippyArray) value).toJSONArray(); - jArray.put(jObjectArray); - } else { - jArray.put(value); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - - return jArray; - } - - public String getSignature(int index) { - Object obj = get(index); - if (obj == null) { - return null; - } - return ArgumentUtils.getSupportSignature(obj.getClass()); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyMap.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyMap.java deleted file mode 100644 index 810d478f79c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyMap.java +++ /dev/null @@ -1,290 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.common; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -@SuppressWarnings({"deprecation", "unused"}) -@Deprecated -public class HippyMap { - - private final HashMap mDatas; - - @Override - public String toString() { - return mDatas.toString(); - } - - public HippyMap() { - mDatas = new HashMap<>(); - } - - public boolean containsKey(String key) { - return mDatas.containsKey(key); - } - - public int size() { - return mDatas.size(); - } - - public Set keySet() { - return mDatas.keySet(); - } - - public Set> entrySet() { - return mDatas.entrySet(); - } - - public Object get(String key) { - return mDatas.get(key); - } - - public String getString(String key) { - Object value = mDatas.get(key); - return value == null ? null : String.valueOf(value); - } - - public void remove(String key) { - mDatas.remove(key); - } - - public double getDouble(String key) { - Object value = mDatas.get(key); - return value instanceof Number ? ((Number) value).doubleValue() : 0; - } - - public int getInt(String key) { - Object value = mDatas.get(key); - return value instanceof Number ? ((Number) value).intValue() : 0; - } - - public boolean getBoolean(String key) { - Object value = mDatas.get(key); - return value != null && (boolean) value; - } - - public long getLong(String key) { - Object value = mDatas.get(key); - return value instanceof Number ? ((Number) value).longValue() : 0; - } - - public HippyMap getMap(String key) { - Object value = mDatas.get(key); - if (value instanceof HippyMap) { - return (HippyMap) value; - } - return null; - } - - public HippyArray getArray(String key) { - Object value = mDatas.get(key); - if (value instanceof HippyArray) { - return (HippyArray) value; - } - return null; - } - - public boolean isNull(String key) { - return mDatas.get(key) == null; - } - - public void pushNull(String key) { - mDatas.put(key, null); - } - - public void pushInt(String key, int value) { - mDatas.put(key, value); - } - - public void pushString(String key, String value) { - mDatas.put(key, value); - } - - public void pushBoolean(String key, boolean value) { - mDatas.put(key, value); - } - - public void pushDouble(String key, double value) { - mDatas.put(key, value); - } - - public void pushLong(String key, long value) { - mDatas.put(key, value); - } - - public void pushArray(String key, HippyArray array) { - mDatas.put(key, array); - } - - public void pushMap(String key, HippyMap map) { - mDatas.put(key, map); - } - - public void pushAll(HippyMap map) { - if (null != map) { - mDatas.putAll(map.mDatas); - } - } - - public void pushObject(String key, Object obj) { - if (obj == null) { - pushNull(key); - } else if (obj instanceof String) { - pushString(key, (String) obj); - } else if (obj instanceof HippyMap) { - pushMap(key, (HippyMap) obj); - } else if (obj instanceof HippyArray) { - pushArray(key, (HippyArray) obj); - } else if (obj instanceof Integer) { - pushInt(key, (Integer) obj); - } else if (obj instanceof Boolean) { - pushBoolean(key, (Boolean) obj); - } else if (obj instanceof Double) { - pushDouble(key, (Double) obj); - } else if (obj instanceof Float) { - pushDouble(key, ((Number) obj).doubleValue()); - } else if (obj instanceof Long) { - pushLong(key, (Long) obj); - } else if (obj instanceof Byte) { - int iObj = ((Byte) obj).intValue(); - pushInt(key, iObj); - } else { - Class clazz = obj.getClass(); - if (clazz.isAssignableFrom(int.class)) { - //noinspection ConstantConditions - pushInt(key, (Integer) obj); - } else if (clazz.isAssignableFrom(boolean.class)) { - //noinspection ConstantConditions - pushBoolean(key, (Boolean) obj); - } else if (clazz.isAssignableFrom(double.class)) { - //noinspection ConstantConditions - pushDouble(key, (Double) obj); - } else if (clazz.isAssignableFrom(float.class)) { - pushDouble(key, ((Number) obj).doubleValue()); - } else if (clazz.isAssignableFrom(long.class)) { - //noinspection ConstantConditions - pushLong(key, (Long) obj); - } else { - throw new RuntimeException("push unsupported object into HippyMap"); - } - } - } - - - public void clear() { - mDatas.clear(); - } - - public HippyMap copy() { - HippyMap newMap = new HippyMap(); - Iterator> it = mDatas.entrySet().iterator(); - Map.Entry entry; - Object value; - Object newValue; - while (it.hasNext()) { - entry = it.next(); - value = entry.getValue(); - - if (value instanceof HippyMap) { - newValue = ((HippyMap) value).copy(); - } else if (value instanceof HippyArray) { - newValue = ((HippyArray) value).copy(); - } else { - newValue = value; - } - newMap.pushObject(entry.getKey(), newValue); - } - - return newMap; - } - - public void pushJSONObject(JSONObject jObject) { - if (jObject == null) { - return; - } - - try { - Iterator it = jObject.keys(); - while (it.hasNext()) { - String key = it.next().toString(); - Object obj = jObject.opt(key); - if (jObject.isNull(key)) { - pushNull(key); - } else if (obj instanceof JSONObject) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushJSONObject((JSONObject) obj); - pushMap(key, hippyMap); - } else if (obj instanceof JSONArray) { - HippyArray hippyArray = new HippyArray(); - hippyArray.pushJSONArray((JSONArray) obj); - pushArray(key, hippyArray); - } else { - pushObject(key, obj); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - public JSONObject toJSONObject() { - JSONObject jObject = new JSONObject(); - if (size() <= 0) { - return jObject; - } - - Iterator var2 = entrySet().iterator(); - try { - while (var2.hasNext()) { - @SuppressWarnings({"unchecked", - "rawtypes"}) Map.Entry entry = (Map.Entry) var2.next(); - String key = entry.getKey(); - if (entry.getValue() instanceof HippyMap) { - JSONObject jObjectMap = ((HippyMap) entry.getValue()).toJSONObject(); - jObject.put(key, jObjectMap); - } else if (entry.getValue() instanceof HippyArray) { - JSONArray jObjectArray = ((HippyArray) entry.getValue()).toJSONArray(); - jObject.put(key, jObjectArray); - } else { - jObject.put(key, entry.getValue()); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - - return jObject; - } - - public HippyArray toHippyArray() { - if (size() == 0) { - return null; - } - - HippyArray hippyArray = new HippyArray(); - for (Map.Entry stringObjectEntry : entrySet()) { - hippyArray.pushObject(stringObjectEntry.getKey()); - hippyArray.pushObject(stringObjectEntry.getValue()); - } - return hippyArray; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyTag.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyTag.java deleted file mode 100644 index 82c4d9191fe..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyTag.java +++ /dev/null @@ -1,84 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.common; - -import android.view.View; - -@SuppressWarnings({"SameParameterValue", "deprecation", "unused"}) -public class HippyTag { - - private final static String TAG_CLASS_NAME = "className"; - - public static HippyMap createTagMap(String className, HippyMap iniProps) { - HippyMap tagMap = new HippyMap(); - tagMap.pushString(TAG_CLASS_NAME, className); - - return tagMap; - } - - private static int getIntValue(View view, String key) { - if (view != null && key != null) { - Object tagObj = view.getTag(); - if (tagObj instanceof HippyMap) { - HippyMap tagMap = (HippyMap) tagObj; - if (tagMap.containsKey(key)) { - return tagMap.getInt(key); - } - } - } - - return -1; - } - - private static void setIntValue(View view, String key, int value) { - if (view != null && key != null) { - Object tagObj = view.getTag(); - if (tagObj instanceof HippyMap) { - HippyMap tagMap = (HippyMap) tagObj; - tagMap.pushInt(key, value); - } - } - } - - private static String getStringValue(View view, String key) { - if (view != null && key != null) { - Object tagObj = view.getTag(); - if (tagObj instanceof HippyMap) { - HippyMap tagMap = (HippyMap) tagObj; - if (tagMap.containsKey(key)) { - return tagMap.getString(key); - } - } - } - - return null; - } - - private static void setStringValue(View view, String key, String value) { - if (view != null && key != null) { - Object tagObj = view.getTag(); - if (tagObj instanceof HippyMap) { - HippyMap tagMap = (HippyMap) tagObj; - tagMap.pushString(key, (value == null ? "" : value)); - } - } - } - - public static String getClassName(View view) { - return getStringValue(view, TAG_CLASS_NAME); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyThreadRunnable.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyThreadRunnable.java deleted file mode 100644 index 457f7f94603..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/HippyThreadRunnable.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.common; - -import com.tencent.mtt.hippy.utils.LogUtils; - -@SuppressWarnings({"TypeParameterExplicitlyExtendsObject", "unused"}) -public abstract class HippyThreadRunnable implements Runnable { - - private final T mParam; - - public HippyThreadRunnable(T param) { - mParam = param; - } - - @Override - public void run() { - try { - run(mParam); - } catch (Throwable e) { - LogUtils.e("HippyThreadRunnable", "run: ", e); - } - } - - public abstract void run(T param); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/ThreadExecutor.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/common/ThreadExecutor.java deleted file mode 100644 index 273deef94e9..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/common/ThreadExecutor.java +++ /dev/null @@ -1,131 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.common; - -public class ThreadExecutor implements Thread.UncaughtExceptionHandler { - - final HippyHandlerThread mJsThread; - final HippyHandlerThread mJsBridgeThread; - final HippyHandlerThread mDomThread; - UncaughtExceptionHandler mUncaughtExceptionHandler; - private final int mGroupId; - - @SuppressWarnings("unused") - public ThreadExecutor(int groupId) { - mGroupId = groupId; - mJsThread = new HippyHandlerThread("hippy-js-Thread"); - mJsThread.setUncaughtExceptionHandler(this); - - mJsBridgeThread = new HippyHandlerThread("hippy-jsBridge-Thread"); - mJsBridgeThread.setUncaughtExceptionHandler(this); - mDomThread = new HippyHandlerThread("hippy-DomThread"); - mDomThread.setUncaughtExceptionHandler(this); - } - - public void setUncaughtExceptionHandler(UncaughtExceptionHandler exceptionHandler) { - mUncaughtExceptionHandler = exceptionHandler; - } - - public void destroy() { - if (mDomThread != null && mDomThread.isThreadAlive()) { - mDomThread.quit(); - - mDomThread.setUncaughtExceptionHandler(null); - } - - if (mJsBridgeThread != null && mJsBridgeThread.isThreadAlive()) { - mJsBridgeThread.quit(); - - mJsBridgeThread.setUncaughtExceptionHandler(null); - } - - if (mJsThread != null && mJsThread.isThreadAlive()) { - mJsThread.quit(); - - mJsThread.setUncaughtExceptionHandler(null); - } - - mUncaughtExceptionHandler = null; - } - - @SuppressWarnings("unused") - public void postDelayOnJsThread(int delay, Runnable runnable) { - mJsThread.getHandler().postDelayed(runnable, delay); - } - - @SuppressWarnings("unused") - public void postOnJsThread(Runnable runnable) { - mJsBridgeThread.runOnQueue(runnable); - } - - @SuppressWarnings("unused") - public void postOnJsBridgeThread(Runnable runnable) { - mJsThread.runOnQueue(runnable); - } - - public void postOnDomThread(Runnable runnable) { - mDomThread.runOnQueue(runnable); - } - - @SuppressWarnings("unused") - public void assertOnJsBridge() { - if (Thread.currentThread().getId() != mJsBridgeThread.getId()) { - throw new RuntimeException("call is not on Js-bridge-thread"); - } - } - - @SuppressWarnings("unused") - public void assertOnJsThread() { - if (Thread.currentThread().getId() != mJsThread.getId()) { - throw new RuntimeException("call is not on Js-thread"); - } - } - - @SuppressWarnings("unused") - public void assertOnDomThread() { - if (Thread.currentThread().getId() != mDomThread.getId()) { - throw new RuntimeException("call is not on dom-thread"); - } - } - - public HippyHandlerThread getJsBridgeThread() { - return mJsBridgeThread; - } - - public HippyHandlerThread getJsThread() { - return mJsThread; - } - - public HippyHandlerThread getDomThread() { - return mDomThread; - } - - @Override - public void uncaughtException(Thread t, - Throwable e) { - if (mUncaughtExceptionHandler != null) { - mUncaughtExceptionHandler.handleThreadUncaughtException(t, e, mGroupId); - } else { - throw new RuntimeException(e); - } - - } - - public interface UncaughtExceptionHandler { - - void handleThreadUncaughtException(Thread t, Throwable e, Integer groupId); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevFactory.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevFactory.java deleted file mode 100644 index 12c0c6de8b5..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - -import com.tencent.mtt.hippy.HippyGlobalConfigs; - -public class DevFactory { - - public static DevServerInterface create(HippyGlobalConfigs configs, boolean enableDev, - String serverHost, String bundleName) { - if (enableDev) { - return new DevServerImpl(configs, serverHost, bundleName); - } else { - return new DevServerImplDisable(configs, serverHost); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevFloatButton.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevFloatButton.java deleted file mode 100644 index 0e90a4d404e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevFloatButton.java +++ /dev/null @@ -1,263 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.StateListDrawable; -import android.graphics.drawable.shapes.RoundRectShape; -import android.os.Build; -import android.os.Looper; -import android.os.MessageQueue; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.MotionEvent; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.utils.LogUtils; - -public class DevFloatButton extends ImageView implements ValueAnimator.AnimatorUpdateListener, - ViewTreeObserver.OnGlobalLayoutListener { - - private int mParentWidth = -1; - private int mParentHeight = -1; - int mStartX; - int mStartY; - int mLastLeft = 0; - int mLastRight = 0; - int mLastTop = 0; - int mLastBottom = 0; - - final int mWidth; - final int SIZE = 30; - @SuppressWarnings("deprecation") - final int TOUCH_SLOP = ViewConfiguration.getTouchSlop(); - - - /** - * 构建背景Drawble - */ - @SuppressWarnings("deprecation") - private void buildDrawableState() { - - int[] mNormalState = new int[]{}; - int[] mFocusedSate = new int[]{android.R.attr.state_focused, android.R.attr.state_enabled}; - - //默认文字和背景颜色 - int mBgNormalColor = Color.parseColor("#ddd9d9"); - int mBgFocusedColor = Color.GREEN; - //创建状态管理器 - StateListDrawable drawable = new StateListDrawable(); - int radius = mWidth / 2; - float[] outRect = new float[]{radius, radius, radius, radius, radius, radius, radius, radius}; - RoundRectShape rectShape = new RoundRectShape(outRect, null, null); - - //创建圆弧形状 - //创建drawable - ShapeDrawable pressedDrawable = new ShapeDrawable(rectShape); - //设置我们按钮背景的颜色 - pressedDrawable.getPaint().setColor(mBgFocusedColor); - //添加到状态管理里面 - drawable.addState(mFocusedSate, pressedDrawable); - - ShapeDrawable normalDrawable = new ShapeDrawable(rectShape); - normalDrawable.getPaint().setColor(mBgNormalColor); - drawable.addState(mNormalState, normalDrawable); - //设置我们的背景,就是xml里面的selector - setBackgroundDrawable(drawable); - - //noinspection AccessStaticViaInstance - Looper.getMainLooper().myQueue().addIdleHandler(new MessageQueue.IdleHandler() { - @Override - public boolean queueIdle() { - boolean result = requestFocusFromTouch(); - LogUtils.d("requestFocus", "requestFocusFromTouch result:" + result); - if (!result) { - result = requestFocus(); - LogUtils.d("requestFocus", "requestFocus result:" + result); - } - return false; - } - }); - } - - float dip2px(Context context) { - DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); - return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, SIZE, displayMetrics); - } - - public DevFloatButton(Context context) { - super(context); - mWidth = (int) dip2px(context); - buildBackground(); - - setFocusable(true); - } - - private void buildBackground() { - buildDrawableState(); - } - - @SuppressWarnings("deprecation") - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - getViewTreeObserver().removeOnGlobalLayoutListener(this); - } else { - getViewTreeObserver().removeGlobalOnLayoutListener(this); - } - } - - @Override - protected void onAttachedToWindow() { - setLayoutParams(getMarginLayoutParams()); - getViewTreeObserver().addOnGlobalLayoutListener(this); - super.onAttachedToWindow(); - - ViewParent parent = getParent(); - // 如果本button是临时add到HippyRootView上的,那么就要摘到RootView上去 - if (parent instanceof HippyRootView) { - ViewGroup rootView = (ViewGroup) getRootView(); - // 如果HippyRootView已经是RootView了,那就不改变了 - if (rootView != parent) { - ((HippyRootView) parent).removeView(this); - rootView.addView(this); - } - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: - getParent().requestDisallowInterceptTouchEvent(true); - mStartX = (int) event.getRawX(); - mStartY = (int) event.getRawY(); - mLastLeft = getLeft(); - mLastRight = getRight(); - mLastTop = getTop(); - mLastBottom = getBottom(); - break; - case MotionEvent.ACTION_MOVE: - int dx = (int) event.getRawX() - mStartX; - int dy = (int) event.getRawY() - mStartY; - - int left = mLastLeft + dx; - int top = mLastTop + dy; - int right = mLastRight + dx; - int bottom = mLastBottom + dy; - if (left < 0) { - left = 0; - right = left + this.getWidth(); - } - if (right > mParentWidth) { - right = mParentWidth; - left = right - this.getWidth(); - } - if (top < 0) { - top = 0; - bottom = top + this.getHeight(); - } - if (bottom > mParentHeight) { - bottom = mParentHeight; - top = bottom - this.getHeight(); - } - this.layout(left, top, right, bottom); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - getParent().requestDisallowInterceptTouchEvent(false); - if (getLeft() > mParentWidth / 2) { - //往右边靠 - ValueAnimator objectAnimator = ObjectAnimator.ofInt(getLeft(), mParentWidth - getWidth()); - objectAnimator.addUpdateListener(this); - objectAnimator.start(); - } else { - ValueAnimator objectAnimator = ObjectAnimator.ofInt(getLeft(), 0); - objectAnimator.addUpdateListener(this); - objectAnimator.start(); - //往 左边靠 - } - int endX = (int) event.getRawX(); - int endY = (int) event.getRawY(); - if (Math.abs(mStartX - endX) > TOUCH_SLOP || Math.abs(mStartY - endY) > TOUCH_SLOP) { - //click - return true; - } - - break; - } - return super.onTouchEvent(event); - } - - - @SuppressWarnings("SuspiciousNameCombination") - private ViewGroup.MarginLayoutParams getMarginLayoutParams() { - if (getParent() != null) { - ViewGroup.LayoutParams layoutParams = getLayoutParams(); - if (layoutParams instanceof FrameLayout.LayoutParams) { - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(mWidth, mWidth); - params.topMargin = mWidth; - return params; - } else if (layoutParams instanceof LinearLayout.LayoutParams) { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mWidth, mWidth); - params.topMargin = mWidth; - return params; - } else if (layoutParams instanceof RelativeLayout.LayoutParams) { - RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mWidth, mWidth); - params.topMargin = mWidth; - return params; - } else { - ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(mWidth, mWidth); - params.topMargin = mWidth; - return params; - } - } else { - ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(mWidth, mWidth); - params.topMargin = mWidth; - return params; - } - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - Object valueObject = animation.getAnimatedValue(); - - if (valueObject instanceof Number) { - int value = ((Number) valueObject).intValue(); - this.layout(value, getTop(), value + getWidth(), getBottom()); - } - } - - @Override - public void onGlobalLayout() { - mParentWidth = ((ViewGroup) getParent()).getWidth(); - mParentHeight = ((ViewGroup) getParent()).getHeight(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevRemoteDebugManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevRemoteDebugManager.java deleted file mode 100644 index bac8722e2b7..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevRemoteDebugManager.java +++ /dev/null @@ -1,52 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - -import android.app.ProgressDialog; - -/** - * Copyright (C) 2005-2020 TENCENT Inc.All Rights Reserved. FileName: DevRemoteDebugManager - * Description: History: - */ -@SuppressWarnings("unused") -public class DevRemoteDebugManager implements DevRemoteDebugProxy { - - ProgressDialog mProgressDialog; - - final RemoteDebugExceptionHandler mRemoteDebugExceptionHandler; - - public DevRemoteDebugManager(RemoteDebugExceptionHandler handler) { - this.mRemoteDebugExceptionHandler = handler; - } - - @Override - public void destroy() { - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - } - } - - public void handleException(Throwable t) { - if (mRemoteDebugExceptionHandler != null) { - mRemoteDebugExceptionHandler.onHandleRemoteDebugException(t); - } - } - - public interface RemoteDebugExceptionHandler { - - void onHandleRemoteDebugException(Throwable t); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerHelper.java deleted file mode 100644 index 9c5bd4f0fba..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerHelper.java +++ /dev/null @@ -1,97 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - - -import com.tencent.mtt.hippy.HippyGlobalConfigs; -import com.tencent.mtt.hippy.adapter.http.HippyHttpAdapter; -import com.tencent.mtt.hippy.adapter.http.HippyHttpRequest; -import com.tencent.mtt.hippy.adapter.http.HippyHttpResponse; - -import java.io.*; -import java.util.Locale; - -@SuppressWarnings({"unused"}) -public class DevServerHelper { - - private static final String BUNDLE_URL_FORMAT = "http://%s/%s?platform=android&dev=%s&hot=%s&minify=%s"; - // --Commented out by Inspection (2021/5/4 20:09):private static final String LAUNCH_JS_DEVTOOLS_COMMAND_URL_FORMAT = "http://%s/launch-js-devtools"; - // --Commented out by Inspection (2021/5/4 20:10):private static final String WEBSOCKET_PROXY_URL_FORMAT = "ws://%s/debugger-proxy?role=client"; - private static final String WEBSOCKET_LIVERELOAD_URL_FORMAT = "ws://%s/debugger-live-reload"; - // --Commented out by Inspection (2021/5/4 20:10):private static final String ONCHANGE_ENDPOINT_URL_FORMAT = "http://%s/onchange"; - - private final HippyGlobalConfigs mGlobalConfigs; - private final String mServerHost; - - public DevServerHelper(HippyGlobalConfigs configs, String serverHost) { - mGlobalConfigs = configs; - mServerHost = serverHost; - } - - public String createBundleURL(String host, String bundleName, boolean devMode, boolean hmr, - boolean jsMinify) { - return String.format(Locale.US, BUNDLE_URL_FORMAT, host, bundleName, devMode, hmr, jsMinify); - } - - public String getLiveReloadURL() { - String[] host = mServerHost.split(":"); - String newHost = host[0] + ":38999"; - return String.format(Locale.US, WEBSOCKET_LIVERELOAD_URL_FORMAT, newHost); - } - - public void fetchBundleFromURL(final BundleFetchCallBack bundleFetchCallBack, final String url) { - HippyHttpRequest request = new HippyHttpRequest(); - request.setUrl(url); - mGlobalConfigs.getHttpAdapter().sendRequest(request, new HippyHttpAdapter.HttpTaskCallback() { - @Override - public void onTaskSuccess(HippyHttpRequest request, HippyHttpResponse response) - throws Exception { - if (bundleFetchCallBack == null) { - return; - } - if (response.getStatusCode() == 200 && response.getInputStream() != null) { - bundleFetchCallBack.onSuccess(response.getInputStream()); - } else { - String message = "unknown"; - if (response.getErrorStream() != null) { - StringBuilder sb = new StringBuilder(); - String readLine; - //noinspection CharsetObjectCanBeUsed - BufferedReader bfReader = new BufferedReader( - new InputStreamReader(response.getErrorStream(), "UTF-8")); - while ((readLine = bfReader.readLine()) != null) { - sb.append(readLine); - sb.append("\r\n"); - } - message = sb.toString(); - } - bundleFetchCallBack.onFail( - new DevServerException("Could not connect to development server." + "URL: " + url - + " try to :adb reverse tcp:38989 tcp:38989 , message : " + message)); - } - } - - @Override - public void onTaskFailed(HippyHttpRequest request, Throwable error) { - if (bundleFetchCallBack != null) { - bundleFetchCallBack.onFail( - new DevServerException("Could not connect to development server." + "URL: " + url - + " try to :adb reverse tcp:38989 tcp:38989 , message : " + error.getMessage())); - } - } - }); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerImpl.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerImpl.java deleted file mode 100644 index ba118cd32e3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerImpl.java +++ /dev/null @@ -1,244 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Application; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; - -import com.tencent.mtt.hippy.HippyGlobalConfigs; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.UIThreadUtils; - -import java.io.InputStream; -import java.util.HashMap; -import java.util.Stack; - -@SuppressWarnings({"unused"}) -public class DevServerImpl implements View.OnClickListener, DevServerInterface, - DevExceptionDialog.OnReloadListener, - DevRemoteDebugManager.RemoteDebugExceptionHandler, LiveReloadController.LiveReloadCallback { - - private static final String TAG = "DevServerImpl"; - - final DevServerHelper mFetchHelper; - DevServerCallBack mServerCallBack; - ProgressDialog mProgressDialog; - DevExceptionDialog mExceptionDialog; - private final DevServerConfig mServerConfig; - private final HashMap mHostButtonMap; - // 一个 DevServerImpl 实例可管理多个 HippyRootView 的调试,对应多个DebugButton - private final Stack mDebugButtonStack; - private final LiveReloadController mLiveReloadController; - - DevServerImpl(HippyGlobalConfigs configs, String serverHost, String bundleName) { - mFetchHelper = new DevServerHelper(configs, serverHost); - mServerConfig = new DevServerConfig(serverHost, bundleName); - mDebugButtonStack = new Stack<>(); - mHostButtonMap = new HashMap<>(); - mLiveReloadController = new LiveReloadController(mFetchHelper); - - showProgressDialog(); - } - - private void showProgressDialog() { - Context host = null; - if (mDebugButtonStack.size() > 0) { - host = mDebugButtonStack.peek().getContext(); - } - - if (host == null) { - return; - } - - if (mProgressDialog == null) { - mProgressDialog = new ProgressDialog(host); - mProgressDialog.setCancelable(true); - mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); - } - mProgressDialog.show(); - } - - @Override - public void onClick(final View v) { - final boolean isLiveReloadEnable = mServerConfig.enableLiveDebug(); - if (v.getContext() instanceof Application) { - LogUtils.e(TAG, "Hippy context is an Application, so can not show a dialog!"); - } else { - new AlertDialog.Builder(v.getContext()).setItems( - new String[]{"Reload"}, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == 0) { - reload(); - } - } - }).show(); - } - } - - void startLiveDebug() { - if (mServerConfig.enableLiveDebug()) { - mLiveReloadController.startLiveReload(this); - } else { - mLiveReloadController.stopLiveReload(); - } - - } - - @Override - public String createResourceUrl(String resName) { - return mFetchHelper - .createBundleURL(mServerConfig.getServerHost(), resName, mServerConfig.enableRemoteDebug(), - false, false); - } - - @Override - public void loadRemoteResource(String url, final DevServerCallBack serverCallBack) { - mFetchHelper.fetchBundleFromURL(new BundleFetchCallBack() { - @Override - public void onSuccess(InputStream inputStream) { - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - } - - if (serverCallBack != null) { - serverCallBack.onDevBundleLoadReady(inputStream); - } - } - - @Override - public void onFail(Exception exception) { - if (serverCallBack != null) { - serverCallBack.onInitDevError(exception); - } - - if (mDebugButtonStack.isEmpty()) { - mServerCallBack.onInitDevError(exception); - } else { - handleException(exception); - } - } - }, url); - } - - @Override - public void reload() { - if (mServerCallBack != null) { - mServerCallBack.onDevBundleReLoad(); - } - } - - @Override - public void setDevServerCallback(DevServerCallBack devServerCallback) { - this.mServerCallBack = devServerCallback; - } - - @Override - public void attachToHost(HippyRootView view) { - LogUtils.d(TAG, "hippy DevServerImpl attachToHost"); - Context host = view.getHost(); - DevFloatButton debugButton = new DevFloatButton(host); - debugButton.setOnClickListener(this); - - if (host instanceof Activity) { - // 添加到Activity的根部,这就稳当了。 - ViewGroup decorView = (ViewGroup) ((Activity) host).getWindow().getDecorView(); - decorView.addView(debugButton); - } else { - view.addView(debugButton); // 添加到HippyRootView,不够稳当,要HippyRootView上屏后,再摘到根部去。 - } - mHostButtonMap.put(host, debugButton); - mDebugButtonStack.push(debugButton); - } - - @Override - public void detachFromHost(HippyRootView view) { - LogUtils.d(TAG, "hippy DevServerImpl detachFromHost"); - Context host = view.getHost(); - DevFloatButton button = mHostButtonMap.get(host); - if (button != null) { - mDebugButtonStack.remove(button); - mHostButtonMap.remove(host); - ViewParent parent = button.getParent(); - if (parent instanceof ViewGroup) { - ((ViewGroup) parent).removeView(button); - } - } - } - - @Override - public void handleException(final Throwable throwable) { - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - } - - if (mDebugButtonStack.size() <= 0) { - return; - } - - if (mExceptionDialog != null && mExceptionDialog.isShowing()) { - return; - } - - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - if (mDebugButtonStack.size() > 0) { - // 用栈顶那个context - mExceptionDialog = new DevExceptionDialog(mDebugButtonStack.peek().getContext()); - mExceptionDialog.handleException(throwable); - mExceptionDialog.setOnReloadListener(DevServerImpl.this); - mExceptionDialog.show(); - } - } - }); - - } - - @Override - public void onReload() { - reload(); - } - - @SuppressWarnings("unused") - @Override - public void onHandleRemoteDebugException(Throwable t) { - if (mDebugButtonStack.isEmpty()) { - mServerCallBack.onInitDevError(t); - } else { - handleException(t); - } - } - - @Override - public void onCompileSuccess() { - reload(); - } - - @Override - public void onLiveReloadReady() { - reload(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerImplDisable.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerImplDisable.java deleted file mode 100644 index d78391a1f0b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerImplDisable.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - -import com.tencent.mtt.hippy.HippyGlobalConfigs; -import com.tencent.mtt.hippy.HippyRootView; -import java.io.InputStream; - -@SuppressWarnings("unused") -public class DevServerImplDisable implements DevServerInterface { - - final DevServerHelper mFetchHelper; - - DevServerImplDisable(HippyGlobalConfigs configs, String serverHost) { - mFetchHelper = new DevServerHelper(configs, serverHost); - } - - @Override - public void reload() { - - } - - @Override - public String createResourceUrl(String resName) { - return null; - } - - @Override - public void loadRemoteResource(String url, final DevServerCallBack serverCallBack) { - mFetchHelper.fetchBundleFromURL(new BundleFetchCallBack() { - @Override - public void onSuccess(InputStream inputStream) { - if (serverCallBack != null) { - serverCallBack.onDevBundleLoadReady(inputStream); - } - } - - @Override - public void onFail(Exception exception) { - if (serverCallBack != null) { - serverCallBack.onInitDevError(exception); - } - } - }, url); - } - - @Override - public void setDevServerCallback(DevServerCallBack devServerCallback) { - - } - - @Override - public void attachToHost(HippyRootView view) { - - } - - @Override - public void detachFromHost(HippyRootView view) { - - } - - @Override - public void handleException(Throwable exception) { - - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerInterface.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerInterface.java deleted file mode 100644 index 29180a8177c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevServerInterface.java +++ /dev/null @@ -1,36 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - -import com.tencent.mtt.hippy.HippyRootView; - -@SuppressWarnings("unused") -public interface DevServerInterface { - - void reload(); - - String createResourceUrl(String resName); - - void loadRemoteResource(String url, DevServerCallBack serverCallBack); - - void setDevServerCallback(DevServerCallBack devServerCallback); - - void attachToHost(HippyRootView view); - - void detachFromHost(HippyRootView view); - - void handleException(Throwable throwable); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevSupportManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevSupportManager.java deleted file mode 100644 index 7d6d7dcdaab..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/DevSupportManager.java +++ /dev/null @@ -1,70 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.devsupport; - -import com.tencent.mtt.hippy.HippyGlobalConfigs; -import com.tencent.mtt.hippy.HippyRootView; -import java.util.UUID; - -@SuppressWarnings({"unused"}) -public class DevSupportManager { - - final DevServerInterface mDevImp; - final boolean mSupportDev; - private UUID mInstanceUUID = UUID.randomUUID(); - - public DevSupportManager(HippyGlobalConfigs configs, boolean enableDev, String serverHost, - String bundleName) { - this.mDevImp = DevFactory.create(configs, enableDev, serverHost, bundleName); - mSupportDev = enableDev; - } - - public DevServerInterface getDevImp() { - return this.mDevImp; - } - - public void setDevCallback(DevServerCallBack devCallback) { - mDevImp.setDevServerCallback(devCallback); - } - - public void attachToHost(HippyRootView view) { - mDevImp.attachToHost(view); - } - - public void detachFromHost(HippyRootView view) { - mDevImp.detachFromHost(view); - } - - public String createResourceUrl(String resName) { - return mDevImp.createResourceUrl(resName); - } - - public void handleException(Throwable throwable) { - mDevImp.handleException(throwable); - } - - public void loadRemoteResource(String url, DevServerCallBack serverCallBack) { - mDevImp.loadRemoteResource(url, serverCallBack); - } - - public String getDevInstanceUUID() { - return mInstanceUUID.toString(); - } - - public boolean isSupportDev() { - return mSupportDev; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/Inspector.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/Inspector.java deleted file mode 100644 index 86323698954..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/Inspector.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector; - -import android.text.TextUtils; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.devsupport.DebugWebSocketClient; -import com.tencent.mtt.hippy.devsupport.inspector.domain.CSSDomain; -import com.tencent.mtt.hippy.devsupport.inspector.domain.DomDomain; -import com.tencent.mtt.hippy.devsupport.inspector.domain.InspectorDomain; -import com.tencent.mtt.hippy.devsupport.inspector.domain.PageDomain; -import com.tencent.mtt.hippy.devsupport.inspector.model.InspectEvent; -import com.tencent.mtt.hippy.dom.DomManager; -import com.tencent.mtt.hippy.dom.DomManager.BatchListener; -import com.tencent.mtt.hippy.utils.LogUtils; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; -import org.json.JSONObject; - -public class Inspector implements BatchListener { - - private static final String TAG = "Inspector"; - - private static final String CHROME_SOCKET_CLOSED = "chrome_socket_closed"; - - private static Inspector sInspector; - - private Map mDomainMap = new HashMap<>(); - private DebugWebSocketClient mDebugWebSocketClient; - private WeakReference mContextRef; - private boolean needBatchUpdateDom = true; - - public static synchronized Inspector getInstance(HippyEngineContext context) { - if (sInspector == null) { - sInspector = new Inspector(context); - } - return sInspector; - } - - private Inspector(HippyEngineContext context) { - DomDomain domDomain = new DomDomain(this); - CSSDomain cssDomain = new CSSDomain(this); - PageDomain pageDomain = new PageDomain(this); - mDomainMap.put(domDomain.getDomainName(), domDomain); - mDomainMap.put(cssDomain.getDomainName(), cssDomain); - mDomainMap.put(pageDomain.getDomainName(), pageDomain); - DomManager domManager = context.getDomManager(); - if (domManager != null) { - domManager.setOnBatchListener(this); - } - } - - public Inspector setWebSocketClient(DebugWebSocketClient client) { - mDebugWebSocketClient = client; - return this; - } - - public boolean dispatchReqFromFrontend(HippyEngineContext context, String msg) { - if (TextUtils.isEmpty(msg)) { - LogUtils.e(TAG, "dispatchReqFromFrontend, msg null"); - return false; - } - - LogUtils.d(TAG, "dispatchReqFromFrontend, msg=" + msg); - - if (CHROME_SOCKET_CLOSED.equals(msg)) { - onFrontendClosed(context); - return false; - } - - try { - JSONObject msgObj = new JSONObject(msg); - String methodParam = msgObj.optString("method"); - if (!TextUtils.isEmpty(methodParam)) { - String[] methodParamArray = methodParam.split("\\."); - if (methodParamArray.length > 1) { - String domain = methodParamArray[0]; - if (!TextUtils.isEmpty(domain) && mDomainMap.containsKey(domain)) { - InspectorDomain inspectorDomain = mDomainMap.get(domain); - if (inspectorDomain != null) { - String method = methodParamArray[1]; - int id = msgObj.optInt("id"); - JSONObject paramsObj = msgObj.optJSONObject("params"); - boolean shouldHandle = inspectorDomain.handleRequestFromBackend(context, method, id, paramsObj); - if (shouldHandle) { - mContextRef = new WeakReference<>(context); - } - return shouldHandle; - } - } - } - } - } catch (Exception e) { - LogUtils.e(TAG, "dispatchReqFromFrontend, exception:", e); - } - return false; - } - - private void onFrontendClosed(HippyEngineContext context) { - for (Map.Entry entry : mDomainMap.entrySet()) { - entry.getValue().onFrontendClosed(context); - } - } - - public HippyEngineContext getContext() { - if (mContextRef == null) { - return null; - } - return mContextRef.get(); - } - - public void rspToFrontend(int id, JSONObject result) { - if (mDebugWebSocketClient == null) { - return; - } - try { - JSONObject resultObj = new JSONObject(); - resultObj.put("id", id); - resultObj.put("result", result != null ? result : new JSONObject()); - LogUtils.d(TAG, "rspToFrontend, msg=" + resultObj.toString()); - mDebugWebSocketClient.sendMessage(resultObj.toString()); - } catch (Exception e) { - LogUtils.e(TAG, "rspToFrontEnd, exception:", e); - } - } - - public void sendEventToFrontend(InspectEvent event) { - String eventJson = event.toJson(); - if (mDebugWebSocketClient == null || eventJson == null) { - return; - } - - LogUtils.d(TAG, "sendEventToFrontend, eventJson=" + eventJson); - mDebugWebSocketClient.sendMessage(eventJson); - } - - public void setNeedBatchUpdateDom(boolean needBatchUpdate) { - needBatchUpdateDom = needBatchUpdate; - } - - @Override - public void onBatch(boolean isAnimation) { - if (needBatchUpdateDom && !isAnimation) { - DomDomain domDomain = (DomDomain) mDomainMap.get(DomDomain.DOM_DOMAIN_NAME); - domDomain.sendUpdateEvent(); - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/CSSDomain.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/CSSDomain.java deleted file mode 100644 index 1ad59da2663..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/CSSDomain.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.domain; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.devsupport.inspector.Inspector; -import com.tencent.mtt.hippy.devsupport.inspector.model.CSSModel; -import org.json.JSONArray; -import org.json.JSONObject; - -public class CSSDomain extends InspectorDomain { - - private static final String TAG = "CSSDomain"; - - private static final String METHOD_GET_MATCHED_STYLES_FOR_NODE = "getMatchedStylesForNode"; - private static final String METHOD_GET_COMPUTED_STYLE_FOR_NODE = "getComputedStyleForNode"; - private static final String METHOD_GET_INLINE_STYLES_FOR_NODE = "getInlineStylesForNode"; - private static final String METHOD_SET_STYLE_TEXTS = "setStyleTexts"; - - private CSSModel cssModel; - - public CSSDomain(Inspector inspector) { - super(inspector); - cssModel = new CSSModel(); - } - - @Override - public String getDomainName() { - return "CSS"; - } - - @Override - public boolean handleRequest(HippyEngineContext context, String method, int id, - JSONObject paramsObj) { - switch (method) { - case METHOD_GET_MATCHED_STYLES_FOR_NODE: - handleGetMatchedStyles(context, id, paramsObj); - break; - case METHOD_GET_COMPUTED_STYLE_FOR_NODE: - handleGetComputedStyle(context, id, paramsObj); - break; - case METHOD_GET_INLINE_STYLES_FOR_NODE: - handleGetInlineStyles(context, id, paramsObj); - break; - case METHOD_SET_STYLE_TEXTS: - handleSetStyleTexts(context, id, paramsObj); - break; - default: - return false; - } - return true; - } - - private void handleGetMatchedStyles(HippyEngineContext context, int id, JSONObject paramsObj) { - int nodeId = paramsObj.optInt("nodeId"); - JSONObject matchedStyles = cssModel.getMatchedStyles(context, nodeId); - sendRspToFrontend(id, matchedStyles); - } - - private void handleGetComputedStyle(HippyEngineContext context, int id, JSONObject paramsObj) { - int nodeId = paramsObj.optInt("nodeId"); - JSONObject computedStyle = cssModel.getComputedStyle(context, nodeId); - sendRspToFrontend(id, computedStyle); - } - - private void handleGetInlineStyles(HippyEngineContext context, int id, JSONObject paramsObj) { - int nodeId = paramsObj.optInt("nodeId"); - JSONObject inlineStyles = cssModel.getInlineStyles(context, nodeId); - sendRspToFrontend(id, inlineStyles); - } - - - private void handleSetStyleTexts(HippyEngineContext context, int id, JSONObject paramsObj) { - JSONArray editArray = paramsObj.optJSONArray("edits"); - JSONObject styleTexts = cssModel.setStyleTexts(context, editArray, this); - sendRspToFrontend(id, styleTexts); - } - - public void setNeedBatchUpdateDom(boolean needBatchUpdate) { - if (mInspectorRef == null) { - return; - } - mInspectorRef.get().setNeedBatchUpdateDom(needBatchUpdate); - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/DomDomain.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/DomDomain.java deleted file mode 100644 index e0f11c9e9fd..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/DomDomain.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.domain; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.devsupport.inspector.Inspector; -import com.tencent.mtt.hippy.devsupport.inspector.model.DomModel; -import com.tencent.mtt.hippy.devsupport.inspector.model.InspectEvent; -import org.json.JSONObject; - -public class DomDomain extends InspectorDomain { - - private static final String TAG = "DomDomain"; - public static final String DOM_DOMAIN_NAME = "DOM"; - - private static final String METHOD_GET_DOCUMENT = "getDocument"; - private static final String METHOD_GET_BOX_MODEL = "getBoxModel"; - private static final String METHOD_GET_NODE_FOR_LOCATION = "getNodeForLocation"; - private static final String METHOD_REMOVE_NODE = "removeNode"; - private static final String METHOD_SET_INSPECT_NODE = "setInspectedNode"; - - private DomModel domModel; - - public DomDomain(Inspector inspector) { - super(inspector); - domModel = new DomModel(); - } - - @Override - public String getDomainName() { - return DOM_DOMAIN_NAME; - } - - @Override - public boolean handleRequest(HippyEngineContext context, String method, int id, - JSONObject paramsObj) { - switch (method) { - case METHOD_GET_DOCUMENT: - handleGetDocument(context, id); - break; - case METHOD_GET_BOX_MODEL: - handleGetBoxModel(context, id, paramsObj); - break; - case METHOD_GET_NODE_FOR_LOCATION: - handleGetNodeForLocation(context, id, paramsObj); - break; - case METHOD_SET_INSPECT_NODE: - handleSetInspectMode(context, id, paramsObj); - break; - default: - return false; - } - return true; - } - - private void handleGetDocument(HippyEngineContext context, int id) { - JSONObject result = domModel.getDocument(context); - sendRspToFrontend(id, result); - } - - private void handleGetBoxModel(HippyEngineContext context, int id, JSONObject paramsObj) { - JSONObject result = domModel.getBoxModel(context, paramsObj); - sendRspToFrontend(id, result); - } - - private void handleGetNodeForLocation(HippyEngineContext context, int id, JSONObject paramsObj) { - JSONObject result = domModel.getNodeForLocation(context, paramsObj); - sendRspToFrontend(id, result); - } - - private void handleSetInspectMode(HippyEngineContext context, int id, JSONObject paramsObj) { - JSONObject result = domModel.setInspectMode(context, paramsObj); - sendRspToFrontend(id, result); - } - - public void sendUpdateEvent() { - InspectEvent updateEvent = new InspectEvent("DOM.documentUpdated", new JSONObject()); - sendEventToFrontend(updateEvent); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/InspectorDomain.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/InspectorDomain.java deleted file mode 100644 index a12b72e3c02..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/InspectorDomain.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.domain; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.devsupport.inspector.Inspector; -import com.tencent.mtt.hippy.devsupport.inspector.model.InspectEvent; -import com.tencent.mtt.hippy.utils.LogUtils; -import java.lang.ref.WeakReference; -import org.json.JSONObject; - -public abstract class InspectorDomain { - - private static final String TAG = "InspectorDomain"; - - private static final String METHOD_ENABLE = "enable"; - private static final String METHOD_DISABLE = "disable"; - - private boolean isEnable; - - protected WeakReference mInspectorRef; - - public InspectorDomain(Inspector inspector) { - mInspectorRef = new WeakReference<>(inspector); - } - - public boolean handleRequestFromBackend(HippyEngineContext context, String method, int id, - JSONObject paramsObj) { - if (mInspectorRef == null) { - LogUtils.e(TAG, "handleRequestFromBackend, mInspectorRef null"); - return false; - } - - Inspector inspector = mInspectorRef.get(); - if (inspector == null) { - LogUtils.e(TAG, "handleRequestFromBackend, inspector null"); - return false; - } - if (METHOD_ENABLE.equals(method)) { - isEnable = true; - inspector.rspToFrontend(id, null); - return true; - } else if (METHOD_DISABLE.equals(method)) { - isEnable = false; - inspector.rspToFrontend(id, null); - return true; - } else { - if (isEnable) { - return handleRequest(context, method, id, paramsObj); - } else { - return false; - } - } - } - - /** - * 处理 frontend 的 method 调用 - * - * 注意:未处理的method,请返回false - * - * @param method 调用方法 - * @param id 调用唯一自增ID - * @param paramsObj 参数 - */ - protected abstract boolean handleRequest(HippyEngineContext context, String method, int id, - JSONObject paramsObj); - - /** - * 获取 domain - * - * @return domain 名称 - */ - public abstract String getDomainName(); - - /** - * 回包给 frontend - * - * @param id 调用过来的自增id - * @param result 回包数据 json - */ - protected void sendRspToFrontend(int id, JSONObject result) { - Inspector inspector = mInspectorRef.get(); - if (inspector != null) { - inspector.rspToFrontend(id, result); - } - } - - /** - * 主动抛事件给 frontend - * - * @param event 事件数据 - */ - protected void sendEventToFrontend(InspectEvent event) { - Inspector inspector = mInspectorRef.get(); - if (inspector != null) { - inspector.sendEventToFrontend(event); - } - } - - /** - * devtools关闭时,清理资源 - * @param context - */ - public void onFrontendClosed(HippyEngineContext context) { - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/PageDomain.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/PageDomain.java deleted file mode 100644 index 2e79403d583..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/domain/PageDomain.java +++ /dev/null @@ -1,215 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.domain; - -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Message; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.devsupport.inspector.Inspector; -import com.tencent.mtt.hippy.devsupport.inspector.model.InspectEvent; -import com.tencent.mtt.hippy.devsupport.inspector.model.PageModel; -import com.tencent.mtt.hippy.utils.LogUtils; -import org.json.JSONObject; - -import java.lang.ref.WeakReference; - -public class PageDomain extends InspectorDomain implements Handler.Callback, PageModel.FrameUpdateListener { - - private static final String TAG = "PageDomain"; - - public static final String PAGE_DOMAIN_NAME = "Page"; - - private static final String METHOD_START_SCREEN_CAST = "startScreencast"; - private static final String METHOD_STOP_SCREEN_CAST = "stopScreencast"; - private static final String METHOD_SCREEN_FRAME_ACK = "screencastFrameAck"; - - private static final int MSG_START_SCREEN_CAST = 0x01; - private static final int MSG_SCREEN_CAST_ACK = 0x02; - - private static final long FRAME_CALLBACK_INTERVAL = 1000L; - private static final long DELAY_FOR_FRAME_UPDATE = 100L; - - public static final String BUNDLE_KEY_PARAM = "params"; - - private PageModel mPageModel; - private ScreenCastHandlerThread mHandlerThread; - private volatile boolean mIsFrameUpdate; - private int mLastSessionId = -1; - - public PageDomain(Inspector inspector) { - super(inspector); - mPageModel = new PageModel(); - } - - @Override - public String getDomainName() { - return PAGE_DOMAIN_NAME; - } - - @Override - public boolean handleRequest(HippyEngineContext context, String method, int id, - JSONObject paramsObj) { - switch (method) { - case METHOD_START_SCREEN_CAST: - handleStartScreenCast(context, id, paramsObj); - break; - case METHOD_STOP_SCREEN_CAST: - handleStopScreenCast(context); - break; - case METHOD_SCREEN_FRAME_ACK: - handleScreenFrameAck(context, paramsObj); - break; - default: - return false; - } - return true; - } - - private void handleStartScreenCast(HippyEngineContext context, int id, JSONObject paramsObj) { - mHandlerThread = new ScreenCastHandlerThread(this); - Handler hander = mHandlerThread.getHandler(); - Message msg = hander.obtainMessage(MSG_START_SCREEN_CAST); - msg.obj = context; - if (paramsObj != null) { - Bundle bundle = new Bundle(); - bundle.putString(BUNDLE_KEY_PARAM, paramsObj.toString()); - msg.setData(bundle); - } - hander.sendMessage(msg); - } - - private void handleStopScreenCast(HippyEngineContext context) { - mPageModel.stopScreenCast(context); - if (mHandlerThread != null) { - Handler hander = mHandlerThread.getHandler(); - hander.removeMessages(MSG_START_SCREEN_CAST); - hander.removeMessages(MSG_SCREEN_CAST_ACK); - mHandlerThread.quit(); - mHandlerThread = null; - } - } - - @Override - public void onFrontendClosed(HippyEngineContext context) { - handleStopScreenCast(context); - mPageModel.clear(); - } - - private void handleScreenFrameAck(final HippyEngineContext context, final JSONObject paramsObj) { - if (mHandlerThread != null && paramsObj != null) { - if (!mPageModel.canListenFrameUpdate()) { - Handler hander = mHandlerThread.getHandler(); - Message msg = hander.obtainMessage(MSG_SCREEN_CAST_ACK); - msg.obj = context; - msg.arg1 = paramsObj.optInt("sessionId"); - hander.removeMessages(MSG_SCREEN_CAST_ACK); - hander.sendMessageDelayed(msg, FRAME_CALLBACK_INTERVAL); - } else { - int sessionId = paramsObj.optInt("sessionId"); - if (mIsFrameUpdate) { - Handler hander = mHandlerThread.getHandler(); - Message msg = hander.obtainMessage(MSG_SCREEN_CAST_ACK); - msg.obj = context; - msg.arg1 = sessionId; - hander.removeMessages(MSG_SCREEN_CAST_ACK); - hander.sendMessageDelayed(msg, DELAY_FOR_FRAME_UPDATE); - mIsFrameUpdate = false; - } else { - mLastSessionId = sessionId; - } - } - } - } - - @Override - public boolean handleMessage(Message message) { - switch (message.what) { - case MSG_START_SCREEN_CAST: { - HippyEngineContext context = (HippyEngineContext) message.obj; - JSONObject paramsObj = null; - Bundle bundle = message.getData(); - if (bundle != null) { - try { - paramsObj = new JSONObject(bundle.getString(BUNDLE_KEY_PARAM)); - } catch (Exception e) { - LogUtils.e(TAG, "handleMessage, MSG_START_SCREEN_CAST paramObj parse exception=", e); - } - } - JSONObject result = mPageModel.startScreenCast(context, paramsObj); - InspectEvent event = new InspectEvent("Page.screencastFrame", result); - sendEventToFrontend(event); - if (mPageModel.canListenFrameUpdate()) { - mPageModel.setFrameUpdateListener(this); - } - break; - } - case MSG_SCREEN_CAST_ACK: { - HippyEngineContext context = (HippyEngineContext) message.obj; - int sessionId = message.arg1; - JSONObject result = mPageModel.screenFrameAck(context, sessionId); - // 无数据不返回 - if (result != null) { - InspectEvent event = new InspectEvent("Page.screencastFrame", result); - sendEventToFrontend(event); - } - break; - } - } - return false; - } - - @Override - public void onFrameUpdate(HippyEngineContext context) { - mIsFrameUpdate = true; - if (mInspectorRef != null && mInspectorRef.get() != null - && mInspectorRef.get().getContext() != null) { - context = mInspectorRef.get().getContext(); - } - if (context != null && mHandlerThread != null && mLastSessionId != -1) { - Handler hander = mHandlerThread.getHandler(); - Message msg = hander.obtainMessage(MSG_SCREEN_CAST_ACK); - msg.obj = context; - msg.arg1 = mLastSessionId; - hander.removeMessages(MSG_SCREEN_CAST_ACK); - hander.sendMessageDelayed(msg, DELAY_FOR_FRAME_UPDATE); - mIsFrameUpdate = false; - } - } - - final static class ScreenCastHandlerThread extends HandlerThread { - - final Handler mHandler; - - public ScreenCastHandlerThread(Handler.Callback callback) { - super("ScreenCastHandlerThread"); - setPriority(Thread.NORM_PRIORITY); - start(); - mHandler = new Handler(getLooper(), callback); - } - - public boolean isThreadAlive() { - return (mHandler != null && getLooper() != null && isAlive()); - } - - @Override - public boolean quit() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { - return super.quitSafely(); - } else { - mHandler.post(new Runnable() { - @Override - public void run() { - ScreenCastHandlerThread.super.quit(); - } - }); - } - return true; - } - - public Handler getHandler() { - return mHandler; - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/CSSModel.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/CSSModel.java deleted file mode 100644 index c7a3d3e1db9..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/CSSModel.java +++ /dev/null @@ -1,408 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.model; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.devsupport.inspector.domain.CSSDomain; -import com.tencent.mtt.hippy.dom.node.DomNode; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.LogUtils; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -public class CSSModel { - - private static final String TAG = "CSSModel"; - - private Map transformEnumMap = new HashMap<>(); - private Set transformDoubleMap = new HashSet<>(); - - public CSSModel() { - initTransformValue(); - } - - /** - * 显示的样式,全部使用内联样式来展示,当前无法区分内联和非内联、继承样式等关系 - * - * @return 显示的样式 - */ - public JSONObject getMatchedStyles(HippyEngineContext context, int nodeId) { - JSONObject matchedObject = new JSONObject(); - try { - HippyMap style = context.getDomManager().getNode(nodeId).getDomainData().style; - if (style != null) { - matchedObject.put("inlineStyle", getCSSStyle(style, nodeId)); - } - } catch (Exception e) { - LogUtils.e(TAG, "getMatchedStyles, Exception: ", e); - } - return matchedObject; - } - - /** - * 内联样式先不单独在标签里展示,可以在 {@link #getMatchedStyles} 中显示到 - * - * @return 标签里内联的样式 - */ - public JSONObject getInlineStyles(HippyEngineContext context, int nodeId) { - // 先在 MatchedStyles 中进行展示 - return new JSONObject(); - } - - /** - * CSS 最终应用生效的样式:属性和盒子模型 - * - * @return 最终生效的样式 - */ - public JSONObject getComputedStyle(HippyEngineContext context, int nodeId) { - JSONObject computedStyle = new JSONObject(); - try { - HippyMap style = context.getDomManager().getNode(nodeId).getDomainData().style; - computedStyle.put("computedStyle", getComputedStyle(context, nodeId, style)); - } catch (Exception e) { - LogUtils.e(TAG, "getComputedStyle, Exception: ", e); - } - return computedStyle; - } - - private JSONArray getComputedStyle(HippyEngineContext context, int nodeId, HippyMap style) - throws JSONException { - JSONArray computedArray = new JSONArray(); - if (style != null) { - // property style - for (Map.Entry entry : style.entrySet()) { - String key = (String) entry.getKey(); - if (!isCanHandleStyle(key) || NodeProps.WIDTH.equals(key) || NodeProps.HEIGHT - .equals(key)) { - continue; - } - String value = entry.getValue().toString(); - computedArray.put(getStyleProperty(unCamelize(key), value)); - } - - // box model property - Map boxModelRequireMap = getBoxModelRequireMap(); - for (Map.Entry entry : boxModelRequireMap.entrySet()) { - if (!style.containsKey(entry.getKey())) { - computedArray.put(getStyleProperty(unCamelize(entry.getKey()), entry.getValue())); - } - } - RenderNode renderNode = context.getRenderManager().getRenderNode(nodeId); - if (renderNode != null) { - computedArray.put( - getStyleProperty(unCamelize(NodeProps.WIDTH), String.valueOf(renderNode.getWidth()))); - computedArray.put( - getStyleProperty(unCamelize(NodeProps.HEIGHT), String.valueOf(renderNode.getHeight()))); - } - } - return computedArray; - } - - /** - * 设置样式,并触发 DOM 更新 - * - * @return 设置后的样式 - */ - public JSONObject setStyleTexts(HippyEngineContext context, JSONArray editArray, - CSSDomain cssDomain) { - JSONObject styleObject = new JSONObject(); - try { - JSONArray styleList = new JSONArray(); - for (int i = 0; i < editArray.length(); i++) { - JSONObject editObj = (JSONObject) editArray.opt(i); - JSONObject styleText = setStyleText(context, editObj); - if (styleText == null) { - continue; - } - styleList.put(styleText); - } - - /// 更新样式集合不为空,就批量更新节点样式 - if (styleList.length() > 0) { - // 避免更新 CSS 时,触发 DOM 监听 batch 的更新,同时避免入侵 DomManager 的结构,加个变量控制下 - cssDomain.setNeedBatchUpdateDom(false); - context.getDomManager().batch(); - cssDomain.setNeedBatchUpdateDom(true); - } - styleObject.put("styles", styleList); - } catch (Exception e) { - LogUtils.e(TAG, "setStyleTexts, Exception: ", e); - } - return styleObject; - } - - private JSONObject setStyleText(HippyEngineContext context, JSONObject editObj) { - // set style - int nodeId = editObj.optInt("styleSheetId"); - DomNode node = context.getDomManager().getNode(nodeId); - if (node == null || node.getDomainData() == null) { - LogUtils.e(TAG, "setStyleText node is null"); - return null; - } - HippyRootView hippyRootView = context.getInstance(node.getDomainData().rootId); - if (hippyRootView == null) { - LogUtils.e(TAG, "setStyleText hippyRootView is null"); - return null; - } - HippyMap newMap = node.getTotalProps() == null ? new HippyMap() : node.getTotalProps().copy(); - HippyMap style = - newMap.get(NodeProps.STYLE) != null ? (HippyMap) newMap.get(NodeProps.STYLE) : new HippyMap(); - - String text = editObj.optString("text"); - String[] textList = text.split(";"); - for (String item : textList) { - String[] propertyList = item.trim().split(":"); - if (propertyList.length != 2) { - continue; - } - String key = camelize(propertyList[0].trim()); - String value = propertyList[1].trim(); - Object formatValue = getTransformValue(key, value); - style.pushObject(key, formatValue); - } - newMap.pushMap(NodeProps.STYLE, style); - context.getDomManager().updateNode(nodeId, newMap, hippyRootView); - return getCSSStyle(style, nodeId); - } - - private JSONObject getCSSStyle(HippyMap style, int nodeId) { - JSONObject cssStyle = new JSONObject(); - if (style == null) { - return cssStyle; - } - StringBuilder totalCSSText = new StringBuilder(); - try { - JSONArray cssPropertyArray = new JSONArray(); - for (Map.Entry entry : style.entrySet()) { - String key = (String) entry.getKey(); - if (!isCanHandleStyle(key)) { - continue; - } - - String cssName = unCamelize(key); - String cssValue = entry.getValue().toString(); - String cssText = "cssName" + ":" + cssValue; - JSONObject cssProperty = getCSSProperty(cssName, cssValue, - getRange(0, totalCSSText.length(), 0, totalCSSText.length() + cssText.length() + 1)); - cssPropertyArray.put(cssProperty); - totalCSSText.append(cssText).append(";"); - } - - cssStyle.put("styleSheetId", nodeId); - cssStyle.put("cssProperties", cssPropertyArray); - cssStyle.put("shorthandEntries", new JSONArray()); - cssStyle.put("cssText", totalCSSText); - cssStyle.put("range", getRange(0, 0, 0, totalCSSText.length())); - } catch (Exception e) { - LogUtils.e(TAG, "getCSSStyle, Exception: ", e); - } - return cssStyle; - } - - private JSONObject getRange(int startLine, int startColumn, int endLine, int endColumn) - throws JSONException { - JSONObject range = new JSONObject(); - range.put("startLine", startLine); - range.put("startColumn", startColumn); - range.put("endLine", endLine); - range.put("endColumn", endColumn); - return range; - } - - private JSONObject getCSSProperty(String name, String value, JSONObject sourceRange) - throws JSONException { - JSONObject cssProperty = new JSONObject(); - cssProperty.put("name", name); - cssProperty.put("value", value); - cssProperty.put("important", false); - cssProperty.put("implicit", false); - cssProperty.put("text", null); - cssProperty.put("parsedOk", true); - cssProperty.put("disabled", false); - cssProperty.put("range", sourceRange); - return cssProperty; - } - - private JSONObject getStyleProperty(String name, String value) throws JSONException { - JSONObject object = new JSONObject(); - object.put("name", name); - object.put("value", value); - return object; - } - - private boolean isCanHandleStyle(String key) { - return transformDoubleMap.contains(key) || transformEnumMap.containsKey(key); - } - - private static double getDoubleValue(String value) { - try { - return Double.parseDouble(value); - } catch (Exception e) { - LogUtils.e(TAG, "getDoubleValue, Exception: ", e); - } - return 0; - } - - private static String getEnumValue(String[] options, String value) { - if (options == null) { - return null; - } - for (String option : options) { - if (option.equals(value)) { - return value; - } - } - return options[0]; - } - - /** - * 可接收 css 样式显示的初始化 - */ - private void initTransformValue() { - transformDoubleMap.add(NodeProps.FLEX); - transformDoubleMap.add(NodeProps.FLEX_GROW); - transformDoubleMap.add(NodeProps.FLEX_SHRINK); - transformDoubleMap.add(NodeProps.FLEX_BASIS); - transformDoubleMap.add(NodeProps.WIDTH); - transformDoubleMap.add(NodeProps.HEIGHT); - transformDoubleMap.add(NodeProps.MAX_WIDTH); - transformDoubleMap.add(NodeProps.MIN_WIDTH); - transformDoubleMap.add(NodeProps.MAX_HEIGHT); - transformDoubleMap.add(NodeProps.MIN_HEIGHT); - transformDoubleMap.add(NodeProps.MARGIN_TOP); - transformDoubleMap.add(NodeProps.MARGIN_RIGHT); - transformDoubleMap.add(NodeProps.MARGIN_BOTTOM); - transformDoubleMap.add(NodeProps.MARGIN_LEFT); - transformDoubleMap.add(NodeProps.PADDING_TOP); - transformDoubleMap.add(NodeProps.PADDING_RIGHT); - transformDoubleMap.add(NodeProps.PADDING_BOTTOM); - transformDoubleMap.add(NodeProps.PADDING_LEFT); - transformDoubleMap.add(NodeProps.BORDER_WIDTH); - transformDoubleMap.add(NodeProps.BORDER_TOP_WIDTH); - transformDoubleMap.add(NodeProps.BORDER_RIGHT_WIDTH); - transformDoubleMap.add(NodeProps.BORDER_BOTTOM_WIDTH); - transformDoubleMap.add(NodeProps.BORDER_LEFT_WIDTH); - transformDoubleMap.add(NodeProps.BORDER_RADIUS); - transformDoubleMap.add(NodeProps.BORDER_TOP_LEFT_RADIUS); - transformDoubleMap.add(NodeProps.BORDER_TOP_RIGHT_RADIUS); - transformDoubleMap.add(NodeProps.BORDER_BOTTOM_LEFT_RADIUS); - transformDoubleMap.add(NodeProps.BORDER_BOTTOM_RIGHT_RADIUS); - transformDoubleMap.add(NodeProps.TOP); - transformDoubleMap.add(NodeProps.RIGHT); - transformDoubleMap.add(NodeProps.BOTTOM); - transformDoubleMap.add(NodeProps.LEFT); - transformDoubleMap.add(NodeProps.Z_INDEX); - transformDoubleMap.add(NodeProps.OPACITY); - transformDoubleMap.add(NodeProps.FONT_SIZE); - transformDoubleMap.add(NodeProps.LINE_HEIGHT); - - transformEnumMap.put(NodeProps.DISPLAY, new String[]{"flex", "none"}); - transformEnumMap.put(NodeProps.FLEX_DIRECTION, - new String[]{"column", "column-reverse", "row", "row-reverse"}); - transformEnumMap.put(NodeProps.FLEX_WRAP, new String[]{"nowrap", "wrap", "wrap-reverse"}); - transformEnumMap.put(NodeProps.ALIGN_ITEMS, - new String[]{"flex-start", "center", "flex-end", "stretch", "center", "baseline"}); - transformEnumMap.put(NodeProps.ALIGN_SELF, - new String[]{"auto", "flex-start", "center", "flex-end", "stretch", "center", "baseline"}); - transformEnumMap.put(NodeProps.JUSTIFY_CONTENT, - new String[]{"flex-start", "center", "flex-end", "space-between", "space-around", - "space-evenly"}); - transformEnumMap.put(NodeProps.OVERFLOW, new String[]{"hidden", "visible", "scroll"}); - transformEnumMap.put(NodeProps.POSITION, new String[]{"relative", "absolute"}); - transformEnumMap - .put(NodeProps.BACKGROUND_SIZE, new String[]{"auto", "contain", "cover", "fit"}); - transformEnumMap.put(NodeProps.BACKGROUND_POSITION_X, new String[]{"left", "center", "right"}); - transformEnumMap.put(NodeProps.BACKGROUND_POSITION_Y, new String[]{"top", "center", "bottom"}); - transformEnumMap.put(NodeProps.FONT_STYLE, new String[]{"normal", "italic"}); - transformEnumMap.put(NodeProps.FONT_WEIGHT, - new String[]{"normal", "bold", "100", "200", "300", "400", "500", "600", "700", "800", - "900"}); - transformEnumMap.put(NodeProps.TEXT_ALIGN, new String[]{"left", "center", "right"}); - transformEnumMap - .put(NodeProps.RESIZE_MODE, new String[]{"cover", "contain", "stretch", "repeat", "center"}); - } - - private Map getBoxModelRequireMap() { - String lengthDefault = "0"; - String displayDefault = "block"; - String positionDefault = "relative"; - Map map = new HashMap<>(); - map.put(NodeProps.PADDING_TOP, lengthDefault); - map.put(NodeProps.PADDING_RIGHT, lengthDefault); - map.put(NodeProps.PADDING_BOTTOM, lengthDefault); - map.put(NodeProps.PADDING_LEFT, lengthDefault); - map.put(NodeProps.BORDER_TOP_WIDTH, lengthDefault); - map.put(NodeProps.BORDER_RIGHT_WIDTH, lengthDefault); - map.put(NodeProps.BORDER_BOTTOM_WIDTH, lengthDefault); - map.put(NodeProps.BORDER_LEFT_WIDTH, lengthDefault); - map.put(NodeProps.MARGIN_TOP, lengthDefault); - map.put(NodeProps.MARGIN_RIGHT, lengthDefault); - map.put(NodeProps.MARGIN_BOTTOM, lengthDefault); - map.put(NodeProps.MARGIN_LEFT, lengthDefault); - map.put(NodeProps.DISPLAY, displayDefault); - map.put(NodeProps.POSITION, positionDefault); - return map; - } - - /** - * 判断是否可以转换 - * - * @param key css key - * @param value css value - * @return 转换的 value - */ - private Object getTransformValue(String key, String value) { - if (transformDoubleMap.contains(key)) { - return getDoubleValue(value); - } - if (transformEnumMap.containsKey(key)) { - return getEnumValue(transformEnumMap.get(key), value); - } - return value; - } - - /** - * a-b to aB 转为驼峰 - */ - public static String camelize(String str) { - StringBuilder result = new StringBuilder(); - String[] splitStr = str.split("-"); - boolean skipFirst = true; - for (String split : splitStr) { - if (skipFirst) { - skipFirst = false; - result.append(split); - continue; - } - result - .append(split.replaceFirst(split.substring(0, 1), split.substring(0, 1).toUpperCase())); - } - return result.toString(); - } - - /** - * aB to a-b 驼峰还原中线连接 - */ - public static String unCamelize(String str) { - StringBuilder result = new StringBuilder(); - String[] splitStr = str.split("(?=(?!^)[A-Z])"); - boolean skipFirst = true; - for (String split : splitStr) { - if (skipFirst) { - skipFirst = false; - result.append(split); - continue; - } - result.append( - split.replaceFirst(split.substring(0, 1), "-" + split.substring(0, 1).toLowerCase())); - } - return result.toString(); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/DomModel.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/DomModel.java deleted file mode 100644 index 33f7f9f8ec6..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/DomModel.java +++ /dev/null @@ -1,536 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.model; - -import android.app.Activity; -import android.os.Build; -import android.text.TextUtils; -import android.view.View; -import android.view.WindowManager; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.DomDomainData; -import com.tencent.mtt.hippy.dom.DomManager; -import com.tencent.mtt.hippy.dom.node.DomNode; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.RenderManager; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.LogUtils; -import java.util.Map; -import org.json.JSONArray; -import org.json.JSONObject; - -public class DomModel { - - private static final String TAG = "DomModel"; - - private static final String DEFAULT_FRAME_ID = "main_frame"; - private DomNode mInspectNode; - - private JSONObject getNode(HippyEngineContext context, int nodeId) { - JSONArray childrenArray = new JSONArray(); - JSONObject result = null; - DomManager domManager = context.getDomManager(); - if (domManager != null) { - DomNode domNode = domManager.getNode(nodeId); - if (domNode == null) { - return null; - } - - DomDomainData domainData = domNode.getDomainData(); - // rootNode domainData为空 - if (domainData != null && !TextUtils.isEmpty(domainData.text)) { - childrenArray.put(getTextNodeJson(domainData)); - } - - for (int i = 0, size = domNode.getChildCount(); i < size; i++) { - DomNode childNode = domNode.getChildAt(i); - childrenArray.put(getNode(context, childNode.getId())); - } - - try { - result = getNodeJson(domainData, NodeType.ELEMENT_NODE); - if (result == null) { - result = new JSONObject(); - } - result.put("childNodeCount", childrenArray.length()); - result.put("children", childrenArray); - } catch (Exception e) { - LogUtils.e(TAG, "getNode, exception:", e); - } - } - return result; - } - - private JSONObject getTextNodeJson(DomDomainData domainData) { - JSONObject result = getNodeJson(domainData, NodeType.TEXT_NODE); - try { - result.put("childNodeCount", 0); - result.put("children", new JSONArray()); - } catch (Exception e) { - LogUtils.e(TAG, "getTextNodeJson, exception:", e); - } - return result; - } - - private JSONObject getNodeJson(DomDomainData domainData, int nodeType) { - if (domainData == null) { - return null; - } - JSONObject result = new JSONObject(); - try { - result.put("nodeId", domainData.id); - result.put("backendNodeId", 0); - result.put("nodeType", nodeType); - result.put("localName", domainData.tagName); - result.put("nodeName", domainData.tagName); - result.put("nodeValue", domainData.text); - result.put("parentId", domainData.pid); - result.put("attributes", getAttributeList(domainData.attributes)); - } catch (Exception e) { - LogUtils.e(TAG, "getTextNodeJson, exception:", e); - } - return result; - } - - private JSONArray getAttributeList(HippyMap attributes) { - JSONArray attributeList = new JSONArray(); - try { - for (Map.Entry entry : attributes.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (NodeProps.STYLE.equals(key) && value instanceof HippyMap) { - value = getInlineStyle((HippyMap) value); - } - if (value == null || (value instanceof String && TextUtils.isEmpty((String) value))) { - continue; - } - attributeList.put(key); - attributeList.put(value.toString()); - } - } catch (Exception e) { - LogUtils.e(TAG, "getAttributeList, exception:", e); - } - return attributeList; - } - - private String getInlineStyle(HippyMap data) { - StringBuilder resultBuilder = new StringBuilder(); - for (Map.Entry entry : data.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (value instanceof Number) { - value = String.format("%.1f", ((Number) value).doubleValue()); - } - resultBuilder.append(key).append(":").append(value).append(";"); - } - resultBuilder.deleteCharAt(resultBuilder.length() - 1); - return resultBuilder.toString(); - } - - public JSONObject getDocument(HippyEngineContext context) { - if (context == null) { - return new JSONObject(); - } - try { - JSONObject result = new JSONObject(); - JSONObject root = new JSONObject(); - int documentNodeId = -3; - result.put("root", root); - root.put("nodeId", documentNodeId); - root.put("backendNodeId", documentNodeId); - root.put("nodeType", 9); - root.put("childNodeCount", 1); - root.put("nodeName", "#document"); - root.put("baseURL", ""); - root.put("documentURL", ""); - DomManager domManager = context.getDomManager(); - if (domManager != null) { - int rootId = domManager.getRootNodeId(); - JSONObject rootNode = getNode(context, rootId); - if (rootNode != null) { - JSONArray childrenArray = rootNode.optJSONArray("children"); - if (childrenArray != null) { - root.put("children", childrenArray); - } - } - } - return result; - } catch (Exception e) { - LogUtils.e(TAG, "getDocument, exception:", e); - } - return new JSONObject(); - } - - private JSONArray getBorder(int x, int y, int width, int height) { - JSONArray border = new JSONArray(); - try { - border.put(x); - border.put(y); - border.put(x + width); - border.put(y); - border.put(x + width); - border.put(y + height); - border.put(x); - border.put(y + height); - } catch (Exception e) { - LogUtils.e(TAG, "getBorder, exception:", e); - } - return border; - } - - private JSONArray getPadding(JSONArray border, HippyMap style) { - int borderTop = 0; - int borderRight = 0; - int borderBottom = 0; - int borderLeft = 0; - if (style != null) { - if (style.containsKey(NodeProps.BORDER_TOP_WIDTH)) { - borderTop = (int) style.get(NodeProps.BORDER_TOP_WIDTH); - } - if (style.containsKey(NodeProps.BORDER_RIGHT_WIDTH)) { - borderRight = (int) style.get(NodeProps.BORDER_RIGHT_WIDTH); - } - if (style.containsKey(NodeProps.BORDER_BOTTOM_WIDTH)) { - borderBottom = (int) style.get(NodeProps.BORDER_BOTTOM_WIDTH); - } - if (style.containsKey(NodeProps.BORDER_LEFT_WIDTH)) { - borderLeft = (int) style.get(NodeProps.BORDER_LEFT_WIDTH); - } - } - - JSONArray padding = new JSONArray(); - try { - padding.put(border.getInt(0) + borderLeft); - padding.put(border.getInt(1) + borderTop); - padding.put(border.getInt(2) - borderRight); - padding.put(border.getInt(3) + borderTop); - padding.put(border.getInt(4) - borderRight); - padding.put(border.getInt(5) - borderBottom); - padding.put(border.getInt(6) + borderLeft); - padding.put(border.getInt(7) - borderBottom); - } catch (Exception e) { - LogUtils.e(TAG, "getPadding, exception:", e); - } - return padding; - } - - private JSONArray getContent(JSONArray padding, HippyMap style) { - int paddingTop = 0; - int paddingRight = 0; - int paddingBottom = 0; - int paddingLeft = 0; - if (style != null) { - if (style.containsKey(NodeProps.PADDING_TOP)) { - paddingTop = (int) style.get(NodeProps.PADDING_TOP); - } - if (style.containsKey(NodeProps.PADDING_RIGHT)) { - paddingRight = (int) style.get(NodeProps.PADDING_RIGHT); - } - if (style.containsKey(NodeProps.PADDING_BOTTOM)) { - paddingBottom = (int) style.get(NodeProps.PADDING_BOTTOM); - } - if (style.containsKey(NodeProps.PADDING_LEFT)) { - paddingLeft = (int) style.get(NodeProps.PADDING_LEFT); - } - } - - JSONArray content = new JSONArray(); - try { - content.put(padding.getInt(0) + paddingLeft); - content.put(padding.getInt(1) + paddingTop); - content.put(padding.getInt(2) - paddingRight); - content.put(padding.getInt(3) + paddingTop); - content.put(padding.getInt(4) - paddingRight); - content.put(padding.getInt(5) - paddingBottom); - content.put(padding.getInt(6) + paddingLeft); - content.put(padding.getInt(7) - paddingBottom); - } catch (Exception e) { - LogUtils.e(TAG, "getPadding, exception:", e); - } - return content; - } - - private JSONArray getMargin(JSONArray border, HippyMap style) { - int marginTop = 0; - int marginRight = 0; - int marginBottom = 0; - int marginLeft = 0; - if (style != null) { - if (style.containsKey(NodeProps.MARGIN_TOP)) { - marginTop = (int) style.get(NodeProps.MARGIN_TOP); - } - if (style.containsKey(NodeProps.MARGIN_RIGHT)) { - marginRight = (int) style.get(NodeProps.MARGIN_RIGHT); - } - if (style.containsKey(NodeProps.MARGIN_BOTTOM)) { - marginBottom = (int) style.get(NodeProps.MARGIN_BOTTOM); - } - if (style.containsKey(NodeProps.MARGIN_LEFT)) { - marginLeft = (int) style.get(NodeProps.MARGIN_LEFT); - } - } - - JSONArray margin = new JSONArray(); - try { - margin.put(border.getInt(0) - marginLeft); - margin.put(border.getInt(1) - marginTop); - margin.put(border.getInt(2) + marginRight); - margin.put(border.getInt(3) - marginTop); - margin.put(border.getInt(4) + marginRight); - margin.put(border.getInt(5) + marginBottom); - margin.put(border.getInt(6) - marginLeft); - margin.put(border.getInt(7) + marginBottom); - } catch (Exception e) { - LogUtils.e(TAG, "getPadding, exception:", e); - } - return margin; - } - - public JSONObject getBoxModel(HippyEngineContext context, JSONObject paramsObj) { - if (context == null || paramsObj == null) { - return new JSONObject(); - } - try { - int nodeId = paramsObj.optInt("nodeId", -1); - DomManager domManager = context.getDomManager(); - RenderManager renderManager = context.getRenderManager(); - if (domManager != null && renderManager != null) { - DomNode domNode = domManager.getNode(nodeId); - RenderNode renderNode = renderManager.getRenderNode(nodeId); - if (domNode != null && domNode.getDomainData() != null && renderNode != null) { - int[] viewLocation = getRenderViewLocation(context, renderNode); - // 没找到view,还未创建 - if (viewLocation == null) { - return new JSONObject(); - } - - JSONArray border = getBorder(viewLocation[0], viewLocation[1], renderNode.getWidth(), - renderNode.getHeight()); - HippyMap style = domNode.getDomainData().style; - JSONArray padding = getPadding(border, style); - JSONArray content = getContent(padding, style); - JSONArray margin = getMargin(border, style); - JSONObject result = new JSONObject(); - JSONObject model = new JSONObject(); - model.put("content", content); - model.put("padding", padding); - model.put("border", border); - model.put("margin", margin); - model.put("width", renderNode.getWidth()); - model.put("height", renderNode.getHeight()); - result.put("model", model); - return result; - } - } - } catch (Exception e) { - LogUtils.e(TAG, "getDocument, exception:", e); - } - return new JSONObject(); - } - - private int[] getRenderViewLocation(HippyEngineContext context, RenderNode renderNode) { - int[] viewLocation = new int[2]; - viewLocation[0] = renderNode.getX(); - viewLocation[1] = renderNode.getY(); - ControllerManager controllerManager = context.getRenderManager().getControllerManager(); - if (controllerManager != null) { - View view = controllerManager.findView(renderNode.getId()); - if (view != null) { - view.getLocationOnScreen(viewLocation); - HippyRootView rootView = getRootView(context); - if (rootView != null) { - int[] rootViewLocation = new int[2]; - rootView.getLocationOnScreen(rootViewLocation); - viewLocation[0] = viewLocation[0] - rootViewLocation[0]; - viewLocation[1] = viewLocation[1] - rootViewLocation[1]; - } - } else { - return null; - } - } - return viewLocation; - } - - private boolean isLocationHitRenderNode(HippyEngineContext context, int x, int y, - RenderNode renderNode) { - if (renderNode == null) { - return false; - } - int[] viewLocation = getRenderViewLocation(context, renderNode); - if (viewLocation == null) { - return false; - } - int dx = viewLocation[0]; - int dy = viewLocation[1]; - int width = renderNode.getWidth(); - int height = renderNode.getHeight(); - boolean isInTopOffset = x >= dx && y >= dy; - boolean isInBottomOffset = x <= (dx + width) && y <= (dy + height); - boolean isHit = isInTopOffset && isInBottomOffset; - return isHit; - } - - /** - * @return 是否是沉浸式状态栏 - */ - private boolean isTranslucentStatus(HippyEngineContext context) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - return false; - } - int rootId = context.getDomManager().getRootNodeId(); - HippyRootView rootView = context.getInstance(rootId); - if (rootView == null || !(rootView.getHost() instanceof Activity)) { - return false; - } - int flag = ((Activity) rootView.getHost()).getWindow().getAttributes().flags; - if ((WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS & flag) - == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) { - return true; - } - int options = ((Activity) rootView.getHost()).getWindow().getDecorView() - .getSystemUiVisibility(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP - && (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN & options) - == View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) { - return true; - } - return false; - } - - /** - * 获取面积更小的渲染节点 - * - * @param oldNode - * @param newNode - * @return - */ - private RenderNode getSmallerAreaRenderNode(RenderNode oldNode, RenderNode newNode) { - if (oldNode == null) { - return newNode; - } - if (newNode == null) { - return oldNode; - } - - int oldNodeArea = oldNode.getWidth() * oldNode.getHeight(); - int newNodeArea = newNode.getWidth() * newNode.getHeight(); - return oldNodeArea > newNodeArea ? newNode : oldNode; - } - - /** - * 获取当前坐标(x, y)所在的最深层级且面积最小的RenderNode节点 - * - * @param x - * @param y - * @param rootNode - * @return - */ - private RenderNode getMaxDepthAndMinAreaHitRenderNode(HippyEngineContext context, int x, int y, - RenderNode rootNode) { - if (rootNode == null || !isLocationHitRenderNode(context, x, y, rootNode)) { - return null; - } - - RenderNode hitNode = null; - for (int i = 0, size = rootNode.getChildCount(); i < size; i++) { - RenderNode childNode = rootNode.getChildAt(i); - if (isLocationHitRenderNode(context, x, y, childNode)) { - RenderNode newHitNode = getMaxDepthAndMinAreaHitRenderNode(context, x, y, childNode); - hitNode = getSmallerAreaRenderNode(hitNode, newHitNode); - } - } - - return hitNode != null ? hitNode : rootNode; - } - - public JSONObject getNodeForLocation(HippyEngineContext context, JSONObject paramsObj) { - if (context == null || paramsObj == null) { - return new JSONObject(); - } - try { - int x = paramsObj.optInt("x", 0); - int y = paramsObj.optInt("y", 0); - DomManager domManager = context.getDomManager(); - RenderManager renderManager = context.getRenderManager(); - if (domManager != null && renderManager != null) { - int rootId = domManager.getRootNodeId(); - RenderNode renderNode = renderManager.getRenderNode(rootId); - if (renderNode.getChildCount() > 0) { - RenderNode rootNode = getRootRenderNode(renderNode, x, y); - if (rootNode != null) { - RenderNode hitRenderNode = getMaxDepthAndMinAreaHitRenderNode(context, x, y, rootNode); - JSONObject result = new JSONObject(); - if (hitRenderNode != null) { - result.put("backendId", hitRenderNode.getId()); - result.put("frameId", DEFAULT_FRAME_ID); - result.put("nodeId", hitRenderNode.getId()); - } - return result; - } - } - } - } catch (Exception e) { - LogUtils.e(TAG, "getDocument, exception:", e); - } - return new JSONObject(); - } - - private RenderNode getRootRenderNode(RenderNode rootNode, int x, int y) { - if (rootNode.getWidth() > 0 && rootNode.getHeight() > 0) { - return rootNode; - } - // 当 rootNode 没有宽、高信息时,返回一个包含x,y的子节点 - RenderNode resultNode = null; - for (int i = 0; i < rootNode.getChildCount(); i++) { - RenderNode childNode = rootNode.getChildAt(i); - if (resultNode == null || childNode.getX() <= x && childNode.getY() <= y - && resultNode.getHeight() <= childNode.getHeight() - && resultNode.getWidth() <= childNode.getWidth()) { - // 选择一个范围更大的,且起始点在 x,y 的左上方 - resultNode = rootNode.getChildAt(i); - } - } - return resultNode; - } - - public JSONObject setInspectMode(HippyEngineContext context, JSONObject paramsObj) { - if (context == null || paramsObj == null) { - return new JSONObject(); - } - try { - int nodeId = paramsObj.optInt("nodeId", 0); - DomManager domManager = context.getDomManager(); - if (domManager != null) { - DomNode domNode = domManager.getNode(nodeId); - if (domNode != null) { - mInspectNode = domNode; - } - } - } catch (Exception e) { - LogUtils.e(TAG, "setInspectMode, exception:", e); - } - return new JSONObject(); - } - - private static HippyRootView getRootView(HippyEngineContext context) { - int rootId = context.getDomManager().getRootNodeId(); - return context.getInstance(rootId); - } - - /** - * https://dom.spec.whatwg.org/#dom-node-nodetype - */ - public static class NodeType { - - public static final int ELEMENT_NODE = 1; - public static final int ATTRIBUTE_NODE = 2; - public static final int TEXT_NODE = 3; - public static final int CDATA_SECTION_NODE = 4; - public static final int PROCESSING_INSTRUCTION_NODE = 5; - public static final int COMMENT_NODE = 6; - public static final int DOCUMENT_NODE = 7; - public static final int DOCUMENT_TYPE_NODE = 8; - public static final int DOCUMENT_FRAGMENT_NODE = 9; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/InspectEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/InspectEvent.java deleted file mode 100644 index 3dd684360c8..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/InspectEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.model; - -import com.tencent.mtt.hippy.utils.LogUtils; -import org.json.JSONObject; - -public class InspectEvent { - - private final String method; - private final JSONObject paramsObject; - - public InspectEvent(String method, JSONObject paramsObject) { - this.method = method; - this.paramsObject = paramsObject; - } - - public String toJson() { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("method", method); - jsonObject.put("params", paramsObject); - } catch (Exception e) { - LogUtils.e("InspectEvent", "toJson, exception:", e); - return null; - } - return jsonObject.toString(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/PageModel.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/PageModel.java deleted file mode 100644 index 95028f169a4..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/devsupport/inspector/model/PageModel.java +++ /dev/null @@ -1,226 +0,0 @@ -package com.tencent.mtt.hippy.devsupport.inspector.model; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.os.Build; -import android.text.TextUtils; -import android.util.Base64; -import android.util.DisplayMetrics; -import android.view.ViewTreeObserver; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.dom.DomManager; -import com.tencent.mtt.hippy.utils.LogUtils; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.lang.ref.WeakReference; - -import org.json.JSONObject; - -public class PageModel { - - private static final String TAG = "PageModel"; - - private volatile boolean isFramingScreenCast; - private long lastSessionId; - - private JSONObject paramObj; - private String format; - private int quality; - private int maxWidth; - private int maxHeight; - private Bitmap screenBitmap; - private WeakReference mFrameUpdateListenerRef; - private ViewTreeObserver.OnDrawListener mOnDrawListener; - - public JSONObject startScreenCast(HippyEngineContext context, final JSONObject paramsObj) { - isFramingScreenCast = true; - this.paramObj = paramsObj; - if (paramsObj != null) { - format = paramsObj.optString("format"); - quality = paramsObj.optInt("quality"); - maxWidth = paramsObj.optInt("maxWidth"); - maxHeight = paramsObj.optInt("maxHeight"); - } - - // 开始截屏时,监听重绘变化 - listenFrameUpdate(context); - return getScreenCastData(context); - } - - public boolean canListenFrameUpdate() { - return Build.VERSION.SDK_INT >= 16; - } - - private void listenFrameUpdate(final HippyEngineContext context) { - if (canListenFrameUpdate()) { - HippyRootView hippyRootView = getHippyRootView(context); - if (hippyRootView == null) { - LogUtils.e(TAG, "listenFrameUpdate error none hippyRootView"); - return; - } - if (mOnDrawListener == null) { - mOnDrawListener = new ViewTreeObserver.OnDrawListener() { - @Override - public void onDraw() { - LogUtils.d(TAG, "HippyRootView, onDraw"); - if (mFrameUpdateListenerRef != null) { - FrameUpdateListener listener = mFrameUpdateListenerRef.get(); - if (listener != null) { - listener.onFrameUpdate(context); - } - } - } - }; - } - try { - hippyRootView.getViewTreeObserver().removeOnDrawListener(mOnDrawListener); - hippyRootView.getViewTreeObserver().addOnDrawListener(mOnDrawListener); - } catch (Exception e) { - LogUtils.e(TAG, "listenFrameUpdate e:", e); - } - } - } - - public void setFrameUpdateListener(FrameUpdateListener listener) { - if (listener != null) { - mFrameUpdateListenerRef = new WeakReference<>(listener); - } else { - mFrameUpdateListenerRef = null; - } - } - - public void stopScreenCast(HippyEngineContext context) { - isFramingScreenCast = false; - - if (canListenFrameUpdate()) { - HippyRootView hippyRootView = getHippyRootView(context); - if (hippyRootView == null) { - LogUtils.e(TAG, "stopScreenCast error none hippyRootView"); - return; - } - hippyRootView.getViewTreeObserver().removeOnDrawListener(mOnDrawListener); - } - } - - public void clear() { - if (screenBitmap != null && !screenBitmap.isRecycled()) { - screenBitmap.recycle(); - screenBitmap = null; - } - } - - public JSONObject screenFrameAck(HippyEngineContext context, int sessionId) { - if (isFramingScreenCast) { - return getScreenCastData(context); - } - LogUtils.e(TAG, "screencast, screenFrameAck, isFramingScreenCast=" + isFramingScreenCast); - return null; - } - - private HippyRootView getHippyRootView(HippyEngineContext context) { - DomManager domManager = context.getDomManager(); - int rootNodeId = domManager.getRootNodeId(); - HippyRootView hippyRootView = context.getInstance(rootNodeId); - return hippyRootView; - } - - private JSONObject getScreenCastData(HippyEngineContext context) { - JSONObject result = new JSONObject(); - try { - HippyRootView hippyRootView = getHippyRootView(context); - if (hippyRootView == null) { - LogUtils.e(TAG, "getScreenCastData error none hippyRootView"); - return null; - } - int viewWidth = hippyRootView.getWidth(); - int viewHeight = hippyRootView.getHeight(); - float scale = 1.0f; - if (paramObj != null) { - float scaleX = (float) this.maxWidth / (float) viewWidth; - float scaleY = (float) this.maxHeight / (float) viewHeight; - scale = Math.min(scaleX, scaleY); - } - Bitmap bitmap = screenBitmap; - if (bitmap == null) { - bitmap = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.ARGB_8888); - screenBitmap = bitmap; - } - Canvas canvas = new Canvas(bitmap); - hippyRootView.draw(canvas); - if (scale != 1.0f) { - Matrix matrix = new Matrix(); - matrix.postScale(scale, scale); - Bitmap scaledBitmap = Bitmap - .createBitmap(bitmap, 0, 0, viewWidth, viewHeight, matrix, true); - bitmap = scaledBitmap; - } - String bitmapBase64Str = bitmapToBase64Str(bitmap); - DisplayMetrics windowDisplayMetrics = hippyRootView.getContext().getResources() - .getDisplayMetrics(); - final int sessionId = (int) (System.currentTimeMillis() / 1000); - JSONObject meta = new JSONObject(); - meta.put("offsetTop", 0); - meta.put("pageScaleFactor", 1); - meta.put("deviceWidth", windowDisplayMetrics.widthPixels); - meta.put("deviceHeight", windowDisplayMetrics.heightPixels); - meta.put("scrollOffsetX", 0); - meta.put("scrollOffsetY", 0); - meta.put("timestamp", sessionId); - result.put("data", TextUtils.isEmpty(bitmapBase64Str) ? "" : bitmapBase64Str); - result.put("metadata", meta); - result.put("sessionId", sessionId); - lastSessionId = sessionId; - } catch (Exception e) { - LogUtils.e(TAG, "getScreenCastData, exception=", e); - return null; - } - return result; - } - - private String bitmapToBase64Str(Bitmap bitmap) { - String result = null; - ByteArrayOutputStream baos = null; - try { - if (bitmap != null) { - baos = new ByteArrayOutputStream(); - Bitmap.CompressFormat format = Bitmap.CompressFormat.JPEG; - int quality = 80; - // 工具如果没传参数,使用默认值 - if (paramObj != null) { - if (!TextUtils.isEmpty(this.format)) { - if ("jpeg".equalsIgnoreCase(this.format)) { - format = Bitmap.CompressFormat.JPEG; - } else if ("png".equalsIgnoreCase(this.format)) { - format = Bitmap.CompressFormat.PNG; - } - } - quality = this.quality; - } - bitmap.compress(format, quality, baos); - baos.flush(); - baos.close(); - byte[] bitmapBytes = baos.toByteArray(); - result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT); - } - } catch (IOException e) { - LogUtils.e(TAG, "screenFrameAck, exception1=", e); - } finally { - try { - if (baos != null) { - baos.flush(); - baos.close(); - } - } catch (IOException e) { - LogUtils.e(TAG, "screenFrameAck, exception2=", e); - } - } - return result; - } - - public interface FrameUpdateListener { - void onFrameUpdate(HippyEngineContext context); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/ChoreographerCompat.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/ChoreographerCompat.java deleted file mode 100644 index 3f05595ebf0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/ChoreographerCompat.java +++ /dev/null @@ -1,70 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom; - -import android.os.Build; -import android.view.Choreographer; - -import java.util.HashMap; -import java.util.Map; - -public class ChoreographerCompat { - - private final static boolean IS_JELLY_BEAN = Build.VERSION.SDK_INT >= 16; - private static ChoreographerCompat sInstance; - - private ChoreographerCompat() { - - } - - public static ChoreographerCompat getInstance() { - if (sInstance == null) { - sInstance = new ChoreographerCompat(); - } - return sInstance; - } - - private final Map mMapper = new HashMap<>(); - - public void postFrameCallback(final HippyChoreographer.FrameCallback callback) { - if (IS_JELLY_BEAN) { - Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() { - @Override - public void doFrame(long frameTimeNanos) { - if (callback != null) { - callback.doFrame(frameTimeNanos); - } - } - }; - mMapper.put(callback, frameCallback); - Choreographer.getInstance().postFrameCallback(frameCallback); - } else { - ICSChoreographer.getInstance().postFrameCallback(callback); - } - } - - public void removeFrameCallback(HippyChoreographer.FrameCallback callback) { - if (IS_JELLY_BEAN) { - Choreographer.FrameCallback frameCallback = mMapper.get(callback); - if (frameCallback != null) { - mMapper.remove(callback); - Choreographer.getInstance().removeFrameCallback(frameCallback); - } - } else { - ICSChoreographer.getInstance().removeFrameCallback(callback); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomManager.java deleted file mode 100644 index 917b42167dd..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomManager.java +++ /dev/null @@ -1,903 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom; - - -import android.text.Layout; -import android.text.TextUtils; -import android.util.SparseBooleanArray; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyEngineLifecycleEventListener; -import com.tencent.mtt.hippy.HippyInstanceLifecycleEventListener; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.DomDomainData; -import com.tencent.mtt.hippy.dom.flex.FlexSpacing; -import com.tencent.mtt.hippy.dom.node.*; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.uimanager.DiffUtils; -import com.tencent.mtt.hippy.uimanager.RenderManager; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.utils.UIThreadUtils; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; - -@SuppressWarnings({"deprecation", "unused", "UnusedReturnValue", "rawtypes"}) -public class DomManager implements HippyInstanceLifecycleEventListener, - HippyEngineLifecycleEventListener { - - private static final String TAG = "DomManager"; - protected final DispatchUIFrameCallback mDispatchUIFrameCallback; - private final SparseBooleanArray mTagsWithLayoutVisited = new SparseBooleanArray(); - protected volatile boolean mIsDispatchUIFrameCallbackEnqueued; - protected boolean mRenderBatchStarted = false; - final DomNodeRegistry mNodeRegistry; - final ArrayList mUITasks; - final ArrayList mPaddingNulUITasks; - final ArrayList mDispatchRunnable = new ArrayList<>(); - final Object mDispatchLock = new Object(); - final DomUpdateManager mDomStyleUpdateManager = new DomUpdateManager(); - final RenderManager mRenderManager; - volatile CopyOnWriteArrayList mActionInterceptors; - final LayoutHelper mLayoutHelper; - private final HippyEngineContext mContext; - private volatile boolean mIsDestroyed = false; - private volatile boolean mEnginePaused = false; - private BatchListener mBatchListener; - - public DomManager(HippyEngineContext context) { - this.mContext = context; - mNodeRegistry = new DomNodeRegistry(); - - mUITasks = new ArrayList<>(); - //noinspection unchecked - mPaddingNulUITasks = new ArrayList(); - - mRenderManager = context.getRenderManager(); - context.addInstanceLifecycleEventListener(this); - mDispatchUIFrameCallback = new DispatchUIFrameCallback(); - - mContext.addEngineLifecycleEventListener(this); - mLayoutHelper = new LayoutHelper(); - - } - - private static boolean jsJustLayout(HippyMap props) { - if (props == null) { - return true; - } - - if (props.get(NodeProps.COLLAPSABLE) != null && !((Boolean) props - .get(NodeProps.COLLAPSABLE))) { - return false; - } - - Set sets = props.keySet(); - - for (String key : sets) { - if (!NodeProps.isJustLayout(props, key)) { - return false; - } - } - return true; - } - - public void addActionInterceptor(DomActionInterceptor interceptor) { - if (mActionInterceptors == null) { - synchronized (DomManager.class) { - if (mActionInterceptors == null) { - mActionInterceptors = new CopyOnWriteArrayList<>(); - } - } - } - mActionInterceptors.add(interceptor); - } - - public void removeActionInterceptor(DomActionInterceptor interceptor) { - if (mActionInterceptors != null) { - mActionInterceptors.remove(interceptor); - } - } - - public void createRootNode(int instanceId) { - HippyRootView view = mContext.getInstance(instanceId); - if (view != null) { - DomNode node = new StyleNode(); - node.setId(instanceId); - node.setViewClassName(NodeProps.ROOT_NODE); - node.setStyleWidth(view.getWidth()); - node.setStyleHeight(view.getHeight()); - addRootNode(node); - mRenderManager.createRootNode(instanceId); - // mContext.getGlobalConfigs().getLogAdapter().init(instanceId,view.getName()); - } else { - LogUtils.e(TAG, "createRootNode RootView Null error"); - } - } - - @Override - public void onInstanceLoad(final int instanceId) { - mContext.getThreadExecutor().postOnDomThread(new Runnable() { - @Override - public void run() { - createRootNode(instanceId); - } - }); - - } - - @Override - public void onInstanceResume(int instanceId) { - - } - - @Override - public void onInstancePause(int instanceId) { - - } - - @Override - public void onInstanceDestroy(int instanceId) { - - } - - void clearDestroy() { - mIsDestroyed = true; - if (mNodeRegistry != null) { - mNodeRegistry.clear(); - } - mLayoutHelper.release(); - mContext.removeInstanceLifecycleEventListener(this); - mUITasks.clear(); - mPaddingNulUITasks.clear(); - - mContext.removeEngineLifecycleEventListener(this); - - mIsDispatchUIFrameCallbackEnqueued = false; - if (UIThreadUtils.isOnUiThread()) { - HippyChoreographer.getInstance().removeFrameCallback(mDispatchUIFrameCallback); - } else { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - HippyChoreographer.getInstance().removeFrameCallback(mDispatchUIFrameCallback); - } - }); - } - } - - public void destroy() { - mContext.getThreadExecutor().postOnDomThread(new Runnable() { - @Override - public void run() { - clearDestroy(); - } - }); - } - - private void markTextNodeDirty(DomNode domNode) { - if (domNode != null) { - int childCount = domNode.getChildCount(); - for (int i = 0; i < childCount; i++) { - markTextNodeDirty(domNode.getChildAt(i)); - } - if (domNode instanceof TextNode) { - TextNode textNode = (TextNode) domNode; - if (textNode.enableScale()) { - textNode.dirty(); - } - } - } - } - - public void forceUpdateNode(int rootId) { - DomNode node = mNodeRegistry.getNode(rootId); - markTextNodeDirty(node); - if (!mRenderBatchStarted) { - batch(); - } - } - - public void updateNodeSize(int rootId, int width, int height) { - DomNode node = mNodeRegistry.getNode(rootId); - - if (node != null) { - - node.setStyleWidth(width); - node.setStyleHeight(height); - if (!mRenderBatchStarted) { - batch(); - } - } - } - - public void addRootNode(DomNode node) { - mNodeRegistry.addRootNode(node); - } - - public void renderBatchStart() { - LogUtils.d(TAG, "renderBatchStart"); - mRenderBatchStarted = true; - } - - public void renderBatchEnd() { - LogUtils.d(TAG, "renderBatchEnd"); - mRenderBatchStarted = false; - batch(); - } - - public void batchByAnimation() { - if (!mRenderBatchStarted) { - batch(true); - } - } - - public DomNode getNode(final int id) { - return mNodeRegistry.getNode(id); - } - - public int getRootNodeId() { - int count = mNodeRegistry.getRootNodeCount(); - return count >= 1 ? mNodeRegistry.getRootTag(0) : 0; - } - - public void createNode(final HippyRootView hippyRootView, int rootId, final int id, int pid, int index, - final String className, String tagName, HippyMap map) { - // assertThread(); - - //create node - - final DomNode parentNode = mNodeRegistry.getNode(pid); - if (parentNode != null) { - if (mActionInterceptors != null) { - for (DomActionInterceptor interceptor : mActionInterceptors) { - map = interceptor.onCreateNode(id, hippyRootView, map); - } - } - HippyMap props = map; - - boolean isVirtual = false; - if (TextUtils.equals(parentNode.getViewClass(), NodeProps.TEXT_CLASS_NAME)) { - isVirtual = true; - } - - DomNode node = mContext.getRenderManager() - .createStyleNode(className, isVirtual, id, hippyRootView.getId()); - - node.setLazy(parentNode.isLazy() || mContext.getRenderManager().getControllerManager() - .isControllerLazy(className)); - node.setProps(map); - - if (mContext.getDevSupportManager().isSupportDev()) { - node.setDomainData(new DomDomainData(id, rootId, pid, className, tagName, map)); - } - - // boolean isLayoutOnly=false; - boolean isLayoutOnly = - (NodeProps.VIEW_CLASS_NAME.equals(node.getViewClass())) && jsJustLayout( - (HippyMap) props.get(NodeProps.STYLE)) - && !isTouchEvent(props); - LogUtils.d(TAG, - "dom create node id: " + id + " mClassName " + className + " pid " + pid + " mIndex:" - + index + " isJustLayout :" - + isLayoutOnly + " isVirtual " + isVirtual); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"dom create node id: " + id + " mClassName " + className + " pid " + pid + " mIndex:" + index + " isJustLayout :" - // + isLayoutOnly + " isVirtual " + isVirtual); - //updateProps - node.updateProps(props); - //noinspection unchecked - mDomStyleUpdateManager.updateStyle(node, props); - - //add to parent - int realIndex = index; - if (realIndex > parentNode.getChildCount()) { - realIndex = parentNode.getChildCount(); - LogUtils.d("DomManager", "createNode addChild error index > parent.size"); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"createNode addChild error index > parent.size"); - } - parentNode.addChildAt(node, realIndex); - - //add to registry - mNodeRegistry.addNode(node); - - node.setIsJustLayout(isLayoutOnly); - - if (!isLayoutOnly && !node.isVirtual()) { - final DomNode nativeParentNode = findNativeViewParent(node); - final ViewIndex childIndex = findNativeViewIndex(nativeParentNode, node, 0); - final HippyMap newProps = map; - - //this is create view ahead in every doframe - if (!node.isLazy()) { - synchronized (mDispatchLock) { - addDispatchTask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager - .createPreView(hippyRootView, id, nativeParentNode.getId(), childIndex.mIndex, - className, newProps); - } - }); - } - } - - addUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager - .createNode(hippyRootView, id, nativeParentNode.getId(), childIndex.mIndex, - className, newProps); - } - }); - } - } else { - LogUtils.d("DomManager", "Create Node DomManager Parent IS Null"); - } - - } - - private boolean isTouchEvent(HippyMap props) { - if (props == null) { - return false; - } - Set sets = props.keySet(); - for (String key : sets) { - if (NodeProps.isTouchEventProp(key)) { - return true; - } - } - return false; - } - - public void postWarmLayout(Layout layout) { - if (mLayoutHelper != null) { - mLayoutHelper.postWarmLayout(layout); - } - } - - @Override - public void onEngineResume() { - mEnginePaused = false; - } - - @Override - public void onEnginePause() { - mEnginePaused = true; - } - - private ViewIndex findNativeViewIndex(DomNode nativeParentNode, DomNode node, int index) { - - for (int i = 0; i < nativeParentNode.getChildCount(); i++) { - DomNode childNode = nativeParentNode.getChildAt(i); - if (childNode == node) { - return new ViewIndex(true, index); - } - - if (childNode.isJustLayout()) { - ViewIndex viewIndex = findNativeViewIndex(childNode, node, index); - if (viewIndex.mResult) { - return viewIndex; - } else { - index = viewIndex.mIndex; - } - } else { - index++; - } - } - return new ViewIndex(false, index); - } - - DomNode findNativeViewParent(DomNode domNode) { - DomNode nativeParent = domNode.getParent(); - while (nativeParent.isJustLayout()) { - nativeParent = nativeParent.getParent(); - } - return nativeParent; - } - - @SuppressWarnings("unused") - public void removeRootNode(int tag) { - mNodeRegistry.removeRootNode(tag); - } - - @SuppressWarnings("unused") - public boolean existNode(int tag) { - return mNodeRegistry.getNode(tag) != null; - } - - public void updateNode(final int id, HippyMap map, HippyRootView hippyRootView) { - DomNode node = mNodeRegistry.getNode(id); - - // 这个日志暴多 - // LogUtils.d(TAG, "dom updateNode node id: " + id + "node is not null:" + (node != null) + " params:" + map.toString()); - - if (node != null) { - if (mActionInterceptors != null) { - for (DomActionInterceptor interceptor : mActionInterceptors) { - map = interceptor.onUpdateNode(id, hippyRootView, map); - } - } - HippyMap props = map; - - HippyMap hippyMap = DiffUtils.diffProps(node.getTotalProps(), props, 0); - - node.setProps(props); - - //noinspection unchecked - mDomStyleUpdateManager.updateStyle(node, hippyMap); - - boolean layoutOnlyHasChanged = - node.isJustLayout() && (!jsJustLayout((HippyMap) props.get(NodeProps.STYLE)) - || isTouchEvent(props)); - - if (layoutOnlyHasChanged) { - changeJustLayout2View(node, props, hippyRootView); - } else if (!node.isJustLayout()) { - if (!node.isVirtual()) { - // final HippyMap newProps = props.copy(); - final HippyMap newProps = props; - addUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager.updateNode(id, newProps); - } - }); - } - } - } else { - LogUtils.d(TAG, "update error node is null id " + id); - - mContext.getGlobalConfigs().getLogAdapter().log(TAG, "update error node is null id " + id); - } - } - - private void changeJustLayout2View(final DomNode node, final HippyMap hippyMap, - final HippyRootView hippyRootView) { - - //step1: create child - final DomNode reallyParent = findNativeViewParent(node); - - final ViewIndex viewIndex = findNativeViewIndex(reallyParent, node, 0); - - if (!node.isVirtual()) { - addUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager - .createNode(hippyRootView, node.getId(), reallyParent.getId(), viewIndex.mIndex, - node.getViewClass(), - hippyMap); - } - }); - } - //step2: move child - final ArrayList moveIds = new ArrayList<>(); - node.markUpdated(); - findMoveChildren(node, moveIds); - node.setIsJustLayout(false); - - if (!node.isVirtual()) { - addUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager.moveNode(moveIds, reallyParent.getId(), node.getId()); - } - }); - } - //step3:updateStyle Layout - applyLayoutUpdateRecursive(node); - mTagsWithLayoutVisited.clear(); - - } - - private void findMoveChildren(DomNode node, ArrayList remove) { - - for (int i = 0; i < node.getChildCount(); i++) { - DomNode childNode = node.getChildAt(i); - - if (childNode.isJustLayout()) { - findMoveChildren(childNode, remove); - } else { - childNode.markUpdated(); - remove.add(childNode.getId()); - } - - } - } - - void deleteNode(DomNode node) { - //这里来拦截所有deleteNode(包括它的子node)操作 - if (mActionInterceptors != null) { - for (DomActionInterceptor interceptor : mActionInterceptors) { - interceptor.onDeleteNode(node.getId()); - } - } - - int count = node.getChildCount(); - for (int i = 0; i < count; i++) { - deleteNode(node.getChildAt(i)); - } - if (TextUtils.equals(NodeProps.ROOT_NODE, node.getViewClass())) { - mNodeRegistry.removeRootNode(node.getId()); - } - mNodeRegistry.removeNode(node.getId()); - LogUtils.d(TAG, "dom deleteNode remove form mNodeRegistry node.getId() " + node.getId()); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"dom deleteNode remove form mNodeRegistry node.getId() " + node.getId()); - } - - public void deleteNode(final int id) { - DomNode node = mNodeRegistry.getNode(id); - LogUtils.d(TAG, "dom deleteNode delete node.getId() " + id); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"dom deleteNode delete node.getId() " + id); - if (node != null) { - if (node.isJustLayout()) { - deleteJustLayoutChild(node); - } else { - if (!node.isVirtual()) { - addUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager.deleteNode(id); - } - }); - } - } - DomNode parentNode = node.getParent(); - if (parentNode != null) { - int index = parentNode.indexOf(node); - parentNode.removeChildAt(index); - } - deleteNode(node); - } else { - LogUtils.e(TAG, "dom deleteNode delete node is null node.getId() " + id); - - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"dom deleteNode delete node is null node.getId() " + id); - } - - - } - - private void deleteJustLayoutChild(DomNode node) { - for (int i = 0; i < node.getChildCount(); i++) { - final DomNode childNode = node.getChildAt(i); - if (childNode.isJustLayout()) { - deleteJustLayoutChild(childNode); - } else { - if (!childNode.isVirtual()) { - addUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager.deleteNode(childNode.getId()); - } - }); - - } - } - } - } - - private void addUITask(IDomExecutor executor) { - mUITasks.add(executor); - } - - private void addNulUITask(IDomExecutor executor) { - - if (mRenderBatchStarted) { - mPaddingNulUITasks.add(executor); - } else { - synchronized (mDispatchLock) { - addDispatchTask(executor); - } - } - } - - private void addDispatchTask(IDomExecutor executor) { - - if (mIsDestroyed) { - return; - } - - mDispatchRunnable.add(executor); - - if (!mIsDispatchUIFrameCallbackEnqueued) { - mIsDispatchUIFrameCallbackEnqueued = true; - if (UIThreadUtils.isOnUiThread()) { - HippyChoreographer.getInstance().postFrameCallback(mDispatchUIFrameCallback); - } else { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - HippyChoreographer.getInstance().postFrameCallback(mDispatchUIFrameCallback); - } - }); - } - } - } - - private void applyLayoutUpdateRecursive(final DomNode domStyle) { - if (domStyle.hasUpdates()) { - for (int i = 0; i < domStyle.getChildCount(); i++) { - applyLayoutUpdateRecursive(domStyle.getChildAt(i)); - } - - if (domStyle.getData() != null) { - final TextNode textNode = (TextNode) domStyle; - if (!domStyle.isVirtual()) { - addUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager.updateExtra(domStyle.getId(), - new TextExtra(domStyle.getData(), textNode.getPadding(FlexSpacing.START), - textNode.getPadding(FlexSpacing.END), - textNode.getPadding(FlexSpacing.BOTTOM), - textNode.getPadding(FlexSpacing.TOP))); - } - }); - } - } - - if (!TextUtils.equals(NodeProps.ROOT_NODE, domStyle.getViewClass())) { - applyLayout(domStyle); - } - if (domStyle.shouldNotifyOnLayout()) { - notifyLayout(domStyle); - } - domStyle.markUpdateSeen(); - } - } - - private void notifyLayout(DomNode domStyle) { - if (mContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) != null) { - if (!Float.isNaN(domStyle.getLayoutX()) && !Float.isNaN(domStyle.getLayoutY()) && !Float - .isNaN(domStyle.getLayoutWidth()) - && !Float.isNaN(domStyle.getLayoutHeight())) { - HippyMap onLayoutMap = new HippyMap(); - onLayoutMap.pushObject("x", (int) PixelUtil.px2dp(domStyle.getLayoutX())); - onLayoutMap.pushObject("y", (int) PixelUtil.px2dp(domStyle.getLayoutY())); - onLayoutMap.pushObject("width", (int) PixelUtil.px2dp(domStyle.getLayoutWidth())); - onLayoutMap.pushObject("height", (int) PixelUtil.px2dp(domStyle.getLayoutHeight())); - - HippyMap event = new HippyMap(); - - event.pushMap("layout", onLayoutMap); - event.pushInt("target", domStyle.getId()); - mContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(domStyle.getId(), "onLayout", event); - } - } - } - - private void applyLayout(DomNode domStyle) { - - int tag = domStyle.getId(); - if (mTagsWithLayoutVisited.get(tag)) { - return; - } - mTagsWithLayoutVisited.put(tag, true); - - float x = domStyle.getLayoutX(); - float y = domStyle.getLayoutY(); - - DomNode parent = domStyle.getParent(); - while (parent != null && parent.isJustLayout()) { - x += parent.getLayoutX(); - y += parent.getLayoutY(); - parent = parent.getParent(); - } - - applyLayoutXY(domStyle, x, y); - - } - - private void applyLayoutXY(final DomNode domStyle, final float x, final float y) { - if (!domStyle.isJustLayout() && !domStyle.isVirtual()) { - // final int pos[] = findReallyXY(domStyle); - if (domStyle.shouldUpdateLayout(x, y)) { - addUITask(new IDomExecutor() { - @Override - public void exec() { - - int newLeft = Math.round(x); - int newTop = Math.round(y); - int newRight = Math.round(x + domStyle.getLayoutWidth()); - int newBottom = Math.round(y + domStyle.getLayoutHeight()); - - int newWidth = newRight - newLeft; - - int newHeight = newBottom - newTop; - - mRenderManager.updateLayout(domStyle.getId(), newLeft, newTop, newWidth, newHeight); - } - }); - } - return; - } - - for (int i = 0; i < domStyle.getChildCount(); i++) { - DomNode child = domStyle.getChildAt(i); - int childTag = child.getId(); - if (mTagsWithLayoutVisited.get(childTag)) { - continue; - } - mTagsWithLayoutVisited.put(childTag, true); - - float childX = child.getLayoutX(); - float childY = child.getLayoutY(); - - childX += x; - childY += y; - - applyLayoutXY(child, childX, childY); - } - } - - void applyLayoutBefore(DomNode domNode) { - if (domNode != null && domNode.hasUpdates()) { - for (int i = 0; i < domNode.getChildCount(); i++) { - applyLayoutBefore(domNode.getChildAt(i)); - } - domNode.layoutBefore(mContext); - } - } - - void applyLayoutAfter(DomNode domNode) { - - if (domNode != null && domNode.hasUpdates()) { - for (int i = 0; i < domNode.getChildCount(); i++) { - applyLayoutAfter(domNode.getChildAt(i)); - } - domNode.layoutAfter(mContext); - } - } - - public void batch() { - batch(false); - } - - public void batch(boolean isAnimation) { - int rootNodeCount = mNodeRegistry.getRootNodeCount(); - - for (int i = 0; i < rootNodeCount; i++) { - int rootTag = mNodeRegistry.getRootTag(i); - DomNode rootNode = mNodeRegistry.getNode(rootTag); - if (rootNode != null) { - applyLayoutBefore(rootNode); - - LogUtils.d(TAG, " dom start calculateLayout"); - - rootNode.calculateLayout(); - - applyLayoutAfter(rootNode); - - applyLayoutUpdateRecursive(rootNode); - - LogUtils.d(TAG, "dom end calculateLayout"); - // LogUtils.l(TAG, rootNode.toString()); - } - } - - mTagsWithLayoutVisited.clear(); - LogUtils.d(TAG, "dom batch complete"); - - synchronized (mDispatchLock) { - for (int i = 0; i < mUITasks.size(); i++) { - addDispatchTask(mUITasks.get(i)); - } - - for (int i = 0; i < mPaddingNulUITasks.size(); i++) { - addDispatchTask(mPaddingNulUITasks.get(i)); - } - - } - mPaddingNulUITasks.clear(); - mUITasks.clear(); - - if (mBatchListener != null) { - mBatchListener.onBatch(isAnimation); - } - } - - void flushPendingBatches() { - - if (mEnginePaused) { - mIsDispatchUIFrameCallbackEnqueued = false; - } else { - HippyChoreographer.getInstance().postFrameCallback(mDispatchUIFrameCallback); - } - - synchronized (mDispatchLock) { - Iterator iterator = mDispatchRunnable.iterator(); - boolean shouldBatch = mDispatchRunnable.size() > 0; - long startTime = System.currentTimeMillis(); - while (iterator.hasNext()) { - IDomExecutor iDomExecutor = iterator.next(); - if (iDomExecutor != null && !mIsDestroyed) { - try { - iDomExecutor.exec(); - } catch (RuntimeException e) { - e.printStackTrace(); - // mContext.handleException(e); - } - } - iterator.remove(); - if (mIsDispatchUIFrameCallbackEnqueued) { - if (System.currentTimeMillis() - startTime > 500) { - break; - } - } - } - if (shouldBatch) { - mRenderManager.batch(); - } - } - - } - - public void dispatchUIFunction(final int id, final String functionName, final HippyArray array, - final Promise promise) { - addNulUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager.dispatchUIFunction(id, functionName, array, promise); - } - }); - } - - public void measureInWindow(final int id, final Promise promise) { - addNulUITask(new IDomExecutor() { - @Override - public void exec() { - mRenderManager.measureInWindow(id, promise); - } - }); - } - - static class ViewIndex { - - public final boolean mResult; - public final int mIndex; - - public ViewIndex(boolean mResult, int mIndex) { - this.mResult = mResult; - this.mIndex = mIndex; - } - } - - @SuppressWarnings("unused") - private class DispatchUIFrameCallback implements HippyChoreographer.FrameCallback { - - @Override - public void doFrame(long frameTimeNanos) { - flushPendingBatches(); - } - } - - public void setOnBatchListener(BatchListener listener) { - mBatchListener = listener; - } - - public interface BatchListener { - - void onBatch(boolean isAnimation); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomNodeRegistry.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomNodeRegistry.java deleted file mode 100644 index 37c8d9fd9b5..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomNodeRegistry.java +++ /dev/null @@ -1,74 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom; - -import android.util.SparseArray; -import android.util.SparseBooleanArray; - -import com.tencent.mtt.hippy.dom.node.DomNode; - -public class DomNodeRegistry { - - private final SparseArray mNodeTags; - private final SparseBooleanArray mRootTags; - - public DomNodeRegistry() { - mNodeTags = new SparseArray<>(); - mRootTags = new SparseBooleanArray(); - } - - public synchronized void removeNode(int tag) { - mNodeTags.remove(tag); - } - - public synchronized void addRootNode(DomNode node) { - int tag = node.getId(); - mNodeTags.put(tag, node); - mRootTags.put(tag, true); - } - - public synchronized void removeRootNode(int tag) { - mNodeTags.remove(tag); - mRootTags.delete(tag); - } - - public synchronized void addNode(DomNode node) { - mNodeTags.put(node.getId(), node); - } - - public synchronized DomNode getNode(int tag) { - return mNodeTags.get(tag); - } - - @SuppressWarnings("unused") - public synchronized boolean isRootNode(int tag) { - return mRootTags.get(tag); - } - - public synchronized int getRootNodeCount() { - return mRootTags.size(); - } - - public synchronized int getRootTag(int index) { - return mRootTags.keyAt(index); - } - - public synchronized void clear() { - mNodeTags.clear(); - mRootTags.clear(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomUpdateManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomUpdateManager.java deleted file mode 100644 index b66ced795e3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/DomUpdateManager.java +++ /dev/null @@ -1,134 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom; - -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.utils.ArgumentUtils; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -@SuppressWarnings({"deprecation", "unused", "rawtypes"}) -public class DomUpdateManager { - - static final Map> CLASS_STYLE_METHOD = new HashMap<>(); - - public void updateStyle(T t, HippyMap hippyMap) { - if (hippyMap == null) { - return; - } - Class cla = t.getClass(); - - Map methods = CLASS_STYLE_METHOD.get(cla); - if (methods == null) { - methods = findStyleMethod(cla); - } - Set styles = hippyMap.keySet(); - for (String style : styles) { - StyleMethod styleMethodHolder = methods.get(style); - if (styleMethodHolder != null) { - { - try { - if (hippyMap.get(style) == null) { - switch (styleMethodHolder.mDefaultType) { - case HippyControllerProps.BOOLEAN: - styleMethodHolder.mMethod.invoke(t, styleMethodHolder.mDefaultBoolean); - break; - case HippyControllerProps.NUMBER: - styleMethodHolder.mMethod.invoke(t, - ArgumentUtils.parseArgument(styleMethodHolder.mParamTypes[0], - styleMethodHolder.mDefaultNumber)); - break; - case HippyControllerProps.STRING: - styleMethodHolder.mMethod.invoke(t, styleMethodHolder.mDefaultString); - break; - default: - Object o = null; - //noinspection ConstantConditions - styleMethodHolder.mMethod.invoke(t, o); - break; - } - } else { - styleMethodHolder.mMethod.invoke(t, - ArgumentUtils.parseArgument(styleMethodHolder.mParamTypes[0], hippyMap, style)); - } - } catch (Throwable e) { - LogUtils.e("ControllerUpdateManager", e.getMessage(), e); - e.printStackTrace(); - } - } - } else { - if (hippyMap.get(style) instanceof HippyMap && style.equals(NodeProps.STYLE)) { - updateStyle(t, (HippyMap) hippyMap.get(style)); - } - } - } - } - - private void findStyleMethod(Class cls, Map hashMap) { - if (cls != StyleNode.class) { - // find parent methods first - findStyleMethod(cls.getSuperclass(), hashMap); - } - Map methodHolder = CLASS_STYLE_METHOD.get(cls); - if (methodHolder == null) { - Method[] methods = cls.getDeclaredMethods(); - for (Method method : methods) { - HippyControllerProps controllerProps = method.getAnnotation(HippyControllerProps.class); - if (controllerProps != null) { - String style = controllerProps.name(); - StyleMethod propsMethodHolder = new StyleMethod(); - propsMethodHolder.mDefaultNumber = controllerProps.defaultNumber(); - propsMethodHolder.mDefaultType = controllerProps.defaultType(); - propsMethodHolder.mDefaultString = controllerProps.defaultString(); - propsMethodHolder.mDefaultBoolean = controllerProps.defaultBoolean(); - propsMethodHolder.mMethod = method; - propsMethodHolder.mParamTypes = method.getGenericParameterTypes(); - hashMap.put(style, propsMethodHolder); - } - } - // put to CLASS_PROPS_METHOD - CLASS_STYLE_METHOD.put(cls, new HashMap<>(hashMap)); - } else { - hashMap.putAll(methodHolder); - } - - } - - private Map findStyleMethod(Class cla) { - Map hashMap = new HashMap<>(); - findStyleMethod(cla, hashMap); - return hashMap; - } - - public static class StyleMethod { - - Method mMethod; - String mDefaultType; - String mDefaultString; - double mDefaultNumber; - boolean mDefaultBoolean; - Type[] mParamTypes; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/HippyChoreographer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/HippyChoreographer.java deleted file mode 100644 index 17faa195e40..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/HippyChoreographer.java +++ /dev/null @@ -1,99 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom; - -import com.tencent.mtt.hippy.utils.LogUtils; -import java.util.ArrayDeque; - -/** - * A simple wrapper around Choreographer that allows us to control the order certain callbacks are - * executed within a given frame. The main difference is that we enforce this is accessed from the - * UI thread: this is because this ordering cannot be guaranteed across multiple threads. - */ -public class HippyChoreographer { - - public interface FrameCallback { - - void doFrame(long frameTimeNanos); - } - - - private static HippyChoreographer sInstance; - - public static HippyChoreographer getInstance() { - if (sInstance == null) { - sInstance = new HippyChoreographer(); - } - return sInstance; - } - - private final HippyChoreographerDispatcher mReactChoreographerDispatcher; - final ArrayDeque mCallbackQueues; - - int mTotalCallbacks = 0; - boolean mHasPostedCallback = false; - - private HippyChoreographer() { - mReactChoreographerDispatcher = new HippyChoreographerDispatcher(); - mCallbackQueues = new ArrayDeque<>(); - } - - public void postFrameCallback(FrameCallback frameCallback) { - if (!mCallbackQueues.contains(frameCallback)) { - mCallbackQueues.addLast(frameCallback); - mTotalCallbacks++; - if (!mHasPostedCallback) { - try { - ChoreographerCompat.getInstance().postFrameCallback(mReactChoreographerDispatcher); - mHasPostedCallback = true; - } catch (Exception e) { - LogUtils.d("HippyChoreographer", "postFrameCallback: " + e.getMessage()); - } - } - } - } - - public void removeFrameCallback(FrameCallback frameCallback) { - if (mCallbackQueues.removeFirstOccurrence(frameCallback)) { - mTotalCallbacks--; - maybeRemoveFrameCallback(); - } - } - - void maybeRemoveFrameCallback() { - if (mTotalCallbacks == 0 && mHasPostedCallback) { - ChoreographerCompat.getInstance().removeFrameCallback(mReactChoreographerDispatcher); - mHasPostedCallback = false; - } - } - - @SuppressWarnings({"unused"}) - private class HippyChoreographerDispatcher implements FrameCallback { - - @Override - public void doFrame(long frameTimeNanos) { - mHasPostedCallback = false; - int initialLength = mCallbackQueues.size(); - for (int callback = 0; callback < initialLength; callback++) { - mCallbackQueues.removeFirst().doFrame(frameTimeNanos); - mTotalCallbacks--; - } - maybeRemoveFrameCallback(); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/ICSChoreographer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/ICSChoreographer.java deleted file mode 100644 index ffbeb8e9a27..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/ICSChoreographer.java +++ /dev/null @@ -1,618 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.SystemClock; -import android.util.Log; -import android.view.Choreographer; -import android.view.View; - -/** - * Coordinates the timing of animations, input and drawing. - *

- * The choreographer receives timing pulses (such as vertical synchronization) from the display - * subsystem then schedules work to occur as part of rendering the next display frame. - *

- *

- * Applications typically interact with the choreographer indirectly using higher level abstractions - * in the animation framework or the view hierarchy. Here are some examples of things you can do - * using the higher-level APIs. - *

- *
    - *
  • To post an animation to be processed on a regular time basis synchronized - * with - * display frame rendering, use {@link android.animation.ValueAnimator#start}. - *
  • - *
  • To post a {@link Runnable} to be invoked once at the beginning of the - * next display - * frame, use {@link View#postOnAnimation}.
  • - *
  • To post a {@link Runnable} to be invoked once at the beginning of the - * next display - * frame after a delay, use {@link View#postOnAnimationDelayed}.
  • - *
  • To post a call to {@link View#invalidate()} to occur once at the - * beginning of the - * next display frame, use {@link View#postInvalidateOnAnimation()} or - * {@link View#postInvalidateOnAnimation(int, int, int, int)}.
  • - *
  • To ensure that the contents of a {@link View} scroll smoothly and are - * drawn in - * sync with display frame rendering, do nothing. This already happens - * automatically. - * will be called at the appropriate time.
  • - *
- *

- * However, there are a few cases where you might want to use the functions of - * the - * choreographer directly in your application. Here are some examples. - *

- *
    - *
  • If your application does its rendering in a different thread, possibly - * using GL, - * or does not use the animation framework or view hierarchy at all - * and you want to ensure that it is appropriately synchronized with the - * display, then use - * {@link Choreographer#postFrameCallback}.
  • - *
  • ... and that's about it.
  • - *
- *

- * Each {@link Looper} thread has its own choreographer. Other threads can - * post callbacks to run on the choreographer but they will run on the - * {@link Looper} - * to which the choreographer belongs. - *

- */ -@SuppressWarnings({"unused"}) -public final class ICSChoreographer { - - private static final String TAG = "Choreographer"; - private static final boolean DEBUG = false; - - private static final long DEFAULT_FRAME_DELAY = 10; - - // Thread local storage for the choreographer. - private static final ThreadLocal sThreadInstance = new ThreadLocal() { - @Override - protected ICSChoreographer initialValue() { - Looper looper = Looper.myLooper(); - if (looper == null) { - throw new IllegalStateException( - "The current thread must have a looper!"); - } - return new ICSChoreographer(looper); - } - }; - - // Enable/disable vsync for animations and drawing. - private static final boolean USE_VSYNC = false; - - // Enable/disable using the frame time instead of returning now. - private static final boolean USE_FRAME_TIME = true; - - // Set a limit to warn about skipped frames. - // Skipped frames imply jank. - private static final int SKIPPED_FRAME_WARNING_LIMIT = 30; - - private static final long NANOS_PER_MS = 1000000; - - private static final int MSG_DO_FRAME = 0; - private static final int MSG_DO_SCHEDULE_VSYNC = 1; - private static final int MSG_DO_SCHEDULE_CALLBACK = 2; - - // All frame callbacks posted by applications have this token. - static final Object FRAME_CALLBACK_TOKEN = new Object() { - public String toString() { - return "FRAME_CALLBACK_TOKEN"; - } - }; - - private final Object mLock = new Object(); - - private final Looper mLooper; - private final FrameHandler mHandler; - - // The display event receiver can only be accessed by the looper thread to - // which - // it is attached. We take care to ensure that we post message to the looper - // if appropriate when interacting with the display event receiver. - private final FrameDisplayEventReceiver mDisplayEventReceiver; - - private CallbackRecord mCallbackPool; - - private final CallbackQueue[] mCallbackQueues; - - private boolean mFrameScheduled; - private long mLastFrameTimeNanos; - private final long mFrameIntervalNanos; - - public static final int CALLBACK_INPUT = 0; - - public static final int CALLBACK_ANIMATION = 1; - - public static final int CALLBACK_TRAVERSAL = 2; - - private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL; - - private ICSChoreographer(Looper looper) { - mLooper = looper; - mHandler = new FrameHandler(looper); - mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; - mLastFrameTimeNanos = Long.MIN_VALUE; - - mFrameIntervalNanos = (long) (1000000000 / getRefreshRate()); - - mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; - for (int i = 0; i <= CALLBACK_LAST; i++) { - mCallbackQueues[i] = new CallbackQueue(); - } - } - - @SuppressWarnings("SameReturnValue") - private static float getRefreshRate() { - return 60; - } - - /** - * Gets the choreographer for the calling thread. Must be called from a thread that already has a - * {@link android.os.Looper} associated with it. - * - * @return The choreographer for this thread. - * @throws IllegalStateException if the thread does not have a looper. - */ - public static ICSChoreographer getInstance() { - return sThreadInstance.get(); - } - - @SuppressWarnings("SameParameterValue") - private void postCallbackDelayedInternal(int callbackType, Object action, Object token, - long delayMillis) { - if (DEBUG) { - Log.d(TAG, "PostCallback: type=" + callbackType + ", action=" + action + ", token=" + token - + ", delayMillis=" + delayMillis); - } - - synchronized (mLock) { - final long now = SystemClock.uptimeMillis(); - final long dueTime = now + delayMillis; - mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); - - if (dueTime <= now) { - scheduleFrameLocked(now); - } else { - Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); - msg.arg1 = callbackType; - // msg.setAsynchronous(true); - mHandler.sendMessageAtTime(msg, dueTime); - } - } - } - - @SuppressWarnings("SameParameterValue") - private void removeCallbacksInternal(int callbackType, Object action, Object token) { - if (DEBUG) { - Log.d(TAG, - "RemoveCallbacks: type=" + callbackType + ", action=" + action + ", token=" + token); - } - - synchronized (mLock) { - mCallbackQueues[callbackType].removeCallbacksLocked(action, token); - if (action != null && token == null) { - mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action); - } - } - } - - /** - * Posts a frame callback to run on the next frame. - *

- * The callback runs once then is automatically removed. - *

- * - * @param callback The frame callback to run during the next frame. - * @see #postFrameCallbackDelayed - * @see #removeFrameCallback - */ - public void postFrameCallback(HippyChoreographer.FrameCallback callback) { - postFrameCallbackDelayed(callback, 0); - } - - /** - * Posts a frame callback to run on the next frame after the specified delay. - *

- * The callback runs once then is automatically removed. - *

- * - * @param callback The frame callback to run during the next frame. - * @param delayMillis The delay time in milliseconds. - * @see #postFrameCallback - * @see #removeFrameCallback - */ - public void postFrameCallbackDelayed(HippyChoreographer.FrameCallback callback, - long delayMillis) { - if (callback == null) { - throw new IllegalArgumentException("callback must not be null"); - } - - postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN, delayMillis); - } - - /** - * Removes a previously posted frame callback. - * - * @param callback The frame callback to remove. - * @see #postFrameCallback - * @see #postFrameCallbackDelayed - */ - public void removeFrameCallback(HippyChoreographer.FrameCallback callback) { - if (callback == null) { - throw new IllegalArgumentException("callback must not be null"); - } - - removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN); - } - - private void scheduleFrameLocked(long now) { - if (!mFrameScheduled) { - mFrameScheduled = true; - if (USE_VSYNC) { - if (DEBUG) { - Log.d(TAG, "Scheduling next frame on vsync."); - } - - // If running on the Looper thread, then schedule the vsync - // immediately, - // otherwise post a message to schedule the vsync from the UI - // thread - // as soon as possible. - if (isRunningOnLooperThreadLocked()) { - scheduleVsyncLocked(); - } else { - Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); - // msg.setAsynchronous(true); - mHandler.sendMessageAtFrontOfQueue(msg); - } - } else { - final long nextFrameTime = Math - .max(mLastFrameTimeNanos / NANOS_PER_MS + DEFAULT_FRAME_DELAY, now); - if (DEBUG) { - Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); - } - Message msg = mHandler.obtainMessage(MSG_DO_FRAME); - // msg.setAsynchronous(true); - mHandler.sendMessageAtTime(msg, nextFrameTime); - } - } - } - - void doFrame(long frameTimeNanos, int frame) { - final long startNanos; - synchronized (mLock) { - if (!mFrameScheduled) { - return; // no work to do - } - - startNanos = System.nanoTime(); - final long jitterNanos = startNanos - frameTimeNanos; - if (jitterNanos >= mFrameIntervalNanos) { - final long skippedFrames = jitterNanos / mFrameIntervalNanos; - if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { - Log.i(TAG, "Skipped " + skippedFrames + " frames! " - + "The application may be doing too much work on its main thread."); - } - final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; - if (DEBUG) { - Log.d(TAG, - "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " - + "which is more than the frame interval of " - + (mFrameIntervalNanos * 0.000001f) + " ms! " + "Skipping " + skippedFrames - + " frames and setting frame " - + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); - } - frameTimeNanos = startNanos - lastFrameOffset; - } - - if (frameTimeNanos < mLastFrameTimeNanos) { - if (DEBUG) { - Log.d(TAG, "Frame time appears to be going backwards. May be due to a " - + "previously skipped frame. Waiting for next vsync."); - } - scheduleVsyncLocked(); - return; - } - - mFrameScheduled = false; - mLastFrameTimeNanos = frameTimeNanos; - } - - doCallbacks(0, frameTimeNanos); - doCallbacks(1, frameTimeNanos); - doCallbacks(2, frameTimeNanos); - - if (DEBUG) { - final long endNanos = System.nanoTime(); - Log.d(TAG, "Frame " + frame + ": Finished, took " + (endNanos - startNanos) * 0.000001f - + " ms, latency " - + (startNanos - frameTimeNanos) * 0.000001f + " ms."); - } - } - - void doCallbacks(int callbackType, long frameTimeNanos) { - CallbackRecord callbacks; - synchronized (mLock) { - // We use "now" to determine when callbacks become due because it's - // possible - // for earlier processing phases in a frame to post callbacks that - // should run - // in a following phase, such as an input event that causes an - // animation to start. - final long now = SystemClock.uptimeMillis(); - callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now); - if (callbacks == null) { - return; - } - } - try { - for (CallbackRecord c = callbacks; c != null; c = c.next) { - if (DEBUG) { - Log.d(TAG, - "RunCallback: type=" + callbackType + ", action=" + c.action + ", token=" + c.token - + ", latencyMillis=" - + (SystemClock.uptimeMillis() - c.dueTime)); - } - c.run(frameTimeNanos); - } - } finally { - synchronized (mLock) { - do { - final CallbackRecord next = callbacks.next; - recycleCallbackLocked(callbacks); - callbacks = next; - } - while (callbacks != null); - } - } - } - - void doScheduleVsync() { - synchronized (mLock) { - if (mFrameScheduled) { - scheduleVsyncLocked(); - } - } - } - - void doScheduleCallback(int callbackType) { - synchronized (mLock) { - if (!mFrameScheduled) { - final long now = SystemClock.uptimeMillis(); - if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) { - scheduleFrameLocked(now); - } - } - } - } - - private void scheduleVsyncLocked() { - mDisplayEventReceiver.scheduleVsync(); - } - - private boolean isRunningOnLooperThreadLocked() { - return Looper.myLooper() == mLooper; - } - - CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) { - CallbackRecord callback = mCallbackPool; - if (callback == null) { - callback = new CallbackRecord(); - } else { - mCallbackPool = callback.next; - callback.next = null; - } - callback.dueTime = dueTime; - callback.action = action; - callback.token = token; - return callback; - } - - void recycleCallbackLocked(CallbackRecord callback) { - callback.action = null; - callback.token = null; - callback.next = mCallbackPool; - mCallbackPool = callback; - } - - /** - * Implement this interface to receive a callback when a new display frame is being rendered. The - * callback is invoked on the {@link Looper} thread to - */ - - private final class FrameHandler extends Handler { - - public FrameHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_DO_FRAME: - doFrame(System.nanoTime(), 0); - break; - case MSG_DO_SCHEDULE_VSYNC: - doScheduleVsync(); - break; - case MSG_DO_SCHEDULE_CALLBACK: - doScheduleCallback(msg.arg1); - break; - } - } - } - - private final class FrameDisplayEventReceiver implements Runnable { - - private boolean mHavePendingVsync; - private long mTimestampNanos; - private int mFrame; - private final Handler mHandler; - - public FrameDisplayEventReceiver(Looper looper) { - mHandler = new Handler(looper); - } - - public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { - // Ignore vsync from secondary display. - // This can be problematic because the call to scheduleVsync() is a - // one-shot. - // We need to ensure that we will still receive the vsync from the - // primary - // display which is the one we really care about. Ideally we should - // schedule - // vsync for a particular display. - // At this time Surface Flinger won't send us vsyncs for secondary - // displays - // but that could change in the future so let's log a message to - // help us remember - // that we need to fix this. - - // Post the vsync event to the Handler. - // The idea is to prevent incoming vsync events from completely - // starving - // the message queue. If there are no messages in the queue with - // timestamps - // earlier than the frame time, then the vsync event will be - // processed immediately. - // Otherwise, messages that predate the vsync event will be handled - // first. - long now = System.nanoTime(); - if (timestampNanos > now) { - Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) - + " ms in the future! Check that graphics HAL is generating vsync " - + "timestamps using the correct timebase."); - timestampNanos = now; - } - - if (mHavePendingVsync) { - Log.w(TAG, "Already have a pending vsync event. There should only be " + "one at a time."); - } else { - mHavePendingVsync = true; - } - - mTimestampNanos = timestampNanos; - mFrame = frame; - Message msg = Message.obtain(mHandler, this); - // msg.setAsynchronous(true); - mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS); - } - - @Override - public void run() { - mHavePendingVsync = false; - doFrame(mTimestampNanos, mFrame); - } - - public void scheduleVsync() { - mHandler.postDelayed(this, 16); - } - } - - static final class CallbackRecord { - - public CallbackRecord next; - public long dueTime; - public Object action; // Runnable or FrameCallback - public Object token; - - public void run(long frameTimeNanos) { - if (token == FRAME_CALLBACK_TOKEN) { - ((HippyChoreographer.FrameCallback) action).doFrame(frameTimeNanos); - } else { - ((Runnable) action).run(); - } - } - } - - private final class CallbackQueue { - - private CallbackRecord mHead; - - public boolean hasDueCallbacksLocked(long now) { - return mHead != null && mHead.dueTime <= now; - } - - public CallbackRecord extractDueCallbacksLocked(long now) { - CallbackRecord callbacks = mHead; - if (callbacks == null || callbacks.dueTime > now) { - return null; - } - - CallbackRecord last = callbacks; - CallbackRecord next = last.next; - while (next != null) { - if (next.dueTime > now) { - last.next = null; - break; - } - last = next; - next = next.next; - } - mHead = next; - return callbacks; - } - - public void addCallbackLocked(long dueTime, Object action, Object token) { - CallbackRecord callback = obtainCallbackLocked(dueTime, action, token); - CallbackRecord entry = mHead; - if (entry == null) { - mHead = callback; - return; - } - if (dueTime < entry.dueTime) { - callback.next = entry; - mHead = callback; - return; - } - while (entry.next != null) { - if (dueTime < entry.next.dueTime) { - callback.next = entry.next; - break; - } - entry = entry.next; - } - entry.next = callback; - } - - public void removeCallbacksLocked(Object action, Object token) { - CallbackRecord predecessor = null; - for (CallbackRecord callback = mHead; callback != null; ) { - final CallbackRecord next = callback.next; - if ((action == null || callback.action == action) && (token == null - || callback.token == token)) { - if (predecessor != null) { - predecessor.next = next; - } else { - mHead = next; - } - recycleCallbackLocked(callback); - } else { - predecessor = callback; - } - callback = next; - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/IDomExecutor.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/IDomExecutor.java deleted file mode 100644 index 9758bda1661..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/IDomExecutor.java +++ /dev/null @@ -1,23 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom; - - -public interface IDomExecutor { - - @SuppressWarnings("UnusedReturnValue") - void exec(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexAlign.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexAlign.java deleted file mode 100644 index 97eb15f349c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexAlign.java +++ /dev/null @@ -1,53 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public enum FlexAlign { - AUTO, - FLEX_START, - CENTER, - FLEX_END, - STRETCH, - BASELINE, - SPACE_BETWEEN, - SPACE_AROUND, - ; - - @SuppressWarnings("unused") - public static FlexAlign fromInt(int value) { - switch (value) { - case 0: - return AUTO; - case 1: - return FLEX_START; - case 2: - return CENTER; - case 3: - return FLEX_END; - case 4: - return STRETCH; - case 5: - return BASELINE; - case 6: - return SPACE_BETWEEN; - case 7: - return SPACE_AROUND; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexCSSDirection.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexCSSDirection.java deleted file mode 100644 index ce761c18b13..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexCSSDirection.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public enum FlexCSSDirection { - ROW, - ROW_REVERSE, - COLUMN, - COLUMN_REVERSE; - - @SuppressWarnings("unused") - public static FlexCSSDirection fromInt(int value) { - switch (value) { - case 0: - return ROW; - case 1: - return ROW_REVERSE; - case 2: - return COLUMN; - case 3: - return COLUMN_REVERSE; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexConstants.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexConstants.java deleted file mode 100644 index 10d3bc3c763..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexConstants.java +++ /dev/null @@ -1,26 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public class FlexConstants { - - public static final float UNDEFINED = Float.NaN; - - public static boolean isUndefined(float value) { - return Float.compare(value, UNDEFINED) == 0; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexDirection.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexDirection.java deleted file mode 100644 index 1d8733f2f08..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexDirection.java +++ /dev/null @@ -1,36 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public enum FlexDirection { - INHERIT, - LTR, - RTL; - - @SuppressWarnings("unused") - public static FlexDirection fromInt(int value) { - switch (value) { - case 0: - return INHERIT; - case 1: - return LTR; - case 2: - return RTL; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexJustify.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexJustify.java deleted file mode 100644 index 7ab2ece0164..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexJustify.java +++ /dev/null @@ -1,42 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public enum FlexJustify { - FLEX_START, - CENTER, - FLEX_END, - SPACE_BETWEEN, - SPACE_AROUND; - - @SuppressWarnings("unused") - public static FlexJustify fromInt(int value) { - switch (value) { - case 0: - return FLEX_START; - case 1: - return CENTER; - case 2: - return FLEX_END; - case 3: - return SPACE_BETWEEN; - case 4: - return SPACE_AROUND; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexMeasureMode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexMeasureMode.java deleted file mode 100644 index 521b5ceec79..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexMeasureMode.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public enum FlexMeasureMode { - UNDEFINED, - EXACTLY, - AT_MOST; - - public static FlexMeasureMode fromInt(int value) { - switch (value) { - case 0: - return UNDEFINED; - case 1: - return EXACTLY; - case 2: - return AT_MOST; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexNodeAPI.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexNodeAPI.java deleted file mode 100644 index b958b384cbd..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexNodeAPI.java +++ /dev/null @@ -1,166 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -import com.tencent.smtt.flexbox.FlexNodeStyle; - -@SuppressWarnings({"unused", "rawtypes"}) -public interface FlexNodeAPI { - - interface MeasureFunction { - - long measure( - FlexNodeAPI node, - float width, - FlexMeasureMode widthMode, - float height, - FlexMeasureMode heightMode); - } - - int getChildCount(); - - FlexNodeType getChildAt(int i); - - void addChildAt(FlexNodeType child, int i); - - FlexNodeType removeChildAt(int i); - - FlexNodeType getParent(); - - int indexOf(FlexNodeType child); - - void setMeasureFunction(MeasureFunction measureFunction); - - boolean isMeasureDefined(); - - void calculateLayout(); - - boolean isDirty(); - - boolean hasNewLayout(); - - void dirty(); - - void markLayoutSeen(); - - boolean valuesEqual(float f1, float f2); - - FlexDirection getStyleDirection(); - - void setDirection(FlexDirection direction); - - FlexCSSDirection getFlexDirection(); - - void setFlexDirection(FlexCSSDirection flexDirection); - - FlexJustify getJustifyContent(); - - void setJustifyContent(FlexJustify justifyContent); - - FlexAlign getAlignItems(); - - void setAlignItems(FlexAlign alignItems); - - FlexAlign getAlignSelf(); - - void setAlignSelf(FlexAlign alignSelf); - - FlexAlign getAlignContent(); - - void setAlignContent(FlexAlign alignContent); - - FlexPositionType getPositionType(); - - void setPositionType(FlexPositionType positionType); - - void setWrap(FlexWrap flexWrap); - - void setFlex(float flex); - - void setDisplay(FlexNodeStyle.Display display); - - float getFlexGrow(); - - void setFlexGrow(float flexGrow); - - float getFlexShrink(); - - void setFlexShrink(float flexShrink); - - float getFlexBasis(); - - void setFlexBasis(float flexBasis); - - float getMargin(int spacingType); - - void setMargin(int spacingType, float margin); - - float getPadding(int spacingType); - - void setPadding(int spacingType, float padding); - - float getBorder(int spacingType); - - void setBorder(int spacingType, float border); - - float getPosition(int spacingType); - - void setPosition(int spacingType, float position); - - float getStyleWidth(); - - void setStyleWidth(float width); - - float getStyleHeight(); - - void setStyleHeight(float height); - - float getStyleMaxWidth(); - - void setStyleMaxWidth(float maxWidth); - - float getStyleMinWidth(); - - void setStyleMinWidth(float minWidth); - - float getStyleMaxHeight(); - - void setStyleMaxHeight(float maxHeight); - - float getStyleMinHeight(); - - void setStyleMinHeight(float minHeight); - - float getLayoutX(); - - float getLayoutY(); - - float getLayoutWidth(); - - float getLayoutHeight(); - - FlexDirection getLayoutDirection(); - - FlexOverflow getOverflow(); - - void setOverflow(FlexOverflow overflow); - - void setData(Object data); - - Object getData(); - - void reset(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexOutput.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexOutput.java deleted file mode 100644 index 80dc72d4294..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexOutput.java +++ /dev/null @@ -1,38 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -@SuppressWarnings("all") -public class FlexOutput { - - public static long make(float width, float height) { - return make((int) width, (int) height); - } - - public static long make(int width, int height) { - return ((long) width) << 32 | ((long) height); - } - - @SuppressWarnings("PointlessBitwiseExpression") - public static int getWidth(long measureOutput) { - return (int) (0xFFFFFFFF & (measureOutput >> 32)); - } - - @SuppressWarnings("PointlessBitwiseExpression") - public static int getHeight(long measureOutput) { - return (int) (0xFFFFFFFF & measureOutput); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexOverflow.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexOverflow.java deleted file mode 100644 index a6ad78374cf..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexOverflow.java +++ /dev/null @@ -1,36 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public enum FlexOverflow { - VISIBLE, - HIDDEN, - SCROLL; - - @SuppressWarnings("unused") - public static FlexOverflow fromInt(int value) { - switch (value) { - case 0: - return VISIBLE; - case 1: - return HIDDEN; - case 2: - return SCROLL; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexPositionType.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexPositionType.java deleted file mode 100644 index 434cc868a79..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexPositionType.java +++ /dev/null @@ -1,33 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public enum FlexPositionType { - RELATIVE, - ABSOLUTE; - - @SuppressWarnings("unused") - public static FlexPositionType fromInt(int value) { - switch (value) { - case 0: - return RELATIVE; - case 1: - return ABSOLUTE; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexSpacing.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexSpacing.java deleted file mode 100644 index 859de33e9a9..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexSpacing.java +++ /dev/null @@ -1,146 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -import java.util.Arrays; - -@SuppressWarnings("unused") -public class FlexSpacing { - - public static final int LEFT = 0; - - public static final int TOP = 1; - - public static final int RIGHT = 2; - - public static final int BOTTOM = 3; - - public static final int START = 4; - - public static final int END = 5; - - public static final int HORIZONTAL = 6; - - public static final int VERTICAL = 7; - - public static final int ALL = 8; - - private static final int[] sFlagsMap = { - 1, /*LEFT*/ - 2, /*TOP*/ - 4, /*RIGHT*/ - 8, /*BOTTOM*/ - 16, /*START*/ - 32, /*END*/ - 64, /*HORIZONTAL*/ - 128, /*VERTICAL*/ - 256, /*ALL*/ - }; - - private final float[] mSpacing = newFullSpacingArray(); - private int mValueFlags = 0; - private final float mDefaultValue; - private boolean mHasAliasesSet; - - public FlexSpacing() { - this(0); - } - - public FlexSpacing(float defaultValue) { - mDefaultValue = defaultValue; - } - - - public boolean set(int spacingType, float value) { - if (!FloatUtil.floatsEqual(mSpacing[spacingType], value)) { - mSpacing[spacingType] = value; - - if (FlexConstants.isUndefined(value)) { - mValueFlags &= ~sFlagsMap[spacingType]; - } else { - mValueFlags |= sFlagsMap[spacingType]; - } - - mHasAliasesSet = - (mValueFlags & sFlagsMap[ALL]) != 0 || - (mValueFlags & sFlagsMap[VERTICAL]) != 0 || - (mValueFlags & sFlagsMap[HORIZONTAL]) != 0; - - return true; - } - - return false; - } - - public float get(int spacingType) { - float defaultValue = (spacingType == START || spacingType == END - ? FlexConstants.UNDEFINED - : mDefaultValue); - - if (mValueFlags == 0) { - return defaultValue; - } - - if ((mValueFlags & sFlagsMap[spacingType]) != 0) { - return mSpacing[spacingType]; - } - - if (mHasAliasesSet) { - int secondType = spacingType == TOP || spacingType == BOTTOM ? VERTICAL : HORIZONTAL; - if ((mValueFlags & sFlagsMap[secondType]) != 0) { - return mSpacing[secondType]; - } else if ((mValueFlags & sFlagsMap[ALL]) != 0) { - return mSpacing[ALL]; - } - } - - return defaultValue; - } - - - public float getRaw(int spacingType) { - return mSpacing[spacingType]; - } - - - public void reset() { - Arrays.fill(mSpacing, FlexConstants.UNDEFINED); - mHasAliasesSet = false; - mValueFlags = 0; - } - - - float getWithFallback(int spacingType, int fallbackType) { - return - (mValueFlags & sFlagsMap[spacingType]) != 0 - ? mSpacing[spacingType] - : get(fallbackType); - } - - private static float[] newFullSpacingArray() { - return new float[]{ - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - FlexConstants.UNDEFINED, - }; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexWrap.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexWrap.java deleted file mode 100644 index 845a2e2177a..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FlexWrap.java +++ /dev/null @@ -1,38 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - - -public enum FlexWrap { - NOWRAP, - WRAP, - WRAP_REVERSE; - - @SuppressWarnings("unused") - public static FlexWrap fromInt(int value) { - switch (value) { - case 0: - return NOWRAP; - case 1: - return WRAP; - case 2: - return WRAP_REVERSE; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FloatUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FloatUtil.java deleted file mode 100644 index aea21b604ce..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/flex/FloatUtil.java +++ /dev/null @@ -1,28 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.flex; - -public class FloatUtil { - - private static final float EPSILON = .00001f; - - public static boolean floatsEqual(float f1, float f2) { - if (Float.isNaN(f1) || Float.isNaN(f2)) { - return Float.isNaN(f1) && Float.isNaN(f2); - } - return Math.abs(f2 - f1) < EPSILON; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomActionInterceptor.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomActionInterceptor.java deleted file mode 100644 index 59dfbc8216e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomActionInterceptor.java +++ /dev/null @@ -1,32 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; - -/** - * FileName: DomActionInterceptor Description: History: - */ -@SuppressWarnings("deprecation") -public interface DomActionInterceptor { - - HippyMap onCreateNode(int tagId, HippyRootView rootView, HippyMap props); - - HippyMap onUpdateNode(int tagId, HippyRootView rootView, HippyMap props); - - void onDeleteNode(int tagId); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomDomainData.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomDomainData.java deleted file mode 100644 index 3ede1a68770..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomDomainData.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.tencent.mtt.hippy.dom.node; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; - -public class DomDomainData { - - public DomDomainData(int id, int rootId, int pid, String className, String tagName, - HippyMap map) { - this.id = id; - this.rootId = rootId; - this.pid = pid; - this.name = className; - this.tagName = tagName; - if (map != null) { - this.style = map.getMap(NodeProps.STYLE); - this.text = map.getString("text"); - this.attributes = map.getMap(NodeProps.ATTRIBUTES); - } - } - - public void updateLayout(double layoutX, double layoutY, double width, double height) { - this.layoutX = layoutX; - this.layoutY = layoutY; - this.width = width; - this.height = height; - } - - public int id; - public int rootId; - public int pid; - public String name; - public String tagName; - public double layoutX; - public double layoutY; - public double width; - public double height; - public String text; - public HippyMap style; - public HippyMap attributes; -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomNode.java deleted file mode 100644 index 621eae1da97..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/DomNode.java +++ /dev/null @@ -1,226 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.smtt.flexbox.FlexNode; - -@SuppressWarnings("deprecation") -public class DomNode extends FlexNode { - - private int mID; - private String mViewClassName; - private boolean mNodeUpdated = true; - - private boolean mIsJustLayout = false; - - float mLastX, mLastY, mLastWidth, mLastHeight; - - HippyMap mTotalProps = null; - - - boolean mIsLazy = false; - - private DomDomainData mDomainData; - - public void setLazy(boolean lazy) { - this.mIsLazy = lazy; - } - - public boolean isLazy() { - return mIsLazy; - } - - - public boolean shouldUpdateLayout(float x, float y) { - - boolean res = !(mLastX == x && mLastY == y && mLastWidth == getLayoutWidth() - && mLastHeight == getLayoutHeight()); - - if (res) { - mLastX = x; - mLastY = y; - mLastWidth = getLayoutWidth(); - mLastHeight = getLayoutHeight(); - - updateDomainData(); - } - - return res; - } - - protected void toStringWithIndentation(StringBuilder result, int level) { - // Spaces and tabs are dropped by IntelliJ logcat integration, so rely on __ instead. - StringBuilder indentation = new StringBuilder(); - for (int i = 0; i < level; ++i) { - indentation.append("__"); - } - - result.append(indentation.toString()); - result.append("id:").append(getId()); - result.append(" className:").append(getViewClass()).append(" "); - // result.append(mFlexNodeStyle.toString()); - result.append(resultToString()); - - if (getChildCount() == 0) { - return; - } - - result.append(", children: [\n"); - for (int i = 0; i < getChildCount(); i++) { - getChildAt(i).toStringWithIndentation(result, level + 1); - result.append("\n"); - } - result.append(indentation).append("]"); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - this.toStringWithIndentation(sb, 0); - return sb.toString(); - } - - @Override - public DomNode getParent() { - return (DomNode) super.getParent(); - } - - public HippyMap getTotalProps() { - return mTotalProps; - } - - public void setProps(HippyMap props) { - mTotalProps = props; - } - - public void setDomainData(DomDomainData domainData) { - mDomainData = domainData; - } - - public DomDomainData getDomainData() { - return mDomainData; - } - - private void updateDomainData() { - if (mDomainData != null) { - mDomainData.updateLayout(mLastX, mLastY, mLastWidth, mLastHeight); - } - } - - @Override - public void dirty() { - if (!isVirtual()) { - super.dirty(); - } - } - - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - public boolean isVirtual() { - return false; - } - - @Override - public DomNode getChildAt(int i) { - return (DomNode) super.getChildAt(i); - } - - public final String getViewClass() { - return mViewClassName; - } - - - public final boolean hasUpdates() { - return mNodeUpdated || hasNewLayout() || isDirty(); - } - - public final void markUpdateSeen() { - mNodeUpdated = false; - if (hasNewLayout()) { - markLayoutSeen(); - } - } - - public void markUpdated() { - if (mNodeUpdated) { - return; - } - mNodeUpdated = true; - DomNode parent = getParent(); - if (parent != null) { - parent.markUpdated(); - } - } - - public void setDefaultPadding(int spacingType, float padding) { - super.setPadding(spacingType, padding); - } - - @Override - public void addChildAt(FlexNode child, int i) { - super.addChildAt(child, i); - markUpdated(); - } - - @Override - public DomNode removeChildAt(int i) { - DomNode removed = (DomNode) super.removeChildAt(i); - markUpdated(); - - return removed; - } - - public void setIsJustLayout(boolean mIsLayOutOnly) { - this.mIsJustLayout = mIsLayOutOnly; - } - - public boolean isJustLayout() { - return this.mIsJustLayout; - } - - - public void layoutBefore(HippyEngineContext context) { - } - - public void layoutAfter(HippyEngineContext context) { - } - - public final int getId() { - return mID; - } - - public void setId(int id) { - mID = id; - } - - public void setViewClassName(String viewClassName) { - mViewClassName = viewClassName; - } - - public void updateProps(HippyMap props) { - } - - public boolean shouldNotifyOnLayout() { - return mShouldNotifyOnlayout; - } - - boolean mShouldNotifyOnlayout = false; - - @SuppressWarnings("unused") - public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) { - this.mShouldNotifyOnlayout = shouldNotifyOnLayout; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyImageSpan.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyImageSpan.java deleted file mode 100644 index e08bd42ad71..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyImageSpan.java +++ /dev/null @@ -1,295 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import static com.tencent.mtt.hippy.views.image.HippyImageView.ImageEvent.ONERROR; -import static com.tencent.mtt.hippy.views.image.HippyImageView.ImageEvent.ONLOAD; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Movie; -import android.graphics.Paint; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.text.TextUtils; -import android.text.style.DynamicDrawableSpan; -import android.text.style.ImageSpan; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.adapter.image.HippyDrawable; -import com.tencent.mtt.hippy.adapter.image.HippyImageLoader; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.flex.FlexSpacing; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.utils.UIThreadUtils; -import com.tencent.mtt.hippy.utils.UrlUtils; - -import com.tencent.mtt.hippy.views.image.HippyImageView.ImageEvent; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; - -@SuppressWarnings("deprecation") -public class HippyImageSpan extends ImageSpan { - - public final static int STATE_UNLOAD = 0; - public final static int STATE_LOADING = 1; - public final static int STATE_LOADED = 2; - - private int mLeft; - private int mTop; - private int mWidth; - private int mHeight; - private String mUrl; - private final WeakReference mImageNodeWeakRefrence; - private int mImageLoadState = STATE_UNLOAD; - private int mVerticalAlignment; - private final HippyImageLoader mImageAdapter; - private final HippyEngineContext engineContext; - private Movie mGifMovie = null; - private int mGifProgress = 0; - private long mGifLastPlayTime = -1; - - public HippyImageSpan(Drawable d, String source, ImageNode node, - HippyImageLoader imageAdapter, HippyEngineContext context) { - super(d, source, node.getVerticalAlignment()); - engineContext = context; - mImageNodeWeakRefrence = new WeakReference<>(node); - mImageAdapter = imageAdapter; - setUrl(source); - } - - private void updateBoundsAttribute() { - if (mImageNodeWeakRefrence != null) { - ImageNode node = mImageNodeWeakRefrence.get(); - if (node != null) { - int width = Math.round(node.getStyleWidth()); - int height = Math.round(node.getStyleHeight()); - float y = node.getPosition(FlexSpacing.TOP); - float x = node.getPosition(FlexSpacing.LEFT); - int left = (Float.isNaN(x)) ? 0 : Math.round(x); - int top = (Float.isNaN(y)) ? 0 : Math.round(y); - - mLeft = left; - mTop = top; - mWidth = width; - mHeight = height; - mVerticalAlignment = node.getVerticalAlignment(); - } - } - } - - protected boolean shouldUseFetchImageMode(String url) { - return UrlUtils.isWebUrl(url) || UrlUtils.isFileUrl(url); - } - - private void loadImageWithUrl(String url) { - if (!TextUtils.isEmpty(mUrl) && mUrl.equals(url) && mImageLoadState != STATE_UNLOAD) { - return; - } - - mUrl = url; - mImageLoadState = STATE_UNLOAD; - - updateBoundsAttribute(); - - if (mImageAdapter != null) { - if (shouldUseFetchImageMode(mUrl)) { - final HippyMap props = new HippyMap(); - props.pushBoolean(NodeProps.CUSTOM_PROP_ISGIF, false); - props.pushInt(NodeProps.WIDTH, mWidth); - props.pushInt(NodeProps.HEIGHT, mHeight); - - doFetchImage(mUrl, props, mImageAdapter); - } else { - HippyDrawable hippyDrawable = mImageAdapter.getImage(mUrl, null); - shouldReplaceDrawable(hippyDrawable); - } - } - } - - public void setUrl(final String url) { - if (TextUtils.isEmpty(url)) { - return; - } - - if (UIThreadUtils.isOnUiThread()) { - loadImageWithUrl(url); - } else { - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - loadImageWithUrl(url); - } - }); - } - } - - private void drawGIF(Canvas canvas, float left, float top, int width, int height) { - if (mGifMovie == null) { - return; - } - - int duration = mGifMovie.duration(); - if (duration == 0) { - duration = 1000; - } - - long now = System.currentTimeMillis(); - - if (mGifLastPlayTime != -1) { - mGifProgress += now - mGifLastPlayTime; - - if (mGifProgress > duration) { - mGifProgress = 0; - } - } - mGifLastPlayTime = now; - - float mGifScaleX = width / (float) mGifMovie.width(); - float mGifScaleY = height / (float) mGifMovie.height(); - float x = (mGifScaleX != 0) ? left / mGifScaleX : left; - float y = (mGifScaleY != 0) ? top / mGifScaleY : top; - - mGifMovie.setTime(mGifProgress); - canvas.save(); - canvas.scale(mGifScaleX, mGifScaleY); - mGifMovie.draw(canvas, x, y); - canvas.restore(); - postInvalidateDelayed(40); - } - - @Override - public void draw(Canvas canvas, CharSequence text, - int start, int end, float x, - int top, int y, int bottom, Paint paint) { - int transY; - Paint.FontMetricsInt fm = paint.getFontMetricsInt(); - if (mGifMovie != null) { - int width = (mWidth == 0) ? mGifMovie.width() : mWidth; - int height = (mHeight == 0) ? mGifMovie.height() : mHeight; - - transY = (y + fm.descent + y + fm.ascent) / 2 - height / 2; - drawGIF(canvas, x + mLeft, transY + mTop, width, height); - } else if (mVerticalAlignment == ImageSpan.ALIGN_BASELINE) { - Drawable b = getDrawable(); - - transY = (y + fm.descent + y + fm.ascent) / 2 - - b.getBounds().bottom / 2; - - canvas.save(); - canvas.translate(x + mLeft, transY + mTop); - b.draw(canvas); - canvas.restore(); - } else { - super.draw(canvas, text, start, end, x, top, y, bottom, paint); - } - } - - private void postInvalidateDelayed(long delayMilliseconds) { - if (mImageNodeWeakRefrence != null) { - ImageNode node = mImageNodeWeakRefrence.get(); - if (node != null) { - DomNode parent = node.getParent(); - if (parent instanceof TextNode) { - ((TextNode) parent).postInvalidateDelayed(delayMilliseconds); - } - } - } - } - - private void shouldReplaceDrawable(HippyDrawable hippyDrawable) { - if (hippyDrawable != null) { - Bitmap bitmap = hippyDrawable.getBitmap(); - if (bitmap != null) { - BitmapDrawable drawable = new BitmapDrawable(bitmap); - - int w = (mWidth == 0) ? drawable.getIntrinsicWidth() : mWidth; - int h = (mHeight == 0) ? drawable.getIntrinsicHeight() : mHeight; - drawable.setBounds(0, 0, w, h); - try { - Field mDrawableField; - Field mDrawableRefField; - //noinspection JavaReflectionMemberAccess - mDrawableField = ImageSpan.class.getDeclaredField("mDrawable"); - mDrawableField.setAccessible(true); - mDrawableField.set(HippyImageSpan.this, drawable); - - //noinspection JavaReflectionMemberAccess - mDrawableRefField = DynamicDrawableSpan.class.getDeclaredField("mDrawableRef"); - mDrawableRefField.setAccessible(true); - mDrawableRefField.set(HippyImageSpan.this, null); - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - - mImageLoadState = STATE_LOADED; - } else if (hippyDrawable.isAnimated()) { - mGifMovie = hippyDrawable.getGIF(); - mImageLoadState = STATE_LOADED; - } else { - mImageLoadState = STATE_UNLOAD; - } - postInvalidateDelayed(0); - } else { - mImageLoadState = STATE_UNLOAD; - } - } - - private void sendImageLoadEvent(ImageEvent eventType) { - if (mImageNodeWeakRefrence == null) { - return; - } - - ImageNode node = mImageNodeWeakRefrence.get(); - if (node == null) { - return; - } - - String eventName = null; - if (eventType == ONLOAD) { - eventName = "onLoad"; - } else if (eventType == ONERROR) { - eventName = "onError"; - } - - if (!TextUtils.isEmpty(eventName) && node.isEnableImageEvent(eventType)) { - HippyViewEvent event = new HippyViewEvent(eventName); - event.send(node.getId(), engineContext, null); - } - } - - private void doFetchImage(String url, HippyMap props, HippyImageLoader imageAdapter) { - mImageLoadState = STATE_LOADING; - - imageAdapter.fetchImage(url, new HippyImageLoader.Callback() { - @Override - public void onRequestStart(HippyDrawable hippyDrawable) { - } - - @Override - public void onRequestSuccess(HippyDrawable hippyDrawable) { - shouldReplaceDrawable(hippyDrawable); - sendImageLoadEvent(ONLOAD); - } - - @Override - public void onRequestFail(Throwable throwable, String source) { - mImageLoadState = STATE_UNLOAD; - sendImageLoadEvent(ONERROR); - } - }, props); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyLetterSpacingSpan.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyLetterSpacingSpan.java deleted file mode 100644 index 85cb83270d2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyLetterSpacingSpan.java +++ /dev/null @@ -1,47 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.annotation.TargetApi; -import android.os.Build; -import android.text.TextPaint; -import android.text.style.MetricAffectingSpan; - -@SuppressWarnings({"unused"}) -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class HippyLetterSpacingSpan extends MetricAffectingSpan { - - final float mSpace; - - public HippyLetterSpacingSpan(float mSpace) { - this.mSpace = mSpace; - } - - @Override - public void updateMeasureState(TextPaint p) { - if (!Float.isNaN(mSpace)) { - p.setLetterSpacing(mSpace / p.getTextSize()); - } - } - - - @Override - public void updateDrawState(TextPaint tp) { - if (!Float.isNaN(mSpace)) { - tp.setLetterSpacing(mSpace / tp.getTextSize()); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyLineHeightSpan.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyLineHeightSpan.java deleted file mode 100644 index 914c2514726..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyLineHeightSpan.java +++ /dev/null @@ -1,52 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.graphics.Paint; -import android.text.style.LineHeightSpan; - -@SuppressWarnings({"unused"}) -public class HippyLineHeightSpan implements LineHeightSpan { - - private final int mHeight; - - public HippyLineHeightSpan(float lineHeight) { - this.mHeight = (int) Math.ceil(lineHeight); - } - - @Override - public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, - Paint.FontMetricsInt fm) { - if (fm.descent > mHeight) { - fm.bottom = fm.descent = Math.min(mHeight, fm.descent); - fm.top = fm.ascent = 0; - } else if (-fm.ascent + fm.descent > mHeight) { - fm.bottom = fm.descent; - fm.top = fm.ascent = -mHeight + fm.descent; - } else if (-fm.ascent + fm.bottom > mHeight) { - fm.top = fm.ascent; - fm.bottom = fm.ascent + mHeight; - } else if (-fm.top + fm.bottom > mHeight) { - fm.top = fm.bottom - mHeight; - } else { - final int additional = mHeight - (-fm.top + fm.bottom); - fm.top -= Math.ceil(additional / 2.0f); - fm.bottom += Math.floor(additional / 2.0f); - fm.ascent = fm.top; - fm.descent = fm.bottom; - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyNativeGestureSpan.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyNativeGestureSpan.java deleted file mode 100644 index 7e876d35b31..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyNativeGestureSpan.java +++ /dev/null @@ -1,185 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.text.TextUtils; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.uimanager.NativeGestureProcessor; - -import java.util.ArrayList; - -@SuppressWarnings({"unused"}) -public class HippyNativeGestureSpan implements NativeGestureProcessor.Callback { - - static final int LONG_CLICK = 3; - private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); - private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); - boolean mInLongPress = false; - final int mTagId; - private ArrayList mGestureTypes; - private int lastX = 0; - private int lastY = 0; - private int mViewId; - - private NativeGestureProcessor mGestureProcessor; - private Handler mHandler; - private HippyEngineContext mContext; - - private final boolean mIsVirtual; - - HippyNativeGestureSpan(int tagId, boolean isVirtual) { - this.mTagId = tagId; - this.mIsVirtual = isVirtual; - mGestureTypes = new ArrayList<>(); - } - - public boolean isVirtual() { - return mIsVirtual; - } - - public void addGestureTypes(ArrayList types) { - mGestureTypes = types; - } - - public boolean handleTouchEvent(View view, MotionEvent event) { - - if (mGestureProcessor == null) { - mGestureProcessor = new NativeGestureProcessor(HippyNativeGestureSpan.this); - } - mViewId = view.getId(); - return mGestureProcessor.onTouchEvent(event); - } - - @SuppressWarnings("deprecation") - public boolean handleDispatchTouchEvent(View view, MotionEvent event) { - if (mContext == null) { - if (view.getContext() instanceof HippyInstanceContext) { - mContext = ((HippyInstanceContext) view.getContext()).getEngineContext(); - } - - } - - mViewId = view.getId(); - int action = event.getAction(); - boolean handle = false; - int x = (int) event.getX(); - int y = (int) event.getY(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - handle = true; - mInLongPress = false; - if (mGestureTypes.contains(NodeProps.ON_LONG_CLICK)) { - if (mHandler == null) { - mHandler = new GestureHandler(); - } - mHandler.sendEmptyMessageAtTime(LONG_CLICK, - event.getDownTime() + TAP_TIMEOUT + LONGPRESS_TIMEOUT); - } - break; - } - case MotionEvent.ACTION_MOVE: { - if (mGestureTypes.contains(NodeProps.ON_CLICK) || mGestureTypes - .contains(NodeProps.ON_LONG_CLICK)) { - if (Math.abs(x - lastX) < ViewConfiguration.getTouchSlop() - && Math.abs(y - lastY) < ViewConfiguration.getTouchSlop()) { - handle = true; - } - } - break; - } - case MotionEvent.ACTION_UP: { - if (mGestureTypes.contains(NodeProps.ON_CLICK) || mGestureTypes - .contains(NodeProps.ON_LONG_CLICK)) { - if (Math.abs(x - lastX) < ViewConfiguration.getTouchSlop() - && Math.abs(y - lastY) < ViewConfiguration.getTouchSlop()) { - handle = true; - if (mGestureTypes.contains(NodeProps.ON_LONG_CLICK) && mInLongPress) { - NativeGestureDispatcher.handleLongClick(mContext, mTagId); - } else { - NativeGestureDispatcher.handleClick(view, mContext, mTagId, true); - } - } - } - if (mHandler != null) { - mHandler.removeMessages(LONG_CLICK); - } - break; - } - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_OUTSIDE: { - if (mHandler != null) { - mHandler.removeMessages(LONG_CLICK); - } - if (mGestureTypes.contains(NodeProps.ON_CLICK) || mGestureTypes - .contains(NodeProps.ON_LONG_CLICK)) { - handle = true; - } - break; - } - } - lastX = x; - lastY = y; - return handle; - - } - - @Override - public boolean needHandle(String type) { - if (mGestureTypes != null) { - return mGestureTypes.contains(type); - } - return false; - } - - @Override - public void handle(String type, float x, float y) { - if (TextUtils.equals(type, NodeProps.ON_PRESS_IN)) { - NativeGestureDispatcher.handlePressIn(mContext, mTagId); - } else if (TextUtils.equals(type, NodeProps.ON_PRESS_OUT)) { - NativeGestureDispatcher.handlePressOut(mContext, mTagId); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_DOWN)) { - NativeGestureDispatcher.handleTouchDown(mContext, mTagId, x, y, mViewId); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_MOVE)) { - NativeGestureDispatcher.handleTouchMove(mContext, mTagId, x, y, mViewId); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_END)) { - NativeGestureDispatcher.handleTouchEnd(mContext, mTagId, x, y, mViewId); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_CANCEL)) { - NativeGestureDispatcher.handleTouchCancel(mContext, mTagId, x, y, mViewId); - } - } - - private class GestureHandler extends Handler { - - public GestureHandler() { - super(Looper.getMainLooper()); - } - - @Override - public void handleMessage(Message msg) { - if (msg.what == LONG_CLICK) { - mInLongPress = true; - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyShadowSpan.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyShadowSpan.java deleted file mode 100644 index c7209f407c1..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyShadowSpan.java +++ /dev/null @@ -1,38 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.text.TextPaint; -import android.text.style.CharacterStyle; - -@SuppressWarnings({"unused"}) -public class HippyShadowSpan extends CharacterStyle { - - private final float mDx, mDy, mRadius; - private final int mColor; - - public HippyShadowSpan(float dx, float dy, float radius, int color) { - mDx = dx; - mDy = dy; - mRadius = radius; - mColor = color; - } - - @Override - public void updateDrawState(TextPaint textPaint) { - textPaint.setShadowLayer(mRadius, mDx, mDy, mColor); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyStyleSpan.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyStyleSpan.java deleted file mode 100644 index fe07c79e797..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/HippyStyleSpan.java +++ /dev/null @@ -1,53 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.text.TextPaint; -import android.text.style.MetricAffectingSpan; -import com.tencent.mtt.hippy.adapter.font.HippyFontScaleAdapter; - -@SuppressWarnings({"unused"}) -public class HippyStyleSpan extends MetricAffectingSpan { - - private final int mStyle; - private final int mWeight; - private final String mFontFamily; - private final HippyFontScaleAdapter fontAdapter; - - public HippyStyleSpan(int fontStyle, int fontWeight, String fontFamily, - HippyFontScaleAdapter adapter) { - mStyle = fontStyle; - mWeight = fontWeight; - mFontFamily = fontFamily; - fontAdapter = adapter; - } - - @Override - public void updateDrawState(TextPaint ds) { - TypeFaceUtil.apply(ds, mStyle, mWeight, mFontFamily, fontAdapter); - } - - @Override - public void updateMeasureState(TextPaint paint) { - TypeFaceUtil.apply(paint, mStyle, mWeight, mFontFamily, fontAdapter); - } - - public int getStyle() { - return (mStyle == TextNode.UNSET ? 0 : mStyle); - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/ImageNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/ImageNode.java deleted file mode 100644 index c30155c33e3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/ImageNode.java +++ /dev/null @@ -1,166 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - - -import android.text.style.ImageSpan; - -import com.tencent.mtt.hippy.annotation.HippyControllerProps; - -import com.tencent.mtt.hippy.views.image.HippyImageView.ImageEvent; -import java.util.ArrayList; - -@SuppressWarnings({"unused"}) -public class ImageNode extends StyleNode { - - public static final String PROP_VERTICAL_ALIGNMENT = "verticalAlignment"; - - private final boolean mIsVirtual; - private HippyImageSpan mImageSpan = null; - private int mVerticalAlignment = ImageSpan.ALIGN_BASELINE; - private final boolean[] shouldSendImageEvent; - - private ArrayList mGestureTypes = null; - - public ImageNode(boolean mIsVirtual) { - this.mIsVirtual = mIsVirtual; - shouldSendImageEvent = new boolean[ImageEvent.values().length]; - } - - public void setImageSpan(HippyImageSpan imageSpan) { - mImageSpan = imageSpan; - } - - public boolean isEnableImageEvent(ImageEvent event) { - return shouldSendImageEvent[event.ordinal()]; - } - - public int getVerticalAlignment() { - return mVerticalAlignment; - } - - public boolean isVirtual() { - return mIsVirtual; - } - - public ArrayList getGestureTypes() { - return mGestureTypes; - } - - @HippyControllerProps(name = NodeProps.ON_CLICK, defaultType = HippyControllerProps.BOOLEAN) - public void clickEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_CLICK); - } - } - - @HippyControllerProps(name = NodeProps.ON_LONG_CLICK, defaultType = HippyControllerProps.BOOLEAN) - public void longClickEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_LONG_CLICK); - } - } - - @HippyControllerProps(name = NodeProps.ON_PRESS_IN, defaultType = HippyControllerProps.BOOLEAN) - public void pressInEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_PRESS_IN); - } - } - - @HippyControllerProps(name = NodeProps.ON_PRESS_OUT) - public void pressOutEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_PRESS_OUT); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_DOWN, defaultType = HippyControllerProps.BOOLEAN) - public void touchDownEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_DOWN); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_MOVE, defaultType = HippyControllerProps.BOOLEAN) - public void touchUpEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_MOVE); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_END, defaultType = HippyControllerProps.BOOLEAN) - public void touchEndEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_END); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_CANCEL, defaultType = HippyControllerProps.BOOLEAN) - public void touchCancelable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_CANCEL); - } - } - - @HippyControllerProps(name = PROP_VERTICAL_ALIGNMENT, defaultType = HippyControllerProps.NUMBER, defaultNumber = ImageSpan.ALIGN_BASELINE) - public void setVerticalAlignment(int verticalAlignment) { - mVerticalAlignment = verticalAlignment; - } - - @HippyControllerProps(name = "src", defaultType = HippyControllerProps.STRING) - public void setUrl(String url) { - if (mImageSpan != null) { - mImageSpan.setUrl(url); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "onLoad", defaultType = HippyControllerProps.BOOLEAN) - public void setOnLoadEnd(boolean enable) { - shouldSendImageEvent[ImageEvent.ONLOAD.ordinal()] = enable; - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "onError", defaultType = HippyControllerProps.BOOLEAN) - public void setOnError(boolean enable) { - shouldSendImageEvent[ImageEvent.ONERROR.ordinal()] = enable; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/LayoutHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/LayoutHelper.java deleted file mode 100644 index e3353dc1bc4..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/LayoutHelper.java +++ /dev/null @@ -1,102 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.graphics.Canvas; -import android.graphics.Picture; -import android.os.Build; -import android.text.Layout; -import android.text.StaticLayout; - -import com.tencent.mtt.hippy.common.HippyHandlerThread; -import com.tencent.mtt.hippy.common.HippyThreadRunnable; -import com.tencent.mtt.hippy.utils.LogUtils; - -@SuppressWarnings({"unused"}) -public class LayoutHelper { - - private HippyHandlerThread mHandlerThread; - private final Picture mPicture = new Picture(); - - public LayoutHelper() { - mHandlerThread = new HippyHandlerThread("text-warm-thread"); - } - - public void release() { - if (mHandlerThread != null) { - mHandlerThread.quit(); - } - mHandlerThread = null; - } - - public void postWarmLayout(Layout layout) { - if (mHandlerThread != null && mHandlerThread.isThreadAlive()) { - mHandlerThread.runOnQueue(new HippyThreadRunnable(layout) { - @Override - public void run(Layout param) { - warmUpLayout(param); - } - }); - } - } - - private int getHeight(Layout layout) { - if (layout == null) { - return 0; - } - - int extra = 0; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH - && layout instanceof StaticLayout) { - int above = layout.getLineAscent(layout.getLineCount() - 1); - int below = layout.getLineDescent(layout.getLineCount() - 1); - float originalSize = (below - above - layout.getSpacingAdd()) / layout.getSpacingMultiplier(); - float ex = below - above - originalSize; - if (ex >= 0) { - extra = (int) (ex + 0.5); - } else { - extra = -(int) (-ex + 0.5); - } - } - return layout.getHeight() - extra; - } - - private int getWidth(Layout layout) { - if (layout == null) { - return 0; - } - - // Supplying VERY_WIDE will make layout.getWidth() return a very large value. - int count = layout.getLineCount(); - int maxWidth = 0; - - for (int i = 0; i < count; i++) { - maxWidth = Math.max(maxWidth, (int) layout.getLineRight(i)); - } - - return maxWidth; - } - - private void warmUpLayout(Layout layout) { - try { - Canvas canvas = mPicture.beginRecording(getWidth(layout), getHeight(layout)); - layout.draw(canvas); - mPicture.endRecording(); - } catch (Exception e) { - LogUtils.e("TextNode", "warmUpTextLayoutCache error", e); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java deleted file mode 100644 index e7914d3e028..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java +++ /dev/null @@ -1,245 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import java.util.Arrays; -import java.util.HashSet; - -import com.tencent.mtt.hippy.common.HippyMap; - -import android.graphics.Color; - -@SuppressWarnings({"deprecation", "unused"}) -public class NodeProps { - - public static final String ALIGN_ITEMS = "alignItems"; - public static final String ALIGN_SELF = "alignSelf"; - public static final String OVERFLOW = "overflow"; - public static final String BOTTOM = "bottom"; - public static final String COLLAPSABLE = "collapsable"; - public static final String FLEX = "flex"; - public static final String FLEX_GROW = "flexGrow"; - public static final String FLEX_SHRINK = "flexShrink"; - public static final String FLEX_BASIS = "flexBasis"; - public static final String DIRECTION = "direction"; - public static final String FLEX_DIRECTION = "flexDirection"; - public static final String FLEX_WRAP = "flexWrap"; - public static final String HEIGHT = "height"; - public static final String JUSTIFY_CONTENT = "justifyContent"; - public static final String LEFT = "left"; - public static final String DISPLAY = "display"; - - - public static final String MARGIN = "margin"; - public static final String MARGIN_VERTICAL = "marginVertical"; - public static final String MARGIN_HORIZONTAL = "marginHorizontal"; - public static final String MARGIN_LEFT = "marginLeft"; - public static final String MARGIN_RIGHT = "marginRight"; - public static final String MARGIN_TOP = "marginTop"; - public static final String MARGIN_BOTTOM = "marginBottom"; - - public static final String PADDING = "padding"; - public static final String PADDING_VERTICAL = "paddingVertical"; - public static final String PADDING_HORIZONTAL = "paddingHorizontal"; - public static final String PADDING_LEFT = "paddingLeft"; - public static final String PADDING_RIGHT = "paddingRight"; - public static final String PADDING_TOP = "paddingTop"; - public static final String PADDING_BOTTOM = "paddingBottom"; - - public static final String POSITION = "position"; - public static final String RIGHT = "right"; - public static final String TOP = "top"; - public static final String WIDTH = "width"; - - public static final String MIN_WIDTH = "minWidth"; - public static final String MAX_WIDTH = "maxWidth"; - public static final String MIN_HEIGHT = "minHeight"; - public static final String MAX_HEIGHT = "maxHeight"; - - public static final String BORDER_WIDTH = "borderWidth"; - public static final String BORDER_LEFT_WIDTH = "borderLeftWidth"; - public static final String BORDER_TOP_WIDTH = "borderTopWidth"; - public static final String BORDER_RIGHT_WIDTH = "borderRightWidth"; - public static final String BORDER_BOTTOM_WIDTH = "borderBottomWidth"; - - public static final String BORDER_COLOR = "borderColor"; - public static final String BORDER_LEFT_COLOR = "borderLeftColor"; - public static final String BORDER_TOP_COLOR = "borderTopColor"; - public static final String BORDER_RIGHT_COLOR = "borderRightColor"; - public static final String BORDER_BOTTOM_COLOR = "borderBottomColor"; - public static final String BORDER_STYLES = "borderStyle"; - - public static final String SHADOW_COLOR = "shadowColor"; - public static final String SHADOW_OFFSET = "shadowOffset"; - public static final String SHADOW_OFFSET_X = "shadowOffsetX"; - public static final String SHADOW_OFFSET_Y = "shadowOffsetY"; - public static final String SHADOW_OPACITY = "shadowOpacity"; - public static final String SHADOW_RADIUS = "shadowRadius"; - public static final String SHADOW_SPREAD = "shadowSpread"; - - public static final String LINEAR_GRADIENT = "linearGradient"; - - //View props - - public static final String ENABLED = "enabled"; - public static final String OPACITY = "opacity"; - public static final String BACKGROUND_COLOR = "backgroundColor"; - public static final String BACKGROUND_COLORS = "backgroundColors"; - public static final String COLORS = "colors"; - public static final String COLOR = "color"; - public static final String BACKGROUND_IMAGE = "backgroundImage"; - public static final String BACKGROUND_POSITION_X = "backgroundPositionX"; - public static final String BACKGROUND_POSITION_Y = "backgroundPositionY"; - public static final String BACKGROUND_SIZE = "backgroundSize"; - public static final String FONT_SIZE = "fontSize"; - public static final String LETTER_SPACING = "letterSpacing"; - public static final String FONT_WEIGHT = "fontWeight"; - public static final String FONT_STYLE = "fontStyle"; - public static final String FONT_FAMILY = "fontFamily"; - public static final String LINE_HEIGHT = "lineHeight"; - public static final String NUMBER_OF_LINES = "numberOfLines"; - public static final String ELLIPSIZE_MODE = "ellipsizeMode"; - public static final String ON = "on"; - public static final String RESIZE_MODE = "resizeMode"; - public static final String RESIZE_METHOD = "resizeMethod"; - public static final String GAUSSIAN_BLUR = "gaussianBlur"; - public static final String TEXT_ALIGN = "textAlign"; - public static final String TEXT_ALIGN_VERTICAL = "textAlignVertical"; - public static final String TEXT_DECORATION_LINE = "textDecorationLine"; - public static final String ON_CLICK = "onClick"; - public static final String ON_LONG_CLICK = "onLongClick"; - public static final String ON_PRESS_IN = "onPressIn"; - public static final String ON_PRESS_OUT = "onPressOut"; - public static final String ON_TOUCH_DOWN = "onTouchDown"; - public static final String ON_TOUCH_MOVE = "onTouchMove"; - public static final String ON_TOUCH_END = "onTouchEnd"; - public static final String ON_TOUCH_CANCEL = "onTouchCancel"; - public static final String ON_INTERCEPT_TOUCH_EVENT = "onInterceptTouchEvent"; - public static final String ON_INTERCEPT_PULL_UP_EVENT = "onInterceptPullUpEvent"; - public static final String ON_ATTACHED_TO_WINDOW = "onAttachedToWindow"; - public static final String ON_DETACHED_FROM_WINDOW = "onDetachedFromWindow"; - - public static final String BORDER_RADIUS = "borderRadius"; - public static final String BORDER_TOP_LEFT_RADIUS = "borderTopLeftRadius"; - public static final String BORDER_TOP_RIGHT_RADIUS = "borderTopRightRadius"; - public static final String BORDER_BOTTOM_LEFT_RADIUS = "borderBottomLeftRadius"; - public static final String BORDER_BOTTOM_RIGHT_RADIUS = "borderBottomRightRadius"; - - public static final String TRANSFORM = "transform"; - public static final String Z_INDEX = "zIndex"; - - public static final float FONT_SIZE_SP = 14.0f; - - public static final String VIEW_CLASS_NAME = "View"; - public static final String TEXT_CLASS_NAME = "Text"; - public static final String IMAGE_CLASS_NAME = "Image"; - - public static final String STYLE = "style"; - public static final String PROPS = "props"; - public static final String ROOT_NODE = "RootNode"; - public static final String CUSTOM_PROP = "customProp"; - public static final String CUSTOM_PROP_ISGIF = "isGif"; - public static final String CUSTOM_PROP_IMAGE_TYPE = "imageType"; - - public static final String PROP_ACCESSIBILITY_LABEL = "accessibilityLabel"; - public static final String FOCUSABLE = "focusable"; - public static final String NEXT_FOCUS_DOWN_ID = "nextFocusDownId"; - public static final String NEXT_FOCUS_UP_ID = "nextFocusUpId"; - public static final String NEXT_FOCUS_LEFT_ID = "nextFocusLeftId"; - public static final String NEXT_FOCUS_RIGHT_ID = "nextFocusRightId"; - public static final String REQUEST_FOCUS = "requestFocus"; - - public static final String VISIBLE = "visible"; - public static final String REPEAT_COUNT = "repeatCount"; - public static final String ATTRIBUTES = "attributes"; - - private static final HashSet JUST_LAYOUT_PROPS = new HashSet<>( - Arrays.asList(ALIGN_SELF, ALIGN_ITEMS, COLLAPSABLE, FLEX, FLEX_DIRECTION, FLEX_WRAP, - JUSTIFY_CONTENT, - - /* - * position - */ - POSITION, RIGHT, TOP, BOTTOM, LEFT, - - /* - * dimensions - */ - WIDTH, HEIGHT, MIN_WIDTH, MAX_WIDTH, MIN_HEIGHT, MAX_HEIGHT, - - /* - * margins - */ - MARGIN, MARGIN_VERTICAL, MARGIN_HORIZONTAL, MARGIN_LEFT, MARGIN_RIGHT, MARGIN_TOP, - MARGIN_BOTTOM, - - /* - * paddings - */ - PADDING, PADDING_VERTICAL, PADDING_HORIZONTAL, PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, - PADDING_BOTTOM)); - private static final HashSet TOUCH_EVENT_PROPS = new HashSet<>( - Arrays.asList(ON_CLICK, ON_LONG_CLICK, ON_PRESS_IN, ON_PRESS_OUT, ON_TOUCH_CANCEL, - ON_TOUCH_DOWN, ON_TOUCH_END, ON_TOUCH_MOVE)); - - public static boolean isTouchEventProp(String prop) { - return TOUCH_EVENT_PROPS.contains(prop); - } - - public static boolean isJustLayout(HippyMap map, String prop) { - if (JUST_LAYOUT_PROPS.contains(prop)) { - return true; - } - - switch (prop) { - case OPACITY: - return map.isNull(OPACITY) || map.getDouble(OPACITY) == 1d; - case BORDER_RADIUS: - if (map.containsKey(BACKGROUND_COLOR) - && map.getInt(BACKGROUND_COLOR) != Color.TRANSPARENT) { - return false; - } - //noinspection RedundantIfStatement - if (map.containsKey(BORDER_WIDTH) && !map.isNull(BORDER_WIDTH) - && map.getDouble(BORDER_WIDTH) != 0d) { - return false; - } - return true; - case BORDER_LEFT_COLOR: - return map.getInt(BORDER_LEFT_COLOR) == Color.TRANSPARENT; - case BORDER_RIGHT_COLOR: - return map.getInt(BORDER_RIGHT_COLOR) == Color.TRANSPARENT; - case BORDER_TOP_COLOR: - return map.getInt(BORDER_TOP_COLOR) == Color.TRANSPARENT; - case BORDER_BOTTOM_COLOR: - return map.getInt(BORDER_BOTTOM_COLOR) == Color.TRANSPARENT; - case BORDER_WIDTH: - return map.isNull(BORDER_WIDTH) || map.getDouble(BORDER_WIDTH) == 0d; - case BORDER_LEFT_WIDTH: - return map.isNull(BORDER_LEFT_WIDTH) || map.getDouble(BORDER_LEFT_WIDTH) == 0d; - case BORDER_TOP_WIDTH: - return map.isNull(BORDER_TOP_WIDTH) || map.getDouble(BORDER_TOP_WIDTH) == 0d; - case BORDER_RIGHT_WIDTH: - return map.isNull(BORDER_RIGHT_WIDTH) || map.getDouble(BORDER_RIGHT_WIDTH) == 0d; - case BORDER_BOTTOM_WIDTH: - return map.isNull(BORDER_BOTTOM_WIDTH) || map.getDouble(BORDER_BOTTOM_WIDTH) == 0d; - case OVERFLOW: - return map.isNull(OVERFLOW) || VISIBLE.equals(map.getString(OVERFLOW)); - default: - return false; - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/StyleNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/StyleNode.java deleted file mode 100644 index bb83cc002e3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/StyleNode.java +++ /dev/null @@ -1,299 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.text.TextUtils; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.dom.flex.*; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.smtt.flexbox.FlexNodeStyle; - -import java.util.Locale; - -@SuppressWarnings("unused") -public class StyleNode extends DomNode { - - @HippyControllerProps(name = NodeProps.WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setWidth(float width) { - setStyleWidth(FlexConstants.isUndefined(width) ? width : PixelUtil.dp2px(width)); - } - - @HippyControllerProps(name = NodeProps.MIN_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setMinWidth(float minWidth) { - setStyleMinWidth(FlexConstants.isUndefined(minWidth) ? minWidth : PixelUtil.dp2px(minWidth)); - } - - @HippyControllerProps(name = NodeProps.MAX_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setMaxWidth(float maxWidth) { - setStyleMaxWidth(FlexConstants.isUndefined(maxWidth) ? maxWidth : PixelUtil.dp2px(maxWidth)); - } - - @HippyControllerProps(name = NodeProps.HEIGHT, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setHeight(float height) { - setStyleHeight(FlexConstants.isUndefined(height) ? height : PixelUtil.dp2px(height)); - } - - @HippyControllerProps(name = NodeProps.MIN_HEIGHT, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setMinHeight(float minHeight) { - setStyleMinHeight( - FlexConstants.isUndefined(minHeight) ? minHeight : PixelUtil.dp2px(minHeight)); - } - - @HippyControllerProps(name = NodeProps.MAX_HEIGHT, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setMaxHeight(float maxHeight) { - setStyleMaxHeight( - FlexConstants.isUndefined(maxHeight) ? maxHeight : PixelUtil.dp2px(maxHeight)); - } - - @HippyControllerProps(name = NodeProps.FLEX, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setFlex(float flex) { - super.setFlex(flex); - } - - @HippyControllerProps(name = NodeProps.FLEX_GROW, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setFlexGrow(float flexGrow) { - super.setFlexGrow(flexGrow); - } - - @HippyControllerProps(name = NodeProps.FLEX_SHRINK, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setFlexShrink(float flexShrink) { - super.setFlexShrink(flexShrink); - } - - @HippyControllerProps(name = NodeProps.FLEX_BASIS, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setFlexBasis(float flexBasis) { - super.setFlexBasis(flexBasis); - } - - @HippyControllerProps(name = NodeProps.SHADOW_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setShadowRadius(float shadowRadius) { - if (shadowRadius > 0) { - setDirection(FlexDirection.LTR); - } - } - - @HippyControllerProps(name = NodeProps.DIRECTION) - public void setDirection(String direction) { - if (TextUtils.isEmpty(direction)) { - return; - } - - FlexDirection flexDirection; - switch (direction) { - case "rtl": - flexDirection = FlexDirection.RTL; - break; - case "inherit": - flexDirection = FlexDirection.INHERIT; - break; - default: - flexDirection = FlexDirection.LTR; - } - - setDirection(flexDirection); - } - - @HippyControllerProps(name = NodeProps.FLEX_DIRECTION) - public void setFlexDirection(String flexDirection) { - setFlexDirection(flexDirection == null ? FlexCSSDirection.COLUMN - : FlexCSSDirection.valueOf(flexDirection.toUpperCase(Locale.US).replace("-", - "_"))); - } - - @HippyControllerProps(name = NodeProps.FLEX_WRAP) - public void setFlexWrap(String flexWrap) { - setWrap(flexWrap == null ? FlexWrap.NOWRAP : FlexWrap.valueOf(flexWrap.toUpperCase(Locale.US))); - } - - @HippyControllerProps(name = NodeProps.ALIGN_SELF) - public void setAlignSelf(String alignSelf) { - setAlignSelf(alignSelf == null ? FlexAlign.AUTO - : FlexAlign.valueOf(alignSelf.toUpperCase(Locale.US).replace("-", "_"))); - } - - @HippyControllerProps(name = NodeProps.ALIGN_ITEMS) - public void setAlignItems(String alignItems) { - setAlignItems(alignItems == null ? FlexAlign.STRETCH - : FlexAlign.valueOf(alignItems.toUpperCase(Locale.US).replace("-", "_"))); - } - - @HippyControllerProps(name = NodeProps.JUSTIFY_CONTENT) - public void setJustifyContent(String justifyContent) { - setJustifyContent(justifyContent == null ? FlexJustify.FLEX_START - : FlexJustify.valueOf(justifyContent.toUpperCase(Locale.US).replace("-", - "_"))); - } - - @HippyControllerProps(name = NodeProps.OVERFLOW) - public void setOverflow(String overflow) { - setOverflow(overflow == null ? FlexOverflow.VISIBLE - : FlexOverflow.valueOf(overflow.toUpperCase(Locale.US).replace("-", "_"))); - } - - @SuppressWarnings("SwitchStatementWithTooFewBranches") - @HippyControllerProps(name = NodeProps.DISPLAY) - public void setDisplay(String display) { - FlexNodeStyle.Display flexDisplay = FlexNodeStyle.Display.DISPLAY_FLEX; - switch (display) { - case "none": - flexDisplay = FlexNodeStyle.Display.DISPLAY_NONE; - break; - default: - - } - setDisplay(flexDisplay); - } - - - @HippyControllerProps(name = NodeProps.MARGIN, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setMargin(float margin) { - setMargin(FlexSpacing.ALL, PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.MARGIN_VERTICAL, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setMarginVertical(float margin) { - setMargin(FlexSpacing.VERTICAL, PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.MARGIN_HORIZONTAL, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setMarginHoriziontal(float margin) { - setMargin(FlexSpacing.HORIZONTAL, PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.MARGIN_LEFT, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setMarginLeft(float margin) { - setMargin(FlexSpacing.LEFT, PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.MARGIN_RIGHT, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setMarginRight(float margin) { - setMargin(FlexSpacing.RIGHT, PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.MARGIN_TOP, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setMarginTop(float margin) { - setMargin(FlexSpacing.TOP, PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.MARGIN_BOTTOM, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setMarginBottom(float margin) { - setMargin(FlexSpacing.BOTTOM, PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.PADDING, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setPadding(float padding) { - setPadding(FlexSpacing.ALL, - FlexConstants.isUndefined(padding) ? padding : PixelUtil.dp2px(padding)); - } - - @HippyControllerProps(name = NodeProps.PADDING_VERTICAL, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setPaddingVertical(float padding) { - setPadding(FlexSpacing.VERTICAL, - FlexConstants.isUndefined(padding) ? padding : PixelUtil.dp2px(padding)); - } - - @HippyControllerProps(name = NodeProps.PADDING_HORIZONTAL, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setPaddingHorizontal(float padding) { - setPadding(FlexSpacing.HORIZONTAL, - FlexConstants.isUndefined(padding) ? padding : PixelUtil.dp2px(padding)); - } - - @HippyControllerProps(name = NodeProps.PADDING_LEFT, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setPaddingLeft(float padding) { - setPadding(FlexSpacing.LEFT, - FlexConstants.isUndefined(padding) ? padding : PixelUtil.dp2px(padding)); - } - - @HippyControllerProps(name = NodeProps.PADDING_RIGHT, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setPaddingRight(float padding) { - setPadding(FlexSpacing.RIGHT, - FlexConstants.isUndefined(padding) ? padding : PixelUtil.dp2px(padding)); - } - - @HippyControllerProps(name = NodeProps.PADDING_TOP, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setPaddingTop(float padding) { - setPadding(FlexSpacing.TOP, - FlexConstants.isUndefined(padding) ? padding : PixelUtil.dp2px(padding)); - } - - @HippyControllerProps(name = NodeProps.PADDING_BOTTOM, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setPaddingBottom(float padding) { - setPadding(FlexSpacing.BOTTOM, - FlexConstants.isUndefined(padding) ? padding : PixelUtil.dp2px(padding)); - } - - - @HippyControllerProps(name = NodeProps.BORDER_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setBorderWidths(float borderWidth) { - setBorder(FlexSpacing.ALL, PixelUtil.dp2px(borderWidth)); - } - - @HippyControllerProps(name = NodeProps.BORDER_LEFT_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setLeftBorderWidths(float borderWidth) { - setBorder(FlexSpacing.LEFT, PixelUtil.dp2px(borderWidth)); - } - - @HippyControllerProps(name = NodeProps.BORDER_RIGHT_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setRightBorderWidths(float borderWidth) { - setBorder(FlexSpacing.RIGHT, PixelUtil.dp2px(borderWidth)); - } - - @HippyControllerProps(name = NodeProps.BORDER_TOP_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setTopBorderWidths(float borderWidth) { - setBorder(FlexSpacing.TOP, PixelUtil.dp2px(borderWidth)); - } - - @HippyControllerProps(name = NodeProps.BORDER_BOTTOM_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setBottomBorderWidths(float borderWidth) { - setBorder(FlexSpacing.BOTTOM, PixelUtil.dp2px(borderWidth)); - } - - @HippyControllerProps(name = NodeProps.LEFT, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setLeftPositionValues(float position) { - setPosition(FlexSpacing.LEFT, - FlexConstants.isUndefined(position) ? position : PixelUtil.dp2px(position)); - } - - @HippyControllerProps(name = NodeProps.RIGHT, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setRightPositionValues(float position) { - setPosition(FlexSpacing.RIGHT, - FlexConstants.isUndefined(position) ? position : PixelUtil.dp2px(position)); - } - - @HippyControllerProps(name = NodeProps.TOP, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setTopPositionValues(float position) { - setPosition(FlexSpacing.TOP, - FlexConstants.isUndefined(position) ? position : PixelUtil.dp2px(position)); - } - - @HippyControllerProps(name = NodeProps.BOTTOM, defaultType = HippyControllerProps.NUMBER, defaultNumber = FlexConstants.UNDEFINED) - public void setBottomPositionValues(float position) { - setPosition(FlexSpacing.BOTTOM, - FlexConstants.isUndefined(position) ? position : PixelUtil.dp2px(position)); - } - - @HippyControllerProps(name = NodeProps.POSITION) - public void setPosition(String position) { - FlexPositionType positionType = position == null ? FlexPositionType.RELATIVE - : FlexPositionType.valueOf(position.toUpperCase(Locale.US)); - setPositionType(positionType); - } - - @HippyControllerProps(name = "onLayout", defaultType = HippyControllerProps.BOOLEAN) - public void setShouldNotifyOnLayout(boolean mShouldNotifyOnLayout) { - super.setShouldNotifyOnLayout(mShouldNotifyOnLayout); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TextExtra.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TextExtra.java deleted file mode 100644 index 636c4b67979..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TextExtra.java +++ /dev/null @@ -1,37 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -@SuppressWarnings({"unused"}) -public class TextExtra { - - public final Object mExtra; - public final float mLeftPadding; - public final float mRightPadding; - public final float mBottomPadding; - public final float mTopPadding; - - public TextExtra(Object extra, float mLeftPadding, float mRightPadding, float mBottomPadding, - float mTopPadding) { - this.mExtra = extra; - this.mLeftPadding = mLeftPadding; - this.mRightPadding = mRightPadding; - this.mBottomPadding = mBottomPadding; - this.mTopPadding = mTopPadding; - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TextNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TextNode.java deleted file mode 100644 index 6bfa67a926d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TextNode.java +++ /dev/null @@ -1,755 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.Typeface; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.text.*; -import android.text.Layout.Alignment; -import android.text.style.*; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.adapter.font.HippyFontScaleAdapter; -import com.tencent.mtt.hippy.adapter.image.HippyDrawable; -import com.tencent.mtt.hippy.adapter.image.HippyImageLoader; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.flex.*; -import com.tencent.mtt.hippy.utils.I18nUtil; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.text.HippyTextView; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; - -@SuppressWarnings({"deprecation", "unused"}) -public class TextNode extends StyleNode { - - SpannableStringBuilder mSpanned; - - public final static int UNSET = -1; - CharSequence mText; - protected int mNumberOfLines = UNSET; - - protected int mFontSize = (int) Math.ceil(PixelUtil.dp2px(NodeProps.FONT_SIZE_SP)); - private float mLineHeight = UNSET; - private float mLetterSpacing = UNSET; - - private int mColor = Color.BLACK; - private final boolean mIsBackgroundColorSet = false; - private int mBackgroundColor; - private String mFontFamily = null; - - public static final int DEFAULT_TEXT_SHADOW_COLOR = 0x55000000; - protected Layout.Alignment mTextAlign = Layout.Alignment.ALIGN_NORMAL; - - protected final TextUtils.TruncateAt mTruncateAt = TextUtils.TruncateAt.END; - - private float mTextShadowOffsetDx = 0; - private float mTextShadowOffsetDy = 0; - private float mTextShadowRadius = 1; - private int mTextShadowColor = DEFAULT_TEXT_SHADOW_COLOR; - - private boolean mIsUnderlineTextDecorationSet = false; - private boolean mIsLineThroughTextDecorationSet = false; - - - private int mFontStyle = UNSET; - private int mFontWeight = UNSET; - - private ArrayList mGestureTypes = null; - - public static final String PROP_SHADOW_OFFSET = "textShadowOffset"; - public static final String PROP_SHADOW_OFFSET_WIDTH = "width"; - public static final String PROP_SHADOW_OFFSET_HEIGHT = "height"; - public static final String PROP_SHADOW_RADIUS = "textShadowRadius"; - public static final String PROP_SHADOW_COLOR = "textShadowColor"; - - public static final String IMAGE_SPAN_TEXT = "[img]"; - - final TextPaint sTextPaintInstance = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - - private final boolean mIsVirtual; - - protected boolean mEnableScale = false; - - private WeakReference mTextViewWeakRefrence = null; - - - public TextNode(boolean mIsVirtual) { - this.mIsVirtual = mIsVirtual; - if (!mIsVirtual) { - setMeasureFunction(TEXT_MEASURE_FUNCTION); - } - - if (I18nUtil.isRTL()) { - mTextAlign = Layout.Alignment.ALIGN_OPPOSITE; - } - } - - public void setTextView(HippyTextView view) { - mTextViewWeakRefrence = new WeakReference<>(view); - } - - public void postInvalidateDelayed(long delayMilliseconds) { - if (mTextViewWeakRefrence != null && mTextViewWeakRefrence.get() != null) { - mTextViewWeakRefrence.get().postInvalidateDelayed(delayMilliseconds); - } - } - - public boolean isVirtual() { - return mIsVirtual; - } - - @HippyControllerProps(name = NodeProps.FONT_STYLE, defaultType = HippyControllerProps.STRING, defaultString = "normal") - public void fontStyle(String fontStyleString) { - int fontStyle = UNSET; - if ("italic".equals(fontStyleString)) { - fontStyle = Typeface.ITALIC; - } else if ("normal".equals(fontStyleString)) { - fontStyle = Typeface.NORMAL; - } - if (fontStyle != mFontStyle) { - mFontStyle = fontStyle; - markUpdated(); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.LETTER_SPACING, defaultType = HippyControllerProps.NUMBER, defaultNumber = UNSET) - public void letterSpacing(float letterSpace) { - if (letterSpace != UNSET) { - mLetterSpacing = PixelUtil.dp2px(letterSpace); - markUpdated(); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void color(Integer color) { - mColor = color; - markUpdated(); - } - - public boolean enableScale() { - return mEnableScale; - } - - @SuppressWarnings("unused") - public Spannable getSpan() { - return mSpanned; - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.FONT_SIZE, defaultType = HippyControllerProps.NUMBER, defaultNumber = NodeProps.FONT_SIZE_SP) - public void fontSize(float fontSize) { - this.mFontSize = (int) Math.ceil(PixelUtil.dp2px(fontSize)); - markUpdated(); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.FONT_FAMILY) - public void fontFamily(String fontFamily) { - mFontFamily = fontFamily; - markUpdated(); - } - - @Override - public void updateProps(HippyMap props) { - super.updateProps(props); - HippyMap styleMap = (HippyMap) props.get(NodeProps.STYLE); - if (styleMap != null && styleMap.get(NodeProps.COLOR) == null) { - styleMap.pushInt(NodeProps.COLOR, Color.BLACK); - } - } - - private static int parseArgument(String wight) { - return wight.length() == 3 && wight.endsWith("00") && wight.charAt(0) <= '9' - && wight.charAt(0) >= '1' ? 100 * (wight.charAt(0) - '0') : -1; - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.FONT_WEIGHT) - public void fontWeight(String wight) { - int fontWeightNumeric = wight != null ? parseArgument(wight) : -1; - int fontWeight = UNSET; - if (fontWeightNumeric >= 500 || "bold".equals(wight)) { - fontWeight = Typeface.BOLD; - } else if ("normal".equals(wight) || fontWeightNumeric != -1) { - fontWeight = Typeface.NORMAL; - } - if (fontWeight != mFontWeight) { - mFontWeight = fontWeight; - markUpdated(); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.TEXT_DECORATION_LINE) - public void textDecorationLine(String textDecorationLineString) { - mIsUnderlineTextDecorationSet = false; - mIsLineThroughTextDecorationSet = false; - if (textDecorationLineString != null) { - for (String textDecorationLineSubString : textDecorationLineString.split(" ")) { - if ("underline".equals(textDecorationLineSubString)) { - mIsUnderlineTextDecorationSet = true; - } else if ("line-through".equals(textDecorationLineSubString)) { - mIsLineThroughTextDecorationSet = true; - } - } - } - markUpdated(); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = PROP_SHADOW_OFFSET) - public void textShadowOffset(HippyMap offsetMap) { - mTextShadowOffsetDx = 0; - mTextShadowOffsetDy = 0; - if (offsetMap != null) { - if (offsetMap.get(PROP_SHADOW_OFFSET_WIDTH) != null) { - mTextShadowOffsetDx = PixelUtil.dp2px(offsetMap.getDouble(PROP_SHADOW_OFFSET_WIDTH)); - } - if (offsetMap.get(PROP_SHADOW_OFFSET_HEIGHT) != null) { - mTextShadowOffsetDy = PixelUtil.dp2px(offsetMap.getDouble(PROP_SHADOW_OFFSET_HEIGHT)); - } - } - - markUpdated(); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = PROP_SHADOW_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void textShadowRadius(float textShadowRadius) { - if (textShadowRadius != mTextShadowRadius) { - mTextShadowRadius = textShadowRadius; - markUpdated(); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = PROP_SHADOW_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setTextShadowColor(int textShadowColor) { - if (textShadowColor != mTextShadowColor) { - mTextShadowColor = textShadowColor; - markUpdated(); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.LINE_HEIGHT, defaultType = HippyControllerProps.NUMBER, defaultNumber = UNSET) - public void lineHeight(int lineHeight) { - mLineHeight = lineHeight == UNSET ? UNSET : PixelUtil.dp2px(lineHeight); - markUpdated(); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.TEXT_ALIGN, defaultType = HippyControllerProps.STRING, defaultString = "left") - public void setTextAlign(String textAlign) { - if (textAlign == null || "auto".equals(textAlign) || "justify".equals(textAlign)) { - mTextAlign = I18nUtil.isRTL() ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL; - } else if ("left".equals(textAlign)) { - mTextAlign = Layout.Alignment.ALIGN_NORMAL; - } else if ("right".equals(textAlign)) { - mTextAlign = Layout.Alignment.ALIGN_OPPOSITE; - } else if ("center".equals(textAlign)) { - mTextAlign = Layout.Alignment.ALIGN_CENTER; - } else { - throw new RuntimeException("Invalid textAlign: " + textAlign); - } - markUpdated(); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "text") - public void text(String text) { - mText = text; - markUpdated(); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_CLICK, defaultType = HippyControllerProps.BOOLEAN) - public void clickEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_CLICK); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_LONG_CLICK, defaultType = HippyControllerProps.BOOLEAN) - public void longClickEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_LONG_CLICK); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_PRESS_IN, defaultType = HippyControllerProps.BOOLEAN) - public void pressInEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_PRESS_IN); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_PRESS_OUT) - public void pressOutEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_PRESS_OUT); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_TOUCH_DOWN, defaultType = HippyControllerProps.BOOLEAN) - public void touchDownEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_DOWN); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_TOUCH_MOVE, defaultType = HippyControllerProps.BOOLEAN) - public void touchUpEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_MOVE); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_TOUCH_END, defaultType = HippyControllerProps.BOOLEAN) - public void touchEndEnable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_END); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.ON_TOUCH_CANCEL, defaultType = HippyControllerProps.BOOLEAN) - public void touchCancelable(boolean flag) { - if (flag) { - if (mGestureTypes == null) { - mGestureTypes = new ArrayList<>(); - } - mGestureTypes.add(NodeProps.ON_TOUCH_CANCEL); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "enableScale", defaultType = HippyControllerProps.BOOLEAN) - public void enableScale(boolean flag) { - this.mEnableScale = flag; - markUpdated(); - } - - @Override - public void markUpdated() { - super.markUpdated(); - if (!mIsVirtual) { - super.dirty(); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.NUMBER_OF_LINES, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setNumberOfLines(int numberOfLines) { - mNumberOfLines = numberOfLines == 0 ? -1 : numberOfLines; - markUpdated(); - } - - protected HippyFontScaleAdapter mFontScaleAdapter; - protected HippyEngineContext engineContext; - protected HippyImageLoader mImageAdapter; - - @Override - public void layoutBefore(HippyEngineContext context) { - super.layoutBefore(context); - - engineContext = context; - if (mFontScaleAdapter == null) { - mFontScaleAdapter = context.getGlobalConfigs().getFontScaleAdapter(); - } - - if (mImageAdapter == null) { - mImageAdapter = context.getGlobalConfigs().getImageLoaderAdapter(); - } - - if (mIsVirtual) { - return; - } - - if (mFontScaleAdapter != null && !TextUtils.isEmpty(mText)) { - CharSequence s = mFontScaleAdapter.getEmoticonText(mText, mFontSize); - if (s != null) { - mText = s; - } - } - - mSpanned = createSpan(mText, true); - } - - @SuppressWarnings({"EmptyMethod", "unused"}) - protected void createCustomSpan(CharSequence text, Spannable spannableText) { - - } - - private SpannableStringBuilder createSpan(CharSequence text, boolean useChild) { - if (text != null) { - SpannableStringBuilder spannable = new SpannableStringBuilder(); - List ops = new ArrayList<>(); - createSpanOperations(ops, spannable, this, text, useChild); - - for (int i = ops.size() - 1; i >= 0; i--) { - SpanOperation op = ops.get(i); - - op.execute(spannable); - } - - createCustomSpan(text, spannable); - - return spannable; - } - return new SpannableStringBuilder(""); - } - - private void createImageSpanOperation(List ops, SpannableStringBuilder sb, - ImageNode imageNode) { - String url = null; - String defaultSource = null; - HippyMap props = imageNode.getTotalProps(); - if (props != null) { - url = props.getString("src"); - defaultSource = props.getString("defaultSource"); - } - - Drawable drawable = null; - if (!TextUtils.isEmpty(defaultSource) && mImageAdapter != null) { - assert defaultSource != null; - HippyDrawable hippyDrawable = mImageAdapter.getImage(defaultSource, null); - Bitmap bitmap = hippyDrawable.getBitmap(); - if (bitmap != null) { - drawable = new BitmapDrawable(bitmap); - } - } - - if (drawable == null) { - drawable = new ColorDrawable(Color.parseColor("#00000000")); - } - - int width = Math.round(imageNode.getStyleWidth()); - int height = Math.round(imageNode.getStyleHeight()); - drawable.setBounds(0, 0, width, height); - - HippyImageSpan imageSpan = new HippyImageSpan(drawable, url, imageNode, mImageAdapter, - engineContext); - imageNode.setImageSpan(imageSpan); - - int start = sb.length(); - sb.append(IMAGE_SPAN_TEXT); - int end = start + IMAGE_SPAN_TEXT.length(); - ops.add(new SpanOperation(start, end, imageSpan)); - - if (imageNode.getGestureTypes() != null && imageNode.getGestureTypes().size() > 0) { - HippyNativeGestureSpan span = new HippyNativeGestureSpan(imageNode.getId(), true); - span.addGestureTypes(imageNode.getGestureTypes()); - ops.add(new SpanOperation(start, end, span)); - } - } - - private void createSpanOperations(List ops, SpannableStringBuilder sb, - TextNode textNode, CharSequence text, boolean useChild) { - int start = sb.length(); - sb.append(text); - int end = sb.length(); - if (start <= end) { - - ops.add(new SpanOperation(start, end, new ForegroundColorSpan(textNode.mColor))); - if (textNode.mIsBackgroundColorSet) { - ops.add(new SpanOperation(start, end, new BackgroundColorSpan(textNode.mBackgroundColor))); - } - if (textNode.mLetterSpacing != UNSET) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - ops.add( - new SpanOperation(start, end, new HippyLetterSpacingSpan(textNode.mLetterSpacing))); - } - } - if (textNode.mFontSize != UNSET) { - int fontSize = textNode.mFontSize; - - if (textNode.mFontScaleAdapter != null && textNode.mEnableScale) { - fontSize = (int) (fontSize * textNode.mFontScaleAdapter.getFontScale()); - } - ops.add(new SpanOperation(start, end, new AbsoluteSizeSpan(fontSize))); - } - - if (textNode.mFontStyle != UNSET || textNode.mFontWeight != UNSET - || textNode.mFontFamily != null) { - ops.add(new SpanOperation(start, end, - new HippyStyleSpan(textNode.mFontStyle, textNode.mFontWeight, textNode.mFontFamily, - mFontScaleAdapter))); - } - if (textNode.mIsUnderlineTextDecorationSet) { - ops.add(new SpanOperation(start, end, new UnderlineSpan())); - } - if (textNode.mIsLineThroughTextDecorationSet) { - ops.add(new SpanOperation(start, end, new StrikethroughSpan())); - } - if (textNode.mTextShadowOffsetDx != 0 || textNode.mTextShadowOffsetDy != 0) { - ops.add(new SpanOperation(start, end, - new HippyShadowSpan(textNode.mTextShadowOffsetDx, textNode.mTextShadowOffsetDy, - textNode.mTextShadowRadius, textNode.mTextShadowColor))); - } - if (textNode.mLineHeight != UNSET) { - float lineHeight = textNode.mLineHeight; - - if (textNode.mFontScaleAdapter != null && textNode.mEnableScale) { - lineHeight = (lineHeight * textNode.mFontScaleAdapter.getFontScale()); - } - ops.add(new SpanOperation(start, end, new HippyLineHeightSpan(lineHeight))); - } - - if (textNode.mGestureTypes != null && textNode.mGestureTypes.size() > 0) { - HippyNativeGestureSpan span = new HippyNativeGestureSpan(textNode.getId(), isVirtual()); - span.addGestureTypes(textNode.mGestureTypes); - ops.add(new SpanOperation(start, end, span)); - } - } - - if (useChild) { - for (int i = 0; i < textNode.getChildCount(); i++) { - DomNode domNode = textNode.getChildAt(i); - if (domNode instanceof TextNode) { - TextNode tempNode = (TextNode) domNode; - CharSequence tempText = tempNode.mText; - if (mFontScaleAdapter != null && !TextUtils.isEmpty(tempText)) { - CharSequence s = mFontScaleAdapter.getEmoticonText(tempText, tempNode.mFontSize); - if (s != null) { - tempText = s; - } - } - //noinspection ConstantConditions - createSpanOperations(ops, sb, tempNode, tempText, useChild); - } else if (domNode instanceof ImageNode) { - createImageSpanOperation(ops, sb, (ImageNode) domNode); - } else { - throw new RuntimeException(domNode.getViewClass() + "is not support in Text"); - } - - domNode.markUpdateSeen(); - } - } - } - - private static final FlexNodeAPI.MeasureFunction TEXT_MEASURE_FUNCTION = new FlexNodeAPI.MeasureFunction() { - @SuppressWarnings("rawtypes") - @Override - public long measure(FlexNodeAPI node, float width, - FlexMeasureMode widthMode, float height, - FlexMeasureMode heightMode) { - TextNode reactCSSNode = (TextNode) node; - - Layout layout = null; - boolean exception = false; - - try { - - layout = reactCSSNode.createLayout(width, widthMode); - } catch (Throwable throwable) { - LogUtils.e("TextNode", "text createLayout", throwable); - exception = true; - } - - //noinspection ConstantConditions - if (exception || layout == null) { - return FlexOutput.make(width, height); - } else { - LogUtils.d("TextNode", - "measure:" + " w: " + layout.getWidth() + " h: " - + layout.getHeight()); - return FlexOutput.make(layout.getWidth(), - layout.getHeight()); - } - } - }; - - public void layoutAfter(HippyEngineContext context) { - if (!isVirtual()) { - LogUtils.d("TextNode", - "measure:layoutAfter" + " w: " + getLayoutWidth() + " h: " + getLayoutHeight()); - Layout mLayout = createLayout( - getLayoutWidth() - getPadding(FlexSpacing.LEFT) - getPadding(FlexSpacing.RIGHT), - FlexMeasureMode.EXACTLY); - context.getDomManager().postWarmLayout(mLayout); - setData(mLayout); - } - - } - - private StaticLayout buildStaticLayout(CharSequence source, TextPaint paint, int width) { - Layout.Alignment textAlign = mTextAlign; - if (I18nUtil.isRTL()) { - BidiFormatter bidiFormatter = BidiFormatter.getInstance(); - if (bidiFormatter.isRtl(source.toString()) && textAlign == Layout.Alignment.ALIGN_OPPOSITE) { - textAlign = Layout.Alignment.ALIGN_NORMAL; - } - } - - return new StaticLayout(source, paint, width, textAlign, 1.f, 0.f, - true); - } - - private Layout createLayout(float width, FlexMeasureMode widthMode) { - TextPaint textPaint = sTextPaintInstance; - Layout layout; - Spanned text = mSpanned == null ? new SpannedString("") : mSpanned; - BoringLayout.Metrics boring = null; - try { - boring = BoringLayout.isBoring(text, textPaint); - } catch (Throwable e) { - LogUtils.d("TextNode", "createLayout: " + e.getMessage()); - } - float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN; - - boolean unconstrainedWidth = widthMode == FlexMeasureMode.UNDEFINED || width < 0; - if (boring == null && (unconstrainedWidth || (!FlexConstants.isUndefined(desiredWidth) - && desiredWidth <= width))) { - layout = new StaticLayout(text, textPaint, (int)Math.ceil(desiredWidth), mTextAlign, 1.f, - 0.f, true); - } else if (boring != null && (unconstrainedWidth || boring.width <= width)) { - layout = BoringLayout.make(text, textPaint, boring.width, mTextAlign, 1.f, 0.f, boring, true); - } else { - layout = buildStaticLayout(text, textPaint, (int)Math.ceil(width)); - } - if (mNumberOfLines != UNSET && mNumberOfLines > 0) { - if (layout.getLineCount() > mNumberOfLines) { - int lastLineStart = layout.getLineStart(mNumberOfLines - 1); - int lastLineEnd = layout.getLineEnd(mNumberOfLines - 1); - if (lastLineStart < lastLineEnd) { - layout = createLayoutWithNumberOfLine(lastLineStart, layout.getWidth()); - } - } - } - - assert layout != null; - layout.getPaint().setTextSize(mFontSize); - return layout; - } - - private StaticLayout createLayoutWithNumberOfLine(int lastLineStart, int width) { - if (mSpanned == null) { - return null; - } - String text = mSpanned.toString(); - SpannableStringBuilder temp = (SpannableStringBuilder) mSpanned.subSequence(0, text.length()); - String ellipsizeStr = (String) TextUtils - .ellipsize(text.substring(lastLineStart), sTextPaintInstance, width, - TextUtils.TruncateAt.END); - String newString = text.subSequence(0, lastLineStart).toString() - + truncate(ellipsizeStr, sTextPaintInstance, width, mTruncateAt); - - int start = Math.max(newString.length() - 1, 0); - CharacterStyle[] hippyStyleSpans = temp.getSpans(start, text.length(), CharacterStyle.class); - if (hippyStyleSpans != null && hippyStyleSpans.length > 0) { - for (CharacterStyle hippyStyleSpan : hippyStyleSpans) { - if (temp.getSpanStart(hippyStyleSpan) >= start) { - temp.removeSpan(hippyStyleSpan); - } - } - } - - return buildStaticLayout(temp.replace(start, text.length(), ELLIPSIS), sTextPaintInstance, width); - } - - private static final String ELLIPSIS = "\u2026"; - - public String truncate(String source, TextPaint paint, int desired, - TextUtils.TruncateAt truncateAt) { - if (!TextUtils.isEmpty(source)) { - StringBuilder builder; - Spanned spanned; - StaticLayout layout; - for (int i = source.length(); i > 0; i--) { - builder = new StringBuilder(i + 1); - if (truncateAt != null) { - builder.append(source, 0, i > 1 ? i - 1 : i); - builder.append(ELLIPSIS); - } else { - builder.append(source, 0, i); - } - spanned = createSpan(builder.toString(), false); - layout = buildStaticLayout(spanned, paint, desired); - if (layout.getLineCount() <= 1) { - return spanned.toString(); - } - } - } - return ""; - } - - private static class SpanOperation { - - protected final int start; - protected final int end; - protected final Object what; - - @SuppressWarnings("unused") - SpanOperation(int start, int end, Object what) { - this.start = start; - this.end = end; - this.what = what; - } - - public void execute(SpannableStringBuilder sb) { - int spanFlags = Spannable.SPAN_EXCLUSIVE_INCLUSIVE; - if (start == 0) { - spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE; - } - - try { - sb.setSpan(what, start, end, spanFlags); - } catch (Exception e) { - LogUtils.e("TextNode", "setSpan exception msg: " + e.getMessage()); - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TypeFaceUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TypeFaceUtil.java deleted file mode 100644 index e34259f4375..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/TypeFaceUtil.java +++ /dev/null @@ -1,218 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.dom.node; - -import android.content.Context; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.text.TextUtils; -import android.util.Base64; - -import com.tencent.mtt.hippy.adapter.font.HippyFontScaleAdapter; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -@SuppressWarnings({"unused"}) -public class TypeFaceUtil { - - final static private String TAG = "TypeFaceUtil"; - private static final String[] EXTENSIONS = {"", "_bold", "_italic", "_bold_italic"}; - private static final String[] FONT_EXTENSIONS = {".ttf", ".otf"}; - private static final String FONTS_PATH = "fonts/"; - - private static final Map mFontCache = new HashMap<>(); - - public static Typeface getTypeface(String fontFamilyName, int style, - HippyFontScaleAdapter fontAdapter) { - String cache = fontFamilyName + style; - Typeface typeface = mFontCache.get(cache); - if (typeface == null) { - typeface = createTypeface(fontFamilyName, style, fontAdapter); - } - - if (typeface != null) { - mFontCache.put(cache, typeface); - } - - return typeface; - } - - private static Typeface createTypeface(String fontFamilyName, int style, - HippyFontScaleAdapter fontAdapter) { - Typeface typeface = null; - String extension = EXTENSIONS[style]; - for (String fileExtension : FONT_EXTENSIONS) { - String fileName = FONTS_PATH + fontFamilyName + extension + fileExtension; - try { - typeface = Typeface.createFromAsset(ContextHolder.getAppContext().getAssets(), fileName); - } catch (Exception e) { - LogUtils.e("TypeFaceUtil", "createTypeface: " + e.getMessage()); - } - } - - if (typeface == null && fontAdapter != null) { - String filePath = fontAdapter.getCustomFontFilePath(fontFamilyName, style); - if (!TextUtils.isEmpty(filePath)) { - try { - typeface = Typeface.createFromFile(filePath); - } catch (Exception e) { - LogUtils.e("TypeFaceUtil", "createTypeface: " + e.getMessage()); - } - } - } - - if (typeface == null) { - typeface = Typeface.create(fontFamilyName, style); - } - - return typeface; - } - - public static boolean checkFontExist(String fontFamilyName, int style) { - String cache = fontFamilyName + style; - Typeface typeface = mFontCache.get(cache); - return typeface != null; - } - - public static Typeface addTypeface(String fontFamilyName, String fontPath, int style) { - String cache = fontFamilyName + style; - Typeface typeface = mFontCache.get(cache); - if (typeface != null) { - return typeface; - } - try { - typeface = Typeface.createFromFile(fontPath); - } catch (RuntimeException e) { - e.printStackTrace(); - } - if (typeface != null) { - mFontCache.put(cache, typeface); - } - return typeface; - } - - public static Typeface addTypefaceWithBase64(String fontFamilyName, String fontBase64Data, - int style) { - String cache = fontFamilyName + style; - Typeface typeface = mFontCache.get(cache); - if (typeface != null) { - return typeface; - } - byte[] fontData; - if (TextUtils.isEmpty(fontBase64Data)) { - return null; - } else { - String fontPath = getFontPath(ContextHolder.getAppContext(), cache); - fontData = getRealTTFBase64(fontBase64Data); - deleteFontFile(fontPath); - saveFontFile(fontPath, fontData); - typeface = TypeFaceUtil.addTypeface(fontFamilyName, fontPath, Typeface.NORMAL); - deleteFontFile(fontPath); - } - return typeface; - } - - public static void apply(Paint paint, int style, int weight, String family, - HippyFontScaleAdapter fontAdapter) { - int oldStyle; - Typeface typeface = paint.getTypeface(); - if (typeface == null) { - oldStyle = 0; - } else { - oldStyle = typeface.getStyle(); - } - - int want = 0; - if ((weight == Typeface.BOLD) || ((oldStyle & Typeface.BOLD) != 0 - && weight == TextNode.UNSET)) { - want |= Typeface.BOLD; - } - - if ((style == Typeface.ITALIC) || ((oldStyle & Typeface.ITALIC) != 0 - && style == TextNode.UNSET)) { - want |= Typeface.ITALIC; - } - - if (family != null) { - typeface = TypeFaceUtil.getTypeface(family, want, fontAdapter); - } else if (typeface != null) { - typeface = Typeface.create(typeface, want); - } - - if (typeface != null) { - paint.setTypeface(typeface); - } else { - paint.setTypeface(Typeface.defaultFromStyle(want)); - } - } - - private static void deleteFontFile(String path) { - if (TextUtils.isEmpty(path)) { - return; - } - File file = new File(path); - boolean exists = file.exists(); - if (exists) { - //noinspection ResultOfMethodCallIgnored - file.delete(); - } - } - - private static void saveFontFile(String path, byte[] data) { - File file = new File(path); - BufferedOutputStream outStream = null; - try { - outStream = new BufferedOutputStream(new FileOutputStream(file)); - outStream.write(data); - outStream.flush(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (null != outStream) { - try { - outStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - private static byte[] getRealTTFBase64(String base64Str) { - LogUtils.d(TAG, "原始字库数据 base64Str:" + base64Str); - if (TextUtils.isEmpty(base64Str)) { - return null; - } - String tag = "base64,"; - int location = base64Str.indexOf(tag); - String realBase64Str = base64Str; - if (location > 0) { - realBase64Str = base64Str.substring(location + tag.length()); - } - return Base64.decode(realBase64Str, Base64.DEFAULT); - } - - private static String getFontPath(Context context, String fileName) { - return context.getCacheDir().getAbsolutePath() + File.separator + fileName + ".ttf"; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleANRMonitor.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleANRMonitor.java deleted file mode 100644 index 44ef9108b4c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleANRMonitor.java +++ /dev/null @@ -1,137 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules; - -import android.os.SystemClock; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorAdapter; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.supportui.utils.struct.Pools; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * FileName: HippyModuleANRMonitor Description: History: - */ -public class HippyModuleANRMonitor { - - static final int ANR_TIME = 100; - static final int MONITOR_ID_NAN = 0; - static int MONITOR_ID = 0; - final HippyEngineContext mContext; - boolean mNeedReportBridgeANR = false; - HippyEngineMonitorAdapter mEngineMonitorAdapter; - ConcurrentHashMap mMonitorMessages; - - public HippyModuleANRMonitor(HippyEngineContext context) { - this.mContext = context; - if (mContext != null) { - this.mEngineMonitorAdapter = mContext.getGlobalConfigs().getEngineMonitorAdapter(); - this.mNeedReportBridgeANR = mEngineMonitorAdapter.needReportBridgeANR(); - if (mNeedReportBridgeANR) { - //noinspection unchecked,rawtypes - mMonitorMessages = new ConcurrentHashMap(); - } - } - } - - public int startMonitor(String parms1, String parms2) { - if (!mNeedReportBridgeANR) { - return MONITOR_ID_NAN; - } - MonitorMessage message = MonitorMessage.obtain(parms1, parms2, SystemClock.elapsedRealtime()); - int id = ++MONITOR_ID; - if (id == MONITOR_ID_NAN) { - id = ++MONITOR_ID; - } - mMonitorMessages.put(id, message); - return id; - } - - public void endMonitor(int id) { - if (!mNeedReportBridgeANR) { - return; - } - MonitorMessage message = mMonitorMessages.get(id); - if (message == null) { - return; - } - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime - message.startTime > ANR_TIME) { - if (mEngineMonitorAdapter != null) { - mEngineMonitorAdapter.reportBridgeANR(message.param1 + " | " + message.param2); - } - } - mMonitorMessages.remove(id); - message.onDispose(); - } - - public void checkMonitor() { - if (mMonitorMessages == null) { - return; - } - for (Map.Entry entry : mMonitorMessages.entrySet()) { - MonitorMessage monitorMessage = entry.getValue(); - if (monitorMessage != null) { - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime - monitorMessage.startTime > ANR_TIME) { - if (mEngineMonitorAdapter != null) { - mEngineMonitorAdapter - .reportBridgeANR(monitorMessage.param1 + " | " + monitorMessage.param2); - } - mMonitorMessages.remove(entry.getKey()); - monitorMessage.onDispose(); - } - } - } - } - - @SuppressWarnings({"unused"}) - static class MonitorMessage { - - private static final int POOL_SIZE = 20; - private static final Pools.SynchronizedPool INSTANCE_POOL = new Pools.SynchronizedPool<>( - POOL_SIZE); - - public String param1; - public String param2; - public long startTime; - - public static MonitorMessage obtain(String param1, String param2, long startTime) { - MonitorMessage instance = INSTANCE_POOL.acquire(); - if (instance == null) { - instance = new MonitorMessage(); - } - instance.init(param1, param2, startTime); - return instance; - } - - private void init(String param1, String param2, long startTime) { - this.param1 = param1; - this.param2 = param2; - this.startTime = startTime; - } - - public void onDispose() { - try { - INSTANCE_POOL.release(this); - } catch (Throwable e) { - LogUtils.d("MonitorMessage", "onDispose: " + e.getMessage()); - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManager.java deleted file mode 100644 index b506215604f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManager.java +++ /dev/null @@ -1,38 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules; - - -import com.tencent.mtt.hippy.bridge.HippyCallNativeParams; -import com.tencent.mtt.hippy.common.Provider; -import com.tencent.mtt.hippy.modules.javascriptmodules.HippyJavaScriptModule; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; - -/** - * FileName: HippyModuleManager Description: History: - */ -public interface HippyModuleManager { - - void callNatives(HippyCallNativeParams params); - - void destroy(); - - T getJavaScriptModule(Class cls); - - T getNativeModule(Class cls); - - void addNativeModule(Class cls, Provider provider); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManagerImpl.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManagerImpl.java deleted file mode 100644 index 1199a775353..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/HippyModuleManagerImpl.java +++ /dev/null @@ -1,336 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; - -import com.tencent.mtt.hippy.HippyAPIProvider; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.bridge.HippyCallNativeParams; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.Provider; -import com.tencent.mtt.hippy.modules.javascriptmodules.HippyJavaScriptModule; -import com.tencent.mtt.hippy.modules.javascriptmodules.HippyJavaScriptModuleInvocationHandler; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleInfo; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.lang.reflect.Proxy; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -@SuppressWarnings({"unchecked", "unused", "rawtypes"}) -public class HippyModuleManagerImpl implements HippyModuleManager, Handler.Callback { - - private static final int MSG_CODE_CALL_NATIVES = 1; - private static final int MSG_CODE_DESTROY_MODULE = 2; - private final ConcurrentHashMap mNativeModuleInfo; - //Only multi-threaded read - private final HashMap, HippyJavaScriptModule> mJsModules; - private final HippyEngineContext mContext; - private boolean isDestroyed = false; - private volatile Handler mUIThreadHandler; - private volatile Handler mBridgeThreadHandler; - private volatile Handler mDomThreadHandler; - private final HippyModuleANRMonitor mANRMonitor; - - public HippyModuleManagerImpl(HippyEngineContext context, List packages) { - this.mContext = context; - mANRMonitor = new HippyModuleANRMonitor(mContext); - mNativeModuleInfo = new ConcurrentHashMap<>(); - mJsModules = new HashMap<>(); - for (HippyAPIProvider pckg : packages) { - Map, Provider> nativeModules = pckg - .getNativeModules(context); - if (nativeModules != null && nativeModules.size() > 0) { - Set> keys = nativeModules.keySet(); - for (Class cls : keys) { - HippyNativeModuleInfo moduleInfo = new HippyNativeModuleInfo(cls, nativeModules.get(cls)); - String[] names = moduleInfo.getNames(); - if (names != null && names.length > 0) { - for (String name : names) { - if (!mNativeModuleInfo.containsKey(name)) { - mNativeModuleInfo.put(name, moduleInfo); - } - } - } - - if (!mNativeModuleInfo.containsKey(moduleInfo.getName())) { - mNativeModuleInfo.put(moduleInfo.getName(), moduleInfo); - //throw new RuntimeException("There is already a native module named : " + moduleInfo.getName()); - } - } - } - - List> jsModules = pckg.getJavaScriptModules(); - if (jsModules != null && jsModules.size() > 0) { - for (Class cls : jsModules) { - String name = getJavaScriptModuleName(cls); - //noinspection SuspiciousMethodCalls - if (mJsModules.containsKey(name)) { - throw new RuntimeException("There is already a javascript module named : " + name); - } - mJsModules.put(cls, null); - } - } - - } - } - - @Override - public synchronized void addNativeModule(Class cls, Provider provider) { - assert provider != null; - if (provider == null) { - return; - } - - HippyNativeModuleInfo moduleInfo = new HippyNativeModuleInfo(cls, provider); - String[] names = moduleInfo.getNames(); - if (names != null && names.length > 0) { - for (String name : names) { - if (!mNativeModuleInfo.containsKey(name)) { - mNativeModuleInfo.put(name, moduleInfo); - } - } - } - - if (!mNativeModuleInfo.containsKey(moduleInfo.getName())) { - mNativeModuleInfo.put(moduleInfo.getName(), moduleInfo); - } - } - - @Override - public void destroy() { - if (mBridgeThreadHandler != null) { - mBridgeThreadHandler.removeMessages(MSG_CODE_CALL_NATIVES); - } - if (mDomThreadHandler != null) { - mDomThreadHandler.removeMessages(MSG_CODE_CALL_NATIVES); - } - if (mUIThreadHandler != null) { - mUIThreadHandler.removeMessages(MSG_CODE_CALL_NATIVES); - } - - if (mANRMonitor != null) { - mANRMonitor.checkMonitor(); - } - - //Must be thrown bridge thread to complete - isDestroyed = true; - Iterator> iterator = mNativeModuleInfo.entrySet() - .iterator(); - Map.Entry entry; - HippyNativeModuleInfo moduleInfo; - while (iterator.hasNext()) { - entry = iterator.next(); - if (entry != null) { - moduleInfo = entry.getValue(); - if (moduleInfo != null && moduleInfo.shouldDestroy()) { - moduleInfo.onDestroy(); - if (moduleInfo.getThread() == HippyNativeModule.Thread.DOM) { - if (mDomThreadHandler != null) { - Message msg = mDomThreadHandler.obtainMessage(MSG_CODE_DESTROY_MODULE, moduleInfo); - mDomThreadHandler.sendMessage(msg); - } - } else if (moduleInfo.getThread() == HippyNativeModule.Thread.MAIN) { - if (mUIThreadHandler != null) { - Message msg = mUIThreadHandler.obtainMessage(MSG_CODE_DESTROY_MODULE, moduleInfo); - mUIThreadHandler.sendMessage(msg); - } - } else { - if (mBridgeThreadHandler != null) { - Message msg = mBridgeThreadHandler.obtainMessage(MSG_CODE_DESTROY_MODULE, moduleInfo); - mBridgeThreadHandler.sendMessage(msg); - } - } - } - } - } - mNativeModuleInfo.clear(); - } - - @Override - public void callNatives(HippyCallNativeParams params) { - if (isDestroyed) { - return; - } - HippyNativeModuleInfo moduleInfo = mNativeModuleInfo.get(params.mModuleName); - if (moduleInfo == null) { - PromiseImpl promise = new PromiseImpl(mContext, params.mModuleName, params.mModuleFunc, - params.mCallId); - promise.doCallback(PromiseImpl.PROMISE_CODE_NORMAN_ERROR, "module can not be found"); - return; - } - - if (moduleInfo.getThread() == HippyNativeModule.Thread.DOM) { - Handler handler = getDomThreadHandler(); - Message msg = handler.obtainMessage(MSG_CODE_CALL_NATIVES, params); - handler.sendMessage(msg); - } else if (moduleInfo.getThread() == HippyNativeModule.Thread.MAIN) { - Handler handler = getUIThreadHandler(); - Message msg = handler.obtainMessage(MSG_CODE_CALL_NATIVES, params); - handler.sendMessage(msg); - } else { - Handler handler = getBridgeThreadHandler(); - Message msg = handler.obtainMessage(MSG_CODE_CALL_NATIVES, params); - handler.sendMessage(msg); - } - } - - @Override - public synchronized T getJavaScriptModule(Class cls) { - HippyJavaScriptModule module = mJsModules.get(cls); - if (module != null) { - return (T) module; - } - ClassLoader clsLoader = cls.getClassLoader(); - if (clsLoader == null) { - return null; - } - HippyJavaScriptModule moduleProxy = (HippyJavaScriptModule) Proxy - .newProxyInstance(clsLoader, new Class[]{cls}, - new HippyJavaScriptModuleInvocationHandler(mContext, getJavaScriptModuleName(cls))); - mJsModules.remove(cls); - mJsModules.put(cls, moduleProxy); - return (T) moduleProxy; - } - - @Override - public synchronized T getNativeModule(Class cls) { - HippyNativeModule annotation = cls.getAnnotation(HippyNativeModule.class); - if (annotation != null) { - String name = annotation.name(); - HippyNativeModuleInfo moduleInfo = mNativeModuleInfo.get(name); - if (moduleInfo != null) { - return (T) moduleInfo.getInstance(); - } - } - return null; - } - - void doCallNatives(String moduleName, String moduleFunc, String callId, HippyArray params) { - PromiseImpl promise = new PromiseImpl(mContext, moduleName, moduleFunc, callId); - try { - HippyNativeModuleInfo moduleInfo = mNativeModuleInfo.get(moduleName); - if (moduleInfo == null) { - promise.doCallback(PromiseImpl.PROMISE_CODE_NORMAN_ERROR, "module can not be found"); - return; - } - - moduleInfo.initialize(); - HippyNativeModuleInfo.HippyNativeMethod method = moduleInfo.findMethod(moduleFunc); - if (method == null || method.isSync()) { - promise - .doCallback(PromiseImpl.PROMISE_CODE_NORMAN_ERROR, "module function can not be found"); - return; - } - method.invoke(mContext, moduleInfo.getInstance(), params, promise); - } catch (Throwable e) { - promise.doCallback(PromiseImpl.PROMISE_CODE_NORMAN_ERROR, e.getMessage()); - mContext.getGlobalConfigs().getExceptionHandler().handleNativeException(new RuntimeException(e), true); - } - } - - private String getJavaScriptModuleName(Class cls) { - String name = cls.getSimpleName(); - int dollarSignIndex = name.lastIndexOf('$'); - if (dollarSignIndex != -1) { - name = name.substring(dollarSignIndex + 1); - } - return name; - } - - private Handler getDomThreadHandler() { - if (mDomThreadHandler == null) { - synchronized (HippyModuleManagerImpl.class) { - if (mDomThreadHandler == null) { - mDomThreadHandler = new Handler(mContext.getThreadExecutor().getDomThread().getLooper(), - this); - } - } - } - return mDomThreadHandler; - } - - private Handler getUIThreadHandler() { - if (mUIThreadHandler == null) { - synchronized (HippyModuleManagerImpl.class) { - if (mUIThreadHandler == null) { - mUIThreadHandler = new Handler(Looper.getMainLooper(), this); - } - } - } - return mUIThreadHandler; - } - - private Handler getBridgeThreadHandler() { - if (mBridgeThreadHandler == null) { - synchronized (HippyModuleManagerImpl.class) { - if (mBridgeThreadHandler == null) { - mBridgeThreadHandler = new Handler( - mContext.getThreadExecutor().getJsBridgeThread().getLooper(), this); - } - } - } - return mBridgeThreadHandler; - } - - @Override - public boolean handleMessage(Message msg) { - - switch (msg.what) { - case MSG_CODE_CALL_NATIVES: { - HippyCallNativeParams param = null; - int id = -1; - try { - param = (HippyCallNativeParams) msg.obj; - HippyArray array = param.mParams; - - id = mANRMonitor.startMonitor(param.mModuleName, param.mModuleFunc); - doCallNatives(param.mModuleName, param.mModuleFunc, param.mCallId, array); - } catch (Throwable e) { - LogUtils.d("HippyModuleManagerImpl", "handleMessage: " + e.getMessage()); - } finally { - if (param != null) { - param.onDispose(); - } - - if (id >= 0) { - mANRMonitor.endMonitor(id); - } - } - return true; - } - case MSG_CODE_DESTROY_MODULE: { - try { - HippyNativeModuleInfo moduleInfo = (HippyNativeModuleInfo) msg.obj; - moduleInfo.destroy(); - } catch (Throwable e) { - LogUtils.d("HippyModuleManagerImpl", "handleMessage: " + e.getMessage()); - } - return true; - } - } - return false; - } - - public ConcurrentHashMap getNativeModuleInfo() { - return mNativeModuleInfo; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/PromiseImpl.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/PromiseImpl.java deleted file mode 100644 index d828d625f37..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/PromiseImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules; - - -import android.text.TextUtils; - -import com.tencent.mtt.hippy.HippyEngine.BridgeTransferType; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.runtime.builtins.JSMap; -import com.tencent.mtt.hippy.runtime.builtins.JSObject; -import com.tencent.mtt.hippy.runtime.builtins.JSValue; -import java.util.HashMap; - -@SuppressWarnings({"deprecation", "unused"}) -public class PromiseImpl implements Promise { - - public static final int PROMISE_CODE_SUCCESS = 0; - public static final int PROMISE_CODE_NORMAN_ERROR = 1; - public static final int PROMISE_CODE_OTHER_ERROR = 2; - private static final String CALL_ID_NO_CALLBACK = "-1"; - private HippyEngineContext mContext; - private final String mModuleName; - private final String mModuleFunc; - private final String mCallId; - private boolean mNeedResolveBySelf = true; - private BridgeTransferType transferType = BridgeTransferType.BRIDGE_TRANSFER_TYPE_NORMAL; - - public PromiseImpl(HippyEngineContext context, String moduleName, String moduleFunc, - String callId) { - this.mContext = context; - this.mModuleName = moduleName; - this.mModuleFunc = moduleFunc; - this.mCallId = callId; - } - - public void setContext(HippyEngineContext context) { - mContext = context; - } - - public String getCallId() { - return mCallId; - } - - public boolean isCallback() { - return !TextUtils.equals(mCallId, CALL_ID_NO_CALLBACK); - } - - @Override - public void setTransferType(BridgeTransferType type) { - transferType = type; - } - - @Override - public void resolve(Object value) { - doCallback(PROMISE_CODE_SUCCESS, value); - } - - @Override - public void reject(Object error) { - doCallback(PROMISE_CODE_OTHER_ERROR, error); - } - - public void setNeedResolveBySelf(boolean falg) { - mNeedResolveBySelf = falg; - } - - public boolean needResolveBySelf() { - return mNeedResolveBySelf; - } - - public void doCallback(int code, Object obj) { - if (TextUtils.equals(CALL_ID_NO_CALLBACK, mCallId)) { - return; - } - - if (obj instanceof JSValue) { - JSObject jsObject = new JSObject(); - jsObject.set("result", code); - jsObject.set("moduleName", mModuleName); - jsObject.set("moduleFunc", mModuleFunc); - jsObject.set("callId", mCallId); - jsObject.set("params", obj); - mContext.getBridgeManager().execCallback(jsObject, transferType); - } else { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushInt("result", code); - hippyMap.pushString("moduleName", mModuleName); - hippyMap.pushString("moduleFunc", mModuleFunc); - hippyMap.pushString("callId", mCallId); - hippyMap.pushObject("params", obj); - mContext.getBridgeManager().execCallback(hippyMap, transferType); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/HippyNativeModuleInfo.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/HippyNativeModuleInfo.java deleted file mode 100644 index a0069b29c02..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/HippyNativeModuleInfo.java +++ /dev/null @@ -1,203 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules; - -import android.text.TextUtils; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.Provider; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.modules.PromiseImpl; -import com.tencent.mtt.hippy.utils.ArgumentUtils; - -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; - -@SuppressWarnings({"unused"}) -public final class HippyNativeModuleInfo { - - private final String mName; - - private final String[] mNames; - - private final HippyNativeModule.Thread mThread; - - private final Provider mProvider; - - private final Class mClass; - - private Map mMethods; - - private HippyNativeModuleBase mInstance; - - private boolean mInit = false; - - private boolean mIsDestroyed = false; - - public HippyNativeModuleInfo(Class cls, Provider provider) { - HippyNativeModule annotation = cls.getAnnotation(HippyNativeModule.class); - assert annotation != null; - this.mName = annotation.name(); - this.mNames = annotation.names(); - this.mClass = cls; - this.mThread = annotation.thread(); - mProvider = provider; - initImmediately(annotation); - - } - - private void initImmediately(HippyNativeModule annotation) { - if (annotation.init()) { - try { - initialize(); - } catch (Throwable e) { - e.printStackTrace(); - } - - } - } - - public boolean shouldDestroy() { - return !mIsDestroyed; - } - - public void onDestroy() { - mIsDestroyed = true; - } - - public String getName() { - return mName; - } - - public String[] getNames() { - return mNames; - } - - public HippyNativeModuleBase getInstance() { - return mInstance; - } - - public HippyNativeModule.Thread getThread() { - return mThread; - } - - public Map getMethods() { - return mMethods; - } - - public void initialize() { - if (mInit) { - return; - } - mMethods = new HashMap<>(); - Method[] targetMethods = mClass.getMethods(); - for (Method targetMethod : targetMethods) { - HippyMethod hippyMethod = targetMethod.getAnnotation(HippyMethod.class); - if (hippyMethod != null) { - String methodName = hippyMethod.name(); - if (TextUtils.isEmpty(methodName)) { - methodName = targetMethod.getName(); - } - if (mMethods.containsKey(methodName)) { - throw new RuntimeException( - "Java Module " + mName + " method name already registered: " + methodName); - } - mMethods.put(methodName, new HippyNativeMethod(targetMethod, hippyMethod.isSync())); - } - } - - mInstance = mProvider.get(); - mInstance.initialize(); - mInit = true; - } - - public void destroy() { - if (mInstance != null) { - mInstance.destroy(); - } - } - - public HippyNativeMethod findMethod(String moduleFunc) { - if (mMethods == null) { - return null; - } - return mMethods.get(moduleFunc); - } - - - public static class HippyNativeMethod { - - private final Method mMethod; - - private final Type[] mParamTypes; - - private boolean mIsSync; - - public HippyNativeMethod(Method method, boolean isSync) { - this.mMethod = method; - this.mIsSync = isSync; - this.mParamTypes = method.getGenericParameterTypes(); - } - - public void invoke(HippyEngineContext context, Object receiver, HippyArray args, - PromiseImpl promise) throws Exception { - Object[] params = prepareArguments(context, mParamTypes, args, promise); - mMethod.invoke(receiver, params); - if (promise.needResolveBySelf()) { - promise.resolve(""); - } - } - - private Object[] prepareArguments(HippyEngineContext context, Type[] paramClss, HippyArray args, - PromiseImpl promise) { - if (paramClss == null || paramClss.length <= 0) { - return new Object[0]; - } - Object[] params = new Object[paramClss.length]; - if (args == null) { - throw new RuntimeException("method argument list not match"); - } - Type paramCls; - int index = 0; - - for (int i = 0; i < paramClss.length; i++) { - paramCls = paramClss[i]; - if (paramCls == Promise.class) { - params[i] = promise; - promise.setNeedResolveBySelf(false); - } else { - if (args.size() <= index) { - throw new RuntimeException("method argument list not match"); - } - params[i] = ArgumentUtils.parseArgument(paramCls, args, index); - index++; - } - - } - return params; - } - - public boolean isSync() { - return mIsSync; - } - - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/Animation.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/Animation.java deleted file mode 100644 index c282235e092..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/Animation.java +++ /dev/null @@ -1,158 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import android.animation.Animator; -import android.animation.ValueAnimator; - -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * FileName: Animation Description: History: - */ -public abstract class Animation implements ValueAnimator.AnimatorUpdateListener, - Animator.AnimatorListener { - - protected final int mId; - - protected CopyOnWriteArrayList mAnimationNodes; - - protected CopyOnWriteArrayList mAnimationListeners; - - - @SuppressWarnings("unused") - public Animation(int id) { - this.mId = id; - } - - public abstract Animator getAnimator(); - - public abstract void start(); - - public abstract void stop(); - - public int getId() { - return mId; - } - - public void addAnimationNode(int tagId) { - if (mAnimationNodes == null) { - mAnimationNodes = new CopyOnWriteArrayList<>(); - } - if (!mAnimationNodes.contains(tagId)) { - mAnimationNodes.add(tagId); - } - } - - public void removeAnimationNode(int tagId) { - if (mAnimationNodes != null) { - mAnimationNodes.remove(Integer.valueOf(tagId)); - } - } - - public CopyOnWriteArrayList getAnimationNodes() { - return mAnimationNodes; - } - - public void addAnimationListener(AnimationListener listener) { - if (mAnimationListeners == null) { - mAnimationListeners = new CopyOnWriteArrayList<>(); - } - mAnimationListeners.add(listener); - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (mAnimationListeners == null) { - return; - } - for (AnimationListener mAnimationListener : mAnimationListeners) { - mAnimationListener.onAnimationUpdate(this); - } - } - - @Override - public void onAnimationStart(Animator animation, boolean isReverse) { - onAnimationStart(animation); - } - - @Override - public void onAnimationEnd(Animator animation, boolean isReverse) { - onAnimationEnd(animation); - } - - @Override - public void onAnimationStart(Animator animation) { - if (mAnimationListeners == null) { - return; - } - for (AnimationListener mAnimationListener : mAnimationListeners) { - mAnimationListener.onAnimationStart(this); - } - } - - @Override - public void onAnimationEnd(Animator animation) { - if (mAnimationListeners == null) { - return; - } - for (AnimationListener mAnimationListener : mAnimationListeners) { - mAnimationListener.onAnimationEnd(this); - } - - } - - @Override - public void onAnimationCancel(Animator animation) { - if (mAnimationListeners == null) { - return; - } - for (AnimationListener mAnimationListener : mAnimationListeners) { - mAnimationListener.onAnimationCancel(this); - } - } - - @Override - public void onAnimationRepeat(Animator animation) { - if (mAnimationListeners == null) { - return; - } - for (AnimationListener mAnimationListener : mAnimationListeners) { - mAnimationListener.onAnimationRepeat(this); - } - } - - public abstract Object getAnimationValue(); - - public abstract Object getAnimationSimpleValue(); - - public abstract void resume(); - - public abstract void pause(); - - public interface AnimationListener { - - void onAnimationStart(Animation animation); - - void onAnimationEnd(Animation animation); - - void onAnimationCancel(Animation animation); - - void onAnimationRepeat(Animation animation); - - void onAnimationUpdate(Animation animation); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationFrameModule.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationFrameModule.java deleted file mode 100644 index ac91f93d1ce..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationFrameModule.java +++ /dev/null @@ -1,46 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.dom.HippyChoreographer; -import com.tencent.mtt.hippy.dom.ICSChoreographer; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; - -@HippyNativeModule(name = "AnimationFrameModule", thread = HippyNativeModule.Thread.MAIN) -public class AnimationFrameModule extends HippyNativeModuleBase { - - public AnimationFrameModule(HippyEngineContext context) { - super(context); - } - - @SuppressWarnings("unused") - @HippyMethod(name = "requestAnimationFrame") - public void requestAnimationFrame(final Promise promise) { - ICSChoreographer.getInstance().postFrameCallback(new HippyChoreographer.FrameCallback() { - @SuppressWarnings("unused") - @Override - public void doFrame(long frameTimeNanos) { - if (promise != null) { - promise.resolve(null); - } - } - }); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationModule.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationModule.java deleted file mode 100644 index 8d0f5171200..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationModule.java +++ /dev/null @@ -1,570 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.SparseArray; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyEngineLifecycleEventListener; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.DomActionInterceptor; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyNativeModule(name = "AnimationModule", thread = HippyNativeModule.Thread.DOM) -public class AnimationModule extends HippyNativeModuleBase implements DomActionInterceptor, - Animation.AnimationListener, Handler.Callback, - HippyEngineLifecycleEventListener { - - public static final String ANIMATION_ID = "animationId"; - public static final String TIMING = "timing"; - public static final String USE_ANIMATION = "useAnimation"; - public static final String HANDLE_MESSAGE_BY_ANIMATION = "handleMessageByAnimation"; - public static final String FOLLOW = "follow"; - - public static final String EVENT_NAME_ANIMATION_START = "onHippyAnimationStart"; - public static final String EVENT_NAME_ANIMATION_END = "onHippyAnimationEnd"; - public static final String EVENT_NAME_ANIMATION_CANCEL = "onHippyAnimationCancel"; - public static final String EVENT_NAME_ANIMATION_REPEAT = "onHippyAnimationRepeat"; - - private static final int ANIMATION_DELAY_TIME = 16; - private static final int MSG_CHANGE_ANIMATION_STATUS = 100; - private static final int MSG_UPDATE_ANIMATION_NODE = 101; - private SparseArray mAnimations; - private SparseArray mAnimationNodes; - private Handler mHandler; - private long mLastUpdateTime; - private final Set mNeedUpdateAnimationNodes; - private Set mWaitUpdateAnimationNodes; - - - public AnimationModule(HippyEngineContext context) { - super(context); - mNeedUpdateAnimationNodes = Collections.synchronizedSet(new HashSet()); - } - - @Override - public boolean handleMessage(Message msg) { - int what = msg.what; - switch (what) { - case MSG_CHANGE_ANIMATION_STATUS: { - if (!mHandler.hasMessages(MSG_UPDATE_ANIMATION_NODE)) { - long time = SystemClock.elapsedRealtime(); - if (time - mLastUpdateTime >= ANIMATION_DELAY_TIME) { - doUpdateAnimationNodes(); - } else { - - mHandler.sendEmptyMessageDelayed(MSG_UPDATE_ANIMATION_NODE, time - mLastUpdateTime); - } - } - break; - } - case MSG_UPDATE_ANIMATION_NODE: { - doUpdateAnimationNodes(); - break; - } - } - return true; - } - - @Override - public void initialize() { - super.initialize(); - mContext.addEngineLifecycleEventListener(this); - mHandler = new Handler(mContext.getThreadExecutor().getDomThread().getLooper(), this); - mAnimations = new SparseArray<>(); - mAnimationNodes = new SparseArray<>(); - if (mContext.getDomManager() != null) { - mContext.getDomManager().addActionInterceptor(this); - } - } - - @Override - public void destroy() { - mContext.removeEngineLifecycleEventListener(this); - if (mContext.getDomManager() != null) { - mContext.getDomManager().removeActionInterceptor(this); - } - super.destroy(); - } - - @Override - public void onAnimationStart(Animation animation) { - mContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeEvent(EVENT_NAME_ANIMATION_START, animation.getId()); - } - - @Override - public void onAnimationEnd(Animation animation) { - onAnimationUpdate(animation); - mContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeEvent(EVENT_NAME_ANIMATION_END, animation.getId()); - } - - @Override - public void onAnimationCancel(Animation animation) { - mContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeEvent(EVENT_NAME_ANIMATION_CANCEL, animation.getId()); - } - - @Override - public void onAnimationRepeat(Animation animation) { - mContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeEvent(EVENT_NAME_ANIMATION_REPEAT, animation.getId()); - } - - @Override - public void onAnimationUpdate(Animation animation) { - if (animation == null) { - return; - } - CopyOnWriteArrayList nodeIds = animation.getAnimationNodes(); - if (nodeIds == null) { - return; - } - - mNeedUpdateAnimationNodes.addAll(nodeIds); - - if (!mHandler.hasMessages(MSG_CHANGE_ANIMATION_STATUS)) { - mHandler.sendEmptyMessage(MSG_CHANGE_ANIMATION_STATUS); - } - } - - @SuppressWarnings("unused") - @HippyMethod(name = "createAnimation") - public void createAnimation(int animationId, String mode, HippyMap params) { - if (mAnimations.get(animationId) != null) { - return; - } - if (TextUtils.isEmpty(mode)) { - mAnimations.put(animationId, null); - } - try { - if (TextUtils.equals(mode, TIMING)) { - preprocessStartValue(params); - TimingAnimation animation = new TimingAnimation(animationId); - animation.addAnimationListener(this); - animation.parseFromData(params); - mAnimations.append(animationId, animation); - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - - private void preprocessStartValue(HippyMap map) { - if (map == null) { - return; - } - - if (map.containsKey("startValue")) { - Object obj = map.get("startValue"); - if (obj instanceof HippyMap) { - int startValueAnimationId = ((HippyMap) obj).getInt(ANIMATION_ID); - map.remove("startValue"); - map.pushObject("startValue", - mAnimations.get(startValueAnimationId).getAnimationSimpleValue()); - } - } - } - - @SuppressWarnings("unused") - @HippyMethod(name = "updateAnimation") - public void updateAnimation(int animationId, HippyMap params) { - LogUtils.d("shit", Thread.currentThread().getName()); - Animation targetAnim = mAnimations.get(animationId); - if (targetAnim == null || (targetAnim.getAnimator() != null && targetAnim.getAnimator() - .isRunning())) { - LogUtils.d("AnimationModule", - "trying to update a unexisted animation or the animation has started"); - return; - } - - if (targetAnim instanceof TimingAnimation) { - preprocessStartValue(params); - ((TimingAnimation) targetAnim).parseFromData(params); - targetAnim.onAnimationUpdate(null); - } - - } - - @SuppressWarnings("unused") - @HippyMethod(name = "createAnimationSet") - public void createAnimationSet(int animationId, HippyMap mapParams) { - AnimationSet animatorSet = new AnimationSet(animationId); - - animatorSet.addAnimationListener(this); - try { - if (mapParams != null) { - if (mapParams.containsKey(NodeProps.REPEAT_COUNT)) { - animatorSet.setRepeatCount(mapParams.getInt(NodeProps.REPEAT_COUNT)); - } - - HippyArray params = mapParams.getArray("children"); - - int size = params.size(); - HippyMap map; - int childId; - boolean follow = false; - for (int i = 0; i < size; i++) { - map = params.getMap(i); - if (!map.containsKey(ANIMATION_ID)) { - break; - } - childId = map.getInt(ANIMATION_ID); - if (i != 0 && map.containsKey(FOLLOW)) { - follow = map.getBoolean(FOLLOW); - } - animatorSet.addAnimation(mAnimations.get(childId), follow); - } - } - } catch (Throwable e) { - LogUtils.d("AnimationModule", "createAnimationSet: " + e.getMessage()); - } - mAnimations.append(animationId, animatorSet); - } - - @SuppressWarnings("unused") - @HippyMethod(name = "startAnimation") - public void startAnimation(int animationId) { - Animation animation = mAnimations.get(animationId); - if (animation != null) { - animation.start(); - } - } - - @HippyMethod(name = "stopAnimation") - public void stopAnimation(int animationId) { - Animation animation = mAnimations.get(animationId); - if (animation != null) { - animation.stop(); - } - } - - @SuppressWarnings("unused") - @HippyMethod(name = "pauseAnimation") - public void pauseAnimation(int animationId) { - Animation animation = mAnimations.get(animationId); - if (animation != null) { - animation.pause(); - } - } - - @SuppressWarnings("unused") - @HippyMethod(name = "resumeAnimation") - public void resumeAnimation(int animationId) { - Animation animation = mAnimations.get(animationId); - if (animation != null) { - animation.resume(); - } - } - - @SuppressWarnings("unused") - @HippyMethod(name = "destroyAnimation") - public void destroyAnimation(int animationId) { - stopAnimation(animationId); - Animation animation = mAnimations.get(animationId); - if (animation instanceof AnimationSet) { - ArrayList childIds = ((AnimationSet) animation).getChildAnimationIds(); - if (childIds != null) { - for (int childId : childIds) { - stopAnimation(childId); - mAnimations.remove(childId); - } - } - } - mAnimations.remove(animationId); - } - - @Override - public HippyMap onCreateNode(int tagId, HippyRootView rootView, HippyMap props) { - return onUpdateAnimationProperty(tagId, rootView, props); - } - - @Override - public HippyMap onUpdateNode(int tagId, HippyRootView rootView, HippyMap props) { - return onUpdateAnimationProperty(tagId, rootView, props); - } - - - @Override - public void onEngineResume() { - if (mHandler != null) { - mHandler.post(new Runnable() { - @Override - public void run() { - if (mAnimations == null) { - return; - } - int size = mAnimations.size(); - Animation animation; - for (int i = 0; i < size; i++) { - animation = mAnimations.valueAt(i); - animation.resume(); - } - } - }); - } - } - - @Override - public void onEnginePause() { - if (mHandler != null) { - mHandler.post(new Runnable() { - @Override - public void run() { - if (mAnimations == null) { - return; - } - int size = mAnimations.size(); - Animation animation; - for (int i = 0; i < size; i++) { - animation = mAnimations.valueAt(i); - animation.pause(); - } - } - }); - } - } - - @Override - public void onDeleteNode(int tagId) { - dealAnimationNode(tagId, null, null, null); - } - - private HippyMap onUpdateAnimationProperty(int tagId, HippyRootView rootView, HippyMap props) { - // LogUtils.d("AnimationModule","dom updateNode node id : "+tagId+" onUpdateAnimationProperty width:" +props.get("width")); - if (props == null) { - return null; - } - if (props.containsKey(HANDLE_MESSAGE_BY_ANIMATION) && props - .getBoolean(HANDLE_MESSAGE_BY_ANIMATION)) { - return props; - } - if (!props.containsKey(USE_ANIMATION)) { - dealAnimationNode(tagId, rootView, null, null); - return props; - } - try { - boolean useAnimation = props.getBoolean(USE_ANIMATION); - if (!useAnimation) { - dealAnimationNode(tagId, rootView, null, null); - return props; - } - HippyMap newProps = new HippyMap(); - ArrayList animations = new ArrayList<>(); - copyAndDealPropertys(tagId, props, newProps, animations); - - dealAnimationNode(tagId, rootView, props, animations); - newProps.pushBoolean(HANDLE_MESSAGE_BY_ANIMATION, true); - return newProps; - } catch (Throwable e) { - e.printStackTrace(); - } - return props; - } - - private void dealAnimationNode(int tagId, HippyRootView rootView, HippyMap newProps, - ArrayList newAnimationIds) { - AnimationNode node = mAnimationNodes.get(tagId); - if (node != null) { - Iterator iterator = node.getAnimations().iterator(); - Animation animation; - while (iterator.hasNext()) { - animation = iterator.next(); - if (animation != null && (newAnimationIds == null || !newAnimationIds - .contains(animation.mId))) { - animation.removeAnimationNode(tagId); - iterator.remove(); - } - } - } - - if (newAnimationIds == null || newAnimationIds.size() <= 0) { - mAnimationNodes.remove(tagId); - } else { - if (node == null) { - node = new AnimationNode(tagId, rootView); - mAnimationNodes.append(tagId, node); - } - Animation animation; - for (Integer animationId : newAnimationIds) { - animation = mAnimations.get(animationId); - if (animation != null) { - node.addAnimation(animation); - animation.addAnimationNode(tagId); - } - } - node.setProps(newProps); - } - } - - private void copyAndDealPropertys(int tagId, HippyMap props, HippyMap newProps, - ArrayList animations) { - if (props == null) { - return; - } - - Set keys = props.keySet(); - Object value; - for (String key : keys) { - value = props.get(key); - if (value instanceof HippyMap) { - boolean flag = isAnimationPropertys((HippyMap) value); - if (flag) { - int animationId = ((HippyMap) value).getInt(ANIMATION_ID); - if (animations != null) { - animations.add(animationId); - } - Object animationValue = findAnimationValue(tagId, animationId); - if (animationValue != null) { - newProps.pushObject(key, animationValue); - } - } else { - HippyMap newChildProps = new HippyMap(); - copyAndDealPropertys(tagId, (HippyMap) value, newChildProps, animations); - newProps.pushMap(key, newChildProps); - } - } else if (value instanceof HippyArray) { - HippyArray newChildProps = new HippyArray(); - copyAndDealPropertys(tagId, (HippyArray) value, newChildProps, animations); - newProps.pushArray(key, newChildProps); - } else { - newProps.pushObject(key, value); - } - } - } - - private void copyAndDealPropertys(int tagId, HippyArray props, HippyArray newProps, - ArrayList animations) { - if (props == null) { - return; - } - - int size = props.size(); - Object value; - for (int i = 0; i < size; i++) { - value = props.get(i); - if (value instanceof HippyMap) { - boolean flag = isAnimationPropertys((HippyMap) value); - if (flag) { - int animationId = ((HippyMap) value).getInt(ANIMATION_ID); - if (animations != null) { - animations.add(animationId); - } - - Object animationValue = findAnimationValue(tagId, animationId); - if (animationValue != null) { - newProps.pushObject(animationValue); - } - } else { - HippyMap newChildProps = new HippyMap(); - copyAndDealPropertys(tagId, (HippyMap) value, newChildProps, animations); - newProps.pushMap(newChildProps); - } - } else if (value instanceof HippyArray) { - HippyArray newChildProps = new HippyArray(); - copyAndDealPropertys(tagId, (HippyArray) value, newChildProps, animations); - newProps.pushArray(newChildProps); - } else { - newProps.pushObject(value); - } - } - } - - private boolean isAnimationPropertys(HippyMap props) { - if (props == null) { - return false; - } - return props.containsKey(ANIMATION_ID) && props.size() == 1; - } - - private Object findAnimationValue(int tagId, int animationId) { - Animation anim = mAnimations.get(animationId); - if (anim != null) { - return anim.getAnimationValue(); - } - - AnimationNode node = mAnimationNodes.get(tagId); - if (node != null) { - ArrayList animations = node.getAnimations(); - for (Animation animation : animations) { - if (animation != null && animation.getId() == animationId) { - return animation.getAnimationValue(); - } - } - } - - return Float.NaN; - } - - private void doUpdateAnimationNodes() { - mLastUpdateTime = SystemClock.elapsedRealtime(); - if (mWaitUpdateAnimationNodes == null) { - mWaitUpdateAnimationNodes = new HashSet<>(); - } - mWaitUpdateAnimationNodes.clear(); - synchronized (mNeedUpdateAnimationNodes) { - Iterator it = mNeedUpdateAnimationNodes.iterator(); - int nodeId; - AnimationNode node; - while (it.hasNext()) { - nodeId = it.next(); - node = mAnimationNodes.get(nodeId); - mWaitUpdateAnimationNodes.add(node); - it.remove(); - } - } - - Iterator it = mWaitUpdateAnimationNodes.iterator(); - while (it.hasNext()) { - updateAnimationNodeProps(it.next()); - it.remove(); - } - if (mContext != null && mContext.getDomManager() != null) { - mContext.getDomManager().batchByAnimation(); - } - } - - private void updateAnimationNodeProps(AnimationNode node) { - if (node == null) { - return; - } - try { - HippyMap newProps = new HippyMap(); - copyAndDealPropertys(node.getId(), node.getProps(), newProps, null); - newProps.pushBoolean(HANDLE_MESSAGE_BY_ANIMATION, true); - - mContext.getDomManager().updateNode(node.getId(), newProps, node.getRootView()); - } catch (Throwable e) { - LogUtils.d("AnimationModule", "updateAnimationNodeProps: " + e.getMessage()); - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationNode.java deleted file mode 100644 index c40fbc84d6e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationNode.java +++ /dev/null @@ -1,63 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; - -import java.util.ArrayList; - -@SuppressWarnings("deprecation") -public class AnimationNode { - - private final int mTagId; - private final HippyRootView mRootView; - private final ArrayList mAnimations; - private HippyMap mProps; - - public AnimationNode(int tagId, HippyRootView rootView) { - mTagId = tagId; - mRootView = rootView; - mAnimations = new ArrayList<>(); - } - - public int getId() { - return mTagId; - } - - public HippyRootView getRootView() { - return mRootView; - } - - public HippyMap getProps() { - return mProps; - } - - public void setProps(HippyMap props) { - this.mProps = props; - } - - public void addAnimation(Animation animation) { - if (!mAnimations.contains(animation)) { - mAnimations.add(animation); - } - } - - public ArrayList getAnimations() { - return mAnimations; - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationSet.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationSet.java deleted file mode 100644 index 9fb3f610139..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/AnimationSet.java +++ /dev/null @@ -1,215 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.os.Build; - -import java.util.ArrayList; - -@SuppressWarnings({"unused"}) -public class AnimationSet extends Animation implements Animator.AnimatorListener { - - private static final int ANIMATION_SET_STATUS_NONE = -1; - private static final int ANIMATION_SET_STATUS_START = 0; - private static final int ANIMATION_SET_STATUS_REPEATING = 1; - private static final int ANIMATION_SET_STATUS_END = 2; - - private final AnimatorSet mAnimatorSet; - - private AnimatorSet.Builder mLastBuilder; - - private Animation mLastPlayAnimation; - - private ArrayList mChildAnimationIds; - - private Animation mCurrentAnimation = null; - - private int mRepeatCount = 0; - - private int mCurrentRepeatCount = 0; - - private int mCurrAnimationStatus = ANIMATION_SET_STATUS_NONE; - - - private final Animation.AnimationListener mChildAnimationListener = new AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - - } - - @Override - public void onAnimationEnd(Animation animation) { - - } - - @Override - public void onAnimationCancel(Animation animation) { - - } - - @Override - public void onAnimationRepeat(Animation animation) { - - } - - @Override - public void onAnimationUpdate(Animation animation) { - mCurrentAnimation = animation; - if (mAnimationListeners == null) { - return; - } - for (AnimationListener mAnimationListener : mAnimationListeners) { - mAnimationListener - .onAnimationUpdate( - AnimationSet.this); - } - } - }; - - @SuppressWarnings("unused") - public AnimationSet(int id) { - super(id); - mAnimatorSet = new AnimatorSet(); - mAnimatorSet.addListener(this); - } - - @Override - public Animator getAnimator() { - return mAnimatorSet; - } - - @Override - public void start() { - if (mCurrAnimationStatus == ANIMATION_SET_STATUS_NONE - || mCurrAnimationStatus == ANIMATION_SET_STATUS_END) { - mCurrentRepeatCount = 0; - mCurrAnimationStatus = ANIMATION_SET_STATUS_START; - mAnimatorSet.start(); - } - } - - @Override - public void stop() { - int lastStatus = mCurrAnimationStatus; - mCurrAnimationStatus = ANIMATION_SET_STATUS_END; - - //如果调stop的时候刚好需要重复的动画已经结束了,但尚未开始,需要补一个事件 - if (!mAnimatorSet.isStarted() && lastStatus == ANIMATION_SET_STATUS_REPEATING) { - onAnimationEnd(mAnimatorSet); - } - mAnimatorSet.cancel(); - } - - @Override - public Object getAnimationValue() { - if (mCurrentAnimation != null) { - return mCurrentAnimation.getAnimationValue(); - } - return 0; - - } - - @Override - public Object getAnimationSimpleValue() { - if (mCurrentAnimation != null) { - return mCurrentAnimation.getAnimationSimpleValue(); - } - return 0; - } - - @Override - public void resume() { - if (mAnimatorSet != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - mAnimatorSet.resume(); - } - } - } - - @Override - public void pause() { - if (mAnimatorSet != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - mAnimatorSet.pause(); - } - } - } - - public void setRepeatCount(int repeatCount) { - mRepeatCount = repeatCount; - mCurrentRepeatCount = 0; - } - - - @Override - public void onAnimationStart(Animator animation) { - if (mCurrAnimationStatus < ANIMATION_SET_STATUS_REPEATING) { - super.onAnimationStart(animation); - } else { - onAnimationRepeat(animation); - } - } - - @Override - public void onAnimationEnd(Animator animation) { - if (mCurrAnimationStatus == ANIMATION_SET_STATUS_END) { - super.onAnimationEnd(animation); - return; - } - - if (mRepeatCount == -1 || (mRepeatCount > 0 && mCurrentRepeatCount < mRepeatCount - 1)) { - mCurrAnimationStatus = ANIMATION_SET_STATUS_REPEATING; - mCurrentRepeatCount++; - mAnimatorSet.start(); - } else { - mCurrAnimationStatus = ANIMATION_SET_STATUS_END; - super.onAnimationEnd(animation); - } - - } - - - public void addAnimation(Animation animation, boolean follow) { - if (animation == null || animation.getAnimator() == null) { - return; - } - animation.addAnimationListener(mChildAnimationListener); - if (mCurrentAnimation == null) { - mCurrentAnimation = animation; - } - if (mChildAnimationIds == null) { - mChildAnimationIds = new ArrayList<>(); - } - mChildAnimationIds.add(animation.getId()); - - if (mLastPlayAnimation == null) { - mLastBuilder = mAnimatorSet.play(animation.getAnimator()); - mLastPlayAnimation = animation; - } else if (!follow) { - mLastBuilder.with(animation.getAnimator()); - } else { - mLastBuilder = mAnimatorSet.play(animation.getAnimator()) - .after(mLastPlayAnimation.getAnimator()); - mLastPlayAnimation = animation; - } - } - - public ArrayList getChildAnimationIds() { - return mChildAnimationIds; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/BezierInterpolator.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/BezierInterpolator.java deleted file mode 100644 index b1a646f0314..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/BezierInterpolator.java +++ /dev/null @@ -1,94 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import android.graphics.Path; -import android.graphics.PathMeasure; -import android.view.animation.Interpolator; - -class BezierInterpolator implements Interpolator { - - private static final float PRECISION = 0.002f; - - private float[] mX; // x coordinates in the line - - private float[] mY; // y coordinates in the line - - @SuppressWarnings("unused") - public BezierInterpolator(float controlX1, float controlY1, float controlX2, float controlY2) { - initCubic(controlX1, controlY1, controlX2, controlY2); - } - - private void initCubic(float x1, float y1, float x2, float y2) { - - Path path = new Path(); - path.moveTo(0, 0); - path.cubicTo(x1, y1, x2, y2, 1f, 1f); - initPath(path); - } - - private void initPath(Path path) { - final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */); - - final float pathLength = pathMeasure.getLength(); - final int numPoints = (int) (pathLength / PRECISION) + 1; - - mX = new float[numPoints]; - mY = new float[numPoints]; - - final float[] position = new float[2]; - for (int i = 0; i < numPoints; ++i) { - final float distance = (i * pathLength) / (numPoints - 1); - pathMeasure.getPosTan(distance, position, null /* tangent */); - - mX[i] = position[0]; - mY[i] = position[1]; - } - } - - @Override - public float getInterpolation(float t) { - if (t <= 0.0f) { - return 0.0f; - } else if (t >= 1.0f) { - return 1.0f; - } - - int startIndex = 0; - int endIndex = mX.length - 1; - while (endIndex - startIndex > 1) { - int midIndex = (startIndex + endIndex) / 2; - if (t < mX[midIndex]) { - endIndex = midIndex; - } else { - startIndex = midIndex; - } - } - - final float xRange = mX[endIndex] - mX[startIndex]; - if (xRange == 0) { - return mY[startIndex]; - } - - final float tInRange = t - mX[startIndex]; - final float fraction = tInRange / xRange; - - final float startY = mY[startIndex]; - final float endY = mY[endIndex]; - - return startY + (fraction * (endY - startY)); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/TimingAnimation.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/TimingAnimation.java deleted file mode 100644 index 9759adbbc7f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/TimingAnimation.java +++ /dev/null @@ -1,219 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import android.animation.Animator; -import android.animation.ArgbEvaluator; -import android.animation.ValueAnimator; -import android.os.Build; -import android.text.TextUtils; -import android.view.animation.*; - -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; - -@SuppressWarnings({"deprecation", "unused"}) -public class TimingAnimation extends Animation implements ValueAnimator.AnimatorUpdateListener, - Animator.AnimatorListener { - - private static final String VALUE_TYPE_RAD = "rad"; - private static final String VALUE_TYPE_DEG = "deg"; - private static final String VALUE_TYPE_COLOR = "color"; - private static final String TIMING_FUNCTION_LINEAR = "linear"; - private static final String TIMING_FUNCTION_EASE_IN = "ease-in"; - private static final String TIMING_FUNCTION_EASE_OUT = "ease-out"; - private static final String TIMING_FUNCTION_EASE_IN_OUT = "ease-in-out"; - private static final String TIMING_FUNCTION_EASE_BEZIER = "ease_bezier"; - private static final Pattern TIMING_FUNCTION_CUBIC_BEZIER_PATTERN = Pattern.compile("^cubic-bezier\\(([^,]*),([^,]*),([^,]*),([^,]*)\\)$"); - protected float mStartValue; - protected float mToValue; - protected int mDuration; - protected String mTimingFunction; - protected final ValueAnimator mAnimator; - protected String mValueType; - protected int mRepeatCount = 0; - protected ValueTransformer mValueTransformer; - - /** - * Animation delay time - */ - protected int mDelay = 0; - private Object mAnimationValue = 0.0; - - public TimingAnimation(int id) { - super(id); - mAnimator = new ValueAnimator(); - mAnimator.addUpdateListener(this); - mAnimator.addListener(this); - } - - @Override - public Animator getAnimator() { - return mAnimator; - } - - @Override - public void start() { - mAnimator.start(); - } - - @Override - public void stop() { - mAnimator.cancel(); - } - - @Override - public Object getAnimationValue() { - Object simpleValue = getAnimationSimpleValue(); - if ((simpleValue instanceof Number) && mValueTransformer != null) { - Object transformValue = mValueTransformer.transform((Number) simpleValue); - if (transformValue != null) { - simpleValue = transformValue; - } - } - if (TextUtils.equals(mValueType, VALUE_TYPE_RAD)) { - return simpleValue + "rad"; - } else if (TextUtils.equals(mValueType, VALUE_TYPE_DEG)) { - return simpleValue + "deg"; - } - return simpleValue; - } - - @Override - public Object getAnimationSimpleValue() { - return mAnimationValue; - } - - @Override - public void resume() { - if (mAnimator != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - mAnimator.resume(); - } - } - } - - @Override - public void pause() { - if (mAnimator != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - mAnimator.pause(); - } - } - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (animation != null) { - mAnimationValue = mAnimator.getAnimatedValue(); - } - - super.onAnimationUpdate(animation); - - } - - public void parseFromData(HippyMap param) { - if (param.containsKey("valueType")) { - mValueType = param.getString("valueType"); - } - - if (param.containsKey("delay")) { - mDelay = param.getInt("delay"); - } - - if (param.containsKey("startValue")) { - mStartValue = (float) param.getDouble("startValue"); - } - mAnimationValue = mStartValue; - - if (param.containsKey("toValue")) { - mToValue = (float) param.getDouble("toValue"); - } - - if (param.containsKey("duration")) { - mDuration = param.getInt("duration"); - } - - if (param.containsKey("timingFunction")) { - mTimingFunction = param.getString("timingFunction"); - } - - if (param.containsKey(NodeProps.REPEAT_COUNT)) { - mRepeatCount = param.getInt(NodeProps.REPEAT_COUNT); - if (mRepeatCount > 0) { - mRepeatCount = mRepeatCount - 1; - } - mAnimator.setRepeatCount(mRepeatCount); - mAnimator.setRepeatMode(ValueAnimator.RESTART); - } - - if (param.containsKey("inputRange")) { - HippyArray inputRange = param.getArray("inputRange"); - if (param.containsKey("outputRange")) { - HippyArray outputRange = param.getArray("outputRange"); - mValueTransformer = new ValueTransformer(inputRange, outputRange); - } - } - - if (!TextUtils.isEmpty(mValueType) && mValueType.equals(VALUE_TYPE_COLOR)) { - mAnimator.setIntValues((int) mStartValue, (int) mToValue); - mAnimator.setEvaluator(new ArgbEvaluator()); - } else { - mAnimator.setFloatValues(mStartValue, mToValue); - } - - mAnimator.setDuration(mDuration); - if (TextUtils.equals(TIMING_FUNCTION_EASE_IN, mTimingFunction)) { - mAnimator.setInterpolator(new AccelerateInterpolator()); - } else if (TextUtils.equals(TIMING_FUNCTION_EASE_OUT, mTimingFunction)) { - mAnimator.setInterpolator(new DecelerateInterpolator()); - } else if (TextUtils.equals(TIMING_FUNCTION_EASE_IN_OUT, mTimingFunction)) { - mAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); - } else if (TextUtils.equals(TIMING_FUNCTION_EASE_BEZIER, mTimingFunction)) { - this.setCubicBezierInterpolator(0.42f, 0, 1, 1); - } else { - Matcher matcher = TIMING_FUNCTION_CUBIC_BEZIER_PATTERN.matcher(mTimingFunction.trim()); - if (matcher.matches()) { - try { - this.setCubicBezierInterpolator( - Float.parseFloat(matcher.group(1)), - Float.parseFloat(matcher.group(2)), - Float.parseFloat(matcher.group(3)), - Float.parseFloat(matcher.group(4)) - ); - } catch (Exception e) { - mAnimator.setInterpolator(new LinearInterpolator()); - } - } else { - mAnimator.setInterpolator(new LinearInterpolator()); - } - } - mAnimator.setStartDelay(mDelay); - } - - private void setCubicBezierInterpolator(float p1x, float p1y, float p2x, float p2y) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - mAnimator.setInterpolator(new PathInterpolator(p1x, p1y, p2x, p2y)); - } else { - mAnimator.setInterpolator(new BezierInterpolator(p1x, p1y, p2x, p2y)); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/ValueTransformer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/ValueTransformer.java deleted file mode 100644 index fafb62d6576..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/animation/ValueTransformer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.animation; - -import com.tencent.mtt.hippy.common.HippyArray; - -public class ValueTransformer { - - protected final HippyArray mInputRange; - protected final HippyArray mOutputRange; - - public ValueTransformer(HippyArray input, HippyArray output) { - this.mInputRange = input; - this.mOutputRange = output; - } - - public Object transform(Number value) { - if (mInputRange == null) { - return null; - } - if (mOutputRange == null) { - return null; - } - int size = mInputRange.size(); - if (size != mOutputRange.size()) { - return null; - } - if (size == 0) { - return null; - } - - int bestIndex = 0; - double bestSpacing = -1; - Object obj; - double rangeValue; - double transformValue = value.doubleValue(); - double spacing; - for (int i = 0; i < size; i++) { - obj = mInputRange.get(i); - if (!(obj instanceof Number)) { - return null; - } - - rangeValue = ((Number) obj).doubleValue(); - if (rangeValue <= transformValue) { - spacing = Math.abs(transformValue - rangeValue); - if (spacing < bestSpacing || bestSpacing == -1) { - bestIndex = i; - bestSpacing = spacing; - } - } - } - - return mOutputRange.get(bestIndex); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/clipboard/ClipboardModule.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/clipboard/ClipboardModule.java deleted file mode 100644 index 27ec7ef200c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/clipboard/ClipboardModule.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.tencent.mtt.hippy.modules.nativemodules.clipboard; - -import android.content.ClipData; -import android.content.Context; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import android.content.ClipboardManager; - -@HippyNativeModule(name = "ClipboardModule") -public class ClipboardModule extends HippyNativeModuleBase { - - private final ClipboardManager mClipboardManager; - - public ClipboardModule(HippyEngineContext context) { - super(context); - mClipboardManager = (ClipboardManager) (mContext.getGlobalConfigs()).getContext() - .getSystemService(Context.CLIPBOARD_SERVICE); - } - - - private ClipboardManager getClipboardService() { - return mClipboardManager; - } - - @SuppressWarnings("unused") - @HippyMethod(name = "getString") - public void getString(Promise promise) { - try { - ClipboardManager clipboard = getClipboardService(); - ClipData clipData = clipboard.getPrimaryClip(); - if (clipData != null && clipData.getItemCount() >= 1) { - ClipData.Item firstItem = clipboard.getPrimaryClip().getItemAt(0); - promise.resolve("" + firstItem.getText()); - } else { - promise.resolve(""); - } - } catch (Exception e) { - promise.reject(e); - } - } - - @SuppressWarnings("unused") - @HippyMethod(name = "setString") - public void setString(String text) { - ClipData clipdata = ClipData.newPlainText(null, text); - ClipboardManager clipboard = getClipboardService(); - clipboard.setPrimaryClip(clipdata); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/debug/DevMenu.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/debug/DevMenu.java deleted file mode 100644 index 865636592cf..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/debug/DevMenu.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.tencent.mtt.hippy.modules.nativemodules.debug; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import com.tencent.mtt.hippy.utils.LogUtils; - -@HippyNativeModule(name = "DevMenu") -public class DevMenu extends HippyNativeModuleBase { - - public DevMenu(HippyEngineContext context) { - super(context); - } - - @HippyMethod(name = "reload") - public void reload() { - try { - mContext.getDevSupportManager().getDevImp().reload(); - } catch (Throwable e) { - LogUtils.d("HippyDevMemo", "reload error: " + e.getMessage()); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/image/ImageLoaderModule.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/image/ImageLoaderModule.java deleted file mode 100644 index e24c8059b3b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/image/ImageLoaderModule.java +++ /dev/null @@ -1,61 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.image; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.adapter.image.HippyDrawable; -import com.tencent.mtt.hippy.adapter.image.HippyImageLoader; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyNativeModule(name = "ImageLoaderModule") -public class ImageLoaderModule extends HippyNativeModuleBase { - - final HippyImageLoader mImageAdapter; - - public ImageLoaderModule(HippyEngineContext context) { - super(context); - mImageAdapter = context.getGlobalConfigs().getImageLoaderAdapter(); - } - - @HippyMethod(name = "getSize") - public void getSize(final String url, final Promise promise) { - if (mImageAdapter != null) { - mImageAdapter.getSize(url, promise); - } - } - - @HippyMethod(name = "prefetch") - public void prefetch(String url) { - mImageAdapter.fetchImage(url, new HippyImageLoader.Callback() { - @Override - public void onRequestStart(HippyDrawable hippyDrawable) { - } - - @Override - public void onRequestSuccess(HippyDrawable hippyDrawable) { - hippyDrawable.onDrawableDetached(); - } - - @Override - public void onRequestFail(Throwable throwable, String source) { - } - }, null); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/network/NetworkModule.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/network/NetworkModule.java deleted file mode 100644 index 4b13ff43c5d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/network/NetworkModule.java +++ /dev/null @@ -1,291 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.network; - -import android.os.Build; -import android.text.TextUtils; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyGlobalConfigs; -import com.tencent.mtt.hippy.adapter.http.HippyHttpAdapter; -import com.tencent.mtt.hippy.adapter.http.HippyHttpRequest; -import com.tencent.mtt.hippy.adapter.http.HippyHttpResponse; -import com.tencent.mtt.hippy.adapter.http.HttpHeader; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.zip.GZIPInputStream; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyNativeModule(name = "network") -public class NetworkModule extends HippyNativeModuleBase { - - // 使用CookieManager之前,需要初始化CookieSyncManager,单例的 - static CookieSyncManager mCookieSyncManager; - - public NetworkModule(HippyEngineContext context) { - super(context); - } - - private void hippyMapToRequestHeaders(HippyHttpRequest request, HippyMap map) { - if (request == null || map == null) { - return; - } - - Set keys = map.keySet(); - for (String oneKey : keys) { - Object valueObj = map.get(oneKey); - if (valueObj instanceof HippyArray) { - HippyArray oneHeaderArray = (HippyArray) valueObj; - List headerValueArray = new ArrayList<>(); - for (int i = 0; i < oneHeaderArray.size(); i++) { - Object oneHeaderValue = oneHeaderArray.get(i); - if (oneHeaderValue instanceof Number) { - headerValueArray.add(oneHeaderValue + ""); - } else if (oneHeaderValue instanceof Boolean) { - headerValueArray.add(oneHeaderValue + ""); - } else if (oneHeaderValue instanceof String) { - headerValueArray.add((String) oneHeaderValue); - } else { - LogUtils.e("hippy_console", "Unsupported Request Header List Type"); - } - } - - if (!headerValueArray.isEmpty()) { - request.addHeader(oneKey, headerValueArray); - } - } else { - LogUtils.e("hippy_console", - "Unsupported Request Header Type, Header Field Should All be an Array!!!"); - } - } - } - - @HippyMethod(name = "fetch") - public void fetch(final HippyMap request, final Promise promise) { - if (request == null) { - promise.reject("invalid request param"); - return; - } - - String url = request.getString("url"); - final String method = request.getString("method"); - if (TextUtils.isEmpty(url) || TextUtils.isEmpty(method)) { - promise.reject("no valid url for request"); - return; - } - - HippyHttpRequest httpRequest = new HippyHttpRequest(); - httpRequest.setConnectTimeout(10 * 1000); - httpRequest.setReadTimeout(10 * 1000); - String redirect = request.getString("redirect"); - httpRequest.setInstanceFollowRedirects( - !TextUtils.isEmpty(redirect) && TextUtils.equals("follow", redirect)); - httpRequest.setUseCaches(false); - httpRequest.setMethod(method); - httpRequest.setUrl(url); - HippyMap headers = request.getMap("headers"); - HippyArray requestCookies = null; - if (headers != null) { - requestCookies = headers.getArray("Cookie"); - hippyMapToRequestHeaders(httpRequest, headers); - } - String body = request.getString("body"); - httpRequest.setBody(body); - - HippyGlobalConfigs configs = mContext.getGlobalConfigs(); - HippyHttpAdapter adapter; - if (configs != null && configs.getHttpAdapter() != null) { - adapter = configs.getHttpAdapter(); - adapter.handleRequestCookie(url, requestCookies, httpRequest); - adapter.sendRequest(httpRequest, new HttpTaskCallbackImpl(promise)); - } - } - - @HippyMethod(name = "getCookie") - public void getCookie(String url, Promise promise) { - String cookie = getCookieManager().getCookie(url); - promise.resolve(cookie); - } - - @HippyMethod(name = "setCookie") - public void setCookie(String url, String keyValue, String expires) { - if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(keyValue)) { - if (!TextUtils.isEmpty(expires)) { - keyValue = keyValue + ";expires=" + expires; - getCookieManager().setCookie(url, keyValue); - syncCookie(); - } else { - saveCookie2Manager(url, keyValue); - } - } - } - - public static void saveCookie2Manager(String url, HippyArray cookies) { - if (cookies != null) { - CookieManager cookieManager = getCookieManager(); - for (int i = 0; i < cookies.size(); i++) { - String cookieStr = (String) cookies.get(i); - saveCookie2Manager(url, cookieStr); - } - } - } - - public static void saveCookie2Manager(String url, String cookies) { - if (cookies != null) { - cookies = cookies.replaceAll("\\s+", ""); - String[] cookieItems = cookies.split(";"); - CookieManager cookieManager = getCookieManager(); - for (String cookie : cookieItems) { - cookieManager.setCookie(url, cookie); - } - - syncCookie(); - } - } - - public static CookieManager getCookieManager() { - if (mCookieSyncManager == null) { - mCookieSyncManager = CookieSyncManager.createInstance(ContextHolder.getAppContext()); - - CookieManager cookieManager = CookieManager.getInstance(); - cookieManager.setAcceptCookie(true); - } - return CookieManager.getInstance(); - } - - private static void syncCookie() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - CookieManager.getInstance().flush(); - } else if (mCookieSyncManager != null) { - mCookieSyncManager.sync(); - } - } - - private static class HttpTaskCallbackImpl implements HippyHttpAdapter.HttpTaskCallback { - - private final Promise mPromise; - - public HttpTaskCallbackImpl(Promise promise) { - mPromise = promise; - } - - @SuppressWarnings("CharsetObjectCanBeUsed") - @Override - public void onTaskSuccess(HippyHttpRequest request, HippyHttpResponse response) - throws Exception { - String respBody = null; - if (response.getInputStream() != null) { - InputStream inputStream = response.getInputStream(); - if (isGzipRequest(request)) { - inputStream = new GZIPInputStream(inputStream); // gzip解压 - } - StringBuilder sb = new StringBuilder(); - String readLine; - BufferedReader bfReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); - while ((readLine = bfReader.readLine()) != null) { - sb.append(readLine).append("\r\n"); - } - respBody = sb.toString(); - } - - HippyMap respMap = new HippyMap(); - respMap.pushInt("statusCode", response.getStatusCode()); - respMap.pushString("statusLine", response.getResponseMessage()); - - HippyMap headerMap = new HippyMap(); - if (response.getRspHeaderMaps() != null && !response.getRspHeaderMaps().isEmpty()) { - Set keys = response.getRspHeaderMaps().keySet(); - for (String oneKey : keys) { - List value = response.getRspHeaderMaps().get(oneKey); - HippyArray oneHeaderFiled = new HippyArray(); - if (value != null && !value.isEmpty()) { - boolean hasSetCookie = false; - for (int i = 0; i < value.size(); i++) { - String valueStr = value.get(i); - oneHeaderFiled.pushString(valueStr); - if (HttpHeader.RSP.SET_COOKIE.equalsIgnoreCase(oneKey)) { - hasSetCookie = true; - getCookieManager().setCookie(request.getUrl(), valueStr); - } - } - if (hasSetCookie) { - syncCookie(); - } - } - - headerMap.pushArray(oneKey, oneHeaderFiled); - } - } - - respMap.pushMap("respHeaders", headerMap); - if (respBody == null) { - respBody = ""; - } - - respMap.pushString("respBody", respBody); - - mPromise.resolve(respMap); - } - - @Override - public void onTaskFailed(HippyHttpRequest request, Throwable error) { - if (error != null) { - mPromise.resolve(error.getMessage()); - } - } - } - - // 检查是否是gzip/deflate压缩的请求 - private static boolean isGzipRequest(HippyHttpRequest request) { - if (request == null) { - return false; - } - Map headers = request.getHeaders(); - if (headers != null) { - for (Map.Entry header : headers.entrySet()) { - String key = header.getKey(); - if (key != null && key.equalsIgnoreCase(HttpHeader.REQ.ACCEPT_ENCODING)) { - Object value = header.getValue(); - if (value instanceof ArrayList) { - //noinspection unchecked - for (String valueItem : (ArrayList) value) { - if (valueItem.equalsIgnoreCase("gzip") || valueItem.equalsIgnoreCase("deflate")) { - return true; - } - } - } - } - } - } - return false; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/uimanager/UIManagerModule.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/uimanager/UIManagerModule.java deleted file mode 100644 index 39177c637a0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/modules/nativemodules/uimanager/UIManagerModule.java +++ /dev/null @@ -1,170 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.modules.nativemodules.uimanager; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyMethod; -import com.tencent.mtt.hippy.annotation.HippyNativeModule; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.DomManager; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; -import com.tencent.mtt.hippy.utils.LogUtils; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyNativeModule(name = UIManagerModule.CLASS_NAME, thread = HippyNativeModule.Thread.DOM) -public class UIManagerModule extends HippyNativeModuleBase { - - public static final String CLASS_NAME = "UIManagerModule"; - - final String OPTION_TYPE = "optionType"; - final String OPTION_TYPE_CREATE_NODE = "createNode"; - final String OPTION_TYPE_UPDATE_NODE = "updateNode"; - final String OPTION_TYPE_DELETE_NODE = "deleteNode"; - final String OPTION_TYPE_PARAM = "param"; - final String ID = "id"; - final String PID = "pId"; - final String INDEX = "index"; - final String NAME = "name"; - final String PROPS = "props"; - final String TAG_NAME = "tagName"; - - public UIManagerModule(HippyEngineContext context) { - super(context); - } - - @HippyMethod(name = "createNode") - public void createNode(int rootID, HippyArray hippyArray) { - HippyRootView hippyRootView = mContext.getInstance(rootID); - DomManager domManager = this.mContext.getDomManager(); - if (hippyArray != null && hippyRootView != null && domManager != null) { - int len = hippyArray.size(); - for (int i = 0; i < len; i++) { - HippyMap nodeArray = hippyArray.getMap(i); - int tag = ((Number)nodeArray.get(ID)).intValue(); - int pTag = ((Number)nodeArray.get(PID)).intValue(); - int index = ((Number)nodeArray.get(INDEX)).intValue(); - if (tag < 0 || pTag < 0 || index < 0) { - throw new IllegalArgumentException( - "createNode invalid value: " + "id=" + tag + ", pId=" + pTag + ", index=" + index); - } - - String className = (String) nodeArray.get(NAME); - String tagName = (String) nodeArray.get(TAG_NAME); - HippyMap props = (HippyMap) nodeArray.get(PROPS); - domManager.createNode(hippyRootView, rootID, tag, pTag, index, className, tagName, props); - } - } - } - - - @HippyMethod(name = "updateNode") - public void updateNode(int rootID, HippyArray updateArray) { - HippyRootView hippyRootView = mContext.getInstance(rootID); - DomManager domManager = this.mContext.getDomManager(); - if (updateArray != null && updateArray.size() > 0 && hippyRootView != null - && domManager != null) { - int len = updateArray.size(); - for (int i = 0; i < len; i++) { - HippyMap nodemap = updateArray.getMap(i); - int id = ((Number)nodemap.get(ID)).intValue(); - if (id < 0) { - throw new IllegalArgumentException("updateNode invalid value: " + "id=" + id); - } - HippyMap props = (HippyMap) nodemap.get(PROPS); - domManager.updateNode(id, props, hippyRootView); - } - } - } - - @HippyMethod(name = "deleteNode") - public void deleteNode(int rootId, HippyArray delete) { - DomManager domManager = this.mContext.getDomManager(); - if (delete != null && delete.size() > 0 && domManager != null) { - int len = delete.size(); - for (int i = 0; i < len; i++) { - HippyMap nodemap = delete.getMap(i); - int id = ((Number)nodemap.get(ID)).intValue(); - if (id < 0) { - throw new IllegalArgumentException("deleteNode invalid value: " + "id=" + id); - } - domManager.deleteNode(id); - } - } - - } - - @HippyMethod(name = "flushBatch") - public void flushBatch(int rootId, HippyArray hippyArray) { - if (hippyArray != null && hippyArray.size() > 0) { - int len = hippyArray.size(); - for (int i = 0; i < len; i++) { - HippyMap hippyMap = hippyArray.getMap(i); - String optionType = (String) hippyMap.get(OPTION_TYPE); - switch (optionType) { - case OPTION_TYPE_CREATE_NODE: - createNode(rootId, (HippyArray) hippyMap.get(OPTION_TYPE_PARAM)); - break; - case OPTION_TYPE_UPDATE_NODE: - updateNode(rootId, (HippyArray) hippyMap.get(OPTION_TYPE_PARAM)); - break; - case OPTION_TYPE_DELETE_NODE: - deleteNode(rootId, (HippyArray) hippyMap.get(OPTION_TYPE_PARAM)); - break; - } - } - } - } - - @HippyMethod(name = "callUIFunction") - public void callUIFunction(HippyArray hippyArray, Promise promise) { - DomManager domManager = this.mContext.getDomManager(); - if (hippyArray != null && hippyArray.size() > 0 && domManager != null) { - int id = hippyArray.getInt(0); - String functionName = hippyArray.getString(1); - HippyArray array = hippyArray.getArray(2); - domManager.dispatchUIFunction(id, functionName, array, promise); - } - } - - @HippyMethod(name = "measureInWindow") - public void measureInWindow(int id, Promise promise) { - DomManager domManager = this.mContext.getDomManager(); - if (domManager != null) { - domManager.measureInWindow(id, promise); - } - LogUtils.d("UIManagerModule", id + "" + promise); - } - - @HippyMethod(name = "startBatch") - public void startBatch() { - DomManager domManager = this.mContext.getDomManager(); - if (domManager != null) { - domManager.renderBatchStart(); - } - } - - @HippyMethod(name = "endBatch") - public void endBatch() { - DomManager domManager = this.mContext.getDomManager(); - if (domManager != null) { - domManager.renderBatchEnd(); - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/PrimitiveValueDeserializer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/PrimitiveValueDeserializer.java deleted file mode 100644 index 0ee30dd73c7..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/PrimitiveValueDeserializer.java +++ /dev/null @@ -1,432 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.serialization; - -import com.tencent.mtt.hippy.serialization.exception.DataCloneOutOfRangeException; -import com.tencent.mtt.hippy.exception.UnreachableCodeException; -import com.tencent.mtt.hippy.serialization.nio.reader.BinaryReader; -import com.tencent.mtt.hippy.serialization.string.DirectStringTable; -import com.tencent.mtt.hippy.serialization.string.StringTable; - -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -/** - * Implementation of {@code v8::(internal::)ValueDeserializer}. - */ -@SuppressWarnings({"unused"}) -public abstract class PrimitiveValueDeserializer extends SharedSerialization { - - /** - * StingTable used for byte[] to String - */ - private final StringTable stringTable; - /** - * Reader used for read buffer. - */ - protected BinaryReader reader; - /** - * Version of the data format used during serialization. - */ - private int version; - /** - * ID of the next deserialized object. - */ - private int nextId; - /** - * Maps ID of a deserialized object to the object itself. - */ - private final Map objectMap = new HashMap<>(); - - protected PrimitiveValueDeserializer(BinaryReader reader, StringTable stringTable) { - super(); - - this.reader = reader; - - if (stringTable == null) { - stringTable = new DirectStringTable(); - } - this.stringTable = stringTable; - } - - protected abstract Object readJSBoolean(boolean value); - - protected abstract Object readJSNumber(); - - protected abstract Object readJSBigInt(); - - protected abstract Object readJSString(StringLocation location, Object relatedKey); - - protected abstract Object readJSArrayBuffer(); - - protected abstract Object readJSRegExp(); - - protected abstract Object readJSObject(); - - protected abstract Object readJSMap(); - - protected abstract Object readJSSet(); - - protected abstract Object readDenseArray(); - - protected abstract Object readSparseArray(); - - protected abstract Object readJSError(); - - protected abstract Object readHostObject(); - - protected abstract Object readTransferredJSArrayBuffer(); - - protected abstract Object readSharedArrayBuffer(); - - protected abstract Object readTransferredWasmModule(); - - protected abstract Object readTransferredWasmMemory(); - - /** - * Set current binary reader - * - * @param reader The binary reader to be set - */ - public void setReader(BinaryReader reader) { - this.reader = reader; - } - - /** - * Get current binary reader - * - * @return The current binary reader - */ - public BinaryReader getReader() { - return reader; - } - - /** - * Get current string table - * - * @return The current string table - */ - public StringTable getStringTable() { - return stringTable; - } - - /** - * Reset Deserializer, for the future using - */ - public void reset() { - objectMap.clear(); - nextId = 0; - } - - /** - * Reads and validates a header (including the format version). Throw an {@link - * UnsupportedOperationException} exception on unsupported wire format. - */ - public void readHeader() { - if (readTag() == SerializationTag.VERSION) { - version = (int) reader.getVarint(); - if (version > LATEST_VERSION) { - throw new UnsupportedOperationException( - "Unable to deserialize cloned data due to invalid or unsupported version."); - } - } - } - - /** - * Deserializes a JavaScript delegate object from the buffer. - * - * @return JavaScript delegate object - */ - public Object readValue() { - return readValue(StringLocation.TOP_LEVEL, null); - } - - protected Object readValue(StringLocation location, Object relatedKey) { - SerializationTag tag = readTag(); - return readValue(tag, location, relatedKey); - } - - protected Object readValue(SerializationTag tag, StringLocation location, Object relatedKey) { - switch (tag) { - case TRUE: - return Boolean.TRUE; - case FALSE: - return Boolean.FALSE; - case THE_HOLE: - return Hole; - case UNDEFINED: - return Undefined; - case NULL: - return Null; - case INT32: - return readZigZag(); - case UINT32: - return reader.getVarint(); - case DOUBLE: - return readDoubleWithRectification(); - case BIG_INT: - return readBigInt(); - case ONE_BYTE_STRING: - return readOneByteString(location, relatedKey); - case TWO_BYTE_STRING: - return readTwoByteString(location, relatedKey); - case UTF8_STRING: - return readUTF8String(location, relatedKey); - case DATE: - return readDate(); - case TRUE_OBJECT: - return readJSBoolean(true); - case FALSE_OBJECT: - return readJSBoolean(false); - case NUMBER_OBJECT: - return readJSNumber(); - case BIG_INT_OBJECT: - return readJSBigInt(); - case STRING_OBJECT: - return readJSString(location, relatedKey); - case REGEXP: - return readJSRegExp(); - case ARRAY_BUFFER: - return readJSArrayBuffer(); - case ARRAY_BUFFER_TRANSFER: - return readTransferredJSArrayBuffer(); - case SHARED_ARRAY_BUFFER: - return readSharedArrayBuffer(); - case BEGIN_JS_OBJECT: - return readJSObject(); - case BEGIN_JS_MAP: - return readJSMap(); - case BEGIN_JS_SET: - return readJSSet(); - case BEGIN_DENSE_JS_ARRAY: - return readDenseArray(); - case BEGIN_SPARSE_JS_ARRAY: - return readSparseArray(); - case OBJECT_REFERENCE: - return readObjectReference(); - case WASM_MODULE_TRANSFER: - return readTransferredWasmModule(); - case HOST_OBJECT: - return readHostObject(); - case WASM_MEMORY_TRANSFER: - return readTransferredWasmMemory(); - case ERROR: - return readJSError(); - default: { - // Before there was an explicit tag for host objects, all unknown tags - // were delegated to the host. - if (version < 13) { - reader.position(-1); - return readHostObject(); - } - - // Unsupported Tag treated as Undefined - return Undefined; - } - } - } - - protected SerializationTag readTag() { - SerializationTag tag; - do { - tag = SerializationTag.fromTag(reader.getByte()); - } while (tag == SerializationTag.PADDING); - return tag; - } - - protected SerializationTag peekTag() { - if (reader.position() < reader.length()) { - SerializationTag tag = SerializationTag.fromTag(reader.getByte()); - reader.position(-1); - return tag; - } - return null; - } - - protected ArrayBufferViewTag readArrayBufferViewTag() { - return ArrayBufferViewTag.fromTag(reader.getByte()); - } - - protected ErrorTag readErrorTag() { - return ErrorTag.fromTag(reader.getByte()); - } - - protected int readZigZag() { - long zigzag = reader.getVarint(); - long value = (zigzag >> 1) ^ -(zigzag & 1); - return (int) value; - } - - /** - * Reads {@code UInt32} data from the buffer. - * - * @return data - */ - public long readUInt32() { - return reader.getVarint(); - } - - /** - * Reads {@code UInt64} data from the buffer. - * - * @return data - */ - public long readUInt64() { - return reader.getVarint(); - } - - /** - * Reads {@code double} or {@code int} data from the buffer. - *

- * If {@code double} can be representable as {@code long}, it will be automatically converted to - * {@code long} type. - *

- *

Background

- * Since the ECMAScript standard does not define the storage (expression) of the number - * type in the VM, different implementations may have different storage implementations of the - * same value.
e.g.
v8 store js number as Smi or Heap Number(out of Smi payload or - * it's double value), if number store in heap, v8 regardless of the original type, treated as - * {@code double}. - * - * @return Number data - */ - private Number readDoubleWithRectification() { - double doubleValue = reader.getDouble(); - long longValue = (long) doubleValue; - //noinspection RedundantIfStatement - if (longValue == doubleValue) { - return longValue; - } - return doubleValue; - } - - /** - * Reads {@code double} data from the buffer. - * - * @return data - */ - public double readDouble() { - return reader.getDouble(); - } - - /** - * Reads {@code byte[]} from the buffer. - * - * @param length read length - * @return a wrapped {@link ByteBuffer} object - */ - public ByteBuffer readBytes(int length) { - return reader.getBytes(length); - } - - protected String readString(StringLocation location, Object relatedKey) { - SerializationTag tag = readTag(); - switch (tag) { - case ONE_BYTE_STRING: - return readOneByteString(location, relatedKey); - case TWO_BYTE_STRING: - return readTwoByteString(location, relatedKey); - case UTF8_STRING: - return readUTF8String(location, relatedKey); - default: - throw new UnreachableCodeException(); - } - } - - protected BigInteger readBigInt() { - int bitField = (int) reader.getVarint(); - boolean negative = (bitField & 1) != 0; - bitField >>= 1; - BigInteger bigInteger = BigInteger.ZERO; - for (int i = 0; i < bitField; i++) { - byte b = reader.getByte(); - for (int bit = 8 * i; bit < 8 * (i + 1); bit++) { - if ((b & 1) != 0) { - bigInteger = bigInteger.setBit(bit); - } - b >>>= 1; - } - } - if (negative) { - bigInteger = bigInteger.negate(); - } - return bigInteger; - } - - protected String readOneByteString(StringLocation location, Object relatedKey) { - return readString("ISO-8859-1", location, relatedKey); - } - - protected String readTwoByteString(StringLocation location, Object relatedKey) { - // Android is always little-endian - return readString("UTF-16LE", location, relatedKey); - } - - protected String readUTF8String(StringLocation location, Object relatedKey) { - return readString("UTF-8", location, relatedKey); - } - - protected String readString(String encoding, StringLocation location, Object relatedKey) { - int byteCount = (int) reader.getVarint(); - if (byteCount < 0) { - throw new DataCloneOutOfRangeException(byteCount); - } - - ByteBuffer byteBuffer = reader.getBytes(byteCount); - try { - return stringTable.lookup(byteBuffer, encoding, location, relatedKey); - } catch (UnsupportedEncodingException e) { - throw new UnreachableCodeException(e); - } - } - - protected Date readDate() { - double millis = reader.getDouble(); - return assignId(new Date((long) millis)); - } - - protected Object readObjectReference() { - int id = (int) reader.getVarint(); - if (id < 0) { - throw new DataCloneOutOfRangeException(id); - } - Object object = objectMap.get(id); - if (object == null) { - throw new AssertionError(String.format("invalid object reference(@%d)", id)); - } - return object; - } - - protected T assignId(T object) { - objectMap.put(nextId++, object); - return object; - } - - /** - * Reads the underlying wire format version. Likely mostly to be useful to legacy code reading old - * wire format versions. - * - * @return wire format version - */ - public int getWireFormatVersion() { - return version; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/SerializationTag.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/SerializationTag.java deleted file mode 100644 index e7b77933d97..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/SerializationTag.java +++ /dev/null @@ -1,82 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.serialization; - -/** - * A tag that determines the type of the serialized value. - */ -@SuppressWarnings({"unused"}) -public enum SerializationTag { - VERSION((char) 0xFF), - TRUE('T'), // kTrue - FALSE('F'), // kFalse - UNDEFINED('_'), // kUndefined - NULL('0'), // kNull - INT32('I'), // kInt32 - UINT32('U'), // kUint32 - DOUBLE('N'), // kDouble - BIG_INT('Z'), // kBigInt - UTF8_STRING('S'), // kUtf8String - ONE_BYTE_STRING('"'), // kOneByteString - TWO_BYTE_STRING('c'), // kTwoByteString - PADDING('\0'), // kPadding - DATE('D'), // kDate - TRUE_OBJECT('y'), // kTrueObject - FALSE_OBJECT('x'), // kFalseObject - NUMBER_OBJECT('n'), // kNumberObject - BIG_INT_OBJECT('z'), // kBigIntObject - STRING_OBJECT('s'), // kStringObject - REGEXP('R'), // kRegExp - ARRAY_BUFFER('B'), // kArrayBuffer - SHARED_ARRAY_BUFFER('u'), // kSharedArrayBuffer - ARRAY_BUFFER_TRANSFER('t'), // kArrayBufferTransfer - ARRAY_BUFFER_VIEW('V'), // kArrayBufferView - BEGIN_JS_MAP(';'), // kBeginJSMap - END_JS_MAP(':'), // kEndJSMap - BEGIN_JS_SET('\''), // kBeginJSSet - END_JS_SET(','), // kEndJSSet - BEGIN_JS_OBJECT('o'), // kBeginJSObject - END_JS_OBJECT('{'), // kEndJSObject - BEGIN_SPARSE_JS_ARRAY('a'), // kBeginSparseJSArray - END_SPARSE_JS_ARRAY('@'), // kEndSparseJSArray - BEGIN_DENSE_JS_ARRAY('A'), // kBeginDenseJSArray - END_DENSE_JS_ARRAY('$'), // kEndDenseJSArray - THE_HOLE('-'), // kTheHole - OBJECT_REFERENCE('^'), // kObjectReference - WASM_MODULE_TRANSFER('w'), // kWasmModuleTransfer - HOST_OBJECT('\\'), // kHostObject - WASM_MEMORY_TRANSFER('m'), // kWasmMemoryTransfer - ERROR('r'); // kError - - private final byte tag; - - SerializationTag(char tag) { - this.tag = (byte) tag; - } - - public byte getTag() { - return tag; - } - - public static SerializationTag fromTag(byte tag) { - for (SerializationTag t : values()) { - if (t.tag == tag) { - return t; - } - } - return null; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/compatible/Deserializer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/compatible/Deserializer.java deleted file mode 100644 index 8f8dc8cd2c8..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/compatible/Deserializer.java +++ /dev/null @@ -1,388 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.serialization.compatible; - -import com.tencent.mtt.hippy.common.ConstantValue; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.exception.UnexpectedException; -import com.tencent.mtt.hippy.exception.UnreachableCodeException; -import com.tencent.mtt.hippy.serialization.ErrorTag; -import com.tencent.mtt.hippy.serialization.PrimitiveValueDeserializer; -import com.tencent.mtt.hippy.serialization.SerializationTag; -import com.tencent.mtt.hippy.serialization.StringLocation; -import com.tencent.mtt.hippy.serialization.exception.DataCloneOutOfRangeException; -import com.tencent.mtt.hippy.serialization.nio.reader.BinaryReader; -import com.tencent.mtt.hippy.serialization.string.StringTable; - -import java.math.BigInteger; - -/** - * Compatible with {@code com.tencent.mtt.hippy.common.HippyMap} - */ -@SuppressWarnings({"unused", "deprecation"}) -public class Deserializer extends PrimitiveValueDeserializer { - - public Deserializer(BinaryReader reader) { - this(reader, null); - } - - public Deserializer(BinaryReader reader, StringTable stringTable) { - super(reader, stringTable); - } - - @Override - protected Object getUndefined() { - return ConstantValue.Undefined; - } - - @Override - protected Object getNull() { - return ConstantValue.Null; - } - - @Override - protected Object getHole() { - return ConstantValue.Hole; - } - - @Override - protected Boolean readJSBoolean(boolean value) { - return assignId(value); - } - - @Override - protected Number readJSNumber() { - return assignId(reader.getDouble()); - } - - @Override - protected BigInteger readJSBigInt() { - return assignId(readBigInt()); - } - - @Override - protected String readJSString(StringLocation location, Object relatedKey) { - return assignId(readString(location, relatedKey)); - } - - @Override - protected Object readJSArrayBuffer() { - int byteLength = (int) reader.getVarint(); - if (byteLength < 0) { - throw new DataCloneOutOfRangeException(byteLength); - } - reader.position(reader.position() + byteLength); - - assignId(Undefined); - if (peekTag() == SerializationTag.ARRAY_BUFFER_VIEW) { - readJSArrayBufferView(); - } - - return null; - } - - @Override - protected Object readJSRegExp() { - readString(StringLocation.VOID, null); - reader.getVarint(); - return assignId(Undefined); - } - - @Override - protected HippyMap readJSObject() { - HippyMap object = new HippyMap(); - assignId(object); - int read = readJSProperties(object, SerializationTag.END_JS_OBJECT); - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of properties"); - } - return object; - } - - private int readJSProperties(HippyMap object, SerializationTag endTag) { - final StringLocation keyLocation, valueLocation; - if (endTag == SerializationTag.END_DENSE_JS_ARRAY) { - keyLocation = StringLocation.DENSE_ARRAY_KEY; - valueLocation = StringLocation.DENSE_ARRAY_ITEM; - } else if (endTag == SerializationTag.END_JS_OBJECT) { - keyLocation = StringLocation.OBJECT_KEY; - valueLocation = StringLocation.OBJECT_VALUE; - } else { - throw new UnreachableCodeException(); - } - - SerializationTag tag; - int count = 0; - while ((tag = readTag()) != endTag) { - count++; - Object key = readValue(tag, keyLocation, null); - Object value = readValue(valueLocation, key); - - if (object != null && value != Undefined) { - if (key instanceof Number) { - object.pushObject(String.valueOf(key), value); - } else if (key instanceof String) { - if (key == "null") { - object.pushObject(null, value); - } else { - object.pushObject((String) key, value); - } - } else { - throw new AssertionError("Object key is not of String(null) nor Number type"); - } - } - } - return count; - } - - @Override - protected HippyMap readJSMap() { - HippyMap object = new HippyMap(); - assignId(object); - SerializationTag tag; - int read = 0; - while ((tag = readTag()) != SerializationTag.END_JS_MAP) { - read++; - Object key = readValue(tag, StringLocation.MAP_KEY, null); - key = key.toString(); - Object value = readValue(StringLocation.MAP_VALUE, key); - if (value != Undefined) { - if (key == "null") { - object.pushObject(null, value); - } else { - object.pushObject((String) key, value); - } - } - } - int expected = (int) reader.getVarint(); - if (2 * read != expected) { - throw new UnexpectedException("unexpected number of entries"); - } - return object; - } - - @Override - protected HippyArray readJSSet() { - HippyArray array = new HippyArray(); - assignId(array); - SerializationTag tag; - int read = 0; - while ((tag = readTag()) != SerializationTag.END_JS_SET) { - read++; - Object value = readValue(tag, StringLocation.SET_ITEM, null); - array.pushObject(value); - } - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of values"); - } - return array; - } - - @Override - protected HippyArray readDenseArray() { - int length = (int) reader.getVarint(); - if (length < 0) { - throw new DataCloneOutOfRangeException(length); - } - HippyArray array = new HippyArray(); - assignId(array); - for (int i = 0; i < length; i++) { - SerializationTag tag = readTag(); - if (tag != SerializationTag.THE_HOLE) { - array.pushObject(readValue(tag, StringLocation.DENSE_ARRAY_ITEM, i)); - } - } - - int read = readJSProperties(null, SerializationTag.END_DENSE_JS_ARRAY); - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of properties"); - } - int length2 = (int) reader.getVarint(); - if (length != length2) { - throw new AssertionError("length ambiguity"); - } - return array; - } - - /** - * Reads Spare Array from buffer. - * - *

Note

- * Sparse arrays will be serialized as an object-like manner. Normally, it should be representable - * as {@link HippyMap}, but in order to be compatible with the previous serialization implement, - * we use {@link HippyArray} to express sparse arrays.
When a hole is encountered, {@link - * ConstantValue#Null} is used to fill it. - * - * @return array - */ - @Override - protected HippyArray readSparseArray() { - long length = reader.getVarint(); - HippyArray array = new HippyArray(); - assignId(array); - - SerializationTag tag; - int read = 0; - while ((tag = readTag()) != SerializationTag.END_SPARSE_JS_ARRAY) { - read++; - Object key = readValue(tag, StringLocation.SPARSE_ARRAY_KEY, null); - Object value = readValue(StringLocation.SPARSE_ARRAY_ITEM, key); - - int index = -1; - if (key instanceof Number) { - index = ((Number) key).intValue(); - } else if (key instanceof String) { - try { - index = Integer.parseInt((String) key); - } catch (NumberFormatException ignored) { - // ignore not parsable string - } - } - - if (index >= 0) { - int spaceNeeded = (index + 1) - array.size(); - if (spaceNeeded - == 1) { // Fast path, item are ordered in general ECMAScript(VM) implementation - array.pushObject(value); - } else { // Slow path, universal - for (int i = 0; i < spaceNeeded; i++) { - array.pushNull(); - } - array.setObject(index, value); - } - } - } - - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of properties"); - } - long length2 = reader.getVarint(); - if (length != length2) { - throw new AssertionError("length ambiguity"); - } - return array; - } - - private void readJSArrayBufferView() { - SerializationTag arrayBufferViewTag = readTag(); - if (arrayBufferViewTag != SerializationTag.ARRAY_BUFFER_VIEW) { - throw new AssertionError("ArrayBufferViewTag: " + arrayBufferViewTag); - } - reader.getVarint(); - reader.getVarint(); - readArrayBufferViewTag(); - - assignId(Undefined); - } - - @Override - protected HippyMap readJSError() { - String message = null; - String stack = null; - String errorType = null; - boolean done = false; - while (!done) { - ErrorTag tag = readErrorTag(); - if (tag == null) { - break; - } - switch (tag) { - case EVAL_ERROR: - errorType = "EvalError"; - break; - case RANGE_ERROR: - errorType = "RangeError"; - break; - case REFERENCE_ERROR: - errorType = "ReferenceError"; - break; - case SYNTAX_ERROR: - errorType = "SyntaxError"; - break; - case TYPE_ERROR: - errorType = "TypeError"; - break; - case URI_ERROR: - errorType = "URIError"; - break; - case MESSAGE: - message = readString(StringLocation.ERROR_MESSAGE, null); - break; - case STACK: - stack = readString(StringLocation.ERROR_STACK, null); - break; - default: - if (!(tag == ErrorTag.END)) { - throw new AssertionError("ErrorTag: " + tag); - } - done = true; - break; - } - } - - HippyMap error = new HippyMap(); - error.pushString("message", message); - error.pushString("stack", stack); - error.pushString("type", errorType); - assignId(error); - return error; - } - - @Override - protected Object readHostObject() { - return assignId(Undefined); - } - - @Override - public Object readTransferredJSArrayBuffer() { - reader.getVarint(); - assignId(Undefined); - if (peekTag() == SerializationTag.ARRAY_BUFFER_VIEW) { - readJSArrayBufferView(); - } - return null; - } - - @Override - public Object readSharedArrayBuffer() { - reader.getVarint(); - assignId(Undefined); - if (peekTag() == SerializationTag.ARRAY_BUFFER_VIEW) { - readJSArrayBufferView(); - } - return null; - } - - @Override - protected Object readTransferredWasmModule() { - reader.getVarint(); - assignId(Undefined); - return null; - } - - @Override - protected Object readTransferredWasmMemory() { - reader.getVarint(); - readSharedArrayBuffer(); - assignId(Undefined); - return null; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/compatible/Serializer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/compatible/Serializer.java deleted file mode 100644 index 5f79f8e408b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/compatible/Serializer.java +++ /dev/null @@ -1,101 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.serialization.compatible; - -import androidx.annotation.NonNull; - -import com.tencent.mtt.hippy.common.ConstantValue; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.serialization.PrimitiveValueSerializer; -import com.tencent.mtt.hippy.serialization.SerializationTag; -import com.tencent.mtt.hippy.serialization.nio.writer.BinaryWriter; - -import java.util.Set; - -/** - * Implementation of {@code v8::(internal::)ValueSerializer}. - */ -@SuppressWarnings({"deprecation", "unused"}) -public class Serializer extends PrimitiveValueSerializer { - - public Serializer() { - super(null); - } - - public Serializer(BinaryWriter writer) { - super(writer); - } - - @Override - protected Object getUndefined() { - return ConstantValue.Undefined; - } - - @Override - protected Object getNull() { - return ConstantValue.Null; - } - - @Override - protected Object getHole() { - return ConstantValue.Hole; - } - - @Override - public boolean writeValue(Object object) { - if (super.writeValue(object)) { - return true; - } - if (object instanceof HippyArray) { - assignId(object); - writeJSArray((HippyArray) object); - } else if (object instanceof HippyMap) { - assignId(object); - writeJSObject((HippyMap) object); - } else { - return false; - } - return true; - } - - private void writeJSObject(@NonNull HippyMap value) { - writeTag(SerializationTag.BEGIN_JS_OBJECT); - Set keys = value.keySet(); - for (String key : keys) { - if (key == Null) { - writeString("null"); - } else { - writeString(key); - } - writeValue(value.get(key)); - } - writeTag(SerializationTag.END_JS_OBJECT); - writer.putVarint(keys.size()); - } - - private void writeJSArray(@NonNull HippyArray value) { - long length = value.size(); - writeTag(SerializationTag.BEGIN_DENSE_JS_ARRAY); - writer.putVarint(length); - for (int i = 0; i < length; i++) { - writeValue(value.get(i)); - } - writeTag(SerializationTag.END_DENSE_JS_ARRAY); - writer.putVarint(0); - writer.putVarint(length); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/recommend/Deserializer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/recommend/Deserializer.java deleted file mode 100644 index b08e2c24333..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/recommend/Deserializer.java +++ /dev/null @@ -1,522 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.serialization.recommend; - -import androidx.annotation.NonNull; - -import com.tencent.mtt.hippy.serialization.exception.DataCloneOutOfRangeException; -import com.tencent.mtt.hippy.serialization.exception.DataCloneOutOfValueException; -import com.tencent.mtt.hippy.exception.UnexpectedException; -import com.tencent.mtt.hippy.exception.UnreachableCodeException; -import com.tencent.mtt.hippy.runtime.builtins.JSRegExp; -import com.tencent.mtt.hippy.runtime.builtins.JSValue; -import com.tencent.mtt.hippy.runtime.builtins.array.JSSparseArray; -import com.tencent.mtt.hippy.runtime.builtins.wasm.WasmMemory; -import com.tencent.mtt.hippy.runtime.builtins.wasm.WasmModule; -import com.tencent.mtt.hippy.serialization.exception.DataCloneDeserializationException; -import com.tencent.mtt.hippy.serialization.ErrorTag; -import com.tencent.mtt.hippy.serialization.PrimitiveValueDeserializer; -import com.tencent.mtt.hippy.serialization.SerializationTag; -import com.tencent.mtt.hippy.runtime.builtins.array.JSDenseArray; -import com.tencent.mtt.hippy.runtime.builtins.JSArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.JSDataView; -import com.tencent.mtt.hippy.runtime.builtins.JSError; -import com.tencent.mtt.hippy.runtime.builtins.JSMap; -import com.tencent.mtt.hippy.runtime.builtins.JSObject; -import com.tencent.mtt.hippy.runtime.builtins.JSOddball; -import com.tencent.mtt.hippy.runtime.builtins.JSSet; -import com.tencent.mtt.hippy.runtime.builtins.JSSharedArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSBigintObject; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSBooleanObject; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSNumberObject; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSStringObject; -import com.tencent.mtt.hippy.serialization.StringLocation; -import com.tencent.mtt.hippy.serialization.exception.DataCloneException; -import com.tencent.mtt.hippy.serialization.nio.reader.BinaryReader; -import com.tencent.mtt.hippy.serialization.string.StringTable; - -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; - -/** - * Implementation of {@code v8::(internal::)ValueDeserializer}. - */ -@SuppressWarnings("unused") -public class Deserializer extends PrimitiveValueDeserializer { - - public interface Delegate { - - /** - * Implement this method to read some kind of host object, if possible. If not, a {@link - * DataCloneException} exception should be thrown. - * - * @param deserializer current deserializer - * @return host object - */ - Object readHostObject(Deserializer deserializer); - - /** - * Get a {@link JSSharedArrayBuffer} given a clone_id previously provided by - * Serializer.Delegate#getSharedArrayBufferId - * - * @param deserializer current deserializer - * @param clone_id clone id - * @return JSSharedArrayBuffer - */ - JSSharedArrayBuffer getSharedArrayBufferFromId(Deserializer deserializer, int clone_id); - - /** - * Get a {@link WasmModule} given a transfer_id previously provided by - * erializer.Delegate#getWasmModuleTransferId - * - * @param deserializer current deserializer - * @param transfer_id transfer id - * @return WebAssembly Module - */ - WasmModule getWasmModuleFromId(Deserializer deserializer, int transfer_id); - } - - /** - * Implement for Delegate interface - */ - private final Delegate delegate; - /** - * Maps transfer ID to the transferred {@link JSArrayBuffer}s. - */ - private Map arrayBufferTransferMap; - - public Deserializer(BinaryReader reader) { - this(reader, null, null); - } - - public Deserializer(BinaryReader reader, StringTable stringTable) { - this(reader, stringTable, null); - } - - public Deserializer(BinaryReader reader, Delegate delegate) { - this(reader, null, delegate); - } - - public Deserializer(BinaryReader reader, StringTable stringTable, Delegate delegate) { - super(reader, stringTable); - this.delegate = delegate; - } - - @Override - protected Object getHole() { - return JSOddball.Hole; - } - - @Override - protected Object getUndefined() { - return JSOddball.Undefined; - } - - @Override - protected Object getNull() { - return JSOddball.Null; - } - - @Override - protected Object readJSBoolean(boolean value) { - return assignId(value ? JSBooleanObject.True : JSBooleanObject.False); - } - - @Override - protected JSNumberObject readJSNumber() { - double value = reader.getDouble(); - return assignId(new JSNumberObject(value)); - } - - @Override - protected JSBigintObject readJSBigInt() { - BigInteger value = readBigInt(); - return assignId(new JSBigintObject(value)); - } - - @Override - protected JSStringObject readJSString(StringLocation location, Object relatedKey) { - String value = readString(location, relatedKey); - return assignId(new JSStringObject(value)); - } - - @Override - protected Object readJSArrayBuffer() { - int byteLength = (int) reader.getVarint(); - if (byteLength < 0) { - throw new DataCloneOutOfRangeException(byteLength); - } - JSArrayBuffer arrayBufferObject = JSArrayBuffer.allocate(byteLength); - ByteBuffer arrayBuffer = arrayBufferObject.getBuffer(); - arrayBuffer.put(reader.getBytes(byteLength)); - assignId(arrayBufferObject); - return (peekTag() == SerializationTag.ARRAY_BUFFER_VIEW) ? readJSArrayBufferView( - arrayBufferObject) : arrayBuffer; - } - - @Override - protected JSRegExp readJSRegExp() { - String pattern = readString(StringLocation.REGEXP, null); - int flags = (int) reader.getVarint(); - if (flags < 0) { - throw new DataCloneOutOfValueException(flags); - } - return assignId(new JSRegExp(pattern, flags)); - } - - @Override - protected JSObject readJSObject() { - JSObject object = new JSObject(); - assignId(object); - int read = readJSProperties(object, SerializationTag.END_JS_OBJECT); - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of properties"); - } - return object; - } - - private int readJSProperties(@NonNull JSObject object, SerializationTag endTag) { - final StringLocation keyLocation, valueLocation; - switch (endTag) { - case END_DENSE_JS_ARRAY: { - keyLocation = StringLocation.DENSE_ARRAY_KEY; - valueLocation = StringLocation.DENSE_ARRAY_ITEM; - break; - } - case END_SPARSE_JS_ARRAY: { - keyLocation = StringLocation.SPARSE_ARRAY_KEY; - valueLocation = StringLocation.SPARSE_ARRAY_ITEM; - break; - } - case END_JS_OBJECT: { - keyLocation = StringLocation.OBJECT_KEY; - valueLocation = StringLocation.OBJECT_VALUE; - break; - } - default: { - throw new UnreachableCodeException(); - } - } - - SerializationTag tag; - int count = 0; - while ((tag = readTag()) != endTag) { - count++; - Object key = readValue(tag, keyLocation, null); - if (key instanceof Integer) { - Object value = readValue(valueLocation, key); - if (endTag == SerializationTag.END_SPARSE_JS_ARRAY) { - ((JSSparseArray) object).set((int) key, value); - } else { - object.set(String.valueOf(key), value); - } - } else if (key instanceof String) { - Object value = readValue(valueLocation, key); - object.set((String) key, value); - } else { - throw new AssertionError("Object key is not of String nor Integer type"); - } - } - return count; - } - - @Override - protected JSMap readJSMap() { - JSMap map = new JSMap(); - assignId(map); - SerializationTag tag; - int read = 0; - HashMap internalMap = map.getInternalMap(); - while ((tag = readTag()) != SerializationTag.END_JS_MAP) { - read++; - Object key = readValue(tag, StringLocation.MAP_KEY, null); - Object value = readValue(StringLocation.MAP_VALUE, key); - internalMap.put(key, value); - } - int expected = (int) reader.getVarint(); - if (2 * read != expected) { - throw new UnexpectedException("unexpected number of entries"); - } - return map; - } - - @Override - protected JSSet readJSSet() { - JSSet set = new JSSet(); - assignId(set); - SerializationTag tag; - int read = 0; - HashSet internalSet = set.getInternalSet(); - while ((tag = readTag()) != SerializationTag.END_JS_SET) { - read++; - Object value = readValue(tag, StringLocation.SET_ITEM, null); - internalSet.add(value); - } - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of values"); - } - return set; - } - - @Override - protected JSDenseArray readDenseArray() { - int length = (int) reader.getVarint(); - if (length < 0) { - throw new DataCloneOutOfRangeException(length); - } - JSDenseArray array = new JSDenseArray(length); - assignId(array); - for (int i = 0; i < length; i++) { - SerializationTag tag = readTag(); - array.push(readValue(tag, StringLocation.DENSE_ARRAY_ITEM, i)); - } - - int read = readJSProperties(array, SerializationTag.END_DENSE_JS_ARRAY); - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of properties"); - } - int length2 = (int) reader.getVarint(); - if (length != length2) { - throw new AssertionError("length ambiguity"); - } - return array; - } - - @Override - protected JSSparseArray readSparseArray() { - long length = reader.getVarint(); - JSSparseArray array = new JSSparseArray(); - assignId(array); - int read = readJSProperties(array, SerializationTag.END_SPARSE_JS_ARRAY); - int expected = (int) reader.getVarint(); - if (read != expected) { - throw new UnexpectedException("unexpected number of properties"); - } - long length2 = reader.getVarint(); - if (length != length2) { - throw new AssertionError("length ambiguity"); - } - return array; - } - - private JSDataView readJSArrayBufferView(JSArrayBuffer arrayBuffer) { - SerializationTag arrayBufferViewTag = readTag(); - if (arrayBufferViewTag != SerializationTag.ARRAY_BUFFER_VIEW) { - throw new AssertionError("ArrayBufferViewTag: " + arrayBufferViewTag); - } - int offset = (int) reader.getVarint(); - if (offset < 0) { - throw new DataCloneOutOfValueException(offset); - } - int byteLength = (int) reader.getVarint(); - if (byteLength < 0) { - throw new DataCloneOutOfValueException(byteLength); - } - JSDataView.DataViewKind kind; - switch (readArrayBufferViewTag()) { - case DATA_VIEW: { - kind = JSDataView.DataViewKind.DATA_VIEW; - break; - } - case FLOAT32_ARRAY: { - kind = JSDataView.DataViewKind.FLOAT32_ARRAY; - break; - } - case FLOAT64_ARRAY: { - kind = JSDataView.DataViewKind.FLOAT64_ARRAY; - break; - } - case INT8_ARRAY: { - kind = JSDataView.DataViewKind.INT8_ARRAY; - break; - } - case INT16_ARRAY: { - kind = JSDataView.DataViewKind.INT16_ARRAY; - break; - } - case INT32_ARRAY: { - kind = JSDataView.DataViewKind.INT32_ARRAY; - break; - } - case UINT8_ARRAY: { - kind = JSDataView.DataViewKind.UINT8_ARRAY; - break; - } - case UINT8_CLAMPED_ARRAY: { - kind = JSDataView.DataViewKind.UINT8_CLAMPED_ARRAY; - break; - } - case UINT16_ARRAY: { - kind = JSDataView.DataViewKind.UINT16_ARRAY; - break; - } - case UINT32_ARRAY: { - kind = JSDataView.DataViewKind.UINT32_ARRAY; - break; - } - default: { - throw new UnreachableCodeException(); - } - } - JSDataView view = new JSDataView<>(arrayBuffer, kind, offset, byteLength); - assignId(view); - return view; - } - - @Override - protected JSError readJSError() { - JSError.ErrorType errorType = JSError.ErrorType.Error; - String message = null; - String stack = null; - boolean done = false; - while (!done) { - ErrorTag tag = readErrorTag(); - if (tag == null) { - break; - } - switch (tag) { - case EVAL_ERROR: { - errorType = JSError.ErrorType.EvalError; - break; - } - case RANGE_ERROR: { - errorType = JSError.ErrorType.RangeError; - break; - } - case REFERENCE_ERROR: { - errorType = JSError.ErrorType.ReferenceError; - break; - } - case SYNTAX_ERROR: { - errorType = JSError.ErrorType.SyntaxError; - break; - } - case TYPE_ERROR: { - errorType = JSError.ErrorType.TypeError; - break; - } - case URI_ERROR: { - errorType = JSError.ErrorType.URIError; - break; - } - case MESSAGE: { - message = readString(StringLocation.ERROR_MESSAGE, null); - break; - } - case STACK: { - stack = readString(StringLocation.ERROR_STACK, null); - break; - } - default: { - if (!(tag == ErrorTag.END)) { - throw new AssertionError("ErrorTag: " + tag); - } - done = true; - break; - } - } - } - - JSError error = new JSError(errorType, message, stack); - assignId(error); - return error; - } - - @Override - protected Object readHostObject() { - if (delegate == null) { - throw new DataCloneDeserializationException(); - } - return assignId(delegate.readHostObject(this)); - } - - /** - * Accepts the {@link JSArrayBuffer} corresponding to the one passed previously to {@link - * Serializer#transferArrayBuffer(int, JSArrayBuffer)} - * - * @param transferId transfer id - * @param arrayBuffer JSArrayBuffer - */ - public void transferArrayBuffer(int transferId, @NonNull JSArrayBuffer arrayBuffer) { - if (arrayBufferTransferMap == null) { - arrayBufferTransferMap = new HashMap<>(); - } - arrayBufferTransferMap.put(transferId, arrayBuffer); - } - - @Override - protected Object readTransferredJSArrayBuffer() { - int id = (int) reader.getVarint(); - if (id < 0) { - throw new DataCloneOutOfValueException(id); - } - if (arrayBufferTransferMap == null) { - throw new AssertionError("Call |transferArrayBuffer(int, JSArrayBuffer)| first."); - } - JSArrayBuffer arrayBuffer = (JSArrayBuffer) arrayBufferTransferMap.get(id); - if (arrayBuffer == null) { - throw new AssertionError("Invalid transfer id " + id); - } - assignId(arrayBuffer); - return (peekTag() == SerializationTag.ARRAY_BUFFER_VIEW) ? readJSArrayBufferView(arrayBuffer) - : arrayBuffer; - } - - @Override - protected Object readSharedArrayBuffer() { - if (delegate == null) { - throw new DataCloneDeserializationException(); - } - int id = (int) reader.getVarint(); - if (id < 0) { - throw new DataCloneOutOfValueException(id); - } - JSSharedArrayBuffer sharedArrayBuffer = delegate.getSharedArrayBufferFromId(this, id); - assignId(sharedArrayBuffer); - return (peekTag() == SerializationTag.ARRAY_BUFFER_VIEW) ? readJSArrayBufferView( - sharedArrayBuffer) : sharedArrayBuffer; - } - - @Override - protected Object readTransferredWasmModule() { - if (delegate == null) { - throw new DataCloneDeserializationException(); - } - int id = (int) reader.getVarint(); - if (id < 0) { - throw new DataCloneOutOfValueException(id); - } - WasmModule wasmModule = delegate.getWasmModuleFromId(this, id); - return assignId(wasmModule); - } - - @Override - protected Object readTransferredWasmMemory() { - long maximumPages = reader.getVarint(); - JSValue memory = (JSValue) readSharedArrayBuffer(); - if (!memory.isSharedArrayBuffer()) { - throw new UnexpectedException("expected SharedArrayBuffer"); - } - WasmMemory wasmMemory = new WasmMemory(maximumPages, (JSSharedArrayBuffer) memory); - return assignId(wasmMemory); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/recommend/Serializer.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/recommend/Serializer.java deleted file mode 100644 index a89342485c0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/serialization/recommend/Serializer.java +++ /dev/null @@ -1,480 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.serialization.recommend; - -import android.util.Pair; - -import androidx.annotation.NonNull; - -import com.tencent.mtt.hippy.exception.UnreachableCodeException; -import com.tencent.mtt.hippy.runtime.builtins.JSRegExp; -import com.tencent.mtt.hippy.runtime.builtins.JSValue; -import com.tencent.mtt.hippy.runtime.builtins.array.JSAbstractArray; -import com.tencent.mtt.hippy.runtime.builtins.array.JSSparseArray; -import com.tencent.mtt.hippy.runtime.builtins.wasm.WasmModule; -import com.tencent.mtt.hippy.serialization.ArrayBufferViewTag; -import com.tencent.mtt.hippy.serialization.exception.DataCloneException; -import com.tencent.mtt.hippy.serialization.ErrorTag; -import com.tencent.mtt.hippy.serialization.utils.IntegerPolyfill; -import com.tencent.mtt.hippy.serialization.PrimitiveValueSerializer; -import com.tencent.mtt.hippy.serialization.SerializationTag; -import com.tencent.mtt.hippy.runtime.builtins.JSArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.JSError; -import com.tencent.mtt.hippy.runtime.builtins.JSMap; -import com.tencent.mtt.hippy.runtime.builtins.JSObject; -import com.tencent.mtt.hippy.runtime.builtins.JSSet; -import com.tencent.mtt.hippy.runtime.builtins.JSSharedArrayBuffer; -import com.tencent.mtt.hippy.runtime.builtins.JSDataView; -import com.tencent.mtt.hippy.runtime.builtins.JSOddball; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSBigintObject; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSBooleanObject; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSNumberObject; -import com.tencent.mtt.hippy.runtime.builtins.objects.JSStringObject; -import com.tencent.mtt.hippy.serialization.nio.writer.BinaryWriter; - -import java.nio.ByteBuffer; -import java.util.Date; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -/** - * Implementation of {@code v8::(internal::)ValueSerializer}. - */ -@SuppressWarnings({"unused"}) -public class Serializer extends PrimitiveValueSerializer { - - public interface Delegate { - - /** - * Implement this method to write some kind of host object, if possible. If not, return value - * will be false. - * - * @param serializer current serializer - * @param object host object - * @return whether the serialization is successful - */ - @SuppressWarnings("SameReturnValue") - boolean writeHostObject(Serializer serializer, Object object); - - /** - * Called when the Serializer is going to serialize a {@link JSSharedArrayBuffer} object. - * Implement must return an ID for the object, using the same ID if this {@link - * JSSharedArrayBuffer} has already been serialized in this buffer.
When deserializing, - * this ID will be passed to Deserializer.Delegate#getSharedArrayBufferFromId as |clone_id|. - *
If the object cannot be serialized, an exception {@link DataCloneException} should be - * thrown. - * - * @param serializer current serializer - * @param sharedArrayBuffer SharedArrayBuffer - * @return ID - */ - int getSharedArrayBufferId(Serializer serializer, JSSharedArrayBuffer sharedArrayBuffer); - - /** - * Called when the Serializer is going to serialize a {@link WasmModule} object. Implement must - * return an ID for the object, using the same ID if this {@link WasmModule} has already been - * serialized in this buffer.
When deserializing, this ID will be passed to - * Deserializer.Delegate#getWasmModuleFromId as |transfer_id|.
If the object cannot be - * serialized, an exception {@link DataCloneException} should be thrown. - * - * @param serializer current serializer - * @param module WebAssembly Module - * @return ID - */ - int getWasmModuleTransferId(Serializer serializer, WasmModule module); - } - - /** - * Implement for Delegate interface - */ - private final Delegate delegate; - /** - * Maps a transferred {@link JSArrayBuffer} to its transfer ID. - */ - private Map arrayBufferTransferMap; - /** - * Determines whether {@link JSArrayBuffer}s should be serialized as host objects. - */ - private boolean treatArrayBufferViewsAsHostObjects; - - public Serializer() { - this(null, null); - } - - public Serializer(Delegate delegate) { - this(null, delegate); - } - - public Serializer(BinaryWriter writer) { - this(writer, null); - } - - public Serializer(BinaryWriter writer, Delegate delegate) { - super(writer); - this.delegate = delegate; - } - - /** - * Indicate whether to treat {@link JSDataView} objects as host objects, i.e. pass them to - * Delegate#WriteHostObject. This should not be called when no Delegate was passed.
The - * default is not to treat ArrayBufferViews as host objects. - * - * @param mode treat mode - */ - public void setTreatArrayBufferViewsAsHostObjects(boolean mode) { - treatArrayBufferViewsAsHostObjects = mode; - } - - @Override - protected Object getHole() { - return JSOddball.Hole; - } - - @Override - protected Object getUndefined() { - return JSOddball.Undefined; - } - - @Override - protected Object getNull() { - return JSOddball.Null; - } - - @Override - public boolean writeValue(Object object) { - if (super.writeValue(object)) { - return true; - } - - if (!treatArrayBufferViewsAsHostObjects && JSValue.is(object) && ((JSValue) object) - .isDataView()) { - JSDataView view = (JSDataView) object; - assignId(view); - if (view.getBufferObject() instanceof JSArrayBuffer) { - writeJSSharedArrayBuffer((JSSharedArrayBuffer) view.getBufferObject()); - } else { - writeJSArrayBuffer(view.getBufferObject()); - } - } - - if (object instanceof Date) { - assignId(object); - writeTag(SerializationTag.DATE); - writeDate((Date) object); - } else if (JSValue.is(object)) { - assignId(object); - JSValue value = (JSValue) object; - - if (value.isArray()) { - writeJSArray((JSAbstractArray) value); - } else if (value.isDataView()) { - writeJSArrayBufferView((JSDataView) value); - } else if (value.isError()) { - writeJSError((JSError) value); - } else if (value.isRegExp()) { - writeJSRegExp((JSRegExp) value); - } else if (value.isObject()) { - writeJSObject((JSObject) value); - } else if (value.isMap()) { - writeJSMap((JSMap) value); - } else if (value.isSet()) { - writeJSSet((JSSet) value); - } else if (value.isSharedArrayBuffer()) { - writeJSSharedArrayBuffer((JSSharedArrayBuffer) value); - } else if (value.isArrayBuffer()) { - writeJSArrayBuffer((JSArrayBuffer) value); - } else if (value.isBooleanObject()) { - writeJSBoolean((JSBooleanObject) value); - } else if (value.isBigIntObject()) { - writeTag(SerializationTag.BIG_INT_OBJECT); - writeJSBigIntContents((JSBigintObject) value); - } else if (value.isNumberObject()) { - writeJSNumber((JSNumberObject) value); - } else if (value.isStringObject()) { - writeJSString((JSStringObject) value); - } else { - throw new UnreachableCodeException(); - } - } else { - if (writeHostObject(object)) { - assignId(object); - } else { - return false; - } - } - return true; - } - - private void writeDate(@NonNull Date date) { - writer.putDouble(date.getTime()); - } - - private void writeJSBoolean(@NonNull JSBooleanObject value) { - writeTag(value.isTrue() ? SerializationTag.TRUE_OBJECT : SerializationTag.FALSE_OBJECT); - } - - private void writeJSBigIntContents(@NonNull JSBigintObject value) { - writeBigIntContents(value.getValue()); - } - - private void writeJSNumber(@NonNull JSNumberObject value) { - writeTag(SerializationTag.NUMBER_OBJECT); - writeDouble(value.getValue().doubleValue()); - } - - private void writeJSString(@NonNull JSStringObject value) { - writeTag(SerializationTag.STRING_OBJECT); - writeString(value.getValue().toString()); - } - - private void writeJSRegExp(@NonNull JSRegExp value) { - writeTag(SerializationTag.REGEXP); - writeString(value.getSource()); - writer.putVarint(value.getFlags()); - } - - private void writeJSArrayBuffer(@NonNull JSArrayBuffer value) { - if (arrayBufferTransferMap == null) { - arrayBufferTransferMap = new IdentityHashMap<>(); - } - - Integer id = arrayBufferTransferMap.get(value); - if (id == null) { - ByteBuffer source = value.getBuffer(); - int byteLength = source.limit(); - writeTag(SerializationTag.ARRAY_BUFFER); - writer.putVarint(byteLength); - for (int i = 0; i < byteLength; i++) { - writer.putByte(source.get(i)); - } - } else { - writeTag(SerializationTag.ARRAY_BUFFER_TRANSFER); - writer.putVarint(IntegerPolyfill.toUnsignedLong(id)); - } - } - - private void writeJSSharedArrayBuffer(@NonNull JSSharedArrayBuffer value) { - if (delegate == null) { - throw new DataCloneException(value); - } - int id = delegate.getSharedArrayBufferId(this, value); - writeTag(SerializationTag.SHARED_ARRAY_BUFFER); - writer.putVarint(id); - } - - private void writeJSObject(JSObject value) { - writeTag(SerializationTag.BEGIN_JS_OBJECT); - writeJSObjectProperties(value.entries()); - writeTag(SerializationTag.END_JS_OBJECT); - writer.putVarint(value.size()); - } - - private void writeJSObjectProperties(@NonNull Set> props) { - for (Pair prop : props) { - writeString(prop.first); - writeValue(prop.second); - } - } - - private void writeJSMap(@NonNull JSMap value) { - writeTag(SerializationTag.BEGIN_JS_MAP); - Iterator> entries = value.getInternalMap().entrySet().iterator(); - int count = 0; - while (entries.hasNext()) { - count++; - Map.Entry entry = entries.next(); - writeValue(entry.getKey()); - writeValue(entry.getValue()); - } - writeTag(SerializationTag.END_JS_MAP); - writer.putVarint(2 * count); - } - - private void writeJSSet(@NonNull JSSet value) { - writeTag(SerializationTag.BEGIN_JS_SET); - Iterator entries = value.getInternalSet().iterator(); - int count = 0; - while (entries.hasNext()) { - count++; - writeValue(entries.next()); - } - writeTag(SerializationTag.END_JS_SET); - writer.putVarint(count); - } - - private void writeJSArray(@NonNull JSAbstractArray value) { - int length = value.size(); - if (value.isDenseArray()) { - writeTag(SerializationTag.BEGIN_DENSE_JS_ARRAY); - writer.putVarint(length); - for (int i = 0; i < length; i++) { - writeValue(value.get(i)); - } - writeJSObjectProperties(JSObject.entries(value)); - writeTag(SerializationTag.END_DENSE_JS_ARRAY); - } else if (value.isSparseArray()) { - writeTag(SerializationTag.BEGIN_SPARSE_JS_ARRAY); - writer.putVarint(length); - for (Pair item : ((JSSparseArray) value).items()) { - writer.putVarint(item.first); - writeValue(item.second); - } - writeJSObjectProperties(JSObject.entries(value)); - writeTag(SerializationTag.END_SPARSE_JS_ARRAY); - } else { - throw new UnreachableCodeException(); - } - writer.putVarint(JSObject.size(value)); - writer.putVarint(length); - } - - private void writeJSArrayBufferView(@NonNull JSDataView value) { - if (treatArrayBufferViewsAsHostObjects) { - if (!writeHostObject(value)) { - throw new DataCloneException(value); - } - } else { - writeTag(SerializationTag.ARRAY_BUFFER_VIEW); - ArrayBufferViewTag tag; - switch (value.getKind()) { - case DATA_VIEW: { - tag = ArrayBufferViewTag.DATA_VIEW; - break; - } - case FLOAT32_ARRAY: { - tag = ArrayBufferViewTag.FLOAT32_ARRAY; - break; - } - case FLOAT64_ARRAY: { - tag = ArrayBufferViewTag.FLOAT64_ARRAY; - break; - } - case INT8_ARRAY: { - tag = ArrayBufferViewTag.INT8_ARRAY; - break; - } - case INT16_ARRAY: { - tag = ArrayBufferViewTag.INT16_ARRAY; - break; - } - case INT32_ARRAY: { - tag = ArrayBufferViewTag.INT32_ARRAY; - break; - } - case UINT8_ARRAY: { - tag = ArrayBufferViewTag.UINT8_ARRAY; - break; - } - case UINT8_CLAMPED_ARRAY: { - tag = ArrayBufferViewTag.UINT8_CLAMPED_ARRAY; - break; - } - case UINT16_ARRAY: { - tag = ArrayBufferViewTag.UINT16_ARRAY; - break; - } - case UINT32_ARRAY: { - tag = ArrayBufferViewTag.UINT32_ARRAY; - break; - } - default: { - throw new UnreachableCodeException(); - } - } - writeTag(tag); - writer.putVarint(value.getByteOffset()); - writer.putVarint(value.getByteLength()); - } - } - - private void writeJSError(@NonNull JSError error) { - writeTag(SerializationTag.ERROR); - writeErrorTypeTag(error); - - String message = error.getMessage(); - if (!message.isEmpty()) { - writeTag(ErrorTag.MESSAGE); - writeString(message); - } - - String stack = error.getStack(); - if (!stack.isEmpty()) { - writeTag(ErrorTag.STACK); - writeString(stack); - } - - writeTag(ErrorTag.END); - } - - private void writeErrorTypeTag(@NonNull JSError error) { - JSError.ErrorType errorType = error.getType(); - ErrorTag tag; - switch (errorType) { - case EvalError: - tag = ErrorTag.EVAL_ERROR; - break; - case RangeError: - tag = ErrorTag.RANGE_ERROR; - break; - case ReferenceError: - tag = ErrorTag.REFERENCE_ERROR; - break; - case SyntaxError: - tag = ErrorTag.SYNTAX_ERROR; - break; - case TypeError: - tag = ErrorTag.TYPE_ERROR; - break; - case URIError: - tag = ErrorTag.URI_ERROR; - break; - default: - tag = null; - if (errorType != JSError.ErrorType.Error && errorType != JSError.ErrorType.AggregateError) { - throw new UnreachableCodeException(); - } - break; - } - if (tag != null) { - writeTag(tag); - } - } - - private boolean writeHostObject(Object object) { - writeTag(SerializationTag.HOST_OBJECT); - if (delegate == null) { - throw new DataCloneException(object); - } - return delegate.writeHostObject(this, object); - } - - /** - * Marks an {@link JSArrayBuffer} as having its contents transferred out of band. Pass the - * corresponding {@link JSArrayBuffer} in the deserializing context to {@link - * Deserializer#transferArrayBuffer(int, JSArrayBuffer)}. - * - * @param transferId transfer id - * @param arrayBuffer JSArrayBuffer - */ - public void transferArrayBuffer(int transferId, @NonNull JSArrayBuffer arrayBuffer) { - if (arrayBufferTransferMap == null) { - arrayBufferTransferMap = new IdentityHashMap<>(); - } - arrayBufferTransferMap.put(arrayBuffer, transferId); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerHolder.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerHolder.java deleted file mode 100644 index 1a96b9621d7..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerHolder.java +++ /dev/null @@ -1,30 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -@SuppressWarnings("rawtypes") -public class ControllerHolder { - - public final HippyViewController hippyViewController; - public final boolean isLazy; - - public ControllerHolder(HippyViewController hippyViewController, boolean isLazy) { - this.hippyViewController = hippyViewController; - this.isLazy = isLazy; - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java deleted file mode 100644 index 891399ac672..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java +++ /dev/null @@ -1,501 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.annotation.SuppressLint; -import android.content.res.Resources.NotFoundException; -import android.text.TextUtils; -import android.util.SparseArray; -import android.view.View; -import android.view.ViewGroup; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceLifecycleEventListener; -import com.tencent.mtt.hippy.HippyAPIProvider; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.common.HippyTag; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.utils.UIThreadUtils; -import com.tencent.mtt.hippy.views.custom.HippyCustomPropsController; -import com.tencent.mtt.hippy.views.list.HippyRecycler; -import com.tencent.mtt.hippy.views.scroll.HippyHorizontalScrollView; -import com.tencent.mtt.hippy.views.view.HippyViewGroupController; - -import java.lang.reflect.Field; -import java.util.List; - -@SuppressWarnings({"deprecation", "unchecked", "rawtypes", "unused"}) -public class ControllerManager implements HippyInstanceLifecycleEventListener { - - final HippyEngineContext mContext; - final ControllerRegistry mControllerRegistry; - final ControllerUpdateManger mControllerUpdateManger; - final SparseArray mPreCacheView = new SparseArray<>(); - - public ControllerManager(HippyEngineContext context, List hippyPackages) { - mContext = context; - mControllerRegistry = new ControllerRegistry(context); - mControllerUpdateManger = new ControllerUpdateManger(); - mContext.addInstanceLifecycleEventListener(this); - processControllers(hippyPackages); - mControllerUpdateManger.setCustomPropsController(mControllerRegistry.getViewController( - HippyCustomPropsController.CLASS_NAME)); - } - - private void processControllers(List hippyPackages) { - for (HippyAPIProvider hippyPackage : hippyPackages) { - List> components = hippyPackage.getControllers(); - if (components != null) { - for (Class hippyComponent : components) { - HippyController hippyNativeModule = (HippyController) hippyComponent - .getAnnotation(HippyController.class); - assert hippyNativeModule != null; - String name = hippyNativeModule.name(); - String[] names = hippyNativeModule.names(); - boolean lazy = hippyNativeModule.isLazyLoad(); - try { - ControllerHolder holder = new ControllerHolder( - (HippyViewController) hippyComponent.newInstance(), lazy); - mControllerRegistry.addControllerHolder(name, holder); - if (names.length > 0) { - for (String s : names) { - mControllerRegistry.addControllerHolder(s, holder); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - mControllerRegistry.addControllerHolder(NodeProps.ROOT_NODE, - new ControllerHolder(new HippyViewGroupController(), false)); - } - - public void destroy() { - mContext.removeInstanceLifecycleEventListener(this); - UIThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - int count = mControllerRegistry.getRootViewCount(); - if (count > 0) { - for (int i = count - 1; i >= 0; i--) { - deleteRootView(mControllerRegistry.getRootIDAt(i)); - } - } - } - }); - } - - public View findView(int id) { - return mControllerRegistry.getView(id); - } - - public boolean hasView(int id) { - return mControllerRegistry.getView(id) != null; - } - - public void createPreView(HippyRootView rootView, int id, String className, - HippyMap initialProps) { - View view = mControllerRegistry.getView(id); - if (view == null) { - HippyViewController controller = mControllerRegistry.getViewController(className); - view = controller.createView(rootView, id, mContext, className, initialProps); - - mPreCacheView.put(id, view); - } - - } - - public View createView(HippyRootView rootView, int id, String className, HippyMap initialProps) { - View view = mControllerRegistry.getView(id); - if (view == null) { - //first get the preView - view = mPreCacheView.get(id); - - mPreCacheView.remove(id); - - HippyViewController controller = mControllerRegistry.getViewController(className); - if (view == null) { - view = controller.createView(rootView, id, mContext, className, initialProps); - } - - if (view != null) { - mControllerRegistry.addView(view); - mControllerUpdateManger.updateProps(controller, view, initialProps); - controller.onAfterUpdateProps(view); - } - } - // mContext.getGlobalConfigs().getLogAdapter().log(TAG, " createView id:" + id + " className:" + className + " view is null" + (view == null)); - return view; - } - - public StyleNode createStyleNode(String className, boolean isVirtual, int rootId) { - StyleNode tempNode = mControllerRegistry.getViewController(className) - .createNode(isVirtual, rootId); - if (tempNode != null) { - return tempNode; - } - return mControllerRegistry.getViewController(className).createNode(isVirtual); - } - - - public void updateView(int id, String name, HippyMap newProps) { - View view = mControllerRegistry.getView(id); - HippyViewController viewComponent = mControllerRegistry.getViewController(name); - if (view != null && viewComponent != null && newProps != null) { - mControllerUpdateManger.updateProps(viewComponent, view, newProps); - viewComponent.onAfterUpdateProps(view); - } - } - - - public void updateLayout(String name, int id, int x, int y, int width, int height) { - HippyViewController component = mControllerRegistry.getViewController(name); - component.updateLayout(id, x, y, width, height, mControllerRegistry); - } - - @Override - public void onInstanceLoad(int instanceId) { - if (mContext != null && mContext.getInstance(instanceId) != null) { - mControllerRegistry.addRootView(mContext.getInstance(instanceId)); - } - } - - @Override - public void onInstanceResume(int instanceId) { - - } - - @Override - public void onInstancePause(int instanceId) { - - } - - @Override - public void onInstanceDestroy(int instanceId) { - - } - - public void updateExtra(int viewID, String name, Object object) { - HippyViewController component = mControllerRegistry.getViewController(name); - View view = mControllerRegistry.getView(viewID); - component.updateExtra(view, object); - } - - - public void move(int id, int toId, int index) { - View view = mControllerRegistry.getView(id); - - if (view != null) { - if (view.getParent() != null) { - ViewGroup oldParent = (ViewGroup) view.getParent(); - oldParent.removeView(view); - } - ViewGroup newParent = (ViewGroup) mControllerRegistry.getView(toId); - if (newParent != null) { - String parentClassName = HippyTag.getClassName(newParent); - mControllerRegistry.getViewController(parentClassName).addView(newParent, view, index); - } - - // newParent.addView(view, index); - LogUtils.d("ControllerManager", "move id: " + id + " toid: " + toId); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG, "move id: " + id + " toid: " + toId); - } - - - } - - public boolean isControllerLazy(String className) { - return mControllerRegistry.getControllerHolder(className).isLazy; - } - - public void replaceID(int oldId, int newId) { - View view = mControllerRegistry.getView(oldId); - mControllerRegistry.removeView(oldId); - - if (view == null) { - // Toast.makeText(mControllerRegistry.getRootView(mControllerRegistry.getRootIDAt(0)).getContext(),"replaceID时候出异常了",Toast.LENGTH_LONG).show(); - // Debug.waitForDebugger(); - LogUtils.d("HippyListView", "error replaceID null oldId " + oldId); - } else { - if (view instanceof HippyRecycler) { - ((HippyRecycler) view).clear(); - } - - view.setId(newId); - - if (view instanceof HippyHorizontalScrollView) { - ((HippyHorizontalScrollView)view).setContentOffset4Reuse(); - } - - mControllerRegistry.addView(view); - } - } - - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, boolean lazy) { - return mControllerRegistry.getViewController(className) - .createRenderNode(id, props, className, hippyRootView, this, lazy); - } - - public void dispatchUIFunction(int id, String className, String functionName, HippyArray var, - Promise promise) { - HippyViewController hippyViewController = mControllerRegistry.getViewController(className); - View view = mControllerRegistry.getView(id); - if (!promise.isCallback()) { - hippyViewController.dispatchFunction(view, functionName, var); - } else { - hippyViewController.dispatchFunction(view, functionName, var, promise); - } - - } - - public void onBatchComplete(String className, int id) { - HippyViewController hippyViewController = mControllerRegistry.getViewController(className); - View view = mControllerRegistry.getView(id); - if (view != null) { - hippyViewController.onBatchComplete(view); - } - } - - public void deleteChildRecursive(ViewGroup viewParent, View child, int childIndex) { - if (viewParent == null || child == null) { - return; - } - HippyViewController hippyChildViewController = null; - String childTagString = HippyTag.getClassName(child); - if (!TextUtils.isEmpty(childTagString)) { - hippyChildViewController = mControllerRegistry.getViewController(childTagString); - if (hippyChildViewController != null) { - hippyChildViewController.onViewDestroy(child); - } - } - - if (child instanceof ViewGroup) { - ViewGroup childViewGroup = (ViewGroup) child; - if (hippyChildViewController != null) { - for (int i = hippyChildViewController.getChildCount(childViewGroup) - 1; i >= 0; i--) { - deleteChildRecursive(childViewGroup, - hippyChildViewController.getChildAt(childViewGroup, i), -1); - } - } else { - for (int i = childViewGroup.getChildCount() - 1; i >= 0; i--) { - deleteChildRecursive(childViewGroup, childViewGroup.getChildAt(i), -1); - } - } - } - - if (mControllerRegistry.getView(child.getId()) != child - && mControllerRegistry.getView(viewParent.getId()) != viewParent) { - return; - } - - String parentTagString = HippyTag.getClassName(viewParent); - if (parentTagString != null) { - //remove component Like listView there is a RecycleItemView is not js UI - if (mControllerRegistry.getControllerHolder(parentTagString) != null) { - HippyViewController hippyViewController = mControllerRegistry.getViewController( - parentTagString); - hippyViewController.deleteChild(viewParent, child, childIndex); - // LogUtils.d("HippyListView", "delete " + child.getId()); - } - } else { - viewParent.removeView(child); - } - - // mContext.getGlobalConfigs().getLogAdapter().log(TAG, "deleteChildRecursive id:" + child.getId() + " className:" + childTagString); - mControllerRegistry.removeView(child.getId()); - } - - public void deleteChild(int pId, int childId) { - deleteChild(pId, childId, -1); - } - - public void deleteChild(int pId, int childId, int childIndex) { - View parentView = mControllerRegistry.getView(pId); - View childView = mControllerRegistry.getView(childId); - if (parentView instanceof ViewGroup && childView != null) { - deleteChildRecursive((ViewGroup) parentView, childView, childIndex); - } -// else -// { -// mContext.getGlobalConfigs().getLogAdapter().log(TAG, "deleteChild error pId: " + pId + " childId: " + childId +(parentView instanceof ViewGroup)+ (childView != null)); -// } - } - - private static int statusBarHeight = -1; - - public static int getStatusBarHeightFromSystem() { - if (statusBarHeight > 0) { - return statusBarHeight; - } - - Class c; - Object obj; - Field field; - int x; - try { - c = Class.forName("com.android.internal.R$dimen"); - obj = c.newInstance(); - field = c.getField("status_bar_height"); - //noinspection ConstantConditions - x = Integer.parseInt(field.get(obj).toString()); - statusBarHeight = ContextHolder.getAppContext().getResources().getDimensionPixelSize(x); - } catch (Exception e1) { - statusBarHeight = -1; - e1.printStackTrace(); - } - - if (statusBarHeight < 1) { - try { - int statebarH_id = ContextHolder.getAppContext().getResources() - .getIdentifier("statebar_height", "dimen", - ContextHolder.getAppContext().getPackageName()); - statusBarHeight = Math - .round(ContextHolder.getAppContext().getResources().getDimension(statebarH_id)); - } catch (NotFoundException e) { - LogUtils.d("ControllerManager", "getStatusBarHeightFromSystem: " + e.getMessage()); - } - } - return statusBarHeight; - } - - @SuppressLint("Range") - public void measureInWindow(int id, Promise promise) { - View v = mControllerRegistry.getView(id); - if (v == null) { - promise.reject("this view is null"); - } else { - int[] outputBuffer = new int[4]; - int statusBarHeight; - try { - v.getLocationOnScreen(outputBuffer); - - // We need to remove the status bar from the height. getLocationOnScreen will include the - // status bar. - statusBarHeight = getStatusBarHeightFromSystem(); - if (statusBarHeight > 0) { - outputBuffer[1] -= statusBarHeight; - } - - // outputBuffer[0,1] already contain what we want - outputBuffer[2] = v.getWidth(); - outputBuffer[3] = v.getHeight(); - } catch (Throwable e) { - promise.reject("exception" + e.getMessage()); - e.printStackTrace(); - return; - } - - float x = PixelUtil.px2dp(outputBuffer[0]); - float y = PixelUtil.px2dp(outputBuffer[1]); - float width = PixelUtil.px2dp(outputBuffer[2]); - float height = PixelUtil.px2dp(outputBuffer[3]); - float fStatusbarHeight = PixelUtil.px2dp(statusBarHeight); - - HippyMap hippyMap = new HippyMap(); - hippyMap.pushDouble("x", x); - hippyMap.pushDouble("y", y); - hippyMap.pushDouble("width", width); - hippyMap.pushDouble("height", height); - hippyMap.pushDouble("statusBarHeight", fStatusbarHeight); - promise.resolve(hippyMap); - } - - } - - public void onManageChildComplete(String className, int id) { - HippyViewController hippyViewController = mControllerRegistry.getViewController(className); - View view = mControllerRegistry.getView(id); - if (view != null) { - hippyViewController.onManageChildComplete(view); - } - } - - public void addChild(int pid, int id, int index) { - View childView = mControllerRegistry.getView(id); - View parentView = mControllerRegistry.getView(pid); - - if (childView != null && parentView instanceof ViewGroup) { - if (childView.getParent() == null) { - LogUtils.d("ControllerManager", "addChild id: " + id + " pid: " + pid); - // mContext.getGlobalConfigs().getLogAdapter().log( TAG,"addChild id: " + id + " pid: " + pid); - // childView.getParent()==null this is the move action do first so the child has a parent we do nothing temp - - String parentClassName = HippyTag.getClassName(parentView); - mControllerRegistry.getViewController(parentClassName) - .addView((ViewGroup) parentView, childView, index); - } -// else -// { -// mContext.getGlobalConfigs().getLogAdapter().log( TAG,"addChild error childView has parent id: " + id + " pid: " + pid); -// } - } else { - RenderNode parentNode = mContext.getRenderManager().getRenderNode(pid); - String renderNodeClass = "null"; - if (parentNode != null) { - renderNodeClass = parentNode.getClassName(); - } - - // 上报重要错误 - // 这个错误原因是:前端用了某个UI控件来做父亲,而这个UI控件实际上是不应该做父亲的(不是ViewGroup),务必要把这个parentView的className打出来 - String parentTag = null, parentClass = null, childTag = null, childClass = null; - if (parentView != null) { - Object temp = HippyTag.getClassName(parentView); - if (temp != null) { - parentTag = temp.toString(); - } - parentClass = parentView.getClass().getName(); - } - if (childView != null) { - Object temp = HippyTag.getClassName(childView); - if (temp != null) { - childTag = temp.toString(); - } - childClass = childView.getClass().getName(); - } - Exception exception = new RuntimeException("child null or parent not ViewGroup pid " + pid - + " parentTag " + parentTag - + " parentClass " + parentClass - + " renderNodeClass " + renderNodeClass + " id " + id - + " childTag " + childTag - + " childClass " + childClass); - mContext.getGlobalConfigs().getExceptionHandler().handleNativeException(exception, true); - } - } - - public void deleteRootView(int mId) { - - View view = mControllerRegistry.getRootView(mId); - if (view != null) { - HippyRootView hippyRootView = (HippyRootView) view; - int count = hippyRootView.getChildCount(); - - for (int i = count - 1; i >= 0; i--) { - deleteChild(mId, hippyRootView.getChildAt(i).getId()); - } - } - mControllerRegistry.removeRootView(mId); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java deleted file mode 100644 index 27006a77407..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java +++ /dev/null @@ -1,103 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.util.SparseArray; -import android.view.View; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.util.HashMap; -import java.util.Map; - -public class ControllerRegistry { - - private final SparseArray mViews; // store all views here - private final SparseArray mRoots; // store all root views here - private final Map mControllers; // store all viewManager instance here - final HippyEngineContext engineContext; - - public ControllerRegistry(HippyEngineContext context) { - mViews = new SparseArray<>(); - mRoots = new SparseArray<>(); - mControllers = new HashMap<>(); - engineContext = context; - } - - public void addControllerHolder(String name, ControllerHolder controllerHolder) { - mControllers.put(name, controllerHolder); - } - - public ControllerHolder getControllerHolder(String className) { - return mControllers.get(className); - } - - @SuppressWarnings({"rawtypes"}) - public HippyViewController getViewController(String className) { - try { - return mControllers.get(className).hippyViewController; - } catch (Throwable e) { - if (engineContext != null) { - String message = "getViewController: error className=" + className; - Exception exception = new RuntimeException(message); - engineContext.getGlobalConfigs().getExceptionHandler() - .handleNativeException(exception, true); - } - } - return null; - } - - public View getView(int id) { - View view = mViews.get(id); - if (view == null) { - view = mRoots.get(id); - } - return view; - } - - public int getRootViewCount() { - return mRoots.size(); - } - - public int getRootIDAt(int index) { - return mRoots.keyAt(index); - } - - public View getRootView(int id) { - return mRoots.get(id); - } - - - public void addView(View view) { - mViews.put(view.getId(), view); - } - - public void addRootView(HippyRootView rootView) { - mRoots.put(rootView.getId(), rootView); - } - - - public void removeView(int id) { - mViews.remove(id); - } - - public void removeRootView(int id) { - mRoots.remove(id); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java deleted file mode 100644 index b1ef8417dc2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java +++ /dev/null @@ -1,197 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.view.View; - -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.utils.ArgumentUtils; -import com.tencent.mtt.hippy.utils.LogUtils; - -import com.tencent.mtt.hippy.views.custom.HippyCustomPropsController; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -@SuppressWarnings({"deprecation", "unused", "rawtypes"}) -public class ControllerUpdateManger { - - static final Map> CLASS_PROPS_METHOD = new HashMap<>(); - - public static class PropsMethodHolder { - - Method mMethod; - String mDefaultType; - String mDefaultString; - double mDefaultNumber; - boolean mDefaultBoolean; - Type[] mTypes; - } - - private T customPropsController; - - public void setCustomPropsController(T controller) { - assert (controller != null); - customPropsController = controller; - } - - private void findPropsMethod(Class cls, Map hashMap) { - if (cls != HippyViewController.class) { - // find parent methods first - findPropsMethod(cls.getSuperclass(), hashMap); - } - - Map methodHolder = CLASS_PROPS_METHOD.get(cls); - if (methodHolder == null) { - - Method[] methods = cls.getMethods(); - for (Method method : methods) { - HippyControllerProps controllerProps = method.getAnnotation(HippyControllerProps.class); - if (controllerProps != null) { - String style = controllerProps.name(); - PropsMethodHolder propsMethodHolder = new PropsMethodHolder(); - propsMethodHolder.mDefaultNumber = controllerProps.defaultNumber(); - propsMethodHolder.mDefaultType = controllerProps.defaultType(); - propsMethodHolder.mDefaultString = controllerProps.defaultString(); - propsMethodHolder.mDefaultBoolean = controllerProps.defaultBoolean(); - propsMethodHolder.mMethod = method; - hashMap.put(style, propsMethodHolder); - } - } - // put to CLASS_PROPS_METHOD - CLASS_PROPS_METHOD.put(cls, new HashMap<>(hashMap)); - } else { - hashMap.putAll(methodHolder); - } - - } - - private Map findPropsMethod(Class cla) { - Map hashMap = new HashMap<>(); - findPropsMethod(cla, hashMap); - return hashMap; - } - - private void invokePropMethod(T t, G g, HippyMap hippyMap, String prop, - PropsMethodHolder propsMethodHolder) { - try { - if (hippyMap.get(prop) == null) { - switch (propsMethodHolder.mDefaultType) { - case HippyControllerProps.BOOLEAN: - propsMethodHolder.mMethod.invoke(t, g, propsMethodHolder.mDefaultBoolean); - break; - case HippyControllerProps.NUMBER: - if (propsMethodHolder.mTypes == null) { - propsMethodHolder.mTypes = propsMethodHolder.mMethod.getGenericParameterTypes(); - } - propsMethodHolder.mMethod.invoke(t, g, ArgumentUtils - .parseArgument(propsMethodHolder.mTypes[1], propsMethodHolder.mDefaultNumber)); - break; - case HippyControllerProps.STRING: - propsMethodHolder.mMethod.invoke(t, g, propsMethodHolder.mDefaultString); - break; - default: - propsMethodHolder.mMethod.invoke(t, g, null); - break; - } - } else { - Object object = hippyMap.get(prop); - if (object instanceof Number) { - if (propsMethodHolder.mTypes == null) { - propsMethodHolder.mTypes = propsMethodHolder.mMethod.getGenericParameterTypes(); - } - object = ArgumentUtils.parseArgument(propsMethodHolder.mTypes[1], hippyMap, prop); - } - - propsMethodHolder.mMethod.invoke(t, g, object); - } - } catch (Throwable e) { - LogUtils.e("ControllerUpdateManager", e.getMessage(), e); - e.printStackTrace(); - } - } - - private void handleCustomProps(T t, G g, HippyMap hippyMap, String prop) { - assert (g instanceof View); - assert (customPropsController instanceof HippyCustomPropsController); - - boolean hasCustomMethodHolder = false; - - //noinspection ConstantConditions - if (!(g instanceof View)) { - return; - } - - Object customProps = hippyMap.get(prop); - - if (customPropsController != null - && customPropsController instanceof HippyCustomPropsController) { - Class cla = customPropsController.getClass(); - Map methodHolder = CLASS_PROPS_METHOD.get(cla); - if (methodHolder == null) { - methodHolder = findPropsMethod(cla); - } - PropsMethodHolder propsMethodHolder = methodHolder.get(prop); - try { - if (propsMethodHolder != null) { - invokePropMethod(customPropsController, g, hippyMap, prop, propsMethodHolder); - hasCustomMethodHolder = true; - } - } catch (Throwable e) { - LogUtils.e("ControllerUpdateManager", "customProps " + e.getMessage(), e); - e.printStackTrace(); - } - } - - if (!hasCustomMethodHolder && t instanceof HippyViewController) { - //noinspection unchecked - ((HippyViewController) t).setCustomProp((View) g, prop, customProps); - } - } - - public void updateProps(T t, G g, HippyMap hippyMap) { - assert (hippyMap != null); - - //noinspection ConstantConditions - if (hippyMap == null) { - return; - } - Class cla = t.getClass(); - - Map methodHolder = CLASS_PROPS_METHOD.get(cla); - if (methodHolder == null) { - methodHolder = findPropsMethod(cla); - } - - Set props = hippyMap.keySet(); - for (String prop : props) { - PropsMethodHolder propsMethodHolder = methodHolder.get(prop); - if (propsMethodHolder != null) { - invokePropMethod(t, g, hippyMap, prop, propsMethodHolder); - } else { - if (prop.equals(NodeProps.STYLE) && hippyMap.get(prop) instanceof HippyMap) { - updateProps(t, g, (HippyMap) hippyMap.get(prop)); - } else { - handleCustomProps(t, g, hippyMap, prop); - } - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/DiffUtils.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/DiffUtils.java deleted file mode 100644 index f70ef79651a..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/DiffUtils.java +++ /dev/null @@ -1,519 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.text.TextUtils; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; - -import com.tencent.mtt.hippy.utils.LogUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static com.tencent.mtt.hippy.views.custom.HippyCustomPropsController.DT_EBLID; - - -@SuppressWarnings("deprecation") -public class DiffUtils { - - public static ArrayList diff(RenderNode from, RenderNode toNoe) { - ArrayList patchTypes = new ArrayList<>(); - if (from.getId() == toNoe.getId()) { - //when first create view form eq toNode - return patchTypes; - } - - try { - diffFromNode(from, toNoe, patchTypes); - diffToNode(from, toNoe, patchTypes); - } catch (Throwable e) { - LogUtils.d("DiffUtils", "diff: " + e.getMessage()); - } - - return patchTypes; - } - - private static void diffToNode(RenderNode from, RenderNode toNoe, - ArrayList patchTypes) { - if (from == null || toNoe == null) { - return; - } - - for (int i = 0; i < toNoe.getChildCount(); i++) { - if (i >= from.getChildCount()) { - RenderNode toNoeChild = toNoe.getChildAt(i); - patchTypes.add(new PatchType(Patch.TYPE_CREATE, new CreatePatch(toNoeChild))); - if (TextUtils.equals(toNoeChild.getClassName(), NodeProps.TEXT_CLASS_NAME)) { - patchTypes.add(new PatchType(Patch.TYPE_EXTRA, - new ExtraPatch(toNoeChild.mId, toNoeChild.mTextExtra, toNoeChild.getClassName()))); - } - - patchTypes.add(new PatchType(Patch.TYPE_LAYOUT, - new LayoutPatch(toNoeChild.mX, toNoeChild.mY, toNoeChild.mHeight, toNoeChild - .getWidth(), toNoeChild.mId, toNoeChild.mParent.mId, toNoeChild.mClassName))); - } else { - diffToNode(from.getChildAt(i), toNoe.getChildAt(i), patchTypes); - } - - } - } - - - private static void diffFromNode(RenderNode from, RenderNode toNode, - ArrayList patchTypes) { - if (TextUtils.equals(from.getClassName(), toNode.getClassName())) { - patchTypes.add( - new PatchType(Patch.TYPE_REPLACE_ID, new ReplacePatch(from.getId(), toNode.getId()))); - - HippyMap updateProps = diffProps(from.getProps(), toNode.getProps(), 0); - if (updateProps != null && updateProps.size() >= 1) { - patchTypes.add(new PatchType(Patch.TYPE_PROPS, - new PropsPatch(updateProps, toNode.getId(), toNode.getClassName()))); - } - - LayoutPatch lp = diffLayout(from, toNode); - if (lp != null) { - patchTypes.add(new PatchType(Patch.TYPE_LAYOUT, lp)); - } - - ExtraPatch extraPatch = diffExtra(from, toNode); - if (extraPatch != null) { - patchTypes.add(new PatchType(Patch.TYPE_EXTRA, extraPatch)); - } - } - - for (int i = 0; i < from.getChildCount(); i++) { - RenderNode fromChild = from.getChildAt(i); - RenderNode toChild = null; - if (i < toNode.getChildCount()) { - toChild = toNode.getChildAt(i); - } - if (toChild != null && TextUtils.equals(fromChild.getClassName(), toChild.getClassName())) { - diffFromNode(fromChild, toChild, patchTypes); - } else { - if (toChild != null) { - patchTypes.add(new PatchType(Patch.TYPE_CREATE, new CreatePatch(toChild))); - if (TextUtils.equals(toChild.getClassName(), NodeProps.TEXT_CLASS_NAME)) { - patchTypes.add(new PatchType(Patch.TYPE_EXTRA, - new ExtraPatch(toChild.mId, toChild.mTextExtra, toChild.getClassName()))); - } - - patchTypes.add(new PatchType(Patch.TYPE_LAYOUT, - new LayoutPatch(toChild.mX, toChild.mY, toChild.mHeight, toChild.getWidth(), - toChild.mId, toChild.mParent.mId, toChild.mClassName))); - } - - patchTypes.add(new PatchType(Patch.TYPE_DELETE_CHILDREN, - new DeletePatch(fromChild.getId(), fromChild.getParent().getId(), fromChild - .getParent().getClassName()))); - } - } - - - } - - private static ExtraPatch diffExtra(RenderNode from, RenderNode toNode) { - if (from.mTextExtra != null && toNode.mTextExtra != null && !TextUtils - .equals(from.mTextExtra.toString(), toNode.mTextExtra.toString())) { - return new ExtraPatch(toNode.getId(), toNode.mTextExtra, toNode.getClassName()); - } - - return null; - } - - private static LayoutPatch diffLayout(RenderNode fromNode, RenderNode toNode) { - if (fromNode == null || fromNode.getX() != toNode.getX() || fromNode.getY() != toNode.getY() - || fromNode.getWidth() != toNode.getWidth() - || fromNode.getHeight() != toNode.getHeight()) { - return new LayoutPatch(toNode.getX(), toNode.getY(), toNode.getHeight(), toNode.getWidth(), - toNode.getId(), toNode.mParent.getId(), - toNode.getClassName()); - } - return null; - } - - - public static HippyMap diffProps(HippyMap from, HippyMap to, int diffLevel) { - if (from == null) { - return to; - } - HippyMap updateProps = new HippyMap(); - Set fromKeys = from.keySet(); - for (String fromKey : fromKeys) { - if (fromKey.equals(DT_EBLID)) { - continue; - } - - Object fromValue = from.get(fromKey); - Object toValue = to.get(fromKey); - if (fromValue instanceof Boolean) { - boolean fromBool = (boolean) fromValue; - if (toValue != null && fromBool == (boolean) toValue) { - LogUtils.d("DiffUtils", "don't do anything for bool value"); - } else { - updateProps.pushObject(fromKey, toValue); - } - } else if (fromValue instanceof Number) { - boolean isSame = false; - double fromDoubleValue = ((Number) fromValue).doubleValue(); - if (toValue instanceof Number) { - double toDoubleValue = ((Number) toValue).doubleValue(); - isSame = (fromDoubleValue == toDoubleValue); - } - // if toValue is null, push null to trigger default value - if (!isSame) { - updateProps.pushObject(fromKey, toValue); - } - } else if (fromValue instanceof String) { - if (toValue != null && TextUtils.equals(fromValue.toString(), toValue.toString())) { - LogUtils.d("DiffUtils", "don't do anything for same value"); - } else { - updateProps.pushObject(fromKey, toValue); - } - } else if (fromValue instanceof HippyArray) { - if (toValue instanceof HippyArray) { - HippyArray diffResult = diffArray((HippyArray) fromValue, (HippyArray) toValue, - diffLevel + 1); - //tintColor复用的时候必须要强制更新 - if (fromKey.equals("tintColors") || fromKey.equals("tintColor")) { - diffResult = (HippyArray) toValue; - } - //这里diffResult == null标识属性没有更新 - if (diffResult != null /* && diffResult.size() > 0*/) { - updateProps.pushObject(fromKey, toValue); - } - } else { // toValue(Array)没有的时候,要给个默认值 - updateProps.pushObject(fromKey, null); - } - } else if (fromValue instanceof HippyMap) { - if (toValue instanceof HippyMap) { - - HippyMap diffResult = diffProps((HippyMap) fromValue, (HippyMap) toValue, diffLevel + 1); - if (diffResult != null && diffResult.size() > 0) { - if (diffLevel == 0 && fromKey.equals(NodeProps.STYLE)) { - updateProps.pushObject(fromKey, diffResult); - } else { - updateProps.pushObject(fromKey, toValue); - } - } - } else if (diffLevel == 0 && fromKey.equals(NodeProps.STYLE)) { - //style is null - HippyMap diffResult = diffProps((HippyMap) fromValue, new HippyMap(), diffLevel + 1); - updateProps.pushMap(fromKey, diffResult); - } else { // toValue没有的时候,要给个默认值 - updateProps.pushObject(fromKey, null); - } - } - } - - // new has prop, but old doesn't - // so we push these props directly - - Set tos = to.keySet(); - - for (String toKey : tos) { - - if (from.get(toKey) != null || toKey.equals(DT_EBLID)) { - continue; - } - Object toValue = to.get(toKey); - updateProps.pushObject(toKey, toValue); - } - - return updateProps; - } - - - private static HippyArray diffArray(HippyArray fromValue, HippyArray toValue, int diffLevel) { - - if (fromValue.size() != toValue.size()) { - return toValue; - } - int size = fromValue.size(); - - for (int i = 0; i < size; i++) { - Object from = fromValue.getObject(i); - Object to = toValue.getObject(i); - // 这里默认from & to的类型相同 - if (from instanceof Boolean) { - if ((boolean) from != (boolean) to) { - return toValue; - } - } else if (from instanceof Number) { - - boolean isSame = false; - - double fromDoubleValue = ((Number) from).doubleValue(); - if (to instanceof Number) { - double toDoubleValue = ((Number) to).doubleValue(); - isSame = (fromDoubleValue == toDoubleValue); - } - // if to is null, push null to trigger default value - - if (!isSame) { - return toValue; - } - - } else if (from instanceof String) { - if (!TextUtils.equals((String) from, (String) to)) { - return toValue; - } - } else if (from instanceof HippyArray) { - if (to instanceof HippyArray) { - HippyArray diffResult = diffArray((HippyArray) from, (HippyArray) to, diffLevel); - if (diffResult != null) { - return toValue; - } - } - } else if (from instanceof HippyMap) { - if (to instanceof HippyMap) { - HippyMap diffResult = diffProps((HippyMap) from, (HippyMap) to, diffLevel); - if (diffResult != null) { - return toValue; - } - } - } - } - return null; - } - - - public static class CreatePatch extends Patch { - - @Override - public String toString() { - // return "CreatePatch"; - return "CreatePatch id :" + renderNode.mId; - } - - public CreatePatch(RenderNode renderNode) { - this.renderNode = renderNode; - } - - final RenderNode renderNode; - - } - - public static class ReplacePatch extends Patch { - - @Override - public String toString() { - return "ReplacePatch oldId:" + oldId + " newId:" + newId; - } - - public ReplacePatch(int oldId, int newId) { - this.oldId = oldId; - this.newId = newId; - } - - final int oldId; - final int newId; - } - - public static class PropsPatch extends Patch { - - final HippyMap mPropsToUpdate; - final int mId; - final String mClassName; - - public PropsPatch(HippyMap array, int tag, String className) { - this.mPropsToUpdate = array; - this.mId = tag; - this.mClassName = className; - } - - @Override - public String toString() { - return "PropsPatch"; - } - } - - public static class ExtraPatch extends Patch { - - public ExtraPatch(int mID, Object mText, String className) { - this.mID = mID; - this.mText = mText; - this.mClassName = className; - } - - @Override - public String toString() { - return "ExtraPatch"; - } - - final String mClassName; - final int mID; - final Object mText; - } - - @SuppressWarnings("unused") - public static class DeletePatch extends Patch { - - final int mId; - final int mPid; - final String mPClassName; - - @Override - public String toString() { - // return "DeletePatch"; - return "DeletePatch Id " + mId; - - } - - public DeletePatch(int id, int pId, String className) { - this.mId = id; - this.mPid = pId; - this.mPClassName = className; - } - } - - @SuppressWarnings("unused") - public static class LayoutPatch extends Patch { - - final int mX; - final int mY; - final int mHeight; - final int mWidth; - final int mId; - final int mParentId; - final String mClassName; - - @Override - public String toString() { - return "LayoutPatch"; - // return "mid" + mId + " x " + mX + " y " + mY + " width " + mWidth + " height " + mHeight; - } - - public LayoutPatch(int mX, int mY, int mHeight, int mWidth, int mID, int mParentId, - String mClassName) { - - this.mX = mX; - this.mY = mY; - this.mHeight = mHeight; - this.mWidth = mWidth; - this.mId = mID; - this.mParentId = mParentId; - this.mClassName = mClassName; - } - } - - public static class PatchType { - - public final int mType; - public final Patch mPatch; - - public PatchType(int type, Patch p) { - mPatch = p; - mType = type; - } - } - - public static class Patch { - - public static final int TYPE_DELETE_CHILDREN = 0; - public static final int TYPE_PROPS = 1; - public static final int TYPE_LAYOUT = 2; - public static final int TYPE_EXTRA = 3; - public static final int TYPE_REPLACE_ID = 4; - public static final int TYPE_CREATE = 5; - } - - public static void deleteViews(ControllerManager controllerManager, List patchTypes) { - - for (int i = patchTypes.size() - 1; i >= 0; i--) { - PatchType patchType = patchTypes.get(i); - if (patchType.mType == Patch.TYPE_DELETE_CHILDREN) { - DeletePatch deletePatch = (DeletePatch) patchType.mPatch; - controllerManager.deleteChild(deletePatch.mPid, deletePatch.mId); - patchTypes.remove(patchType); - } - } - } - - public static void replaceIds(ControllerManager controllerManager, List patchTypes) { - - for (int i = patchTypes.size() - 1; i >= 0; i--) { - PatchType patchType = patchTypes.get(i); - if (patchType.mType == Patch.TYPE_REPLACE_ID) { - ReplacePatch replacePatch = (ReplacePatch) patchType.mPatch; - controllerManager.replaceID(replacePatch.oldId, replacePatch.newId); - patchTypes.remove(patchType); - } - - } - - } - - public static void createView(List patchTypes) { - for (int i = 0; i < patchTypes.size(); i++) { - PatchType patchType = patchTypes.get(i); - if (patchType.mType == Patch.TYPE_CREATE) { - CreatePatch createPatch = (CreatePatch) patchType.mPatch; - createPatch.renderNode.createViewRecursive(); - if (createPatch.renderNode.mParent != null) { - createPatch.renderNode.mParent.update(); - } - createPatch.renderNode.updateViewRecursive(); - } - } - } - - public static void doPatch(ControllerManager controllerManager, List patches) { - HippyEngineContext hippyContext = controllerManager.mContext; - - for (PatchType pt : patches) { - if (pt.mType == Patch.TYPE_PROPS) { - PropsPatch propsPatch = (PropsPatch) pt.mPatch; - HippyMap propsToUpdate = propsPatch.mPropsToUpdate; - RenderNode node = hippyContext.getRenderManager().getRenderNode(propsPatch.mId); - if (node != null) { - HippyMap props = node.getProps(); - if (node.mHasSetDteblId) { - if (propsToUpdate.containsKey(DT_EBLID)) { - propsToUpdate.remove(DT_EBLID); - } - } else if (props != null && props.containsKey(DT_EBLID)) { - propsToUpdate.pushString(DT_EBLID, props.getString(DT_EBLID)); - } - } - - controllerManager.updateView(propsPatch.mId, propsPatch.mClassName, propsToUpdate); - } else if (pt.mType == Patch.TYPE_LAYOUT) { - LayoutPatch layoutPatch = (LayoutPatch) pt.mPatch; - - controllerManager - .updateLayout(layoutPatch.mClassName, layoutPatch.mId, layoutPatch.mX, layoutPatch.mY, - layoutPatch.mWidth, - layoutPatch.mHeight); - } else if (pt.mType == Patch.TYPE_EXTRA) { - ExtraPatch extraPatch = (ExtraPatch) pt.mPatch; - - controllerManager.updateExtra(extraPatch.mID, extraPatch.mClassName, extraPatch.mText); - } - - // else if (pt.mType == Patch.TYPE_CREATE) - // { - // CreatePatch createPatch = (CreatePatch) pt.mPatch; - // controllerManager.createView(createPatch.renderNode.mRootView, createPatch.renderNode.mId, createPatch.renderNode.mPid, - // createPatch.renderNode.mIndex, createPatch.renderNode.mClassName, createPatch.renderNode.mPropsToUpdate); - // } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyCustomViewCreator.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyCustomViewCreator.java deleted file mode 100644 index 199dff9907b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyCustomViewCreator.java +++ /dev/null @@ -1,29 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.content.Context; -import android.view.View; - -import com.tencent.mtt.hippy.common.HippyMap; - -public interface HippyCustomViewCreator { - - String HIPPY_CUSTOM_VIEW_CREATOR = "CustomViewCreator"; - - @SuppressWarnings("deprecation") - View createCustomView(String className, Context context, HippyMap initialProps); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyGroupController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyGroupController.java deleted file mode 100644 index 78dd89de6c4..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyGroupController.java +++ /dev/null @@ -1,46 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.view.ViewGroup; - -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.dom.node.NodeProps; - -@SuppressWarnings({"unused"}) -public abstract class HippyGroupController extends - HippyViewController { - - /** - * touch/click intercept - **/ - @HippyControllerProps(name = NodeProps.ON_INTERCEPT_TOUCH_EVENT, defaultType = HippyControllerProps.BOOLEAN) - public void setInterceptTouch(T viewGroup, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(viewGroup, NodeProps.ON_INTERCEPT_TOUCH_EVENT, flag); - } - } - - /** - * touch/click intercept - **/ - @HippyControllerProps(name = NodeProps.ON_INTERCEPT_PULL_UP_EVENT, defaultType = HippyControllerProps.BOOLEAN) - public void setInterceptPullUp(T viewGroup, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(viewGroup, NodeProps.ON_INTERCEPT_PULL_UP_EVENT, flag); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyViewController.java deleted file mode 100644 index ec64685b5b5..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyViewController.java +++ /dev/null @@ -1,720 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.content.Context; -import android.graphics.Color; -import android.os.Looper; -import android.os.MessageQueue; -import android.text.TextUtils; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.common.HippyTag; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.common.CommonBorder; -import com.tencent.mtt.hippy.views.view.HippyViewGroupController; -import com.tencent.mtt.supportui.views.IGradient; -import com.tencent.mtt.supportui.views.IShadow; - -import java.io.File; -import java.util.ArrayList; -import java.util.Map; - -@SuppressWarnings({"deprecation", "unused"}) -public abstract class HippyViewController implements - View.OnFocusChangeListener { - - private static final String TAG = "HippyViewController"; - - private static final MatrixUtil.MatrixDecompositionContext sMatrixDecompositionContext = new MatrixUtil.MatrixDecompositionContext(); - private static final double[] sTransformDecompositionArray = new double[16]; - private boolean bUserChageFocus = false; - - @SuppressWarnings("deprecation") - public View createView(HippyRootView rootView, int id, HippyEngineContext hippyEngineContext, - String className, - HippyMap initialProps) { - View view = null; - - if (rootView != null) { - Context rootViewContext = rootView.getContext(); - if (rootViewContext instanceof HippyInstanceContext) { - @SuppressWarnings("rawtypes") Map nativeParam = ((HippyInstanceContext) rootViewContext) - .getNativeParams(); - if (nativeParam != null) { - Object object = nativeParam.get(HippyCustomViewCreator.HIPPY_CUSTOM_VIEW_CREATOR); - if (object instanceof HippyCustomViewCreator) { - view = ((HippyCustomViewCreator) object) - .createCustomView(className, rootView.getContext(), initialProps); - } - } - } - if (view == null) { - view = createViewImpl(rootView.getContext(), initialProps); - if (view == null) { - view = createViewImpl(rootView.getContext()); - } - } - - LogUtils.d(TAG, "createView id " + id); - view.setId(id); - //view.setTag(className); - HippyMap tagObj = HippyTag.createTagMap(className, initialProps); - view.setTag(tagObj); - } - return view; - } - - public void onAfterUpdateProps(T v) { - - } - - // public void updateProps(View view, HippyMap props) - // { - // if (props == null) - // return; - // try - // { - // HippyMap styleProps = props.get(NodeProps.STYLE) != null ? (HippyMap) props.get(NodeProps.STYLE) : null; - // Method[] targetMethods = getClass().getMethods(); - // - // for (Method targetMethod : targetMethods) - // { - // HippyControllerProps hippyProps = targetMethod.getAnnotation(HippyControllerProps.class); - // if (hippyProps != null) - // { - // String propsName = hippyProps.name(); - // if (props.get(propsName) != null) // try normal props first - // { - // targetMethod.invoke(this, view, props.get(propsName)); - // } - // else if (styleProps != null && styleProps.get(propsName) != null) // then try styleprops - // { - // targetMethod.invoke(this, view, styleProps.get(propsName)); - // } - // } - // } - // } - // catch (IllegalAccessException e) - // { - // e.printStackTrace(); - // } - // catch (InvocationTargetException e) - // { - // e.printStackTrace(); - // } - // catch (IllegalArgumentException e) - // { - // e.printStackTrace(); - // } - // } - - - protected void updateExtra(View view, Object object) { - - } - - @SuppressWarnings("SameReturnValue") - protected StyleNode createNode(boolean isVirtual, int rootId) { - return null; - } - - protected StyleNode createNode(boolean isVirtual) { - return new StyleNode(); - } - - public void updateLayout(int id, int x, int y, int width, int height, - ControllerRegistry componentHolder) { - View view = componentHolder.getView(id); - if (view != null) { - view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); - if (!shouldInterceptLayout(view, x, y, width, height)) { - view.layout(x, y, x + width, y + height); - } - } - } - - protected boolean shouldInterceptLayout(View view, int x, int y, int width, int height) { - return false; - } - - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - protected boolean handleGestureBySelf() { - return false; - } - - @Deprecated - protected abstract View createViewImpl(Context context); - - protected View createViewImpl(Context context, HippyMap iniProps) { - return null; - } - - - /** - * transform - **/ - @HippyControllerProps(name = NodeProps.TRANSFORM, defaultType = HippyControllerProps.ARRAY) - public void setTransform(T view, HippyArray transformArray) { - if (transformArray == null) { - resetTransform(view); - } else { - applyTransform(view, transformArray); - } - } - - @HippyControllerProps(name = NodeProps.PROP_ACCESSIBILITY_LABEL) - public void setAccessibilityLabel(T view, String accessibilityLabel) { - if (accessibilityLabel == null) { - accessibilityLabel = ""; - } - view.setContentDescription(accessibilityLabel); - } - - /** - * zIndex - **/ - @HippyControllerProps(name = NodeProps.Z_INDEX, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setZIndex(T view, int zIndex) { - HippyViewGroupController.setViewZIndex(view, zIndex); - ViewParent parent = view.getParent(); - if (parent instanceof IHippyZIndexViewGroup) { - ((IHippyZIndexViewGroup) parent).updateDrawingOrder(); - } - } - - /** - * color/border/alpha - **/ - @HippyControllerProps(name = NodeProps.BACKGROUND_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setBackground(T view, int backgroundColor) { - view.setBackgroundColor(backgroundColor); - } - - @HippyControllerProps(name = NodeProps.OPACITY, defaultType = HippyControllerProps.NUMBER, defaultNumber = 1.f) - public void setOpacity(T view, float opacity) { - view.setAlpha(opacity); - } - - @HippyControllerProps(name = NodeProps.BORDER_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setBorderRadius(T view, float borderRadius) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderRadius(borderRadius, CommonBorder.BorderRadiusDirection.ALL.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_TOP_LEFT_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setTopLeftBorderRadius(T view, float topLeftBorderRadius) { - if (view instanceof CommonBorder) { - ((CommonBorder) view).setBorderRadius(topLeftBorderRadius, - CommonBorder.BorderRadiusDirection.TOP_LEFT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_TOP_RIGHT_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setTopRightBorderRadius(T view, float topRightBorderRadius) { - if (view instanceof CommonBorder) { - ((CommonBorder) view).setBorderRadius(topRightBorderRadius, - CommonBorder.BorderRadiusDirection.TOP_RIGHT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_BOTTOM_RIGHT_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setBottomRightBorderRadius(T view, float bottomRightBorderRadius) { - if (view instanceof CommonBorder) { - ((CommonBorder) view).setBorderRadius(bottomRightBorderRadius, - CommonBorder.BorderRadiusDirection.BOTTOM_RIGHT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_BOTTOM_LEFT_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setBottomLeftBorderRadius(T view, float bottomLeftBorderRadius) { - if (view instanceof CommonBorder) { - ((CommonBorder) view).setBorderRadius(bottomLeftBorderRadius, - CommonBorder.BorderRadiusDirection.BOTTOM_LEFT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setBorderWidth(T view, float borderWidth) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderWidth(borderWidth, CommonBorder.BorderWidthDirection.ALL.ordinal()); - } - } - - @HippyControllerProps(name = NodeProps.NEXT_FOCUS_DOWN_ID, defaultType = HippyControllerProps.BOOLEAN) - public void setNextFocusDownId(T view, int id) { - view.setNextFocusDownId(id); - } - - @HippyControllerProps(name = NodeProps.NEXT_FOCUS_UP_ID, defaultType = HippyControllerProps.BOOLEAN) - public void setNextFocusUpId(T view, int id) { - view.setNextFocusUpId(id); - } - - @HippyControllerProps(name = NodeProps.NEXT_FOCUS_LEFT_ID, defaultType = HippyControllerProps.BOOLEAN) - public void setNextFocusLeftId(T view, int id) { - view.setNextFocusLeftId(id); - } - - @HippyControllerProps(name = NodeProps.NEXT_FOCUS_RIGHT_ID, defaultType = HippyControllerProps.BOOLEAN) - public void setNextFocusRightId(T view, int id) { - view.setNextFocusRightId(id); - } - - - @HippyControllerProps(name = NodeProps.FOCUSABLE, defaultType = HippyControllerProps.BOOLEAN) - public void setFocusable(T view, boolean focusable) { - view.setFocusable(focusable); - if (focusable) { - view.setOnFocusChangeListener(this); - } else { - view.setOnFocusChangeListener(null); - } - } - - @HippyControllerProps(name = NodeProps.REQUEST_FOCUS, defaultType = HippyControllerProps.BOOLEAN) - public void requestFocus(final T view, boolean request) { - if (request) { - //noinspection AccessStaticViaInstance - Looper.getMainLooper().myQueue().addIdleHandler(new MessageQueue.IdleHandler() { - @Override - public boolean queueIdle() { - bUserChageFocus = true; - boolean result = view.requestFocusFromTouch(); - - if (!result) { - result = view.requestFocus(); - LogUtils.d("requestFocus", "requestFocus result:" + result); - } - bUserChageFocus = false; - return false; - } - }); - - } - } - - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (bUserChageFocus) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushBoolean("focus", hasFocus); - new HippyViewEvent("onFocus").send(v, hippyMap); - } - } - - @HippyControllerProps(name = NodeProps.LINEAR_GRADIENT, defaultType = HippyControllerProps.MAP) - public void setLinearGradient(T view, HippyMap linearGradient) { - if (linearGradient != null && view instanceof IGradient) { - String angle = linearGradient.getString("angle"); - HippyArray colorStopList = linearGradient.getArray("colorStopList"); - - if (TextUtils.isEmpty(angle) || colorStopList == null || colorStopList.size() == 0) { - return; - } - - int size = colorStopList.size(); - ArrayList colorsArray = new ArrayList<>(); - ArrayList positionsArray = new ArrayList<>(); - for(int i = 0; i < size; i++){ - HippyMap colorStop = colorStopList.getMap(i); - if (colorStop == null) { - continue; - } - - int color = colorStop.getInt("color"); - colorsArray.add(color); - - float ratio = 0.0f; - if (colorStop.containsKey("ratio")) { - ratio = (float)colorStop.getDouble("ratio"); - } else if(i == (size - 1)) { - ratio = 1.0f; - } - - positionsArray.add(ratio); - } - - ((IGradient)view).setGradientAngle(angle); - ((IGradient)view).setGradientColors(colorsArray); - ((IGradient)view).setGradientPositions(positionsArray); - } - } - - @HippyControllerProps(name = NodeProps.SHADOW_OFFSET, defaultType = HippyControllerProps.MAP) - public void setShadowOffset(T view, HippyMap shadowOffset) { - if (shadowOffset != null && view instanceof IShadow) { - float shadowOffsetX = shadowOffset.getInt("x"); - float shadowOffsetY = shadowOffset.getInt("y"); - ((IShadow) view).setShadowOffsetX(shadowOffsetX); - ((IShadow) view).setShadowOffsetY(shadowOffsetY); - } - } - - @HippyControllerProps(name = NodeProps.SHADOW_OFFSET_X, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setShadowOffsetX(T view, float shadowOffsetX) { - if (view instanceof IShadow) { - ((IShadow) view).setShadowOffsetX(shadowOffsetX); - } - } - - @HippyControllerProps(name = NodeProps.SHADOW_OFFSET_Y, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setShadowOffsetY(T view, float shadowOffsetY) { - if (view instanceof IShadow) { - ((IShadow) view).setShadowOffsetY(shadowOffsetY); - } - } - - @HippyControllerProps(name = NodeProps.SHADOW_OPACITY, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setShadowOpacity(T view, float shadowOpacity) { - if (view instanceof IShadow) { - ((IShadow) view).setShadowOpacity(shadowOpacity); - } - } - - @HippyControllerProps(name = NodeProps.SHADOW_RADIUS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setShadowRadius(T view, float shadowRadius) { - if (view instanceof IShadow) { - ((IShadow) view).setShadowRadius(shadowRadius); - } - } - - @HippyControllerProps(name = NodeProps.SHADOW_SPREAD, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setShadowSpread(T view, float shadowSpread) { - if (view instanceof IShadow) { - ((IShadow) view).setShadowSpread(shadowSpread); - } - } - - @HippyControllerProps(name = NodeProps.SHADOW_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setShadowColor(T view, int shadowColor) { - if (view instanceof IShadow) { - ((IShadow) view).setShadowColor(shadowColor); - } - } - - @HippyControllerProps(name = NodeProps.BORDER_LEFT_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setLeftBorderWidth(T view, float borderLeftWidth) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderWidth(borderLeftWidth, CommonBorder.BorderWidthDirection.LEFT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_TOP_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setTopBorderWidth(T view, float borderTopWidth) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderWidth(borderTopWidth, CommonBorder.BorderWidthDirection.TOP.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_RIGHT_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setRightBorderWidth(T view, float borderRightWidth) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderWidth(borderRightWidth, CommonBorder.BorderWidthDirection.RIGHT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_BOTTOM_WIDTH, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setBottomBorderWidth(T view, float borderBottomWidth) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderWidth(borderBottomWidth, CommonBorder.BorderWidthDirection.BOTTOM.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setBorderColor(T view, int borderColor) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderColor(borderColor, CommonBorder.BorderWidthDirection.ALL.ordinal()); - } - } - - @HippyControllerProps(name = NodeProps.BORDER_LEFT_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setBorderLeftColor(T view, int borderLeftColor) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderColor(borderLeftColor, CommonBorder.BorderWidthDirection.LEFT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_TOP_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setBorderTopWidth(T view, int borderTopColor) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderColor(borderTopColor, CommonBorder.BorderWidthDirection.TOP.ordinal()); - } - } - - @HippyControllerProps(name = NodeProps.BORDER_RIGHT_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setBorderRightWidth(T view, int borderRightColor) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderColor(borderRightColor, CommonBorder.BorderWidthDirection.RIGHT.ordinal()); - } - } - - - @HippyControllerProps(name = NodeProps.BORDER_BOTTOM_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setBorderBottomWidth(T view, int borderBottomColor) { - if (view instanceof CommonBorder) { - ((CommonBorder) view) - .setBorderColor(borderBottomColor, CommonBorder.BorderWidthDirection.BOTTOM.ordinal()); - } - } - - /** - * touch/click - **/ - @HippyControllerProps(name = NodeProps.ON_CLICK, defaultType = HippyControllerProps.BOOLEAN) - public void setClickable(T view, boolean flag) { - if (!handleGestureBySelf()) { - if (flag) { - view.setOnClickListener(NativeGestureDispatcher.getOnClickListener()); - } else { - view.setOnClickListener(null); - view.setClickable(false); - } - } - } - - - @HippyControllerProps(name = NodeProps.ON_LONG_CLICK, defaultType = HippyControllerProps.BOOLEAN) - public void setLongClickable(T view, boolean flag) { - if (!handleGestureBySelf()) { - if (flag) { - view.setOnLongClickListener(NativeGestureDispatcher.getOnLongClickListener()); - } else { - view.setOnLongClickListener(null); - view.setLongClickable(false); - } - } - } - - @HippyControllerProps(name = NodeProps.ON_PRESS_IN, defaultType = HippyControllerProps.BOOLEAN) - public void setPressInable(T view, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(view, NodeProps.ON_PRESS_IN, flag); - } - } - - @HippyControllerProps(name = NodeProps.ON_PRESS_OUT, defaultType = HippyControllerProps.BOOLEAN) - public void setPressOutable(T view, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(view, NodeProps.ON_PRESS_OUT, flag); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_DOWN, defaultType = HippyControllerProps.BOOLEAN) - public void setTouchDownHandle(T view, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(view, NodeProps.ON_TOUCH_DOWN, flag); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_MOVE, defaultType = HippyControllerProps.BOOLEAN) - public void setTouchMoveHandle(T view, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(view, NodeProps.ON_TOUCH_MOVE, flag); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_END, defaultType = HippyControllerProps.BOOLEAN) - public void setTouchEndHandle(T view, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(view, NodeProps.ON_TOUCH_END, flag); - } - } - - @HippyControllerProps(name = NodeProps.ON_TOUCH_CANCEL, defaultType = HippyControllerProps.BOOLEAN) - public void setTouchCancelHandle(T view, boolean flag) { - if (!handleGestureBySelf()) { - setGestureType(view, NodeProps.ON_TOUCH_CANCEL, flag); - } - } - - @HippyControllerProps(name = NodeProps.ON_ATTACHED_TO_WINDOW, defaultType = HippyControllerProps.BOOLEAN) - public void setAttachedToWindowHandle(T view, boolean flag) { - if (flag) { - view.addOnAttachStateChangeListener(NativeGestureDispatcher.getOnAttachedToWindowListener()); - } else { - view.removeOnAttachStateChangeListener( - NativeGestureDispatcher.getOnAttachedToWindowListener()); - } - } - - @HippyControllerProps(name = NodeProps.ON_DETACHED_FROM_WINDOW, defaultType = HippyControllerProps.BOOLEAN) - public void setDetachedFromWindowHandle(T view, boolean flag) { - if (flag) { - view.addOnAttachStateChangeListener( - NativeGestureDispatcher.getOnDetachedFromWindowListener()); - } else { - view.removeOnAttachStateChangeListener( - NativeGestureDispatcher.getOnDetachedFromWindowListener()); - } - } - - @HippyControllerProps(name = "renderToHardwareTextureAndroid", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setRenderToHardwareTexture(T view, boolean useHWTexture) { - view.setLayerType(useHWTexture ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null); - } - - @SuppressWarnings("EmptyMethod") - @HippyControllerProps(name = NodeProps.CUSTOM_PROP) - public void setCustomProp(T view, String methodName, Object props) { - - } - - protected void setGestureType(T view, String type, boolean flag) { - if (flag) { - if (view.getGestureDispatcher() == null) { - view.setGestureDispatcher(new NativeGestureDispatcher(view)); - } - view.getGestureDispatcher().addGestureType(type); - } else { - if (view.getGestureDispatcher() != null) { - view.getGestureDispatcher().removeGestureType(type); - } - } - } - - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, ControllerManager controllerManager, - boolean lazy) { - return new RenderNode(id, props, className, hippyRootView, controllerManager, lazy); - } - - private void applyTransform(T view, HippyArray transformArray) { - TransformUtil.processTransform(transformArray, sTransformDecompositionArray); - sMatrixDecompositionContext.reset(); - MatrixUtil.decomposeMatrix(sTransformDecompositionArray, sMatrixDecompositionContext); - view.setTranslationX(PixelUtil.dp2px((float) sMatrixDecompositionContext.translation[0])); - view.setTranslationY(PixelUtil.dp2px((float) sMatrixDecompositionContext.translation[1])); - view.setRotation((float) sMatrixDecompositionContext.rotationDegrees[2]); - view.setRotationX((float) sMatrixDecompositionContext.rotationDegrees[0]); - view.setRotationY((float) sMatrixDecompositionContext.rotationDegrees[1]); - view.setScaleX((float) sMatrixDecompositionContext.scale[0]); - view.setScaleY((float) sMatrixDecompositionContext.scale[1]); - } - - public static void resetTransform(View view) { - view.setTranslationX(0); - view.setTranslationY(0); - view.setRotation(0); - view.setRotationX(0); - view.setRotationY(0); - view.setScaleX(1); - view.setScaleY(1); - } - - public void dispatchFunction(T view, String functionName, HippyArray var) { - } - - public void dispatchFunction(T view, String functionName, HippyArray params, Promise promise) { - } - - public void onBatchComplete(T view) { - - } - - protected void deleteChild(ViewGroup parentView, View childView) { - parentView.removeView(childView); - } - - protected void deleteChild(ViewGroup parentView, View childView, int childIndex) { - deleteChild(parentView, childView); - } - - public void onViewDestroy(T t) { - } - - protected void addView(ViewGroup parentView, View view, int index) { - // TODO: 这里需要复现场景来解,先上一个临时方案 - int realIndex = index; - if (realIndex > parentView.getChildCount()) { - realIndex = parentView.getChildCount(); - } - try { - parentView.addView(view, realIndex); - } catch (Exception e) { - e.printStackTrace(); - } - } - - protected void onManageChildComplete(T view) { - - } - - public int getChildCount(T viewGroup) { - if (viewGroup instanceof ViewGroup) { - return ((ViewGroup) viewGroup).getChildCount(); - } - return 0; - } - - public View getChildAt(T viewGroup, int i) { - if (viewGroup instanceof ViewGroup) { - return ((ViewGroup) viewGroup).getChildAt(i); - } - return null; - } - - protected String getInnerPath(HippyInstanceContext context, String path) { - //hpfile://./assets/file_banner02.jpg - if (path != null && path.startsWith("hpfile://")) { - String relativePath = path.replace("hpfile://./", ""); - //hippysdk的图片加载协议 - String bundlePath = null; - if (context.getBundleLoader() != null) { - bundlePath = context.getBundleLoader().getPath(); - } - - path = bundlePath == null ? null - : bundlePath.subSequence(0, bundlePath.lastIndexOf(File.separator) + 1) + relativePath; - //assets://index.android.jsbundle - //file:sdcard/hippy/feeds/index.android.jsbundle - } - return path; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyViewEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyViewEvent.java deleted file mode 100644 index 24470a077b2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/HippyViewEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.view.View; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.modules.HippyModuleManager; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; - -public class HippyViewEvent { - - private final String mEventName; - - public HippyViewEvent(String eventName) { - this.mEventName = eventName; - } - - public void send(View view, Object param) { - if (view != null && view.getContext() instanceof HippyInstanceContext) { - HippyEngineContext context = ((HippyInstanceContext) view.getContext()).getEngineContext(); - send(view.getId(), context, param); - } - } - - public void send(int id, HippyEngineContext context, Object param) { - if (context == null) { - return; - } - - HippyModuleManager hmm = context.getModuleManager(); - if (hmm != null) { - hmm.getJavaScriptModule(EventDispatcher.class).receiveUIComponentEvent(id, mEventName, param); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/IHippyZIndexViewGroup.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/IHippyZIndexViewGroup.java deleted file mode 100644 index f316e6a15de..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/IHippyZIndexViewGroup.java +++ /dev/null @@ -1,24 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -@SuppressWarnings({"unused"}) -public interface IHippyZIndexViewGroup { - - int getZIndexMappedChildIndex(int index); - - void updateDrawingOrder(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ListItemRenderNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ListItemRenderNode.java deleted file mode 100644 index aa658fd60ee..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ListItemRenderNode.java +++ /dev/null @@ -1,143 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.view.View; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.views.list.IRecycleItemTypeChange; - -@SuppressWarnings({"deprecation", "unused"}) -public class ListItemRenderNode extends RenderNode { - - public static final String ITEM_VIEW_TYPE = "type"; - public static final String ITEM_STICKY = "sticky"; - public static final String ITEM_VIEW_TYPE_NEW = "itemViewType"; - - private boolean mShouldSticky; - private IRecycleItemTypeChange mRecycleItemTypeChangeListener; - - public ListItemRenderNode(int mId, HippyMap mPropsToUpdate, String className, - HippyRootView mRootView, ControllerManager componentManager, - boolean isLazyLoad) { - super(mId, mPropsToUpdate, className, mRootView, componentManager, isLazyLoad); - if (mProps.get(ITEM_STICKY) != null) { - mShouldSticky = mProps.getBoolean(ITEM_STICKY); - } - } - - /** - * y值是前端传入的,前端没有复用的概念,所有y是整个list长度的y值,并不是recyclerView的排版的y。 真正意义上面的y是排版到屏幕范围以内的y,也是子view相对于recyclerView的起始位置的y,也就是子view的top - * 系统的recyclerView在刷新list前,layoutManager会调用anchorInfo.assignFromView,取第一个view计算当前的 - * anchorInfo,如果整个地方把y值修改了,导致anchorInfo会取不对. 这里保证updateLayout不要改变已经挂在到RecyclerView的view的top - */ - @Override - public void updateLayout(int x, int y, int w, int h) { - super.updateLayout(x, y, w, h); - View renderView = mComponentManager.mControllerRegistry.getView(mId); - mY = renderView != null ? renderView.getTop() : 0; - if (getParent() != null && mComponentManager != null && mComponentManager.mContext - != null) { // 若屏幕内node更新引起了item整体变化,需要通知ListView发起dispatchLayout重排版 - RenderManager renderManager = mComponentManager.mContext.getRenderManager(); - if (renderManager != null) { - renderManager.addUpdateNodeIfNeeded(getParent()); - } - } - } - - @Override - public void updateNode(HippyMap map) { - int oldType = getTypeFromMap(mProps); - int newType = getTypeFromMap(map); - if (mRecycleItemTypeChangeListener != null && oldType != newType) { - mRecycleItemTypeChangeListener.onRecycleItemTypeChanged(oldType, newType, this); - } - super.updateNode(map); - if (mProps.get(ITEM_STICKY) != null) { - mShouldSticky = mProps.getBoolean(ITEM_STICKY); - } - } - - /** - * 获取item的Type,用于recyclerView的缓存复用 - * - * @return - */ - public int getItemViewType() { - return getTypeFromMap(mProps); - } - - /** - * 兼容各种版本的itemType - */ - private int getTypeFromMap(HippyMap hippyMap) { - int viewType = hippyMap.getInt(ITEM_VIEW_TYPE); - if (viewType <= 0 && hippyMap.getString(ITEM_VIEW_TYPE) != null) { - try { - viewType = Integer.parseInt(hippyMap.getString(ITEM_VIEW_TYPE)); - } catch (NumberFormatException e) { - //do nothing - } - } - if (viewType <= 0) { - viewType = hippyMap.getInt(ListItemRenderNode.ITEM_VIEW_TYPE_NEW); - } - return viewType; - } - - @Override - public int indexFromParent() { - return super.indexFromParent(); - } - - public void setRecycleItemTypeChangeListener( - IRecycleItemTypeChange recycleItemTypeChangeListener) { - mRecycleItemTypeChangeListener = recycleItemTypeChangeListener; - } - - public boolean isPullFooter() { - return false; - } - - public boolean isPullHeader() { - return false; - } - - public boolean shouldSticky() { - return mShouldSticky; - } - - /** - * 异常情况下,如果view已经存在,需要删除它,前提是view没有parent的情况, 有parent的情况出现在sticky属性的view,当前可能是正在置顶的view,这种是不能调用删除的,是正常情况, - * hasView为true,通过createView是拿到已经存在的view。 - * - * @return 是否需要删除view - */ - public boolean needDeleteExistRenderView() { - if (mComponentManager.hasView(mId)) { - return mComponentManager.createView(mRootView, mId, mClassName, mProps).getParent() == null; - } - return false; - } - - public boolean isViewExist() { - return mComponentManager.hasView(mId); - } - - public boolean hasRootView() { - return mRootView != null; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ListViewRenderNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ListViewRenderNode.java deleted file mode 100644 index 6356a9d3c7b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ListViewRenderNode.java +++ /dev/null @@ -1,44 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; - -@SuppressWarnings({"deprecation", "unused"}) -public class ListViewRenderNode extends RenderNode { - - public ListViewRenderNode(int mId, HippyMap mPropsToUpdate, String className, - HippyRootView mRootView, ControllerManager componentManager, - boolean isLazyLoad) { - super(mId, mPropsToUpdate, className, mRootView, componentManager, isLazyLoad); - } - - - @Override - protected void addChildToPendingList(RenderNode renderNode) { - // super.addPendChild(renderNode); - } - - @Override - public boolean removeChild(RenderNode uiNode) { - if (uiNode instanceof ListItemRenderNode) { - ListItemRenderNode listItemRenderNode = (ListItemRenderNode) uiNode; - listItemRenderNode.setRecycleItemTypeChangeListener(null); - } - return super.removeChild(uiNode); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/MatrixUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/MatrixUtil.java deleted file mode 100644 index 5ae25101ce1..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/MatrixUtil.java +++ /dev/null @@ -1,470 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -public class MatrixUtil { - - private static final double EPSILON = .00001d; - - public static class MatrixDecompositionContext { - - final double[] perspective = new double[4]; - final double[] quaternion = new double[4]; - final double[] scale = new double[3]; - final double[] skew = new double[3]; - final double[] translation = new double[3]; - final double[] rotationDegrees = new double[3]; - - public void reset() { - perspective[0] = 0; - perspective[1] = 0; - perspective[2] = 0; - perspective[3] = 0; - - quaternion[0] = 0; - quaternion[1] = 0; - quaternion[2] = 0; - quaternion[3] = 0; - - scale[0] = 0; - scale[1] = 0; - scale[2] = 0; - - skew[0] = 0; - skew[1] = 0; - skew[2] = 0; - - translation[0] = 0; - translation[1] = 0; - translation[2] = 0; - - rotationDegrees[0] = 0; - rotationDegrees[1] = 0; - rotationDegrees[2] = 0; - } - } - - private static boolean isZero(double d) { - if (Double.isNaN(d)) { - return false; - } - return Math.abs(d) < EPSILON; - } - - // 四维矩阵运算:out = matrixA * matrixB - // 输入:matrixA,长度16的一维数组,代表四维矩阵 - // 输入:matrixB,长度16的一维数组,代表四维矩阵 - public static void multiplyInto(double[] out, double[] matrixA, double[] matrixB) { - double b00 = matrixB[0], b01 = matrixB[1], b02 = matrixB[2], b03 = matrixB[3], - b10 = matrixB[4], b11 = matrixB[5], b12 = matrixB[6], b13 = matrixB[7], - b20 = matrixB[8], b21 = matrixB[9], b22 = matrixB[10], b23 = matrixB[11], - b30 = matrixB[12], b31 = matrixB[13], b32 = matrixB[14], b33 = matrixB[15]; - - double a0 = matrixA[0], a1 = matrixA[1], a2 = matrixA[2], a3 = matrixA[3]; - out[0] = a0 * b00 + a1 * b10 + a2 * b20 + a3 * b30; - out[1] = a0 * b01 + a1 * b11 + a2 * b21 + a3 * b31; - out[2] = a0 * b02 + a1 * b12 + a2 * b22 + a3 * b32; - out[3] = a0 * b03 + a1 * b13 + a2 * b23 + a3 * b33; - - a0 = matrixA[4]; - a1 = matrixA[5]; - a2 = matrixA[6]; - a3 = matrixA[7]; - out[4] = a0 * b00 + a1 * b10 + a2 * b20 + a3 * b30; - out[5] = a0 * b01 + a1 * b11 + a2 * b21 + a3 * b31; - out[6] = a0 * b02 + a1 * b12 + a2 * b22 + a3 * b32; - out[7] = a0 * b03 + a1 * b13 + a2 * b23 + a3 * b33; - - a0 = matrixA[8]; - a1 = matrixA[9]; - a2 = matrixA[10]; - a3 = matrixA[11]; - out[8] = a0 * b00 + a1 * b10 + a2 * b20 + a3 * b30; - out[9] = a0 * b01 + a1 * b11 + a2 * b21 + a3 * b31; - out[10] = a0 * b02 + a1 * b12 + a2 * b22 + a3 * b32; - out[11] = a0 * b03 + a1 * b13 + a2 * b23 + a3 * b33; - - a0 = matrixA[12]; - a1 = matrixA[13]; - a2 = matrixA[14]; - a3 = matrixA[15]; - out[12] = a0 * b00 + a1 * b10 + a2 * b20 + a3 * b30; - out[13] = a0 * b01 + a1 * b11 + a2 * b21 + a3 * b31; - out[14] = a0 * b02 + a1 * b12 + a2 * b22 + a3 * b32; - out[15] = a0 * b03 + a1 * b13 + a2 * b23 + a3 * b33; - } - - /** - * @param transformMatrix 16-element array of numbers representing 4x4 transform matrix - */ - public static void decomposeMatrix(double[] transformMatrix, MatrixDecompositionContext ctx) { - // output values - final double[] perspective = ctx.perspective; - final double[] quaternion = ctx.quaternion; - final double[] scale = ctx.scale; - final double[] skew = ctx.skew; - final double[] translation = ctx.translation; - final double[] rotationDegrees = ctx.rotationDegrees; - - // create normalized, 2d array matrix - // and normalized 1d array perspectiveMatrix with redefined 4th column - if (isZero(transformMatrix[15])) { - return; - } - double[][] matrix = new double[4][4]; - double[] perspectiveMatrix = new double[16]; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - double value = transformMatrix[(i * 4) + j] / transformMatrix[15]; - matrix[i][j] = value; - perspectiveMatrix[(i * 4) + j] = j == 3 ? 0 : value; - } - } - perspectiveMatrix[15] = 1; - - // test for singularity of upper 3x3 part of the perspective matrix - if (isZero(determinant(perspectiveMatrix))) { - return; - } - - // isolate perspective - if (!isZero(matrix[0][3]) || !isZero(matrix[1][3]) || !isZero(matrix[2][3])) { - // rightHandSide is the right hand side of the equation. - // rightHandSide is a vector, or point in 3d space relative to the origin. - double[] rightHandSide = {matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]}; - - // Solve the equation by inverting perspectiveMatrix and multiplying - // rightHandSide by the inverse. - double[] inversePerspectiveMatrix = inverse(perspectiveMatrix); - double[] transposedInversePerspectiveMatrix = transpose(inversePerspectiveMatrix); - multiplyVectorByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspective); - } else { - // no perspective - perspective[0] = perspective[1] = perspective[2] = 0d; - perspective[3] = 1d; - } - - // translation is simple - System.arraycopy(matrix[3], 0, translation, 0, 3); - - // Now get scale and shear. - // 'row' is a 3 element array of 3 component vectors - double[][] row = new double[3][3]; - for (int i = 0; i < 3; i++) { - row[i][0] = matrix[i][0]; - row[i][1] = matrix[i][1]; - row[i][2] = matrix[i][2]; - } - - // Compute X scale factor and normalize first row. - scale[0] = v3Length(row[0]); - row[0] = v3Normalize(row[0], scale[0]); - - // Compute XY shear factor and make 2nd row orthogonal to 1st. - skew[0] = v3Dot(row[0], row[1]); - row[1] = v3Combine(row[1], row[0], 1.0, -skew[0]); - - // Compute XY shear factor and make 2nd row orthogonal to 1st. - skew[0] = v3Dot(row[0], row[1]); - row[1] = v3Combine(row[1], row[0], 1.0, -skew[0]); - - // Now, compute Y scale and normalize 2nd row. - scale[1] = v3Length(row[1]); - row[1] = v3Normalize(row[1], scale[1]); - skew[0] /= scale[1]; - - // Compute XZ and YZ shears, orthogonalize 3rd row - skew[1] = v3Dot(row[0], row[2]); - row[2] = v3Combine(row[2], row[0], 1.0, -skew[1]); - skew[2] = v3Dot(row[1], row[2]); - row[2] = v3Combine(row[2], row[1], 1.0, -skew[2]); - - // Next, get Z scale and normalize 3rd row. - scale[2] = v3Length(row[2]); - row[2] = v3Normalize(row[2], scale[2]); - skew[1] /= scale[2]; - skew[2] /= scale[2]; - - // At this point, the matrix (in rows) is orthonormal. - // Check for a coordinate system flip. If the determinant - // is -1, then negate the matrix and the scaling factors. - double[] pdum3 = v3Cross(row[1], row[2]); - if (v3Dot(row[0], pdum3) < 0) { - for (int i = 0; i < 3; i++) { - scale[i] *= -1; - row[i][0] *= -1; - row[i][1] *= -1; - row[i][2] *= -1; - } - } - - // Now, get the rotations out - quaternion[0] = 0.5 * Math.sqrt(Math.max(1 + row[0][0] - row[1][1] - row[2][2], 0)); - quaternion[1] = 0.5 * Math.sqrt(Math.max(1 - row[0][0] + row[1][1] - row[2][2], 0)); - quaternion[2] = 0.5 * Math.sqrt(Math.max(1 - row[0][0] - row[1][1] + row[2][2], 0)); - quaternion[3] = 0.5 * Math.sqrt(Math.max(1 + row[0][0] + row[1][1] + row[2][2], 0)); - - if (row[2][1] > row[1][2]) { - quaternion[0] = -quaternion[0]; - } - if (row[0][2] > row[2][0]) { - quaternion[1] = -quaternion[1]; - } - if (row[1][0] > row[0][1]) { - quaternion[2] = -quaternion[2]; - } - - // correct for occasional, weird Euler synonyms for 2d rotation - - if (quaternion[0] < 0.001 && quaternion[0] >= 0 && quaternion[1] < 0.001 - && quaternion[1] >= 0) { - // this is a 2d rotation on the z-axis - rotationDegrees[0] = rotationDegrees[1] = 0d; - rotationDegrees[2] = roundTo3Places(Math.atan2(row[0][1], row[0][0]) * 180 / Math.PI); - } else { - quaternionToDegreesXYZ(quaternion, rotationDegrees); - } - } - - public static double determinant(double[] matrix) { - double m00 = matrix[0], m01 = matrix[1], m02 = matrix[2], m03 = matrix[3], m10 = matrix[4], m11 = matrix[5], m12 = matrix[6], m13 = matrix[7], - m20 = matrix[8], m21 = matrix[9], m22 = matrix[10], m23 = matrix[11], m30 = matrix[12], m31 = matrix[13], m32 = matrix[14], - m33 = matrix[15]; - return (m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 - m03 * m11 * m22 * m30 - + m01 * m13 * m22 * m30 + m02 * m11 * m23 * m30 - - m01 * m12 * m23 * m30 - m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 - + m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 - - m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 + m03 * m11 * m20 * m32 - - m01 * m13 * m20 * m32 - m03 * m10 * m21 * m32 - + m00 * m13 * m21 * m32 + m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 - - m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 - + m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 - m01 * m10 * m22 * m33 - + m00 * m11 * m22 * m33); - } - - /** - * Inverse of a matrix. Multiplying by the inverse is used in matrix math instead of division. - *

- * Formula from: http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - */ - public static double[] inverse(double[] matrix) { - double det = determinant(matrix); - if (isZero(det)) { - return matrix; - } - double m00 = matrix[0], m01 = matrix[1], m02 = matrix[2], m03 = matrix[3], m10 = matrix[4], m11 = matrix[5], m12 = matrix[6], m13 = matrix[7], - m20 = matrix[8], m21 = matrix[9], m22 = matrix[10], m23 = matrix[11], m30 = matrix[12], m31 = matrix[13], m32 = matrix[14], - m33 = matrix[15]; - return new double[]{ - (m12 * m23 * m31 - m13 * m22 * m31 + m13 * m21 * m32 - m11 * m23 * m32 - m12 * m21 * m33 - + m11 * m22 * m33) / det, - (m03 * m22 * m31 - m02 * m23 * m31 - m03 * m21 * m32 + m01 * m23 * m32 + m02 * m21 * m33 - - m01 * m22 * m33) / det, - (m02 * m13 * m31 - m03 * m12 * m31 + m03 * m11 * m32 - m01 * m13 * m32 - m02 * m11 * m33 - + m01 * m12 * m33) / det, - (m03 * m12 * m21 - m02 * m13 * m21 - m03 * m11 * m22 + m01 * m13 * m22 + m02 * m11 * m23 - - m01 * m12 * m23) / det, - (m13 * m22 * m30 - m12 * m23 * m30 - m13 * m20 * m32 + m10 * m23 * m32 + m12 * m20 * m33 - - m10 * m22 * m33) / det, - (m02 * m23 * m30 - m03 * m22 * m30 + m03 * m20 * m32 - m00 * m23 * m32 - m02 * m20 * m33 - + m00 * m22 * m33) / det, - (m03 * m12 * m30 - m02 * m13 * m30 - m03 * m10 * m32 + m00 * m13 * m32 + m02 * m10 * m33 - - m00 * m12 * m33) / det, - (m02 * m13 * m20 - m03 * m12 * m20 + m03 * m10 * m22 - m00 * m13 * m22 - m02 * m10 * m23 - + m00 * m12 * m23) / det, - (m11 * m23 * m30 - m13 * m21 * m30 + m13 * m20 * m31 - m10 * m23 * m31 - m11 * m20 * m33 - + m10 * m21 * m33) / det, - (m03 * m21 * m30 - m01 * m23 * m30 - m03 * m20 * m31 + m00 * m23 * m31 + m01 * m20 * m33 - - m00 * m21 * m33) / det, - (m01 * m13 * m30 - m03 * m11 * m30 + m03 * m10 * m31 - m00 * m13 * m31 - m01 * m10 * m33 - + m00 * m11 * m33) / det, - (m03 * m11 * m20 - m01 * m13 * m20 - m03 * m10 * m21 + m00 * m13 * m21 + m01 * m10 * m23 - - m00 * m11 * m23) / det, - (m12 * m21 * m30 - m11 * m22 * m30 - m12 * m20 * m31 + m10 * m22 * m31 + m11 * m20 * m32 - - m10 * m21 * m32) / det, - (m01 * m22 * m30 - m02 * m21 * m30 + m02 * m20 * m31 - m00 * m22 * m31 - m01 * m20 * m32 - + m00 * m21 * m32) / det, - (m02 * m11 * m30 - m01 * m12 * m30 - m02 * m10 * m31 + m00 * m12 * m31 + m01 * m10 * m32 - - m00 * m11 * m32) / det, - (m01 * m12 * m20 - m02 * m11 * m20 + m02 * m10 * m21 - m00 * m12 * m21 - m01 * m10 * m22 - + m00 * m11 * m22) / det}; - } - - /** - * Turns columns into rows and rows into columns. - */ - public static double[] transpose(double[] m) { - return new double[]{m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], - m[3], m[7], m[11], m[15]}; - } - - /** - * Based on: http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c - */ - public static void multiplyVectorByMatrix(double[] v, double[] m, double[] result) { - double vx = v[0], vy = v[1], vz = v[2], vw = v[3]; - result[0] = vx * m[0] + vy * m[4] + vz * m[8] + vw * m[12]; - result[1] = vx * m[1] + vy * m[5] + vz * m[9] + vw * m[13]; - result[2] = vx * m[2] + vy * m[6] + vz * m[10] + vw * m[14]; - result[3] = vx * m[3] + vy * m[7] + vz * m[11] + vw * m[15]; - } - - /** - * From: https://code.google.com/p/webgl-mjs/source/browse/mjs.js - */ - public static double v3Length(double[] a) { - return Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); - } - - /** - * Based on: https://code.google.com/p/webgl-mjs/source/browse/mjs.js - */ - public static double[] v3Normalize(double[] vector, double norm) { - double im = 1 / (isZero(norm) ? v3Length(vector) : norm); - return new double[]{vector[0] * im, vector[1] * im, vector[2] * im}; - } - - /** - * The dot product of a and b, two 3-element vectors. From: https://code.google.com/p/webgl-mjs/source/browse/mjs.js - */ - public static double v3Dot(double[] a, double[] b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; - } - - /** - * From: http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp - */ - public static double[] v3Combine(double[] a, double[] b, double aScale, double bScale) { - return new double[]{aScale * a[0] + bScale * b[0], aScale * a[1] + bScale * b[1], - aScale * a[2] + bScale * b[2]}; - } - - /** - * From: http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp - */ - public static double[] v3Cross(double[] a, double[] b) { - return new double[]{a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], - a[0] * b[1] - a[1] * b[0]}; - } - - /** - * Based on: http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ - * and: http://quat.zachbennett.com/ - *

- * Note that this rounds degrees to the thousandth of a degree, due to floating point errors in - * the creation of the quaternion. - *

- * Also note that this expects the qw value to be last, not first. - *

- * Also, when researching this, remember that: yaw === heading === z-axis pitch === - * elevation/attitude === y-axis roll === bank === x-axis - */ - public static void quaternionToDegreesXYZ(double[] q, double[] result) { - double qx = q[0], qy = q[1], qz = q[2], qw = q[3]; - double qw2 = qw * qw; - double qx2 = qx * qx; - double qy2 = qy * qy; - double qz2 = qz * qz; - double test = qx * qy + qz * qw; - double unit = qw2 + qx2 + qy2 + qz2; - double conv = 180 / Math.PI; - - if (test > 0.49999 * unit) { - result[0] = 0; - result[1] = 2 * Math.atan2(qx, qw) * conv; - result[2] = 90; - return; - } - if (test < -0.49999 * unit) { - result[0] = 0; - result[1] = -2 * Math.atan2(qx, qw) * conv; - result[2] = -90; - return; - } - - result[0] = roundTo3Places(Math.atan2(2 * qx * qw - 2 * qy * qz, 1 - 2 * qx2 - 2 * qz2) * conv); - result[1] = roundTo3Places(Math.atan2(2 * qy * qw - 2 * qx * qz, 1 - 2 * qy2 - 2 * qz2) * conv); - result[2] = roundTo3Places(Math.asin(2 * qx * qy + 2 * qz * qw) * conv); - } - - public static double roundTo3Places(double n) { - return Math.round(n * 1000d) * 0.001; - } - - public static double degreesToRadians(double degrees) { - return degrees * Math.PI / 180; - } - - public static void resetIdentityMatrix(double[] matrix) { - matrix[1] = matrix[2] = matrix[3] = matrix[4] = matrix[6] = matrix[7] = matrix[8] = matrix[9] = matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0; - matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1; - } - - public static void applyPerspective(double[] m, double perspective) { - m[11] = -1 / perspective; - } - - public static void applyScaleX(double[] m, double factor) { - m[0] = factor; - } - - public static void applyScaleY(double[] m, double factor) { - m[5] = factor; - } - - public static void applyTranslate2D(double[] m, double x, double y) { - m[12] = x; - m[13] = y; - } - - public static void applyTranslate3D(double[] m, double x, double y, double z) { - m[12] = x; - m[13] = y; - m[14] = z; - } - - public static void applySkewX(double[] m, double radians) { - m[4] = Math.sin(radians); - m[5] = Math.cos(radians); - } - - public static void applySkewY(double[] m, double radians) { - m[0] = Math.cos(radians); - m[1] = Math.sin(radians); - } - - public static void applyRotateX(double[] m, double radians) { - m[5] = Math.cos(radians); - m[6] = Math.sin(radians); - m[9] = -Math.sin(radians); - m[10] = Math.cos(radians); - } - - public static void applyRotateY(double[] m, double radians) { - m[0] = Math.cos(radians); - m[2] = -Math.sin(radians); - m[8] = Math.sin(radians); - m[10] = Math.cos(radians); - } - - // http://www.w3.org/TR/css3-transforms/#recomposing-to-a-2d-matrix - public static void applyRotateZ(double[] m, double radians) { - m[0] = Math.cos(radians); - m[1] = Math.sin(radians); - m[4] = -Math.sin(radians); - m[5] = Math.cos(radians); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/NativeGestureDispatcher.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/NativeGestureDispatcher.java deleted file mode 100644 index 357622d3af4..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/NativeGestureDispatcher.java +++ /dev/null @@ -1,343 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.text.TextUtils; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorAdapter; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; - -import java.util.HashSet; - -@SuppressWarnings({"deprecation", "unused"}) -public class NativeGestureDispatcher implements NativeGestureProcessor.Callback { - - private static final String TAG = "NativeGestureDispatcher"; - private static final String KEY_EVENT_NAME = "name"; - private static final String KEY_TAG_ID = "id"; - private static final String KEY_PAGE_X = "page_x"; - private static final String KEY_PAGE_Y = "page_y"; - private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); - - private static final View.OnClickListener mOnClickListener = new View.OnClickListener() { - @Override - public void onClick(final View view) { - if (view != null && view.getContext() instanceof HippyInstanceContext) { - view.postDelayed(new Runnable() { - @Override - public void run() { - int tagId = view.getId(); - handleClick(view, ((HippyInstanceContext) view.getContext()) - .getEngineContext(), tagId, false); - } - }, TAP_TIMEOUT); - } - - } - }; - private static final View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() { - @Override - public boolean onLongClick(final View view) { - if (view != null && view.getContext() instanceof HippyInstanceContext) { - view.postDelayed(new Runnable() { - @Override - public void run() { - int tagId = view.getId(); - handleLongClick(((HippyInstanceContext) view.getContext()) - .getEngineContext(), tagId); - } - }, TAP_TIMEOUT); - - - } - return true; - } - }; - - private static final View.OnAttachStateChangeListener mOnAttachedToWindowListener = new View.OnAttachStateChangeListener() { - - @Override - public void onViewAttachedToWindow(View view) { - if (view != null && view.getContext() instanceof HippyInstanceContext) { - int tagId = view.getId(); - handleAttachedToWindow(((HippyInstanceContext) view.getContext()) - .getEngineContext(), tagId); - } - } - - @Override - public void onViewDetachedFromWindow(View view) { - - } - }; - - private static final View.OnAttachStateChangeListener mOnDetachedFromWindowListener = new View.OnAttachStateChangeListener() { - - @Override - public void onViewAttachedToWindow(View view) { - - } - - @Override - public void onViewDetachedFromWindow(View view) { - if (view != null && view.getContext() instanceof HippyInstanceContext) { - int tagId = view.getId(); - handleDetachedFromWindow(((HippyInstanceContext) view.getContext()) - .getEngineContext(), tagId); - } - } - }; - - private final View mTargetView; - private HashSet mGestureTypes = null; - private NativeGestureProcessor mGestureProcessor; - private HippyEngineContext mEngineContext; - - public NativeGestureDispatcher(View view) { - mTargetView = view; - if (view != null && view.getContext() instanceof HippyInstanceContext) { - mEngineContext = ((HippyInstanceContext) view.getContext()).getEngineContext(); - } - } - - public static View.OnClickListener getOnClickListener() { - return mOnClickListener; - } - - public static View.OnLongClickListener getOnLongClickListener() { - return mOnLongClickListener; - } - - public static View.OnAttachStateChangeListener getOnAttachedToWindowListener() { - return mOnAttachedToWindowListener; - } - - public static View.OnAttachStateChangeListener getOnDetachedFromWindowListener() { - return mOnDetachedFromWindowListener; - } - - public static void handleClick(View target, HippyEngineContext context, int tagId, - boolean isCustomEvent) { - if (context == null) { - return; - } - - HippyEngineMonitorAdapter monitorAdapter = context.getGlobalConfigs().getEngineMonitorAdapter(); - if (monitorAdapter != null && target != null) { - monitorAdapter.reportClickEvent(target, isCustomEvent); - } - - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_CLICK); - params.pushInt(KEY_TAG_ID, tagId); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - LogUtils.d(TAG, "send msg: " + NodeProps.ON_CLICK); - } - - public static void handleLongClick(HippyEngineContext context, int tagId) { - if (context == null) { - return; - } - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_LONG_CLICK); - params.pushInt(KEY_TAG_ID, tagId); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - } - - public static void handleAttachedToWindow(HippyEngineContext context, int tagId) { - if (context == null) { - return; - } - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(tagId, NodeProps.ON_ATTACHED_TO_WINDOW, null); - } - - public static void handleDetachedFromWindow(HippyEngineContext context, int tagId) { - if (context == null) { - return; - } - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(tagId, NodeProps.ON_DETACHED_FROM_WINDOW, null); - } - - public static void handlePressIn(HippyEngineContext context, int tagId) { - if (context == null) { - return; - } - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_PRESS_IN); - params.pushInt(KEY_TAG_ID, tagId); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - LogUtils.d(TAG, "send msg: " + NodeProps.ON_PRESS_IN); - } - - public static void handlePressOut(HippyEngineContext context, int tagId) { - if (context == null) { - return; - } - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_PRESS_OUT); - params.pushInt(KEY_TAG_ID, tagId); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - LogUtils.d(TAG, "send msg: " + NodeProps.ON_PRESS_IN); - } - - public static void handleTouchDown(HippyEngineContext context, int mTagId, float x, float y, - int viewId) { - int[] viewCoords = new int[2]; - getLocationInWindow(context, viewId, viewCoords); - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_TOUCH_DOWN); - params.pushInt(KEY_TAG_ID, mTagId); - params.pushDouble(KEY_PAGE_X, PixelUtil.px2dp(viewCoords[0] + x)); - params.pushDouble(KEY_PAGE_Y, PixelUtil.px2dp(viewCoords[1] + y)); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - } - - public static void handleTouchMove(HippyEngineContext context, int mTagId, float x, float y, - int viewId) { - int[] viewCoords = new int[2]; - getLocationInWindow(context, viewId, viewCoords); - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_TOUCH_MOVE); - params.pushInt(KEY_TAG_ID, mTagId); - params.pushDouble(KEY_PAGE_X, PixelUtil.px2dp(viewCoords[0] + x)); - params.pushDouble(KEY_PAGE_Y, PixelUtil.px2dp(viewCoords[1] + y)); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - } - - public static void handleTouchEnd(HippyEngineContext context, int mTagId, float x, float y, - int viewId) { - int[] viewCoords = new int[2]; - getLocationInWindow(context, viewId, viewCoords); - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_TOUCH_END); - params.pushInt(KEY_TAG_ID, mTagId); - params.pushDouble(KEY_PAGE_X, PixelUtil.px2dp(viewCoords[0] + x)); - params.pushDouble(KEY_PAGE_Y, PixelUtil.px2dp(viewCoords[1] + y)); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - } - - public static void handleTouchCancel(HippyEngineContext context, int mTagId, float x, float y, - int viewId) { - int[] viewCoords = new int[2]; - getLocationInWindow(context, viewId, viewCoords); - HippyMap params = new HippyMap(); - params.pushString(KEY_EVENT_NAME, NodeProps.ON_TOUCH_CANCEL); - params.pushInt(KEY_TAG_ID, mTagId); - params.pushDouble(KEY_PAGE_X, PixelUtil.px2dp(viewCoords[0] + x)); - params.pushDouble(KEY_PAGE_Y, PixelUtil.px2dp(viewCoords[1] + y)); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveNativeGesture(params); - } - -// private static void calculateViewCoords(float[] viewCoords, RenderNode node) -// { -// if (node != null) -// { -// viewCoords[0] = viewCoords[0] + node.getX(); -// viewCoords[1] = viewCoords[1] + node.getY(); -// calculateViewCoords(viewCoords, node.mParent); -// } -// } - - private static void getLocationInWindow(HippyEngineContext context, int id, int[] viewCoords) { - if (id >= 0) { - View view = context.getRenderManager().getControllerManager().findView(id); - if (view != null) { - view.getLocationInWindow(viewCoords); - } - } - } - - public boolean handleTouchEvent(MotionEvent event) { - if (mGestureProcessor == null) { - mGestureProcessor = new NativeGestureProcessor(this); - } - return mGestureProcessor.onTouchEvent(event); - } - - public void addGestureType(String type) { - if (mGestureTypes == null) { - mGestureTypes = new HashSet<>(); - } - mGestureTypes.add(type); - } - - public void removeGestureType(String type) { - if (mGestureTypes != null) { - mGestureTypes.remove(type); - } - } - - @Override - public boolean needHandle(String type) { - if (mGestureTypes != null) { - - boolean result = mGestureTypes.contains(type); - if (!result && !TextUtils.equals(type, NodeProps.ON_INTERCEPT_TOUCH_EVENT) && !TextUtils - .equals(type, NodeProps.ON_INTERCEPT_PULL_UP_EVENT)) { - if (needHandle(NodeProps.ON_INTERCEPT_TOUCH_EVENT) || needHandle( - NodeProps.ON_INTERCEPT_PULL_UP_EVENT)) { - return true; - } - } - return result; - } - return false; - } - - @Override - public void handle(String type, float x, float y) { - if (mTargetView == null) { - LogUtils.e("NativeGestureDispatcher", "handle!!! but view is null!!!!"); - return; - } - - if (TextUtils.equals(type, NodeProps.ON_PRESS_IN)) { - handlePressIn(mEngineContext, mTargetView.getId()); - } else if (TextUtils.equals(type, NodeProps.ON_PRESS_OUT)) { - handlePressOut(mEngineContext, mTargetView.getId()); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_DOWN)) { - NativeGestureDispatcher - .handleTouchDown(mEngineContext, mTargetView.getId(), x, y, mTargetView.getId()); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_MOVE)) { - NativeGestureDispatcher - .handleTouchMove(mEngineContext, mTargetView.getId(), x, y, mTargetView.getId()); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_END)) { - NativeGestureDispatcher - .handleTouchEnd(mEngineContext, mTargetView.getId(), x, y, mTargetView.getId()); - } else if (TextUtils.equals(type, NodeProps.ON_TOUCH_CANCEL)) { - NativeGestureDispatcher - .handleTouchCancel(mEngineContext, mTargetView.getId(), x, y, mTargetView.getId()); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/PullFooterRenderNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/PullFooterRenderNode.java deleted file mode 100644 index c1becc5bfc3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/PullFooterRenderNode.java +++ /dev/null @@ -1,43 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; - -@SuppressWarnings({"deprecation", "unused"}) -public class PullFooterRenderNode extends ListItemRenderNode { - - public PullFooterRenderNode(int mId, HippyMap mPropsToUpdate, String className, - HippyRootView mRootView, ControllerManager componentManager, - boolean isLazyLoad) { - super(mId, mPropsToUpdate, className, mRootView, componentManager, isLazyLoad); - } - - /** - * 通过类名的hashCode来定义type,计算出来是一个很大的值,几乎不会和前端类型重复 - */ - @Override - public int getItemViewType() { - return this.getClassName().hashCode(); - } - - @Override - public boolean isPullFooter() { - return true; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/PullHeaderRenderNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/PullHeaderRenderNode.java deleted file mode 100644 index 72d88557e5d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/PullHeaderRenderNode.java +++ /dev/null @@ -1,43 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; - -@SuppressWarnings({"deprecation", "unused"}) -public class PullHeaderRenderNode extends ListItemRenderNode { - - public PullHeaderRenderNode(int mId, HippyMap mPropsToUpdate, String className, - HippyRootView mRootView, ControllerManager componentManager, - boolean isLazyLoad) { - super(mId, mPropsToUpdate, className, mRootView, componentManager, isLazyLoad); - } - - /** - * 通过类名的hashCode来定义type,计算出来是一个很大的值,几乎不会和前端类型重复 - */ - @Override - public int getItemViewType() { - return this.getClassName().hashCode(); - } - - @Override - public boolean isPullHeader() { - return true; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/RenderManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/RenderManager.java deleted file mode 100644 index 080af324427..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/RenderManager.java +++ /dev/null @@ -1,280 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.text.TextUtils; -import android.util.SparseArray; - -import com.tencent.mtt.hippy.HippyAPIProvider; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.DomNode; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.util.ArrayList; -import java.util.List; - -@SuppressWarnings({"deprecation", "unused"}) -public class RenderManager { - - private static final String TAG = "RenderManager"; - final SparseArray mNodes = new SparseArray<>(); - - final SparseArray mPreIsLazy = new SparseArray<>(); - - final ArrayList mUIUpdateNodes = new ArrayList<>(); - final ArrayList mNullUIUpdateNodes = new ArrayList<>(); - - final HippyEngineContext mContext; - - final ControllerManager mControllerManager; - - public RenderManager(HippyEngineContext hippyContext, List packages) { - mContext = hippyContext; - mControllerManager = new ControllerManager(hippyContext, packages); - } - - public ControllerManager getControllerManager() { - return mControllerManager; - } - - public void createRootNode(int id) { - RenderNode uiNode = new RenderNode(id, NodeProps.ROOT_NODE, mControllerManager); - mNodes.put(id, uiNode); - } - - public void destroy() { - getControllerManager().destroy(); - } - - public void createNode(HippyRootView hippyRootView, int id, int pId, int childIndex, - String className, HippyMap props) { - LogUtils.d("RenderManager", - "createNode ID " + id + " mParentId " + pId + " index " + childIndex + "className" - + className); - - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"createNode ID " + id + " mParentId " + pId + " index " + childIndex + "className" + className); - RenderNode parentNode = mNodes.get(pId); - - boolean isLazy = mControllerManager.isControllerLazy(className); - RenderNode uiNode = mControllerManager - .createRenderNode(id, props, className, hippyRootView, isLazy || parentNode.mIsLazyLoad); - - mNodes.put(id, uiNode); - - mPreIsLazy.remove(id); - - parentNode.addChild(uiNode, childIndex); - - addUpdateNodeIfNeeded(parentNode); - - addUpdateNodeIfNeeded(uiNode); - } - - public void addUpdateNodeIfNeeded(RenderNode renderNode) { - if (!mUIUpdateNodes.contains(renderNode)) { - if (null != renderNode) { - mUIUpdateNodes.add(renderNode); - } - } - } - - void addNullUINodeIfNeeded(RenderNode renderNode) { - if (!mNullUIUpdateNodes.contains(renderNode)) { - mNullUIUpdateNodes.add(renderNode); - } - } - - public void updateLayout(int id, int x, int y, int w, int h) { - LogUtils.d("RenderManager", "updateLayout ID " + id); - RenderNode uiNode = mNodes.get(id); - uiNode.updateLayout(x, y, w, h); - - addUpdateNodeIfNeeded(uiNode); - } - - public void updateNode(int id, HippyMap map) { - LogUtils.d("RenderManager", "updateNode ID " + id); - RenderNode uiNode = mNodes.get(id); - uiNode.updateNode(map); - addUpdateNodeIfNeeded(uiNode); - } - - public void moveNode(ArrayList moveIds, int pId, int id) { - - RenderNode parentNode = mNodes.get(pId); - RenderNode newParent = mNodes.get(id); - List arrayList = new ArrayList<>(); - - for (int i = 0; i < moveIds.size(); i++) { - RenderNode renderNode = mNodes.get(moveIds.get(i)); - arrayList.add(renderNode); - parentNode.removeChild(renderNode); - newParent.addChild(renderNode, i); - } - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"render moveNode pId:" + pId+" id: "+id+" moveids:"+moveIds.toString()); - parentNode.move(arrayList, id); - addUpdateNodeIfNeeded(newParent); - } - - public void updateExtra(int id, Object object) { - LogUtils.d("RenderManager", "updateExtra ID " + id); - RenderNode uiNode = mNodes.get(id); - uiNode.updateExtra(object); - - addUpdateNodeIfNeeded(uiNode); - } - - public void deleteNode(int id) { - RenderNode uiNode = mNodes.get(id); - uiNode.setDelete(true); - - if (uiNode.mParent != null && mControllerManager.hasView(id)) { - uiNode.mParent.addDeleteId(id, uiNode); - addUpdateNodeIfNeeded(uiNode.mParent); - } else if (TextUtils.equals(NodeProps.ROOT_NODE, uiNode.getClassName())) { - addUpdateNodeIfNeeded(uiNode); - } - deleteSelfFromParent(uiNode); - - } - - public void dispatchUIFunction(int id, String functionName, HippyArray var, Promise promise) { - RenderNode renderNode = mNodes.get(id); - if (renderNode != null) { - renderNode.dispatchUIFunction(functionName, var, promise); - addNullUINodeIfNeeded(renderNode); - } else { - LogUtils.d("RenderManager", "dispatchUIFunction Node Null"); - } - - } - - public void nonUIBatchEnd() { - LogUtils.d("RenderManager", "do nonUIBatchEnd size " + mUIUpdateNodes.size()); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"do nonUIBatchEnd size " + mShouldUpdateNodes.size()); - - for (int i = 0; i < mUIUpdateNodes.size(); i++) { - mUIUpdateNodes.get(i).createView(); - } - for (int i = 0; i < mUIUpdateNodes.size(); i++) { - RenderNode uiNode = mUIUpdateNodes.get(i); - uiNode.update(); - } - - mUIUpdateNodes.clear(); - } - - public void batch() { - LogUtils.d("RenderManager", "do batch size " + mUIUpdateNodes.size()); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"do batch size " + mShouldUpdateNodes.size()); - - for (int i = 0; i < mUIUpdateNodes.size(); i++) { - mUIUpdateNodes.get(i).createView(); - } - - for (int i = 0; i < mUIUpdateNodes.size(); i++) { - RenderNode uiNode = mUIUpdateNodes.get(i); - uiNode.update(); - } - - for (int i = 0; i < mUIUpdateNodes.size(); i++) { - RenderNode uiNode = mUIUpdateNodes.get(i); - uiNode.batchComplete(); - } - - mUIUpdateNodes.clear(); - // measureInWindow and dispatch ui function - for (int i = 0; i < mNullUIUpdateNodes.size(); i++) { - mNullUIUpdateNodes.get(i).createView(); - } - for (int i = 0; i < mNullUIUpdateNodes.size(); i++) { - mNullUIUpdateNodes.get(i).update(); - } - - mNullUIUpdateNodes.clear(); - } - - private void deleteSelfFromParent(RenderNode uiNode) { - - LogUtils.d("RenderManager", "delete RenderNode " + uiNode.mId + " class " + uiNode.mClassName); - // mContext.getGlobalConfigs().getLogAdapter().log(TAG,"delete RenderNode " + uiNode.mId + " class " + uiNode.mClassName); - if (uiNode.mParent != null) { - uiNode.mParent.removeChild(uiNode); - } - - mNodes.remove(uiNode.mId); - - int childCount = uiNode.getChildCount(); - for (int i = 0; i < childCount; i++) { - deleteSelfFromParent(uiNode.getChildAt(0)); - } - } - - public DomNode createStyleNode(String className, boolean isVirtual, int id, int rootId) { - DomNode domNode = mControllerManager.createStyleNode(className, isVirtual, rootId); - domNode.setViewClassName(className); - domNode.setId(id); - return domNode; - } - - public RenderNode getRenderNode(int id) { - try { - return mNodes.get(id); - } catch (Exception e) { - return null; - } - } - - public void replaceID(int oldId, int newId) { - mControllerManager.replaceID(oldId, newId); - } - - - public void measureInWindow(int id, Promise promise) { - RenderNode renderNode = mNodes.get(id); - if (renderNode == null) { - promise.reject("this view is null"); - } else { - renderNode.measureInWindow(promise); - - addNullUINodeIfNeeded(renderNode); - } - - } - - public void createPreView(HippyRootView hippyRootView, int id, int pid, int mIndex, - String className, HippyMap newProps) { - - boolean isLazy = mControllerManager.isControllerLazy(className); - - RenderNode parentNode = mNodes.get(pid); - if (parentNode != null) { - isLazy = isLazy || parentNode.mIsLazyLoad; - } else { - isLazy = isLazy || mPreIsLazy.get(pid); - } - mPreIsLazy.put(id, isLazy); - - if (!isLazy) { - mControllerManager.createPreView(hippyRootView, id, className, newProps); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/RenderNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/RenderNode.java deleted file mode 100644 index 9e59bf7a8bd..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/RenderNode.java +++ /dev/null @@ -1,450 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.text.TextUtils; -import android.util.SparseArray; -import android.view.View; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.utils.LogUtils; - -import java.util.*; - -@SuppressWarnings({"deprecation", "unused"}) -public class RenderNode { - - final int mId; - int mX; - int mY; - int mWidth; - int mHeight; - - boolean mHasUpdateLayout = false; - HippyMap mProps = null; - HippyMap mPropsToUpdate; - final String mClassName; - final List mChildren = new ArrayList<>(); - - List mMoveHolders = null; - - SparseArray mDeletedIdIndexMap; - - List mMeasureInWindows = null; - Object mTextExtra; - Object mTextExtraUpdate; - - HippyRootView mRootView; - - final ControllerManager mComponentManager; - - - RenderNode mParent = null; - - boolean mIsDelete = false; - boolean mIsRootHasDelete = false; - - - boolean mIsLazyLoad = false; - - boolean mNotifyManageChildren = false; - - public boolean mHasSetDteblId = false; - - List mUIFunction = null; - - public RenderNode getParent() { - return mParent; - } - - int indexFromParent() { - if (mParent != null) { - return mParent.mChildren.indexOf(this); - } - return 0; - } - - @Override - public String toString() { - StringBuilder stringBuilder = new StringBuilder(); - printChild(this, stringBuilder); - return stringBuilder.toString(); - } - - void printChild(RenderNode renderNode, StringBuilder stringBuilder) { - stringBuilder.append(" [Id:").append(renderNode.getId()).append(renderNode.mClassName); - for (RenderNode child : renderNode.mChildren) { - printChild(child, stringBuilder); - } - stringBuilder.append("]"); - } - - public RenderNode(int mId, HippyMap mPropsToUpdate, String className, HippyRootView rootView, - ControllerManager componentManager, - boolean isLazyLoad) { - this.mId = mId; - this.mPropsToUpdate = mPropsToUpdate; - this.mClassName = className; - this.mRootView = rootView; - this.mComponentManager = componentManager; - this.mIsLazyLoad = isLazyLoad; - this.mProps = mPropsToUpdate; - } - - public void addDeleteId(int id, RenderNode node) { - if (shouldUpdateView()) { - if (mDeletedIdIndexMap == null) { - mDeletedIdIndexMap = new SparseArray<>(); - } - mDeletedIdIndexMap.put(id, mChildren.indexOf(node)); - } - } - - public int getId() { - return mId; - } - - - public View createViewRecursive() { - View view = createView(); - mHasUpdateLayout = true; - mTextExtraUpdate = mTextExtra; - for (RenderNode renderNode : mChildren) { - renderNode.createViewRecursive(); - } - return view; - } - - public void updateViewRecursive() { - update(); - - for (RenderNode renderNode : mChildren) { - renderNode.updateViewRecursive(); - } - } - - - public boolean removeChild(RenderNode uiNode) { - uiNode.mParent = null; - return mChildren.remove(uiNode); - } - - void addChild(RenderNode uiNode, int index) { - mChildren.add(index, uiNode); - uiNode.mParent = this; - } - - void setLazy(RenderNode node, boolean isLazy) { - node.mIsLazyLoad = isLazy; - for (int i = 0; i < node.getChildCount(); i++) { - setLazy(node.getChildAt(i), isLazy); - } - } - - public void setLazy(boolean isLazy) { - setLazy(this, isLazy); - } - - public void remove(int index) { - RenderNode uiNode = mChildren.remove(index); - uiNode.mParent = null; - } - - public RenderNode getChildAt(int index) { - if (0 <= index && index < getChildCount()) { - return mChildren.get(index); - } - return null; - } - - public int getChildCount() { - return mChildren.size(); - } - - public RenderNode(int id, String className, ControllerManager componentManager) { - this.mId = id; - this.mClassName = className; - this.mComponentManager = componentManager; - } - - public void updateNode(HippyMap map) { - if (mPropsToUpdate != null) { - //mProps do not syc to UI - HippyMap hippyMap = DiffUtils.diffProps(mPropsToUpdate, map, 0); - if (hippyMap != null && hippyMap.size() > 0) { - Set sets = hippyMap.keySet(); - for (String key : sets) { - if (TextUtils.equals(NodeProps.STYLE, key)) { - HippyMap styles = hippyMap.getMap(key); - if (styles != null) { - HippyMap stylesToUpdate = mPropsToUpdate.getMap(key); - if (stylesToUpdate == null) { - stylesToUpdate = new HippyMap(); - } - Set styleKeys = styles.keySet(); - for (String styleKey : styleKeys) { - stylesToUpdate.pushObject(styleKey, styles.get(styleKey)); - } - - mPropsToUpdate.pushObject(key, stylesToUpdate); - } - } else { - mPropsToUpdate.pushObject(key, hippyMap.get(key)); - } - - } - } - } else { - mPropsToUpdate = DiffUtils.diffProps(mProps, map, 0); - } - - mProps = map; - } - - public HippyMap getProps() { - return mProps; - } - - private boolean shouldCreateView() { - return !mIsLazyLoad && !mComponentManager.hasView(mId); - } - - public String getClassName() { - return mClassName; - } - - public int getX() { - return mX; - } - - public int getY() { - return mY; - } - - public int getWidth() { - return mWidth; - } - - public int getHeight() { - return mHeight; - } - - final List mChildPendingList = new ArrayList<>(); - - public View createView() { - //delete is first when js call delete and create the same node if delete is not call the ui cannot create - if (mDeletedIdIndexMap != null && mDeletedIdIndexMap.size() > 0) { - for (int i = 0; i < mDeletedIdIndexMap.size(); i++) { - int key = mDeletedIdIndexMap.keyAt(i); - mComponentManager - .deleteChild(mId, mDeletedIdIndexMap.keyAt(i), mDeletedIdIndexMap.get(key)); - } - mDeletedIdIndexMap.clear(); - mNotifyManageChildren = true; - } - - if (mIsDelete && TextUtils.equals(NodeProps.ROOT_NODE, mClassName) && !mIsRootHasDelete) { - mIsRootHasDelete = true; - mComponentManager.deleteRootView(mId); - } - if (shouldCreateView() && !TextUtils.equals(NodeProps.ROOT_NODE, mClassName) - && mParent != null) { - mPropsToUpdate = null; - mParent.addChildToPendingList(this); - return mComponentManager.createView(mRootView, mId, mClassName, mProps); - - } - return null; - } - - private boolean shouldUpdateView() { - return mComponentManager.hasView(mId); - } - - - protected void addChildToPendingList(RenderNode renderNode) { - mChildPendingList.add(renderNode); - } - - public void update() { - LogUtils.d("UINode", "mId" + mId + " updateStyle"); - - // long time = System.currentTimeMillis(); - if (shouldUpdateView()) { - if (mChildPendingList.size() > 0) { - Collections.sort(mChildPendingList, new Comparator() { - @Override - public int compare(RenderNode o1, RenderNode o2) { - return o1.indexFromParent() < o2.indexFromParent() ? -1 : 0; - } - }); - for (int i = 0; i < mChildPendingList.size(); i++) { - RenderNode renderNode = mChildPendingList.get(i); - mComponentManager.addChild(mId, renderNode.getId(), renderNode.indexFromParent()); - } - mChildPendingList.clear(); - mNotifyManageChildren = true; - } - if (mPropsToUpdate != null) { - mComponentManager.updateView(mId, mClassName, mPropsToUpdate); - mPropsToUpdate = null; - } - if (mMoveHolders != null) { - for (MoveHolder moveHolder : mMoveHolders) { - Collections.sort(moveHolder.mMoveIds, new Comparator() { - @Override - public int compare(RenderNode o1, RenderNode o2) { - return o1.indexFromParent() < o2.indexFromParent() ? -1 : 0; - } - }); - - for (int j = 0; j < moveHolder.mMoveIds.size(); j++) { - RenderNode moveId = moveHolder.mMoveIds.get(j); - mComponentManager.move(moveId.getId(), moveHolder.mMove2Id, moveId.indexFromParent()); - } - } - mMoveHolders = null; - } - - if (mHasUpdateLayout && !TextUtils.equals(NodeProps.ROOT_NODE, mClassName)) { - mComponentManager.updateLayout(mClassName, mId, mX, mY, mWidth, mHeight); - LogUtils.d("UINode", "mId" + mId + " updateLayout"); - mHasUpdateLayout = false; - } - if (mTextExtraUpdate != null) { - mComponentManager.updateExtra(mId, mClassName, mTextExtraUpdate); - mTextExtraUpdate = null; - } - - if (mUIFunction != null && mUIFunction.size() > 0) { - for (int i = 0; i < mUIFunction.size(); i++) { - UIFunction uiFunction = mUIFunction.get(i); - mComponentManager - .dispatchUIFunction(mId, mClassName, uiFunction.mFunctionName, uiFunction.mParameter, - uiFunction.mPromise); - } - mUIFunction.clear(); - mUIFunction = null; - } - if (mMeasureInWindows != null && mMeasureInWindows.size() > 0) { - for (int i = 0; i < mMeasureInWindows.size(); i++) { - Promise promise = mMeasureInWindows.get(i); - mComponentManager.measureInWindow(mId, promise); - } - mMeasureInWindows.clear(); - mMeasureInWindows = null; - - } - if (mNotifyManageChildren) { - manageChildrenComplete(); - mNotifyManageChildren = false; - } - - } - LogUtils.d("UINode", "mId" + mId + " end updateStyle"); - } - - - public void updateLayout(int x, int y, int w, int h) { - this.mX = x; - this.mY = y; - this.mWidth = w; - this.mHeight = h; - mHasUpdateLayout = true; - } - - public void measureInWindow(Promise promise) { - if (mMeasureInWindows == null) { - mMeasureInWindows = new ArrayList<>(); - } - mMeasureInWindows.add(promise); - } - - - static class MoveHolder { - - public MoveHolder(List moveRenders, int mMove2Id) { - this.mMoveIds = moveRenders; - this.mMove2Id = mMove2Id; - } - - final List mMoveIds; - final int mMove2Id; - } - - public void move(List moveIds, int move2Id) { - if (shouldUpdateView()) { - if (mMoveHolders == null) { - mMoveHolders = new ArrayList<>(); - } - mMoveHolders.add(new MoveHolder(moveIds, move2Id)); - } - } - - public void updateExtra(Object object) { - mTextExtra = object; - mTextExtraUpdate = object; - } - - - public void setDelete(boolean b) { - mIsDelete = b; - } - - public boolean isDelete() { - return mIsDelete; - } - - public void batchComplete() { - if (!mIsLazyLoad && !mIsDelete) { - mComponentManager.onBatchComplete(mClassName, mId); - } - } - - public void manageChildrenComplete() { - if (!mIsLazyLoad && !mIsDelete) { - mComponentManager.onManageChildComplete(mClassName, mId); - } - } - - static class UIFunction { - - public UIFunction(String functionName, HippyArray parameter, Promise promise) { - this.mFunctionName = functionName; - this.mParameter = parameter; - this.mPromise = promise; - } - - final String mFunctionName; - final HippyArray mParameter; - final Promise mPromise; - } - - - public void dispatchUIFunction(String functionName, HippyArray parameter, Promise promise) { - if (mUIFunction == null) { - mUIFunction = new ArrayList<>(); - } - mUIFunction.add(new UIFunction(functionName, parameter, promise)); - } - - public boolean isIsLazyLoad() { - return mIsLazyLoad; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/TransformUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/TransformUtil.java deleted file mode 100644 index f733c929f2d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/TransformUtil.java +++ /dev/null @@ -1,125 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; - -@SuppressWarnings({"deprecation", "unused"}) -public class TransformUtil { - - private static final ThreadLocal sHelperMatrix = new ThreadLocal() { - @Override - protected double[] initialValue() { - return new double[16]; - } - }; - - private static double convertToRadians(HippyMap transformMap, String key) { - double value = 0; - boolean inRadians = true; - if (transformMap.get(key) instanceof String) { - String stringValue = (String) transformMap.get(key); - if (stringValue.endsWith("deg")) { - inRadians = false; - } - if (stringValue.endsWith("rad") || stringValue.endsWith("deg")) { - stringValue = stringValue.substring(0, stringValue.length() - 3); - } - value = Float.parseFloat(stringValue); - } else if (transformMap.get(key) instanceof Number) { - value = ((Number) transformMap.get(key)).doubleValue(); - } - return inRadians ? value : MatrixUtil.degreesToRadians(value); - } - - public static void processTransform(HippyArray transforms, double[] result) { - double[] helperMatrix = sHelperMatrix.get(); - MatrixUtil.resetIdentityMatrix(result); - - for (int transformIdx = 0, size = transforms.size(); transformIdx < size; transformIdx++) { - HippyMap transform = transforms.getMap(transformIdx); - String transformType = transform.keySet().iterator().next(); - - assert helperMatrix != null; - MatrixUtil.resetIdentityMatrix(helperMatrix); - Object value = transform.get(transformType); - if ("matrix".equals(transformType) && value instanceof HippyArray) { - HippyArray matrix = (HippyArray) value; - for (int i = 0; i < 16; i++) { - Object matrixValue = matrix.getObject(i); - if (matrixValue instanceof Number) { - helperMatrix[i] = ((Number) matrixValue).doubleValue(); - } - } - } else if ("perspective".equals(transformType) && value instanceof Number) { - MatrixUtil.applyPerspective(helperMatrix, ((Number) value).doubleValue()); - } else if ("rotateX".equals(transformType)) { - MatrixUtil.applyRotateX(helperMatrix, convertToRadians(transform, transformType)); - } else if ("rotateY".equals(transformType)) { - MatrixUtil.applyRotateY(helperMatrix, convertToRadians(transform, transformType)); - } else if ("rotate".equals(transformType) || "rotateZ".equals(transformType)) { - MatrixUtil.applyRotateZ(helperMatrix, convertToRadians(transform, transformType)); - } else if ("scale".equals(transformType) && value instanceof Number) { - double scale = ((Number) value).doubleValue(); - MatrixUtil.applyScaleX(helperMatrix, scale); - MatrixUtil.applyScaleY(helperMatrix, scale); - } else if ("scaleX".equals(transformType) && value instanceof Number) { - MatrixUtil.applyScaleX(helperMatrix, ((Number) value).doubleValue()); - } else if ("scaleY".equals(transformType)) { - MatrixUtil.applyScaleY(helperMatrix, ((Number) value).doubleValue()); - } else if ("translate".equals(transformType) && value instanceof HippyArray) { - double x = 0d, y = 0d, z = 0d; - - if (((HippyArray) value).size() > 0) { - Object tranX = ((HippyArray) value).getObject(0); - if (tranX instanceof Number) { - x = ((Number) tranX).doubleValue(); - } - } - - if (((HippyArray) value).size() > 1) { - Object tranY = ((HippyArray) value).getObject(1); - if (tranY instanceof Number) { - y = ((Number) tranY).doubleValue(); - } - } - - if (((HippyArray) value).size() > 2) { - Object tranZ = ((HippyArray) value).getObject(2); - if (tranZ instanceof Number) { - z = ((Number) tranZ).doubleValue(); - } - } - MatrixUtil.applyTranslate3D(helperMatrix, x, y, z); - } else if ("translateX".equals(transformType) && value instanceof Number) { - MatrixUtil.applyTranslate2D(helperMatrix, ((Number) value).doubleValue(), 0d); - } else if ("translateY".equals(transformType) && value instanceof Number) { - MatrixUtil.applyTranslate2D(helperMatrix, 0d, ((Number) value).doubleValue()); - } else if ("skewX".equals(transformType)) { - MatrixUtil.applySkewX(helperMatrix, convertToRadians(transform, transformType)); - } else if ("skewY".equals(transformType)) { - MatrixUtil.applySkewY(helperMatrix, convertToRadians(transform, transformType)); - } else { - RuntimeException runtimeException = new RuntimeException( - "Unsupported transform type: " + transformType); - runtimeException.printStackTrace(); - } - - MatrixUtil.multiplyInto(result, result, helperMatrix); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ViewGroupDrawingOrderHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ViewGroupDrawingOrderHelper.java deleted file mode 100644 index d5713b6fb46..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/ViewGroupDrawingOrderHelper.java +++ /dev/null @@ -1,108 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.uimanager; - -import android.view.View; -import android.view.ViewGroup; - -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.views.view.HippyViewGroupController; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; - -public class ViewGroupDrawingOrderHelper { - - private final ViewGroup mViewGroup; - private int mNumberOfChildrenWithZIndex = 0; - private int[] mDrawingOrderIndices; - - public ViewGroupDrawingOrderHelper(ViewGroup viewGroup) { - mViewGroup = viewGroup; - } - - - public void handleAddView(View view) { - if (HippyViewGroupController.getViewZIndex(view) != null) { - mNumberOfChildrenWithZIndex++; - } - - mDrawingOrderIndices = null; - } - - - public void handleRemoveView(View view) { - if (HippyViewGroupController.getViewZIndex(view) != null) { - mNumberOfChildrenWithZIndex--; - } - - mDrawingOrderIndices = null; - } - - - public boolean shouldEnableCustomDrawingOrder() { - return mNumberOfChildrenWithZIndex > 0; - } - - - public int getChildDrawingOrder(int childCount, int index) { - if (mDrawingOrderIndices == null) { - ArrayList viewsToSort = new ArrayList<>(); - for (int i = 0; i < childCount; i++) { - viewsToSort.add(mViewGroup.getChildAt(i)); - } - // Sort the views by zIndex - Collections.sort(viewsToSort, new Comparator() { - @Override - public int compare(View view1, View view2) { - Integer view1ZIndex = HippyViewGroupController.getViewZIndex(view1); - if (view1ZIndex == null) { - view1ZIndex = 0; - } - - Integer view2ZIndex = HippyViewGroupController.getViewZIndex(view2); - if (view2ZIndex == null) { - view2ZIndex = 0; - } - - return view1ZIndex - view2ZIndex; - } - }); - - mDrawingOrderIndices = new int[childCount]; - for (int i = 0; i < childCount; i++) { - View child = viewsToSort.get(i); - mDrawingOrderIndices[i] = mViewGroup.indexOfChild(child); - } - } - if (index >= mDrawingOrderIndices.length) { - LogUtils.d("VGDrawingOrderHelper", "WRONG, index out of mDrawingOrderIndices length"); - return 0; - } - return mDrawingOrderIndices[index]; - } - - public void update() { - mNumberOfChildrenWithZIndex = 0; - for (int i = 0; i < mViewGroup.getChildCount(); i++) { - if (HippyViewGroupController.getViewZIndex(mViewGroup.getChildAt(i)) != null) { - mNumberOfChildrenWithZIndex++; - } - } - mDrawingOrderIndices = null; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/ContextHolder.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/ContextHolder.java deleted file mode 100644 index c2b7701489e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/ContextHolder.java +++ /dev/null @@ -1,33 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -import android.content.Context; - -public class ContextHolder { - - private static Context appContext; - - public static void initAppContext(Context context) { - if (context != null && appContext == null) { - appContext = context.getApplicationContext(); - } - } - - public static Context getAppContext() { - return appContext; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/DimensionsUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/DimensionsUtil.java deleted file mode 100644 index 9ede14aab49..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/DimensionsUtil.java +++ /dev/null @@ -1,219 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.os.Build; -import android.provider.Settings; -import androidx.annotation.NonNull; -import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.view.Display; -import android.view.WindowManager; - -import com.tencent.mtt.hippy.common.HippyMap; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -@SuppressWarnings("deprecation") -public class DimensionsUtil { - - private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"; - private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"; - private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; - private static int STATUS_BAR_HEIGHT = -1; - - private static String getNavigationBarIsMinKeyName() { - String brand = Build.BRAND; - if (TextUtils.isEmpty(brand)) { - return "navigationbar_is_min"; - } - - if (brand.equalsIgnoreCase("HUAWEI")) { - return "navigationbar_is_min"; - } else if (brand.equalsIgnoreCase("XIAOMI")) { - return "force_fsg_nav_bar"; - } else if (brand.equalsIgnoreCase("VIVO")) { - return "navigation_gesture_on"; - } else if (brand.equalsIgnoreCase("OPPO")) { - return "navigation_gesture_on"; - } else { - return "navigationbar_is_min"; - } - } - - private static boolean checkNavigationBarShow(@NonNull Context context) { - boolean checkResult = false; - Resources rs = context.getResources(); - int id = rs.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android"); - if (id > 0) { - checkResult = rs.getBoolean(id); - } - try { - @SuppressWarnings("rawtypes") Class systemPropertiesClass = Class - .forName("android.os.SystemProperties"); - @SuppressWarnings("unchecked") Method m = systemPropertiesClass - .getMethod("get", String.class); - String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys"); - //判断是否隐藏了底部虚拟导航 - int navigationBarIsMin; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - navigationBarIsMin = Settings.System.getInt(context.getContentResolver(), - getNavigationBarIsMinKeyName(), 0); - } else { - navigationBarIsMin = Settings.Global.getInt(context.getContentResolver(), - getNavigationBarIsMinKeyName(), 0); - } - if ("1".equals(navBarOverride) || 1 == navigationBarIsMin) { - checkResult = false; - } else if ("0".equals(navBarOverride)) { - checkResult = true; - } - } catch (Exception e) { - e.printStackTrace(); - } - - return checkResult; - } - - /** - * 获取虚拟按键的高度 1. 全面屏下 1.1 开启全面屏开关-返回0 1.2 关闭全面屏开关-执行非全面屏下处理方式 2. 非全面屏下 2.1 没有虚拟键-返回0 2.1 虚拟键隐藏-返回0 - * 2.2 虚拟键存在且未隐藏-返回虚拟键实际高度 - */ - public static int getNavigationBarHeight(Context context) { - assert (context != null); - - //noinspection ConstantConditions - if (context == null || !checkNavigationBarShow(context)) { - return 0; - } - - String navBarHeightIdentifier = (context.getResources().getConfiguration().orientation - != Configuration.ORIENTATION_LANDSCAPE) - ? NAV_BAR_HEIGHT_RES_NAME : NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME; - - int result = 0; - try { - int resourceId = context.getResources() - .getIdentifier(navBarHeightIdentifier, "dimen", "android"); - result = context.getResources().getDimensionPixelSize(resourceId); - } catch (NotFoundException e) { - LogUtils.d("DimensionsUtil", "getNavigationBarHeight: " + e.getMessage()); - } - return result; - } - - public static HippyMap getDimensions(int windowWidth, int windowHeight, Context context, - boolean shouldUseScreenDisplay) { - if (context == null) { - return null; - } - - DisplayMetrics windowDisplayMetrics = context.getResources().getDisplayMetrics(); - DisplayMetrics screenDisplayMetrics = new DisplayMetrics(); - screenDisplayMetrics.setTo(windowDisplayMetrics); - WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - Display defaultDisplay = windowManager.getDefaultDisplay(); - if (Build.VERSION.SDK_INT >= 17) { - defaultDisplay.getRealMetrics(screenDisplayMetrics); - } else { - try { - @SuppressWarnings("JavaReflectionMemberAccess") Method mGetRawH = Display.class - .getMethod("getRawHeight"); - @SuppressWarnings("JavaReflectionMemberAccess") Method mGetRawW = Display.class - .getMethod("getRawWidth"); - - Object width = mGetRawW.invoke(defaultDisplay); - screenDisplayMetrics.widthPixels = width != null ? (Integer) width : 0; - - Object height = mGetRawH.invoke(defaultDisplay); - screenDisplayMetrics.heightPixels = height != null ? (Integer) height : 0; - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - // construct param - HippyMap dimensionMap = new HippyMap(); - if (STATUS_BAR_HEIGHT < 0) { - Class c; - Object obj; - Field field; - int x; - try { - c = Class.forName("com.android.internal.R$dimen"); - obj = c.newInstance(); - field = c.getField("status_bar_height"); - //noinspection ConstantConditions - x = Integer.parseInt(field.get(obj).toString()); - STATUS_BAR_HEIGHT = context.getResources().getDimensionPixelSize(x); - } catch (Exception e) { - STATUS_BAR_HEIGHT = -1; - e.printStackTrace(); - } - - if (STATUS_BAR_HEIGHT < 1) { - try { - int statebarH_id = context.getResources() - .getIdentifier("statebar_height", "dimen", context.getPackageName()); - STATUS_BAR_HEIGHT = Math.round(context.getResources().getDimension(statebarH_id)); - } catch (NotFoundException e) { - LogUtils.d("DimensionsUtil", "getDimensions: " + e.getMessage()); - } - } - } - - int navigationBarHeight = getNavigationBarHeight(context); - HippyMap windowDisplayMetricsMap = new HippyMap(); - - if (shouldUseScreenDisplay) { - windowDisplayMetricsMap - .pushInt("width", windowWidth >= 0 ? windowWidth : screenDisplayMetrics.widthPixels); - windowDisplayMetricsMap - .pushInt("height", windowHeight >= 0 ? windowHeight : screenDisplayMetrics.heightPixels); - windowDisplayMetricsMap.pushDouble("scale", screenDisplayMetrics.density); - windowDisplayMetricsMap.pushDouble("fontScale", screenDisplayMetrics.scaledDensity); - windowDisplayMetricsMap.pushDouble("densityDpi", screenDisplayMetrics.densityDpi); - } else { - windowDisplayMetricsMap - .pushInt("width", windowWidth >= 0 ? windowWidth : windowDisplayMetrics.widthPixels); - windowDisplayMetricsMap - .pushInt("height", windowHeight >= 0 ? windowHeight : windowDisplayMetrics.heightPixels); - windowDisplayMetricsMap.pushDouble("scale", windowDisplayMetrics.density); - windowDisplayMetricsMap.pushDouble("fontScale", windowDisplayMetrics.scaledDensity); - windowDisplayMetricsMap.pushDouble("densityDpi", windowDisplayMetrics.densityDpi); - } - windowDisplayMetricsMap.pushDouble("statusBarHeight", STATUS_BAR_HEIGHT); - windowDisplayMetricsMap.pushDouble("navigationBarHeight", navigationBarHeight); - dimensionMap.pushMap("windowPhysicalPixels", windowDisplayMetricsMap); - - HippyMap screenDisplayMetricsMap = new HippyMap(); - screenDisplayMetricsMap.pushInt("width", screenDisplayMetrics.widthPixels); - screenDisplayMetricsMap.pushInt("height", screenDisplayMetrics.heightPixels); - screenDisplayMetricsMap.pushDouble("scale", screenDisplayMetrics.density); - screenDisplayMetricsMap.pushDouble("fontScale", screenDisplayMetrics.scaledDensity); - screenDisplayMetricsMap.pushDouble("densityDpi", screenDisplayMetrics.densityDpi); - screenDisplayMetricsMap.pushDouble("statusBarHeight", STATUS_BAR_HEIGHT); - screenDisplayMetricsMap.pushDouble("navigationBarHeight", navigationBarHeight); - - dimensionMap.pushMap("screenPhysicalPixels", screenDisplayMetricsMap); - return dimensionMap; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/HippyViewUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/HippyViewUtil.java deleted file mode 100644 index 73dc206290f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/HippyViewUtil.java +++ /dev/null @@ -1,52 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -import android.view.View; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewItem; - -public class HippyViewUtil { - - public static HippyEngineContext getEngineContext(View view) { - if (view.getContext() instanceof HippyInstanceContext) { - return ((HippyInstanceContext) view.getContext()).getEngineContext(); - } - return null; - } - - public static RenderNode getRenderNode(View view) { - HippyEngineContext engineContext = getEngineContext(view); - if (engineContext != null) { - return engineContext.getRenderManager().getRenderNode(getNodeId(view)); - } - return null; - } - - public static int getNodeId(View view) { - if (view instanceof RecyclerViewItem) { - View child = ((RecyclerViewItem) view).getChildAt(0); - if (child != null) { - return child.getId(); - } - } - return view.getId(); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/LogUtils.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/LogUtils.java deleted file mode 100644 index e18eb1e5443..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/LogUtils.java +++ /dev/null @@ -1,89 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -import android.util.Log; - -import com.tencent.mtt.hippy.BuildConfig; - -@SuppressWarnings({"unused"}) -public class LogUtils { - - private static boolean DEBUG_ENABLE = BuildConfig.DEBUG; - - public static void enableDebugLog(boolean debuggable) { - DEBUG_ENABLE = debuggable; - } - - public static void d(String tag, String msg) { - if (DEBUG_ENABLE) { - Log.d(tag, msg); - } - } - - public static void l(String tag, String msg) { - if (!DEBUG_ENABLE) { - return; - } - - int index = 0; // 当前位置 - int max = 3800;// 需要截取的最大长度,别用4000 - String sub; // 进行截取操作的string - while (index < msg.length()) { - if (msg.length() < max) { // 如果长度比最大长度小 - max = msg.length(); // 最大长度设为length,全部截取完成. - sub = msg.substring(index, max); - } else { - sub = msg.substring(index, max); - } - Log.i(tag, sub); - index = max; - max += 3800; - } - } - - public static void d(String tag, String msg, Throwable throwable) { - if (DEBUG_ENABLE) { - Log.d(tag, msg, throwable); - } - } - - public static void w(String tag, String msg) { - if (DEBUG_ENABLE) { - Log.w(tag, msg); - } - } - - public static void i(String tag, String msg) { - if (DEBUG_ENABLE) { - Log.i(tag, msg); - } - } - - public static void v(String tag, String msg) { - if (DEBUG_ENABLE) { - Log.v(tag, msg); - } - } - - public static void e(String tag, String msg) { - Log.e(tag, msg); - } - - public static void e(String tag, String msg, Throwable e) { - Log.e(tag, msg, e); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/PixelUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/PixelUtil.java deleted file mode 100644 index f8992a7da98..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/PixelUtil.java +++ /dev/null @@ -1,58 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -import android.util.DisplayMetrics; -import android.util.TypedValue; - -@SuppressWarnings({"unused"}) -public class PixelUtil { - - static DisplayMetrics sMetrics = null; - - - private static DisplayMetrics getMetrics() { - if (sMetrics == null) { - sMetrics = ContextHolder.getAppContext().getResources().getDisplayMetrics(); - } - return sMetrics; - } - - - public static float dp2px(float value) { - return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getMetrics()); - } - - public static float dp2px(double value) { - return dp2px((float) value); - } - - public static float px2dp(float value) { - return value / getMetrics().density; - } - - public static float sp2px(float value) { - return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, value, getMetrics()); - } - - public static float px2sp(float value) { - return value / getMetrics().scaledDensity; - } - - public static float getDensity() { - return getMetrics().density; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java deleted file mode 100644 index 15e333285f6..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java +++ /dev/null @@ -1,90 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -import android.os.SystemClock; -import android.text.TextUtils; -import com.tencent.mtt.hippy.adapter.monitor.HippyEngineMonitorEvent; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class TimeMonitor { - - long mStartTime; - int mTotalTime; - final boolean mEnable; - HippyEngineMonitorEvent mCurrentEvent; - List mEvents; - - public TimeMonitor(boolean enable) { - mEnable = enable; - } - - public void startEvent(String event) { - if (!mEnable) { - return; - } - if (mCurrentEvent != null) { - mCurrentEvent.endTime = System.currentTimeMillis(); - mEvents.add(mCurrentEvent); - LogUtils.d("hippy", "hippy endEvent: " + mCurrentEvent.eventName); - } - - if (TextUtils.isEmpty(event)) { - return; - } - - mCurrentEvent = new HippyEngineMonitorEvent(); - mCurrentEvent.eventName = event; - mCurrentEvent.startTime = System.currentTimeMillis(); - LogUtils.d("hippy", "hippy startEvent: " + event); - } - - public void begine() { - if (!mEnable) { - return; - } - mStartTime = SystemClock.elapsedRealtime(); - mCurrentEvent = null; - if (mEvents == null) { - mEvents = Collections.synchronizedList(new ArrayList()); - } - mEvents.clear(); - mTotalTime = 0; - } - - public void end() { - if (!mEnable) { - return; - } - if (mCurrentEvent != null) { - mCurrentEvent.endTime = System.currentTimeMillis(); - mEvents.add(mCurrentEvent); - } - - mTotalTime = (int) (SystemClock.elapsedRealtime() - mStartTime); - } - - public int getTotalTime() { - return mTotalTime; - } - - public List getEvents() { - return mEvents; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/UIThreadUtils.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/UIThreadUtils.java deleted file mode 100644 index 3b88198083d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/UIThreadUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -import android.os.Handler; -import android.os.Looper; - -@SuppressWarnings({"unused"}) -public class UIThreadUtils { - - private static final Handler sMainHandler = new Handler(Looper.getMainLooper()); - - public static void assertOnUiThread() { - if (Looper.getMainLooper().getThread() != Thread.currentThread()) { - throw new RuntimeException("must run on ui thread!"); - } - } - - public static boolean isOnUiThread() { - return Looper.getMainLooper().getThread() == Thread.currentThread(); - } - - public static void runOnUiThread(Runnable runnable) { - sMainHandler.post(runnable); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/UrlUtils.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/UrlUtils.java deleted file mode 100644 index e20976d0bc3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/utils/UrlUtils.java +++ /dev/null @@ -1,44 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.utils; - -public class UrlUtils { - - /** - * @return True iff the url is an http: url. - */ - public static boolean isHttpUrl(String url) { - return (null != url) && (url.length() > 6) && url.substring(0, 7).equalsIgnoreCase("http://"); - } - - /** - * @return True iff the url is an https: url. - */ - public static boolean isHttpsUrl(String url) { - return (null != url) && (url.length() > 7) && url.substring(0, 8).equalsIgnoreCase("https://"); - } - - /** - * @return True iff the url is an file: url. - */ - public static boolean isFileUrl(String url) { - return (null != url) && (url.length() > 6) && url.substring(0, 7).equalsIgnoreCase("file://"); - } - - public static boolean isWebUrl(String url) { - return isHttpUrl(url) || isHttpsUrl(url); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/common/CommonBackgroundDrawable.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/common/CommonBackgroundDrawable.java deleted file mode 100644 index ac4267dd5b9..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/common/CommonBackgroundDrawable.java +++ /dev/null @@ -1,58 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.common; - -import com.tencent.mtt.hippy.dom.flex.FlexConstants; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.supportui.views.asyncimage.BackgroundDrawable; - -public class CommonBackgroundDrawable extends BackgroundDrawable { - - public void setBorderRadius(float radius, int position) { - if (!FlexConstants.isUndefined(radius)) { - radius = PixelUtil.dp2px(radius); - super.setBorderRadius(radius, position); - } - } - - public void setBorderWidth(float width, int position) { - if (!FlexConstants.isUndefined(width)) { - width = PixelUtil.dp2px(width); - super.setBorderWidth(width, position); - } - } - - public void setShadowOffsetX(float x) { - if (!FlexConstants.isUndefined(x)) { - x = PixelUtil.dp2px(x); - super.setShadowOffsetX(x); - } - } - - public void setShadowOffsetY(float y) { - if (!FlexConstants.isUndefined(y)) { - y = PixelUtil.dp2px(y); - super.setShadowOffsetY(y); - } - } - - public void setShadowRadius(float radius) { - if (!FlexConstants.isUndefined(radius)) { - radius = PixelUtil.dp2px(radius); - super.setShadowRadius(radius); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/common/CommonBorder.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/common/CommonBorder.java deleted file mode 100644 index a773c9d0e28..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/common/CommonBorder.java +++ /dev/null @@ -1,37 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.common; - -import com.tencent.mtt.supportui.views.IBorder; - -public interface CommonBorder extends IBorder { - - enum BorderRadiusDirection { - ALL, - TOP_LEFT, - TOP_RIGHT, - BOTTOM_RIGHT, - BOTTOM_LEFT - } - - enum BorderWidthDirection { - ALL, - LEFT, - TOP, - RIGHT, - BOTTOM - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/custom/HippyCustomPropsController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/custom/HippyCustomPropsController.java deleted file mode 100644 index 87f5ca8eb11..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/custom/HippyCustomPropsController.java +++ /dev/null @@ -1,61 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.custom; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.RenderNode; - -import android.content.Context; -import android.view.View; - -@SuppressWarnings("rawtypes") -@HippyController(name = HippyCustomPropsController.CLASS_NAME) -public class HippyCustomPropsController extends HippyViewController { - - public static final String CLASS_NAME = "CustomProps"; - public static final String DT_EBLID = "dt_elementBizLeafIdentifier"; - - @SuppressWarnings("unused") - @Override - protected View createViewImpl(Context context) { - return null; - } - - @SuppressWarnings("unused") - protected void onSetDTElementBizLeafIdentifier(View view) { - if (view == null) { - return; - } - - Context context = view.getContext(); - if (context instanceof HippyInstanceContext) { - HippyEngineContext engineContext = ((HippyInstanceContext) context).getEngineContext(); - assert (engineContext != null); - //noinspection ConstantConditions - if (engineContext == null) { - return; - } - - RenderNode node = engineContext.getRenderManager().getRenderNode(view.getId()); - if (node != null) { - node.mHasSetDteblId = true; - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java deleted file mode 100644 index d4beb560fd0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerListAdapter.java +++ /dev/null @@ -1,403 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.HippyItemTypeHelper; -import androidx.recyclerview.widget.IItemLayoutParams; -import androidx.recyclerview.widget.RecyclerView.Adapter; -import androidx.recyclerview.widget.RecyclerView.LayoutParams; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.uimanager.DiffUtils; -import com.tencent.mtt.hippy.uimanager.DiffUtils.PatchType; -import com.tencent.mtt.hippy.uimanager.ListItemRenderNode; -import com.tencent.mtt.hippy.uimanager.PullHeaderRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.views.list.IRecycleItemTypeChange; -import com.tencent.mtt.hippy.views.refresh.HippyPullHeaderView; -import com.tencent.mtt.nxeasy.recyclerview.helper.skikcy.IStickyItemsProvider; -import java.util.ArrayList; - -public class HippyRecyclerListAdapter extends - Adapter - implements IRecycleItemTypeChange, IStickyItemsProvider, IItemLayoutParams { - - protected final HippyEngineContext hpContext; - protected final HRCV hippyRecyclerView; - protected final HippyItemTypeHelper hippyItemTypeHelper; - protected int positionToCreateHolder; - protected PullFooterEventHelper footerEventHelper; - protected PullHeaderEventHelper headerEventHelper; - protected PreloadHelper preloadHelper; - - public HippyRecyclerListAdapter(HRCV hippyRecyclerView, HippyEngineContext hpContext) { - this.hpContext = hpContext; - this.hippyRecyclerView = hippyRecyclerView; - hippyItemTypeHelper = new HippyItemTypeHelper(hippyRecyclerView); - preloadHelper = new PreloadHelper(hippyRecyclerView); - } - - /** - * 对于吸顶到RenderNode需要特殊处理 吸顶的View需要包一层ViewGroup,吸顶的时候,从ViewGroup把RenderNode的View取出来挂载到顶部 - * 当RenderNode的View已经挂载到Header位置上面,如果重新触发创建ViewHolder,renderView会创建失败, - * 此时就只返回一个空到renderViewContainer上去,等viewHolder需要显示到时候,再把header上面的View还原到这个 ViewHolder上面。 - */ - @NonNull - @Override - public HippyRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - ListItemRenderNode renderNode = getChildNodeByAdapterPosition(positionToCreateHolder); - boolean isViewExist = renderNode.isViewExist(); - boolean needsDelete = renderNode.needDeleteExistRenderView(); - View renderView = createRenderView(renderNode); - if (isPullHeader(positionToCreateHolder)) { - ((HippyPullHeaderView) renderView).setParentView(hippyRecyclerView); - initPullHeadEventHelper((PullHeaderRenderNode) renderNode, renderView); - return new HippyRecyclerViewHolder(headerEventHelper.getView(), renderNode); - } else if (isStickyPosition(positionToCreateHolder)) { - return new HippyRecyclerViewHolder(getStickyContainer(parent, renderView), renderNode); - } else { - if (renderView == null) { - throw new IllegalArgumentException("createRenderView error!" - + ",isDelete:" + renderNode.isDelete() - + ",isViewExist:" + isViewExist - + ",needsDelete:" + needsDelete - + ",className:" + renderNode.getClassName() - + ",isLazy :" + renderNode.isIsLazyLoad() - + ",itemCount :" + getItemCount() - + ",getNodeCount:" + getRenderNodeCount() - + ",notifyCount:" + hippyRecyclerView.renderNodeCount - + "curPos:" + positionToCreateHolder - + ",rootView:" + renderNode.hasRootView() - + ",parentNode:" + (renderNode.getParent() != null) - + ",offset:" + hippyRecyclerView.computeVerticalScrollOffset() - + ",range:" + hippyRecyclerView.computeVerticalScrollRange() - + ",extent:" + hippyRecyclerView.computeVerticalScrollExtent() - + ",viewType:" + viewType - + ",id:" + renderNode.getId() - + ",attachedIds:" + getAttachedIds() - + ",nodeOffset:" + hippyRecyclerView.getNodePositionHelper().getNodeOffset() - + ",view:" + hippyRecyclerView - ); - } - return new HippyRecyclerViewHolder(renderView, renderNode); - } - } - - String getAttachedIds() { - StringBuilder attachedIds = new StringBuilder(); - int childCount = hippyRecyclerView.getChildCount(); - for (int i = 0; i < childCount; ++i) { - View attachedView = hippyRecyclerView.getChildAt(i); - attachedIds.append("|p_" + hippyRecyclerView.getChildAdapterPosition(attachedView)); - attachedIds.append("_i_" + attachedView.getId()); - } - return attachedIds.toString(); - } - - - /** - * deleteExistRenderView 是异常情况,正常情况应该不会走这个逻辑, 本来在{@link HippyRecyclerView#onViewAbound(HippyRecyclerViewHolder)} - * 的地方应该已经调用了deleteExistRenderView,deleteExistRenderView这里不应该可能走到 如果是吸顶的View,shouldSticky为true的情况下,是本身就存在的,不应该去调用deleteExistRenderView - * - * @param renderNode - * @return - */ - protected View createRenderView(ListItemRenderNode renderNode) { - if (renderNode.needDeleteExistRenderView() && !renderNode.shouldSticky()) { - deleteExistRenderView(renderNode); - } - renderNode.setLazy(false); - View view = renderNode.createViewRecursive(); - renderNode.updateViewRecursive(); - return view; - } - - public void deleteExistRenderView(ListItemRenderNode renderNode) { - renderNode.setLazy(true); - RenderNode parentNode = getParentNode(); - if (parentNode != null) { - hpContext.getRenderManager().getControllerManager() - .deleteChild(parentNode.getId(), renderNode.getId()); - } - renderNode.setRecycleItemTypeChangeListener(null); - } - - private FrameLayout getStickyContainer(ViewGroup parent, View renderView) { - FrameLayout container = new FrameLayout(parent.getContext()); - if (renderView != null) { - container.addView(renderView, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); - } - return container; - } - - private void initPullHeadEventHelper(PullHeaderRenderNode renderNode, View renderView) { - if (headerEventHelper == null) { - headerEventHelper = new PullHeaderEventHelper(hippyRecyclerView, renderNode); - } - headerEventHelper.setRenderNodeView(renderView); - } - - @Override - public String toString() { - return "HippyRecyclerAdapter: itemCount:" + getItemCount(); - } - - /** - * 绑定数据 对于全新的viewHolder,isCreated 为true,调用updateViewRecursive进行物理树的创建,以及数据的绑定 - * 对于非全新创建的viewHolder,进行view树的diff,然后在把数据绑定到view树上面 - * - * @param hippyRecyclerViewHolder position当前的viewHolder - * @param position 绑定数据的节点位置 - */ - @Override - public void onBindViewHolder(HippyRecyclerViewHolder hippyRecyclerViewHolder, int position) { - setLayoutParams(hippyRecyclerViewHolder.itemView, position); - RenderNode oldNode = hippyRecyclerViewHolder.bindNode; - ListItemRenderNode newNode = getChildNodeByAdapterPosition(position); - oldNode.setLazy(true); - newNode.setLazy(false); - if (oldNode != newNode) { - //step 1: diff - ArrayList patchTypes = DiffUtils.diff(oldNode, newNode); - //step:2 delete unUseful views - DiffUtils.deleteViews(hpContext.getRenderManager().getControllerManager(), patchTypes); - //step:3 replace id - DiffUtils.replaceIds(hpContext.getRenderManager().getControllerManager(), patchTypes); - //step:4 create view is do not reUse - DiffUtils.createView(patchTypes); - //step:5 patch the dif result - DiffUtils.doPatch(hpContext.getRenderManager().getControllerManager(), patchTypes); - } - newNode.setRecycleItemTypeChangeListener(this); - hippyRecyclerViewHolder.bindNode = newNode; - enablePullFooter(position, hippyRecyclerViewHolder.itemView); - } - - /** - * 检测最后一个item是否是footer,如果是,需要对这个itemView设置监控,footer显示就通知前端加载下一页 - */ - private void enablePullFooter(int position, View itemView) { - if (position == getItemCount() - 1) { - ListItemRenderNode renderNode = getChildNodeByAdapterPosition(position); - if (renderNode.isPullFooter()) { - if (footerEventHelper == null) { - footerEventHelper = new PullFooterEventHelper(hippyRecyclerView); - } - footerEventHelper.enableFooter(itemView); - } else { - if (footerEventHelper != null) { - footerEventHelper.disableFooter(); - } - } - } - } - - /** - * 设置View的LayoutParams排版属性,宽高由render节点提供 - */ - protected void setLayoutParams(View itemView, int position) { - LayoutParams childLp = getLayoutParams(itemView); - ListItemRenderNode childNode = getChildNodeByAdapterPosition(position); - childLp.height = getRenderNodeHeight(position); - childLp.width = childNode.getWidth(); - itemView.setLayoutParams(childLp); - } - - - protected LayoutParams getLayoutParams(View itemView) { - ViewGroup.LayoutParams params = itemView.getLayoutParams(); - LayoutParams childLp = null; - if (params instanceof LayoutParams) { - childLp = (LayoutParams) params; - } - if (childLp == null) { - childLp = new LayoutParams(MATCH_PARENT, 0); - } - return childLp; - } - - @Override - public int getItemViewType(int position) { - //在调用onCreateViewHolder之前,必然会调用getItemViewType,所以这里把position记下来 - //用在onCreateViewHolder的时候来创建View,不然onCreateViewHolder是无法创建RenderNode到View的 - setPositionToCreate(position); - return getChildNodeByAdapterPosition(position).getItemViewType(); - } - - protected void setPositionToCreate(int position) { - positionToCreateHolder = position; - } - - /** - * 获取子节点,理论上面是不会返回空的,否则就是某个流程出了问题 - * - * @param position adapter实际的item位置 - */ - public ListItemRenderNode getChildNodeByAdapterPosition(int position) { - return getChildNode(hippyRecyclerView.getNodePositionHelper().getRenderNodePosition(position)); - } - - /** - * 获取前端的renderNode的子节点 - * - * @param position 前端的子节点的位置 - */ - public ListItemRenderNode getChildNode(int position) { - RenderNode parentNode = getParentNode(); - if (parentNode != null && position < parentNode.getChildCount() && position >= 0) { - return (ListItemRenderNode) parentNode.getChildAt(position); - } - return null; - } - - /** - * listItemView的数量 - */ - @Override - public int getItemCount() { - return getRenderNodeCount(); - } - - /** - * 返回前端的list的内容Item数目 - * - * @return - */ - public int getRenderNodeCount() { - RenderNode listNode = getParentNode(); - if (listNode != null) { - return listNode.getChildCount(); - } - return 0; - } - - /** - * 前端展示的内容的高度 - * - * @return - */ - public int getRenderNodeTotalHeight() { - int renderCount = getRenderNodeCount(); - int renderNodeTotalHeight = 0; - for (int i = 0; i < renderCount; i++) { - renderNodeTotalHeight += getRenderNodeHeight(i); - } - return renderNodeTotalHeight; - } - - public int getItemHeight(int position) { - return getRenderNodeHeight(position); - } - - public int getRenderNodeHeight(int position) { - ListItemRenderNode childNode = getChildNode(position); - if (childNode != null) { - if (childNode.isPullHeader()) { - if (headerEventHelper != null) { - return headerEventHelper.getVisibleHeight(); - } - - return 0; - } - return childNode.getHeight(); - } - return 0; - } - - public int getItemWidth(int position) { - Integer renderNodeWidth = getRenderNodeWidth(position); - if (renderNodeWidth != null) { - return renderNodeWidth; - } - return 0; - } - - public int getRenderNodeWidth(int position) { - ListItemRenderNode childNode = getChildNode(position); - if (childNode != null) { - return childNode.getWidth(); - } - return 0; - } - - protected RenderNode getParentNode() { - return hpContext.getRenderManager().getRenderNode(getHippyListViewId()); - } - - private int getHippyListViewId() { - return ((View) hippyRecyclerView.getParent()).getId(); - } - - @Override - public void onRecycleItemTypeChanged(int oldType, int newType, ListItemRenderNode listItemNode) { - hippyItemTypeHelper.updateItemType(oldType, newType, listItemNode); - } - - @Override - public long getItemId(int position) { - return getChildNodeByAdapterPosition(position).getId(); - } - - /** - * 该position对于的renderNode是否是吸顶的属性 - */ - @Override - public boolean isStickyPosition(int position) { - if (position >= 0 && position < getItemCount()) { - return getChildNodeByAdapterPosition(position).shouldSticky(); - } - return false; - } - - /** - * 该position对于的renderNode是否是Header属性,值判断第一个节点 - */ - private boolean isPullHeader(int position) { - if (position == 0) { - return getChildNodeByAdapterPosition(0).isPullHeader(); - } - return false; - } - - /** - * 获取下拉刷新的事件辅助器 - */ - public PullHeaderEventHelper getHeaderEventHelper() { - return headerEventHelper; - } - - public PreloadHelper getPreloadHelper() { - return preloadHelper; - } - - public void setPreloadItemNumber(int preloadItemNumber) { - preloadHelper.setPreloadItemNumber(preloadItemNumber); - } - - @Override - public void getItemLayoutParams(int position, LayoutParams lp) { - if (lp == null) { - return; - } - lp.height = getRenderNodeHeight(position); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerView.java deleted file mode 100644 index 8ad707ffd50..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerView.java +++ /dev/null @@ -1,375 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import android.content.Context; -import android.graphics.Rect; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.HippyRecyclerViewBase; -import androidx.recyclerview.widget.IHippyViewAboundListener; -import androidx.recyclerview.widget.LinearLayoutManager; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.nxeasy.recyclerview.helper.skikcy.IHeaderAttachListener; -import com.tencent.mtt.nxeasy.recyclerview.helper.skikcy.IHeaderHost; -import com.tencent.mtt.nxeasy.recyclerview.helper.skikcy.StickyHeaderHelper; - -public class HippyRecyclerView extends HippyRecyclerViewBase - implements IHeaderAttachListener, IHippyViewAboundListener { - - protected HippyEngineContext hippyEngineContext; - protected ADP listAdapter; - protected boolean isEnableScroll = true; //使能ListView的滚动功能 - protected StickyHeaderHelper stickyHeaderHelper; //支持吸顶 - protected IHeaderHost headerHost; //用于pullHeader下拉刷新 - protected LayoutManager layoutManager; - protected RecyclerViewEventHelper recyclerViewEventHelper;//事件集合 - private NodePositionHelper nodePositionHelper; - protected int renderNodeCount = 0; - - public HippyRecyclerView(Context context) { - super(context); - } - - public HippyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public HippyRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public ADP getAdapter() { - return listAdapter; - } - - @Override - public void setAdapter(@Nullable Adapter adapter) { - listAdapter = (ADP) adapter; - super.setAdapter(adapter); - } - - public NodePositionHelper getNodePositionHelper() { - if (nodePositionHelper == null) { - nodePositionHelper = new NodePositionHelper(); - } - return nodePositionHelper; - } - - public void setOrientation(LinearLayoutManager layoutManager) { - this.layoutManager = layoutManager; - } - - public void setHeaderHost(IHeaderHost headerHost) { - this.headerHost = headerHost; - } - - public void setHippyEngineContext(HippyEngineContext hippyEngineContext) { - this.hippyEngineContext = hippyEngineContext; - } - - public void initRecyclerView() { - setAdapter(new HippyRecyclerListAdapter(this, this.hippyEngineContext)); - intEventHelper(); - } - - - @Override - public boolean onTouchEvent(MotionEvent e) { - if (!isEnableScroll) { - return false; - } - return super.onTouchEvent(e); - } - - /** - * 刷新数据 - */ - public void setListData() { - LogUtils.d("HippyRecyclerView", "itemCount =" + listAdapter.getItemCount()); - listAdapter.notifyDataSetChanged(); - //notifyDataSetChanged 本身是可以触发requestLayout的,但是Hippy框架下 HippyRootView 已经把 - //onLayout方法重载写成空方法,requestLayout不会回调孩子节点的onLayout,这里需要自己发起dispatchLayout - renderNodeCount = getAdapter().getRenderNodeCount(); - dispatchLayout(); - } - - /** - * 内容偏移,返回recyclerView顶部被滑出去的内容 1、找到顶部第一个View前面的逻辑内容高度 2、加上第一个View被遮住的区域 - */ - public int getContentOffsetY() { - return computeVerticalScrollOffset(); - } - - /** - * 内容偏移,返回recyclerView被滑出去的内容 1、找到顶部第一个View前面的逻辑内容宽度 2、加上第一个View被遮住的区域 - */ - public int getContentOffsetX() { - int firstChildPosition = getFirstChildPosition(); - int totalWidthBeforePosition = getTotalWithBefore(firstChildPosition); - int firstChildOffset = - listAdapter.getItemWidth(firstChildPosition) - getVisibleWidth(getChildAt(0)); - return totalWidthBeforePosition + firstChildOffset; - } - - /** - * 获取一个View的可视高度,并非view本身的height,有可能部分是被滑出到屏幕外部 - */ - protected int getVisibleHeight(View firstChildView) { - return getViewVisibleRect(firstChildView).height(); - } - - /** - * 获取一个View的可视高度,并非view本身的height,有可能部分是被滑出到屏幕外部 - */ - protected int getVisibleWidth(View firstChildView) { - return getViewVisibleRect(firstChildView).width(); - } - - /** - * 获取view在父亲中的可视区域 - */ - private Rect getViewVisibleRect(View view) { - Rect rect = new Rect(); - if (view != null) { - view.getLocalVisibleRect(rect); - } - return rect; - } - - /** - * 获取position 前面的内容高度,不包含position自身的高度 - */ - public int getTotalHeightBefore(int position) { - int totalHeightBefore = 0; - for (int i = 0; i < position; i++) { - totalHeightBefore += listAdapter.getItemHeight(i); - } - return totalHeightBefore; - } - - /** - * 获取renderNodePosition前面的内容高度,不包含renderNodePosition自身的高度 - */ - public int getRenderNodeHeightBefore(int renderNodePosition) { - int renderNodeTotalHeight = 0; - for (int i = 0; i < renderNodePosition; i++) { - renderNodeTotalHeight += listAdapter.getRenderNodeHeight(i); - } - return renderNodeTotalHeight; - } - - - /** - * 获取position 前面的内容高度,不包含position自身的高度 - */ - public int getTotalWithBefore(int position) { - int totalWidthBefore = 0; - for (int i = 0; i < position; i++) { - totalWidthBefore += listAdapter.getItemWidth(i); - } - return totalWidthBefore; - } - - public RecyclerViewEventHelper getRecyclerViewEventHelper() { - return intEventHelper(); - } - - private RecyclerViewEventHelper intEventHelper() { - if (recyclerViewEventHelper == null) { - recyclerViewEventHelper = createEventHelper(); - } - return recyclerViewEventHelper; - } - - protected RecyclerViewEventHelper createEventHelper() { - return new RecyclerViewEventHelper(this); - } - - /** - * 设置recyclerView可以滚动 - */ - public void setScrollEnable(boolean enable) { - isEnableScroll = enable; - } - - public int getNodePositionInAdapter(int position) { - return position; - } - - public void scrollToIndex(int xIndex, int yPosition, boolean animated, int duration) { - int positionInAdapter = getNodePositionInAdapter(yPosition); - if (animated) { - doSmoothScrollY(duration, getTotalHeightBefore(positionInAdapter) - getContentOffsetY()); - postDispatchLayout(); - } else { - scrollToPositionWithOffset(positionInAdapter, 0); - //不能调用postDispatchLayout,需要立即调研dispatchLayout,否则滚动位置不对 - dispatchLayout(); - } - } - - /** - * @param xOffset 暂不支持 - * @param yOffset yOffset>0 内容向上移动,yOffset<0, 内容向下移动 - * @param animated 是否有动画 - * @param duration 动画的时间 - */ - public void scrollToContentOffset(double xOffset, double yOffset, boolean animated, - int duration) { - if (!canScrollToContentOffset()) { - return; - } - int yOffsetInPixel = (int) PixelUtil.dp2px(yOffset); - int deltaY = yOffsetInPixel - getContentOffsetY(); - //增加异常保护 - if (animated) { - doSmoothScrollY(duration, deltaY); - } else { - scrollBy(0, deltaY); - } - } - - /** - * renderNodeCount是在setListData的时候更新,必须调用setListData后,确保renderNodeCount和 - * getAdapter().getRenderNodeCount()的值相等,才能进行滚动,否则scrollBy会出现IndexOutOfBoundsException - * 的问题,主要原因就是RecyclerView的内部状态没有通过setListData进行刷新,还是老的数据 - * RenderManager的batch方法应该把dispatchUIFunction放到batchComplete后面,但是这样改动太大 - * - * @return - */ - private boolean canScrollToContentOffset() { - return renderNodeCount == getAdapter().getRenderNodeCount(); - } - - private void doSmoothScrollY(int duration, int scrollToYPos) { - if (duration != 0) { - if (scrollToYPos != 0 && !didStructureChange()) { - smoothScrollBy(0, scrollToYPos, null, duration); - postDispatchLayout(); - } - } else { - smoothScrollBy(0, scrollToYPos); - postDispatchLayout(); - } - } - - private void postDispatchLayout() { - post(new Runnable() { - @Override - public void run() { - dispatchLayout(); - } - }); - } - - public void scrollToTop() { - LayoutManager layoutManager = getLayoutManager(); - if (layoutManager.canScrollHorizontally()) { - smoothScrollBy(-getContentOffsetX(), 0); - } else { - smoothScrollBy(0, -getContentOffsetY()); - } - postDispatchLayout(); - } - - /** - * @param enable true :支持Item 上滑吸顶功能 - */ - public void setRowShouldSticky(boolean enable) { - if (enable) { - if (stickyHeaderHelper == null) { - stickyHeaderHelper = new StickyHeaderHelper(this, listAdapter, this, headerHost); - addOnScrollListener(stickyHeaderHelper); - } - } else { - if (stickyHeaderHelper != null) { - removeOnScrollListener(stickyHeaderHelper); - } - } - } - - /** - * 同步删除RenderNode对应注册的View,deleteChild是递归删除RenderNode创建的所有的view - */ - @Override - public void onViewAbound(HippyRecyclerViewHolder viewHolder) { - if (viewHolder.bindNode != null && !viewHolder.bindNode.isDelete()) { - getAdapter().deleteExistRenderView(viewHolder.bindNode); - } - } - - /** - * 当header被摘下来,需要对header进行还原或者回收对处理 遍历所有都ViewHolder,看看有没有收纳这个headerView都ViewHolder - * 如果没有,需要把aboundHeader进行回收,并同步删除render节点对应都view - * - * @param aboundHeader HeaderView对应的Holder - * @param currentHeaderView headerView的实体内容 - */ - @Override - public void onHeaderDetached(ViewHolder aboundHeader, View currentHeaderView) { - boolean findHostViewHolder = false; - for (int i = 0; i < getChildCountWithCaches(); i++) { - ViewHolder viewHolder = getChildViewHolder(getChildAtWithCaches(i)); - if (isTheSameRenderNode((HippyRecyclerViewHolder) aboundHeader, - (HippyRecyclerViewHolder) viewHolder)) { - findHostViewHolder = true; - fillContentView(currentHeaderView, viewHolder); - break; - } - } - //当header无处安放,抛弃view都同时,需要同步给Hippy进行View都删除,不然后续无法创建对应都View - if (!findHostViewHolder) { - onViewAbound((HippyRecyclerViewHolder) aboundHeader); - } - } - - private boolean fillContentView(View currentHeaderView, ViewHolder viewHolder) { - if (viewHolder != null && viewHolder.itemView instanceof ViewGroup) { - ViewGroup itemView = (ViewGroup) viewHolder.itemView; - if (itemView.getChildCount() <= 0) { - itemView.addView(currentHeaderView); - } - } - return false; - } - - private boolean isTheSameRenderNode(HippyRecyclerViewHolder aboundHeader, - HippyRecyclerViewHolder viewHolder) { - if (viewHolder.bindNode != null && aboundHeader.bindNode != null) { - return viewHolder.bindNode.getId() == aboundHeader.bindNode.getId(); - } - return false; - } - - public void setNodePositionHelper(NodePositionHelper nodePositionHelper) { - this.nodePositionHelper = nodePositionHelper; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "{renderNodeCount:" + renderNodeCount + ",state:" - + getStateInfo() - + "}"; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewController.java deleted file mode 100644 index 6dd6dbcb4ec..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewController.java +++ /dev/null @@ -1,187 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import android.content.Context; -import androidx.recyclerview.widget.EasyLinearLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import android.view.View; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.ListViewRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; - -@HippyController(name = HippyRecyclerViewController.CLASS_NAME) -public class HippyRecyclerViewController extends - HippyViewController { - - public static final String CLASS_NAME = "RecyclerView"; - public static final String SCROLL_TO_INDEX = "scrollToIndex"; - public static final String SCROLL_TO_CONTENT_OFFSET = "scrollToContentOffset"; - public static final String SCROLL_TO_TOP = "scrollToTop"; - public static final String COLLAPSE_PULL_HEADER = "collapsePullHeader"; - public static final String EXPAND_PULL_HEADER = "expandPullHeader"; - - public HippyRecyclerViewController() { - - } - - @Override - public int getChildCount(HRW viewGroup) { - return viewGroup.getChildCountWithCaches(); - } - - @Override - public View getChildAt(HRW viewGroup, int index) { - return viewGroup.getChildAtWithCaches(index); - } - - @Override - public void onBatchComplete(HRW view) { - super.onBatchComplete(view); - view.setListData(); - } - - @Override - protected View createViewImpl(Context context) { - return createViewImpl(context, null); - } - - @Override - protected View createViewImpl(Context context, HippyMap iniProps) { - return new HippyRecyclerViewWrapper(context, - initDefault(context, iniProps, new HippyRecyclerView(context))); - } - - public static HippyRecyclerView initDefault(Context context, HippyMap iniProps, - HippyRecyclerView recyclerView) { - LinearLayoutManager layoutManager = new EasyLinearLayoutManager(context); - recyclerView.setItemAnimator(null); - if (iniProps != null && iniProps.containsKey("horizontal")) { - layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); - } - recyclerView.setLayoutManager(layoutManager); - recyclerView.setHippyEngineContext(((HippyInstanceContext) context).getEngineContext()); - recyclerView.initRecyclerView(); - return recyclerView; - } - - @Override - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, - ControllerManager controllerManager, - boolean lazy) { - return new ListViewRenderNode(id, props, className, hippyRootView, controllerManager, lazy); - } - - @HippyControllerProps(name = "rowShouldSticky") - public void setRowShouldSticky(HRW view, boolean enable) { - view.setRowShouldSticky(enable); - } - - @HippyControllerProps(name = "onScrollBeginDrag", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setScrollBeginDragEventEnable(HRW view, boolean flag) { - view.getRecyclerViewEventHelper().setScrollBeginDragEventEnable(flag); - } - - @HippyControllerProps(name = "onScrollEndDrag", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setScrollEndDragEventEnable(HRW view, boolean flag) { - view.getRecyclerViewEventHelper().setScrollEndDragEventEnable(flag); - } - - @HippyControllerProps(name = "onMomentumScrollBegin", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setMomentumScrollBeginEventEnable(HRW view, boolean flag) { - view.getRecyclerViewEventHelper().setMomentumScrollBeginEventEnable(flag); - } - - @HippyControllerProps(name = "onMomentumScrollEnd", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setMomentumScrollEndEventEnable(HRW view, boolean flag) { - view.getRecyclerViewEventHelper().setMomentumScrollEndEventEnable(flag); - } - - @HippyControllerProps(name = "onScrollEnable", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setOnScrollEventEnable(HRW view, boolean flag) { - view.getRecyclerViewEventHelper().setOnScrollEventEnable(flag); - } - - @HippyControllerProps(name = "exposureEventEnabled", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setExposureEventEnable(HRW view, boolean flag) { - view.getRecyclerViewEventHelper().setExposureEventEnable(flag); - } - - @HippyControllerProps(name = "scrollEnabled", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void setScrollEnable(HRW view, boolean flag) { - view.setScrollEnable(flag); - } - - @HippyControllerProps(name = "scrollEventThrottle", defaultType = HippyControllerProps.NUMBER, defaultNumber = 30.0D) - public void setscrollEventThrottle(HRW view, int scrollEventThrottle) { - view.getRecyclerViewEventHelper().setScrollEventThrottle(scrollEventThrottle); - } - - @HippyControllerProps(name = "preloadItemNumber") - public void setPreloadItemNumber(HRW view, int preloadItemNumber) { - getAdapter(view).setPreloadItemNumber(preloadItemNumber); - } - - @Override - public void dispatchFunction(HRW view, String functionName, HippyArray dataArray) { - super.dispatchFunction(view, functionName, dataArray); - switch (functionName) { - case SCROLL_TO_INDEX: { - // list滑动到某个item - int xIndex = dataArray.getInt(0); - int yIndex = dataArray.getInt(1); - boolean animated = dataArray.getBoolean(2); - int duration = dataArray.getInt(3); //1.2.7 增加滚动时间 ms,animated==true时生效 - view.scrollToIndex(xIndex, yIndex, animated, duration); - break; - } - case SCROLL_TO_CONTENT_OFFSET: { - // list滑动到某个距离 - double xOffset = dataArray.getDouble(0); - double yOffset = dataArray.getDouble(1); - boolean animated = dataArray.getBoolean(2); - int duration = dataArray.getInt(3); //1.2.7 增加滚动时间 ms,animated==true时生效 - view.scrollToContentOffset(xOffset, yOffset, animated, duration); - break; - } - case SCROLL_TO_TOP: { - view.scrollToTop(); - break; - } - case COLLAPSE_PULL_HEADER: { - getAdapter(view).getHeaderEventHelper().onHeaderRefreshFinish(); - break; - } - case EXPAND_PULL_HEADER: { - getAdapter(view).getHeaderEventHelper().onHeaderRefresh(); - break; - } - } - } - - private HippyRecyclerListAdapter getAdapter(HRW view) { - return view.getRecyclerView().getAdapter(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewHolder.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewHolder.java deleted file mode 100644 index 3334e5f29b9..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewHolder.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import android.view.View; -import com.tencent.mtt.hippy.uimanager.ListItemRenderNode; - -public class HippyRecyclerViewHolder extends ViewHolder { - - public ListItemRenderNode bindNode; - - public HippyRecyclerViewHolder(@NonNull View itemView, ListItemRenderNode renderNode) { - super(itemView); - bindNode = renderNode; - } - - public boolean isRenderDeleted() { - if (bindNode != null) { - return bindNode.isDelete(); - } - return false; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewWrapper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewWrapper.java deleted file mode 100644 index e8daa7d6202..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/HippyRecyclerViewWrapper.java +++ /dev/null @@ -1,134 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import android.content.Context; -import android.os.Build.VERSION_CODES; -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; -import androidx.recyclerview.widget.HippyRecyclerExtension; -import androidx.recyclerview.widget.HippyRecyclerPool; -import android.view.View; -import android.view.ViewTreeObserver.OnGlobalLayoutListener; -import android.widget.FrameLayout; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.nxeasy.recyclerview.helper.skikcy.IHeaderHost; - -public class HippyRecyclerViewWrapper extends FrameLayout implements - HippyViewBase, - IHeaderHost { - - protected final HippyEngineContext hpContext; - protected HRCV recyclerView; - private NativeGestureDispatcher nativeGestureDispatcher; - - public HippyRecyclerViewWrapper(@NonNull Context context, HRCV recyclerView) { - super(context); - this.recyclerView = recyclerView; - addView(recyclerView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - hpContext = ((HippyInstanceContext) context).getEngineContext(); - HippyRecyclerExtension cacheExtension = new HippyRecyclerExtension(recyclerView, hpContext, - recyclerView.getNodePositionHelper()); - recyclerView.setViewCacheExtension(cacheExtension); - recyclerView.setHeaderHost(this); - HippyRecyclerPool pool = new HippyRecyclerPool(hpContext, this, cacheExtension, - recyclerView.getNodePositionHelper()); - pool.setViewAboundListener(recyclerView); - recyclerView.setRecycledViewPool(pool); - - } - - @Override - public int computeVerticalScrollOffset() { - return recyclerView.computeVerticalScrollOffset(); - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return nativeGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - nativeGestureDispatcher = dispatcher; - } - - public int getChildCountWithCaches() { - return recyclerView.getChildCountWithCaches(); - } - - public View getChildAtWithCaches(int index) { - return recyclerView.getChildAtWithCaches(index); - } - - public void setListData() { - recyclerView.setListData(); - } - - public RecyclerViewEventHelper getRecyclerViewEventHelper() { - return recyclerView.getRecyclerViewEventHelper(); - } - - public void setScrollEnable(boolean flag) { - recyclerView.setScrollEnable(flag); - } - - public void scrollToIndex(int xIndex, int yIndex, boolean animated, int duration) { - recyclerView.scrollToIndex(xIndex, yIndex, animated, duration); - } - - public void scrollToContentOffset(double xOffset, double yOffset, boolean animated, - int duration) { - recyclerView.scrollToContentOffset(xOffset, yOffset, animated, duration); - } - - public void scrollToTop() { - recyclerView.scrollToTop(); - } - - public void setRowShouldSticky(boolean enable) { - recyclerView.setRowShouldSticky(enable); - } - - public HRCV getRecyclerView() { - return recyclerView; - } - - /** - * 将HeaderView放到RecyclerView到父亲View上面 - */ - @Override - public void attachHeader(View headerView, LayoutParams layoutParams) { - addView(headerView, layoutParams); - layout(getLeft(), getTop(), getRight(), getBottom()); - getViewTreeObserver().dispatchOnGlobalLayout(); - } - - @Override - public void addOnLayoutListener(OnGlobalLayoutListener listener) { - getViewTreeObserver().addOnGlobalLayoutListener(listener); - } - - @RequiresApi(api = VERSION_CODES.JELLY_BEAN) - @Override - public void removeOnLayoutListener(OnGlobalLayoutListener listener) { - getViewTreeObserver().removeOnGlobalLayoutListener(listener); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/NodePositionHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/NodePositionHelper.java deleted file mode 100644 index b31f17fe124..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/NodePositionHelper.java +++ /dev/null @@ -1,55 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -public class NodePositionHelper { - - private int nodeOffset = 0; - - public NodePositionHelper() { - - } - - /** - * 如果前面加了NativeHeader,nodeOffset就加1 - */ - public void increaseOffset() { - this.nodeOffset++; - } - - /** - * @return 当前render节点的偏移 - */ - public int getNodeOffset() { - return nodeOffset; - } - - /** - * @param adapterPosition 是节点在adapter的位置,adapter上面可能不都是renderNode - * @return 返回adapterPosition对应前端的列表的node节点位置,减去前面的NativeHeader的位置 - */ - public int getRenderNodePosition(int adapterPosition) { - return adapterPosition - nodeOffset; - } - - /** - * 如果去掉nativeHeader,就减1 - */ - public void decreaseOffset() { - nodeOffset--; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PreloadHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PreloadHelper.java deleted file mode 100644 index 4a6740231e7..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PreloadHelper.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.tencent.mtt.hippy.views.hippylist; - -import static com.tencent.mtt.hippy.views.hippylist.PullFooterEventHelper.EVENT_ON_END_REACHED; - -import androidx.recyclerview.widget.RecyclerView; -import android.view.View; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; - -public class PreloadHelper extends RecyclerView.OnScrollListener { - - protected HippyRecyclerView hippyRecyclerView; - protected int preloadItemNumber; - protected boolean isPreloading; - - public PreloadHelper(HippyRecyclerView hippyRecyclerView) { - this.hippyRecyclerView = hippyRecyclerView; - } - - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - int itemCount = recyclerView.getAdapter().getItemCount(); - //频控,记录上次预加载的总条目数,相同就不再次触发预加载 - if (isPreloading) { - return; - } - if (hippyRecyclerView.getAdapter().getRenderNodeCount() > 0) { - View lastChild = recyclerView.getChildAt(recyclerView.getChildCount() - 1); - int lastPosition = recyclerView.getChildAdapterPosition(lastChild); - if (lastPosition + preloadItemNumber >= itemCount) { - isPreloading = true; - sendReachEndEvent(recyclerView); - } - } - } - - public void sendReachEndEvent(RecyclerView recyclerView) { - new HippyViewEvent(EVENT_ON_END_REACHED).send((View) recyclerView.getParent(), null); - } - - /** - * @param preloadItemNumber 提前多少条Item,通知前端加载下一页数据 - */ - public void setPreloadItemNumber(int preloadItemNumber) { - this.preloadItemNumber = preloadItemNumber; - hippyRecyclerView.removeOnScrollListener(this); - if (preloadItemNumber > 0) { - hippyRecyclerView.addOnScrollListener(this); - } - } - - public void reset() { - isPreloading = false; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PullFooterEventHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PullFooterEventHelper.java deleted file mode 100644 index db8bfcf68a8..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PullFooterEventHelper.java +++ /dev/null @@ -1,61 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import android.view.View; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.nxeasy.recyclerview.helper.footer.FooterExposureHelper; -import com.tencent.mtt.nxeasy.recyclerview.helper.footer.IFooterLoadMoreListener; - -class PullFooterEventHelper implements IFooterLoadMoreListener { - - public static final String EVENT_ON_END_REACHED = "onLoadMore"; - private final HippyRecyclerView recyclerView; - private FooterExposureHelper footerExposureHelper; - private HippyViewEvent onEndReachedEvent; - - PullFooterEventHelper(HippyRecyclerView recyclerView) { - this.recyclerView = recyclerView; - } - - public void enableFooter(View itemView) { - disableFooter(); - footerExposureHelper = new FooterExposureHelper(); - footerExposureHelper.setFooterListener(this); - footerExposureHelper.setExposureView(itemView); - recyclerView.addOnScrollListener(footerExposureHelper); - } - - public void disableFooter() { - if (footerExposureHelper != null) { - recyclerView.removeOnScrollListener(footerExposureHelper); - footerExposureHelper = null; - } - } - - protected HippyViewEvent getOnEndReachedEvent() { - if (onEndReachedEvent == null) { - onEndReachedEvent = new HippyViewEvent(EVENT_ON_END_REACHED); - } - return onEndReachedEvent; - } - - @Override - public void onFooterLoadMore() { - getOnEndReachedEvent().send((View) recyclerView.getParent(), null); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PullHeaderEventHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PullHeaderEventHelper.java deleted file mode 100644 index d2bdf6ae17e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/PullHeaderEventHelper.java +++ /dev/null @@ -1,131 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import android.view.Gravity; -import android.view.View; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.uimanager.PullHeaderRenderNode; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.nxeasy.recyclerview.helper.header.HeaderRefreshHelper; -import com.tencent.mtt.nxeasy.recyclerview.helper.header.IHeaderRefreshListener; -import com.tencent.mtt.nxeasy.recyclerview.helper.header.IHeaderRefreshView; -import com.tencent.mtt.nxeasy.recyclerview.helper.header.ILayoutRequester; - -public class PullHeaderEventHelper implements IHeaderRefreshListener, IHeaderRefreshView, - ILayoutRequester { - - public static final String EVENT_TYPE_HEADER_PULLING = "onHeaderPulling"; - public static final String EVENT_TYPE_HEADER_RELEASED = "onHeaderReleased"; - private final PullHeaderRenderNode renderNode; - private HippyRecyclerView recyclerView; - private View renderNodeView; - private LinearLayout headerContainer; - private LayoutParams contentLayoutParams; - private HeaderRefreshHelper headerRefreshHelper; - - PullHeaderEventHelper(HippyRecyclerView recyclerView, PullHeaderRenderNode renderNode) { - this.recyclerView = recyclerView; - this.renderNode = renderNode; - headerContainer = new LinearLayout(recyclerView.getContext()); - headerRefreshHelper = new HeaderRefreshHelper(); - headerRefreshHelper.setHeaderRefreshView(this); - headerRefreshHelper.setHeaderRefreshListener(this); - headerRefreshHelper.setLayoutRequester(this); - recyclerView.setOnTouchListener(headerRefreshHelper); - } - - public void setRenderNodeView(View renderNodeView) { - if (this.renderNodeView != renderNodeView) { - this.renderNodeView = renderNodeView; - headerContainer.removeAllViews(); - contentLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, renderNode.getHeight()); - contentLayoutParams.gravity = Gravity.BOTTOM; - headerContainer.addView(renderNodeView, contentLayoutParams); - } - } - - - public View getView() { - return headerContainer; - } - - @Override - public void onStartDrag() { - - } - - @Override - public void onHeaderHeightChanged(int sumOffset) { - HippyMap params = new HippyMap(); - params.pushDouble("contentOffset", PixelUtil.px2dp(sumOffset)); - sendPullHeaderEvent(EVENT_TYPE_HEADER_PULLING, params); - } - - @Override - public void onRefreshing() { - - } - - @Override - public void onFolded() { - - } - - /** - * 松手后,触发的刷新回调,需要通知Hippy前端业务进行数据的刷新操作 - */ - @Override - public void onHeaderRefreshing(int refreshWay) { - sendPullHeaderEvent(EVENT_TYPE_HEADER_RELEASED, new HippyMap()); - } - - @Override - public int getContentHeight() { - return renderNode.getHeight(); - } - - protected void sendPullHeaderEvent(String eventName, HippyMap param) { - new HippyViewEvent(eventName).send(renderNodeView, param); - } - - /** - * Hippy前端业务通知数据已经刷新完毕,这里通知给headerRefreshHelper,进行header的收起功能 - */ - public void onHeaderRefreshFinish() { - headerRefreshHelper.onRefreshDone(); - } - - /** - * Hippy前端业务调用主动刷新功能,这款需要通知headerRefreshHelper进行自动下拉刷新 - */ - public void onHeaderRefresh() { - headerRefreshHelper.triggerRefresh(); - } - - public int getVisibleHeight() { - return headerRefreshHelper.getVisibleHeight(); - } - - @Override - public void requestLayout() { - recyclerView.dispatchLayout(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/RecyclerViewEventHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/RecyclerViewEventHelper.java deleted file mode 100644 index b9f6652e15e..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/hippylist/RecyclerViewEventHelper.java +++ /dev/null @@ -1,394 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.hippylist; - -import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING; -import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; -import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_SETTLING; - -import android.graphics.Rect; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.OverPullHelper; -import androidx.recyclerview.widget.OverPullListener; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.OnScrollListener; -import android.view.View; -import android.view.View.OnAttachStateChangeListener; -import android.view.View.OnLayoutChangeListener; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.ViewTreeObserver.OnPreDrawListener; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.list.HippyListItemView; -import com.tencent.mtt.hippy.views.scroll.HippyScrollViewEventHelper; - -public class RecyclerViewEventHelper extends OnScrollListener implements OnLayoutChangeListener, - OnAttachStateChangeListener, OverPullListener { - - public static final String EVENT_ON_END_REACHED = "onEndReached"; - public static final String EVENT_ON_TOP_REACHED = "onTopReached"; - public static final String INITIAL_LIST_READY = "initialListReady"; - protected final HippyRecyclerView hippyRecyclerView; - private boolean scrollBeginDragEventEnable; - private boolean scrollEndDragEventEnable; - private HippyViewEvent onScrollDragEndedEvent; - private boolean momentumScrollBeginEventEnable; - private boolean momentumScrollEndEventEnable; - private HippyViewEvent onScrollFlingStartedEvent; - private HippyViewEvent onScrollFlingEndedEvent; - private int currentState; - protected boolean onScrollEventEnable = true; - private HippyViewEvent onScrollEvent; - private long lastScrollEventTimeStamp; - private int scrollEventThrottle; - private boolean exposureEventEnable; - private HippyViewEvent onScrollDragStartedEvent; - - //initialListReady event - private boolean isInitialListReadyNotified = false; - private ViewTreeObserver viewTreeObserver; - private OnPreDrawListener preDrawListener; - - - public RecyclerViewEventHelper(HippyRecyclerView recyclerView) { - this.hippyRecyclerView = recyclerView; - hippyRecyclerView.addOnScrollListener(this); - hippyRecyclerView.addOnAttachStateChangeListener(this); - hippyRecyclerView.addOnLayoutChangeListener(this); - preDrawListener = new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - notifyInitialListReady(); - return true; - } - }; - } - - void notifyInitialListReady() { - if (canNotifyInit()) { - isInitialListReadyNotified = true; - viewTreeObserver.removeOnPreDrawListener(preDrawListener); - hippyRecyclerView.post(new Runnable() { - @Override - public void run() { - new HippyViewEvent(INITIAL_LIST_READY).send(getParentView(), null); - } - }); - } - } - - protected View getParentView() { - return (View) hippyRecyclerView.getParent(); - } - - /** - * 是否满足initialListReady的通知条件,需要有真实view上屏才进行通知 - */ - private boolean canNotifyInit() { - return !isInitialListReadyNotified && hippyRecyclerView.getAdapter().getItemCount() > 0 - && hippyRecyclerView.getChildCount() > 0 - && viewTreeObserver.isAlive(); - } - - public void setScrollBeginDragEventEnable(boolean enable) { - scrollBeginDragEventEnable = enable; - } - - public void setScrollEndDragEventEnable(boolean enable) { - scrollEndDragEventEnable = enable; - } - - public void setMomentumScrollBeginEventEnable(boolean enable) { - momentumScrollBeginEventEnable = enable; - } - - public void setMomentumScrollEndEventEnable(boolean enable) { - momentumScrollEndEventEnable = enable; - } - - public void setOnScrollEventEnable(boolean enable) { - onScrollEventEnable = enable; - } - - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, - int oldTop, int oldRight, - int oldBottom) { - checkSendExposureEvent(); - } - - protected HippyViewEvent getOnScrollDragStartedEvent() { - if (onScrollDragStartedEvent == null) { - onScrollDragStartedEvent = new HippyViewEvent( - HippyScrollViewEventHelper.EVENT_TYPE_BEGIN_DRAG); - } - return onScrollDragStartedEvent; - } - - // scroll - protected HippyViewEvent getOnScrollEvent() { - if (onScrollEvent == null) { - onScrollEvent = new HippyViewEvent(HippyScrollViewEventHelper.EVENT_TYPE_SCROLL); - } - return onScrollEvent; - } - - // start fling - protected HippyViewEvent getOnScrollFlingStartedEvent() { - if (onScrollFlingStartedEvent == null) { - onScrollFlingStartedEvent = new HippyViewEvent( - HippyScrollViewEventHelper.EVENT_TYPE_MOMENTUM_BEGIN); - } - return onScrollFlingStartedEvent; - } - - // end drag event - protected HippyViewEvent getOnScrollDragEndedEvent() { - if (onScrollDragEndedEvent == null) { - onScrollDragEndedEvent = new HippyViewEvent(HippyScrollViewEventHelper.EVENT_TYPE_END_DRAG); - } - return onScrollDragEndedEvent; - } - - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - int oldState = currentState; - currentState = newState; - sendDragEvent(newState); - sendDragEndEvent(oldState, currentState); - sendFlingEvent(newState); - sendFlingEndEvent(oldState, currentState); - } - - @Override - public void onScrolled(@NonNull final RecyclerView recyclerView, int dx, int dy) { - if (dx != 0 || dy != 0) { - checkSendOnScrollEvent(); - } - - checkSendExposureEvent(); - - if (!recyclerView.canScrollVertically(1)) { - sendOnEndReachedEvent(); - } - - if (!recyclerView.canScrollVertically(-1)) { - sendOnTopReachedEvent(); - } - } - - protected void sendOnEndReachedEvent() { - new HippyViewEvent(EVENT_ON_END_REACHED).send(getParentView(), null); - } - - protected void sendOnTopReachedEvent() { - new HippyViewEvent(EVENT_ON_TOP_REACHED).send(getParentView(), null); - } - - private void checkSendOnScrollEvent() { - if (onScrollEventEnable) { - long currTime = System.currentTimeMillis(); - if (currTime - lastScrollEventTimeStamp >= scrollEventThrottle) { - lastScrollEventTimeStamp = currTime; - sendOnScrollEvent(); - } - } - } - - public void sendOnScrollEvent() { - getOnScrollEvent().send(getParentView(), generateScrollEvent()); - } - - private void observePreDraw() { - if (!isInitialListReadyNotified && viewTreeObserver == null) { - viewTreeObserver = hippyRecyclerView.getViewTreeObserver(); - viewTreeObserver.addOnPreDrawListener(preDrawListener); - } - } - - protected void sendFlingEvent(int newState) { - if (momentumScrollBeginEventEnable && newState == SCROLL_STATE_SETTLING) { - getOnScrollFlingStartedEvent().send(getParentView(), generateScrollEvent()); - } - } - - protected void sendDragEndEvent(int oldState, int newState) { - if (scrollEndDragEventEnable && isReleaseDrag(oldState, newState) && !hippyRecyclerView - .isOverPulling()) { - getOnScrollDragEndedEvent().send(getParentView(), generateScrollEvent()); - } - } - - private boolean isReleaseDrag(int oldState, int newState) { - return (oldState == SCROLL_STATE_DRAGGING && - (newState == SCROLL_STATE_IDLE || newState == SCROLL_STATE_SETTLING)); - } - - protected void sendFlingEndEvent(int oldState, int newState) { - if (momentumScrollEndEventEnable && oldState == SCROLL_STATE_SETTLING - && newState != SCROLL_STATE_SETTLING) { - getOnScrollFlingEndedEvent().send(getParentView(), generateScrollEvent()); - } - } - - protected void sendDragEvent(int newState) { - if (scrollBeginDragEventEnable && newState == RecyclerView.SCROLL_STATE_DRAGGING) { - getOnScrollDragStartedEvent().send(getParentView(), generateScrollEvent()); - } - } - - // end fling - protected HippyViewEvent getOnScrollFlingEndedEvent() { - if (onScrollFlingEndedEvent == null) { - onScrollFlingEndedEvent = new HippyViewEvent( - HippyScrollViewEventHelper.EVENT_TYPE_MOMENTUM_END); - } - return onScrollFlingEndedEvent; - } - - public void setScrollEventThrottle(int scrollEventThrottle) { - this.scrollEventThrottle = scrollEventThrottle; - } - - public final HippyMap generateScrollEvent() { - HippyMap contentOffset = new HippyMap(); - - float offsetX = hippyRecyclerView.getContentOffsetX(); - float offsetY = hippyRecyclerView.getContentOffsetY(); - - if (offsetX != 0) { - offsetX = PixelUtil.px2dp(offsetX); - } - - if (offsetY != 0) { - offsetY = PixelUtil.px2dp(offsetY); - } - - contentOffset.pushDouble("x", offsetX); - contentOffset.pushDouble("y", offsetY); - HippyMap event = new HippyMap(); - event.pushMap("contentOffset", contentOffset); - return event; - } - - public void setExposureEventEnable(boolean enable) { - exposureEventEnable = enable; - } - - /** - * 可视面积小于10%,任务view当前已经不在可视区域 - */ - private boolean isViewVisible(View view) { - if (view == null) { - return false; - } - Rect rect = new Rect(); - boolean visibility = view.getGlobalVisibleRect(rect); - if (!visibility) { - return false; - } else { - float visibleArea = rect.height() * rect.width(); //可见区域的面积 - float viewArea = view.getMeasuredWidth() * view.getMeasuredHeight();//当前view的总面积 - return visibleArea > viewArea * 0.1f; - } - } - - protected void checkExposureView(View view) { - if (view instanceof HippyListItemView) { - HippyListItemView itemView = (HippyListItemView) view; - if (isViewVisible(view)) { - if (itemView.getExposureState() != HippyListItemView.EXPOSURE_STATE_APPEAR) { - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_APPEAR); - itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_APPEAR); - } - } else { - if (itemView.getExposureState() != HippyListItemView.EXPOSURE_STATE_DISAPPEAR) { - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_DISAPPEAR); - itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_DISAPPEAR); - } - } - } - } - - protected void sendExposureEvent(View view, String eventName) { - if (eventName.equals(HippyListItemView.EXPOSURE_EVENT_APPEAR) || eventName - .equals(HippyListItemView.EXPOSURE_EVENT_DISAPPEAR)) { - new HippyViewEvent(eventName).send(view, null); - } - } - - private void checkSendExposureEvent() { - if (!exposureEventEnable) { - return; - } - int childCount = hippyRecyclerView.getChildCount(); - for (int i = 0; i < childCount; i++) { - checkExposureView(findHippyListItemView((ViewGroup) hippyRecyclerView.getChildAt(i))); - } - } - - /** - * 由于挂载到RecyclerView到子View可能不是HippyListItemView,比如对于stickyItem,我们会包一层 - * ViewGroup,所以这里拿HippyListItemView,需要做两层的判断 - */ - private View findHippyListItemView(ViewGroup viewGroup) { - if (viewGroup instanceof HippyListItemView) { - return viewGroup; - } - if (viewGroup.getChildCount() > 0) { - View child = viewGroup.getChildAt(0); - if (child instanceof HippyListItemView) { - return child; - } - } - return null; - } - - @Override - public void onViewAttachedToWindow(View v) { - observePreDraw(); - } - - @Override - public void onViewDetachedFromWindow(View v) { - - } - - @Override - public void onOverPullStateChanged(int oldState, int newState, int offset) { - LogUtils.d("QBRecyclerViewEventHelper", "oldState:" + oldState + ",newState:" + newState); - if (oldState == OverPullHelper.OVER_PULL_NONE && isOverPulling(newState)) { - sendOnEndReachedEvent(); - getOnScrollDragStartedEvent().send(getParentView(), generateScrollEvent()); - } - if (isOverPulling(oldState) && isOverPulling(newState)) { - sendOnScrollEvent(); - } - if (newState == OverPullHelper.OVER_PULL_SETTLING - && oldState != OverPullHelper.OVER_PULL_SETTLING) { - getOnScrollDragEndedEvent().send(getParentView(), generateScrollEvent()); - } - } - - private boolean isOverPulling(int newState) { - return newState == OverPullHelper.OVER_PULL_DOWN_ING - || newState == OverPullHelper.OVER_PULL_UP_ING; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyContentDrawable.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyContentDrawable.java deleted file mode 100644 index 993bc901dfe..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyContentDrawable.java +++ /dev/null @@ -1,113 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.image; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.supportui.views.asyncimage.ContentDrawable; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; -import android.graphics.drawable.NinePatchDrawable; - -class HippyContentDrawable extends ContentDrawable { - - private Rect mNinePatchRect; - private NinePatchDrawable mNinePatchDrawable; - - HippyContentDrawable() { - super(); - } - - void setNinePatchCoordinate(Rect rect) { - mNinePatchRect = rect; - mNinePatchDrawable = null; - } - - @Override - public void draw(Canvas canvas) { - // 处理.9Patch的形式,不支持缩放、圆角 - if (mNinePatchRect != null && mContentBitmap != null) { - if (mNinePatchDrawable == null) { - mNinePatchDrawable = new NinePatchDrawable(ContextHolder.getAppContext().getResources(), - mContentBitmap, - createNinePatchTrunk(mContentBitmap, mNinePatchRect), null, null); - } - mNinePatchDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - mNinePatchDrawable.setAlpha(mAlpha); - if (mTintColor != Color.TRANSPARENT) { - mNinePatchDrawable - .setColorFilter(new PorterDuffColorFilter(mTintColor, PorterDuff.Mode.SRC_ATOP)); - } - mNinePatchDrawable.draw(canvas); - return; - } - super.draw(canvas); - } - - private byte[] createNinePatchTrunk(Bitmap bitmap, Rect ninePatchRect) { - int[] xRegions = new int[]{ninePatchRect.left, bitmap.getWidth() - ninePatchRect.right}; - int[] yRegions = new int[]{ninePatchRect.top, bitmap.getHeight() - ninePatchRect.bottom}; - int NO_COLOR = 0x00000001; - int colorSize = 9; - int bufferSize = xRegions.length * 4 + yRegions.length * 4 + colorSize * 4 + 32; - - ByteBuffer byteBuffer = ByteBuffer.allocate(bufferSize).order(ByteOrder.nativeOrder()); - // 第一个byte,要不等于0 - byteBuffer.put((byte) 1); - - //mDivX length - byteBuffer.put((byte) 2); - //mDivY length - byteBuffer.put((byte) 2); - //mColors length - byteBuffer.put((byte) colorSize); - - //skip - byteBuffer.putInt(0); - byteBuffer.putInt(0); - - //padding 先设为0 - byteBuffer.putInt(0); - byteBuffer.putInt(0); - byteBuffer.putInt(0); - byteBuffer.putInt(0); - - //skip - byteBuffer.putInt(0); - - // mDivX - byteBuffer.putInt(xRegions[0]); - byteBuffer.putInt(xRegions[1]); - - // mDivY - byteBuffer.putInt(yRegions[0]); - byteBuffer.putInt(yRegions[1]); - - // mColors - for (int i = 0; i < colorSize; i++) { - byteBuffer.putInt(NO_COLOR); - } - - return byteBuffer.array(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyImageView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyImageView.java deleted file mode 100644 index c3706eff781..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyImageView.java +++ /dev/null @@ -1,635 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.image; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Movie; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.text.TextUtils; -import android.view.MotionEvent; -import android.view.View; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.adapter.image.HippyDrawable; -import com.tencent.mtt.hippy.adapter.image.HippyImageLoader; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.UrlUtils; -import com.tencent.mtt.hippy.views.common.CommonBackgroundDrawable; -import com.tencent.mtt.hippy.views.common.CommonBorder; -import com.tencent.mtt.hippy.views.list.HippyRecycler; -import com.tencent.mtt.supportui.adapters.image.IDrawableTarget; -import com.tencent.mtt.supportui.views.asyncimage.AsyncImageView; -import com.tencent.mtt.supportui.views.asyncimage.BackgroundDrawable; -import com.tencent.mtt.supportui.views.asyncimage.ContentDrawable; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -@SuppressWarnings({"deprecation", "unused"}) -public class HippyImageView extends AsyncImageView implements CommonBorder, HippyViewBase, - HippyRecycler { - - public static final String IMAGE_TYPE_APNG = "apng"; - public static final String IMAGE_TYPE_GIF = "gif"; - public static final String IMAGE_PROPS = "props"; - public static final String IMAGE_VIEW_OBJ = "viewobj"; - - private HippyMap initProps = new HippyMap(); - private boolean mHasSetTempBackgroundColor = false; - private boolean mUserHasSetBackgroudnColor = false; - private int mUserSetBackgroundColor = Color.TRANSPARENT; - - /** - * 播放GIF动画的关键类 - */ - private Movie mGifMovie; - private int mGifStartX = 0; - private int mGifStartY = 0; - private float mGifScaleX = 1; - private float mGifScaleY = 1; - private boolean mGifMatrixComputed = false; - private int mGifProgress = 0; - private long mGifLastPlayTime = -1; - - @Override - public void resetProps() { - HippyViewController.resetTransform(this); - setAlpha(1.0f); - mTintColor = 0; - mBGDrawable = null; - mContentDrawable = null; - mScaleType = AsyncImageView.ScaleType.FIT_XY; - setImagePositionX(0); - setImagePositionY(0); - mUrl = null; - mImageType = null; - setBackgroundDrawable(null); - Arrays.fill(mShouldSendImageEvent, false); - } - - @Override - public void clear() { - //先解决图片绘制黑屏的问题。 更完全的改法是调用resetProps. - mTintColor = 0; - } - - public enum ImageEvent { - ONLOAD, - ONLOAD_START, - ONLOAD_END, - ONERROR - } - - protected NativeGestureDispatcher mGestureDispatcher; - - private OnLoadEvent mOnLoadEvent; - private OnLoadEndEvent mOnLoadEndEvent; - private OnErrorEvent mOnErrorEvent; - private OnLoadStartEvent mOnLoadStartEvent; - private final boolean[] mShouldSendImageEvent; - private Rect mNinePatchRect; - private final HippyEngineContext hippyEngineContext; - - public HippyImageView(Context context) { - super(context); - mShouldSendImageEvent = new boolean[ImageEvent.values().length]; - hippyEngineContext = ((HippyInstanceContext) context).getEngineContext(); - if (hippyEngineContext != null) { - setImageAdapter(hippyEngineContext.getGlobalConfigs().getImageLoaderAdapter()); - } - } - - public void setInitProps(HippyMap props) { - initProps = props; - } - - /** - * 前端传递下来的参数 left 到左边的距离 right 到右边的距离 top 到上边的距离 botttom 到下边的距离 Robinsli - */ - public void setNinePatchCoordinate(boolean shouldClearNinePatch, int left, int top, int right, - int botttom) { - if (shouldClearNinePatch) { - mNinePatchRect = null; - } else { - if (mNinePatchRect == null) { - mNinePatchRect = new Rect(); - } - mNinePatchRect.set(left, top, right, botttom); - } - if (mContentDrawable instanceof HippyContentDrawable) { - ((HippyContentDrawable) mContentDrawable).setNinePatchCoordinate(mNinePatchRect); - invalidate(); - } - } - - protected void setImageEventEnable(int index, boolean enable) { - mShouldSendImageEvent[index] = enable; - } - - @Override - protected void resetContent() { - super.resetContent(); - mGifMovie = null; - mGifProgress = 0; - mGifLastPlayTime = -1; - } - - @Override - protected boolean shouldUseFetchImageMode(String url) { - return UrlUtils.isWebUrl(url) || UrlUtils.isFileUrl(url); - } - - public void setHippyViewDefaultSource(String defaultSourceUrl) { - setDefaultSource(defaultSourceUrl); - } - - @Override - protected void doFetchImage(Object param, final int sourceType) { - if (mImageAdapter != null) { - if (param == null) { - param = new HashMap(); - } - - if (param instanceof Map) { - if (hippyEngineContext != null) { - RenderNode node = hippyEngineContext.getRenderManager().getRenderNode(getId()); - if (node != null) { - initProps = node.getProps(); - } - } - - try { - //noinspection unchecked,rawtypes - ((Map) param).put(IMAGE_PROPS, initProps); - //noinspection unchecked,rawtypes - ((Map) param).put(IMAGE_VIEW_OBJ, this); - } catch (Exception e) { - LogUtils.d("HippyImageView", "doFetchImage: " + e); - } - } - - // 这里不判断下是取背景图片还是取当前图片怎么行? - final String url = sourceType == SOURCE_TYPE_SRC ? mUrl : mDefaultSourceUrl; - //noinspection unchecked - mImageAdapter.fetchImage(url, new HippyImageLoader.Callback() { - @Override - public void onRequestStart(HippyDrawable drawableTarget) { - mSourceDrawable = drawableTarget; - } - - @Override - public void onRequestSuccess(HippyDrawable drawableTarget) { - if (sourceType == SOURCE_TYPE_SRC) { - if (!TextUtils.equals(url, mUrl)) { - return; - } - mUrlFetchState = IMAGE_LOADED; - } - - if (sourceType == SOURCE_TYPE_DEFAULT_SRC && !TextUtils.equals(url, mDefaultSourceUrl)) { - return; - } - - handleImageRequest(drawableTarget, sourceType, null); - } - - @Override - public void onRequestFail(Throwable throwable, String source) { - if (sourceType == SOURCE_TYPE_SRC) { - if (!TextUtils.equals(url, mUrl)) { - return; - } - mUrlFetchState = IMAGE_UNLOAD; - } - - if (sourceType == SOURCE_TYPE_DEFAULT_SRC && !TextUtils.equals(url, mDefaultSourceUrl)) { - return; - } - - handleImageRequest(null, sourceType, throwable); - } - }, param); - } - } - - public void setBackgroundColor(int backgroundColor) { - mUserHasSetBackgroudnColor = true; - mUserSetBackgroundColor = backgroundColor; - super.setBackgroundColor(backgroundColor); - } - - @Override - protected void onFetchImage(String url) { - if (mContentDrawable instanceof ContentDrawable && - ((ContentDrawable) mContentDrawable).getSourceType() == SOURCE_TYPE_DEFAULT_SRC) { - return; - } - - Drawable oldBGDrawable = getBackground(); - resetContent(); - - if (url != null && (UrlUtils.isWebUrl(url) || UrlUtils.isFileUrl(url))) { - int defaultBackgroundColor = Color.LTGRAY; - if (mUserHasSetBackgroudnColor) { - defaultBackgroundColor = mUserSetBackgroundColor; - } - - if (oldBGDrawable instanceof CommonBackgroundDrawable) { - ((CommonBackgroundDrawable) oldBGDrawable).setBackgroundColor(defaultBackgroundColor); - setCustomBackgroundDrawable((CommonBackgroundDrawable) oldBGDrawable); - } else if (oldBGDrawable instanceof LayerDrawable) { - LayerDrawable layerDrawable = (LayerDrawable) oldBGDrawable; - int numberOfLayers = layerDrawable.getNumberOfLayers(); - - if (numberOfLayers > 0) { - Drawable bgDrawable = layerDrawable.getDrawable(0); - if (bgDrawable instanceof CommonBackgroundDrawable) { - ((CommonBackgroundDrawable) bgDrawable).setBackgroundColor(defaultBackgroundColor); - setCustomBackgroundDrawable((CommonBackgroundDrawable) bgDrawable); - } - } - } - super.setBackgroundColor(defaultBackgroundColor); - mHasSetTempBackgroundColor = true; - } - } - - @Override - protected void afterSetContent(String url) { - restoreBackgroundColorAfterSetContent(); - } - - @Override - protected void restoreBackgroundColorAfterSetContent() { - if (mBGDrawable != null && mHasSetTempBackgroundColor) { - int defaultBackgroundColor = Color.TRANSPARENT; - mBGDrawable.setBackgroundColor(defaultBackgroundColor); - mHasSetTempBackgroundColor = false; - } - } - - @Override - protected void updateContentDrawableProperty(int sourceType) { - super.updateContentDrawableProperty(sourceType); - if (mContentDrawable instanceof HippyContentDrawable && sourceType == SOURCE_TYPE_SRC) { - ((HippyContentDrawable) mContentDrawable).setNinePatchCoordinate(mNinePatchRect); - } - } - - @Override - protected ContentDrawable generateContentDrawable() { - return new HippyContentDrawable(); - } - - @Override - protected BackgroundDrawable generateBackgroundDrawable() { - return new CommonBackgroundDrawable(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean result = super.onTouchEvent(event); - if (mGestureDispatcher != null) { - result |= mGestureDispatcher.handleTouchEvent(event); - } - return result; - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return mGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - mGestureDispatcher = dispatcher; - } - - @Override - protected void handleGetImageStart() { - // send onLoadStart event - if (mShouldSendImageEvent[ImageEvent.ONLOAD_START.ordinal()]) { - getOnLoadStartEvent().send(this, null); - } - } - - @Override - protected void handleGetImageSuccess() { - // send onLoad event - if (mShouldSendImageEvent[ImageEvent.ONLOAD.ordinal()]) { - getOnLoadEvent().send(this, null); - } - // send onLoadEnd event - if (mShouldSendImageEvent[ImageEvent.ONLOAD_END.ordinal()]) { - HippyMap map = new HippyMap(); - map.pushInt("success", 1); - if (mSourceDrawable != null) { - Bitmap bitmap = mSourceDrawable.getBitmap(); - if (bitmap != null) { - HippyMap imageSize = new HippyMap(); - imageSize.pushInt("width", bitmap.getWidth()); - imageSize.pushInt("height", bitmap.getHeight()); - map.pushMap("image", imageSize); - } - } - getOnLoadEndEvent().send(this, map); - } - } - - @Override - protected void handleGetImageFail(Throwable throwable) { - // send onError event - if (mShouldSendImageEvent[ImageEvent.ONERROR.ordinal()]) { - getOnErrorEvent().send(this, null); - } - // send onLoadEnd event - if (mShouldSendImageEvent[ImageEvent.ONLOAD_END.ordinal()]) { - HippyMap map = new HippyMap(); - map.pushInt("success", 0); - getOnLoadEndEvent().send(this, map); - } - } - - private void computeMatrixParams() { - if (!mGifMatrixComputed) { - // reset - mGifStartX = 0; - mGifStartY = 0; - mGifScaleX = 1; - mGifScaleY = 1; - if (mGifMovie.width() > 0 && mGifMovie.height() > 0 && getWidth() > 0 && getHeight() > 0) { - mGifScaleX = getWidth() / (float) mGifMovie.width(); - mGifScaleY = getHeight() / (float) mGifMovie.height(); - } - ScaleType type = mScaleType != null ? mScaleType : ScaleType.FIT_XY; - switch (type) { - case FIT_XY: - // 拉伸图片且不维持宽高比,直到宽高都刚好填满容器 - break; - case CENTER: - // 居中不拉伸 - mGifScaleX = 1; - mGifScaleY = 1; - break; - case CENTER_INSIDE: - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸 - // 这样图片完全被包裹在容器中,容器中可能留有空白 - if (mGifScaleX > mGifScaleY) { - //noinspection SuspiciousNameCombination - mGifScaleX = mGifScaleY; - } else { - //noinspection SuspiciousNameCombination - mGifScaleY = mGifScaleX; - } - break; - case CENTER_CROP: - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸 - // 这样图片完全覆盖甚至超出容器,容器中不留任何空白 - if (mGifScaleX < mGifScaleY) { - //noinspection SuspiciousNameCombination - mGifScaleX = mGifScaleY; - } else { - //noinspection SuspiciousNameCombination - mGifScaleY = mGifScaleX; - } - break; - case ORIGIN: - mGifScaleX = mGifScaleY = 1; - // 不拉伸,居左上 - break; - } - if (mScaleType != ScaleType.ORIGIN) { - mGifStartX = (int) ((getWidth() / mGifScaleX - mGifMovie.width()) / 2f); - mGifStartY = (int) ((getHeight() / mGifScaleY - mGifMovie.height()) / 2f); - } - mGifMatrixComputed = true; - } - } - - @Override - protected void handleImageRequest(IDrawableTarget target, int sourceType, Object requestInfo) { - if (target != null && !TextUtils.isEmpty(target.getImageType())) { - mImageType = target.getImageType(); - } - - if (target instanceof HippyDrawable && ((HippyDrawable)target).isAnimated()) { - mGifMovie = ((HippyDrawable) target).getGIF(); - setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - - if (!TextUtils.isEmpty(mImageType) && mImageType.equals(IMAGE_TYPE_APNG) - && sourceType == SOURCE_TYPE_SRC) { - if (target != null) { - Drawable drawable = target.getDrawable(); - if (drawable != null) { - mSourceDrawable = null; - mContentDrawable = drawable; - mUrlFetchState = IMAGE_LOADED; - setContent(sourceType); - handleGetImageSuccess(); - return; - } - } - - mUrlFetchState = IMAGE_UNLOAD; - handleGetImageFail(requestInfo instanceof Throwable ? (Throwable) requestInfo : null); - } else { - super.handleImageRequest(target, sourceType, requestInfo); - } - } - - protected boolean drawGIF(Canvas canvas) { - if (mGifMovie == null) { - return false; - } - - int duration = mGifMovie.duration(); - if (duration == 0) { - duration = 1000; - } - - long now = System.currentTimeMillis(); - - if (!isGifPaused) { - if (mGifLastPlayTime != -1) { - mGifProgress += now - mGifLastPlayTime; - - if (mGifProgress > duration) { - mGifProgress = 0; - } - } - mGifLastPlayTime = now; - } - - computeMatrixParams(); - mGifMovie.setTime(mGifProgress); - canvas.save(); // 保存变换矩阵 - canvas.scale(mGifScaleX, mGifScaleY); - mGifMovie.draw(canvas, mGifStartX, mGifStartY); - canvas.restore(); // 恢复变换矩阵 - - if (!isGifPaused) { - postInvalidateDelayed(40); - } - - return true; - } - - protected boolean shouldFetchImage() { - if (mUrlFetchState == IMAGE_LOADING) { - return false; - } else if (mUrlFetchState == IMAGE_UNLOAD) { - return true; - } - - boolean isGif = (initProps != null) && initProps.getBoolean(NodeProps.CUSTOM_PROP_ISGIF); - if (!isGif) { - isGif = !TextUtils.isEmpty(mImageType) && mImageType.equals(IMAGE_TYPE_GIF); - } - - if (!TextUtils.isEmpty(mImageType) && mImageType.equals(IMAGE_TYPE_APNG) - && mContentDrawable != null && !(mContentDrawable instanceof ContentDrawable)) { - return false; - } else if (isGif) { - return mGifMovie == null; - } else { - Bitmap bitmap = getBitmap(); - //noinspection RedundantIfStatement - if (bitmap == null || bitmap.isRecycled()) { - return true; - } - } - - return false; - } - - // 图片自绘功能(方便自定义支持gif、webp、tpg等)尚未实现,暂时注释 -// private void drawSelf(Canvas canvas, HippyDrawable drawable) { -// computeMatrixParams(); -// canvas.save(); // 保存变换矩阵 -// -// canvas.clipRect(new Rect(mGifStartX, mGifStartY, canvas.getWidth(), canvas.getHeight())); -// canvas.scale(mGifScaleX, mGifScaleY); -// -// drawable.draw(canvas); -// -// // canvas.restore(); // 恢复变换矩阵 -// postInvalidateDelayed(40); -// } - - @Override - public void onDraw(Canvas canvas) { - super.onDraw(canvas); - // 图片自绘功能(方便自定义支持gif、webp、tpg等)尚未实现,暂时注释 -// if (mSourceDrawable instanceof HippyDrawable) -// { -// HippyDrawable drawable = (HippyDrawable) mSourceDrawable; -// if (drawable.isSelfDraw()) -// drawSelf(canvas, drawable); -// } -// else - if (mGifMovie != null) { - // 如果是GIF,就调用drawGIF()方法播放GIF动画 - drawGIF(canvas); - } - } - - private boolean isGifPaused = false; - - public void startPlay() { - isGifPaused = false; - invalidate(); - } - - public void pause() { - isGifPaused = true; - mGifLastPlayTime = -1; - } - - - private OnLoadEvent getOnLoadEvent() { - if (mOnLoadEvent == null) { - mOnLoadEvent = new OnLoadEvent(); - } - return mOnLoadEvent; - } - - private OnLoadEndEvent getOnLoadEndEvent() { - if (mOnLoadEndEvent == null) { - mOnLoadEndEvent = new OnLoadEndEvent(); - } - return mOnLoadEndEvent; - } - - private OnLoadStartEvent getOnLoadStartEvent() { - if (mOnLoadStartEvent == null) { - mOnLoadStartEvent = new OnLoadStartEvent(); - } - return mOnLoadStartEvent; - } - - private OnErrorEvent getOnErrorEvent() { - if (mOnErrorEvent == null) { - mOnErrorEvent = new OnErrorEvent(); - } - return mOnErrorEvent; - } - - /** - * event to js - **/ - static class OnLoadEvent extends HippyViewEvent { - - OnLoadEvent() { - super("onLoad"); - } - } - - static class OnLoadEndEvent extends HippyViewEvent { - - OnLoadEndEvent() { - super("onLoadEnd"); - } - } - - static class OnLoadStartEvent extends HippyViewEvent { - - OnLoadStartEvent() { - super("onLoadStart"); - } - } - - static class OnErrorEvent extends HippyViewEvent { - - OnErrorEvent() { - super("onError"); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyImageViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyImageViewController.java deleted file mode 100644 index 9fe428024f2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/image/HippyImageViewController.java +++ /dev/null @@ -1,155 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.image; - -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.ImageNode; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.uimanager.HippyViewController; - -import android.content.Context; -import android.graphics.Color; -import android.view.View; - -import java.io.File; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyImageViewController.CLASS_NAME) -public class HippyImageViewController extends HippyViewController { - - public static final String CLASS_NAME = "Image"; - - @Override - protected StyleNode createNode(boolean virtual) { - return new ImageNode(virtual); - } - - @Override - protected View createViewImpl(Context context, HippyMap iniProps) { - HippyImageView imageView = new HippyImageView(context); - if (iniProps != null) { - imageView.setInitProps(iniProps); - } - - return imageView; - } - - @SuppressWarnings("unused") - @Override - protected View createViewImpl(Context context) { - return new HippyImageView(context); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.CUSTOM_PROP_IMAGE_TYPE, defaultType = HippyControllerProps.STRING) - public void setImageType(HippyImageView hippyImageView, String type) { - hippyImageView.setImageType(type); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "src", defaultType = HippyControllerProps.STRING) - public void setUrl(HippyImageView hippyImageView, String url) { - hippyImageView.setUrl(getInnerPath((HippyInstanceContext) hippyImageView.getContext(), url)); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "tintColor", defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setTintColor(HippyImageView hippyImageView, int tintColor) { - hippyImageView.setTintColor(tintColor); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.RESIZE_MODE, defaultType = HippyControllerProps.STRING, defaultString = "fitXY") - public void setResizeMode(HippyImageView hippyImageView, String resizeModeValue) { - if ("contain".equals(resizeModeValue)) { - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸 - // 这样图片完全被包裹在容器中,容器中可能留有空白 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_INSIDE); - } else if ("cover".equals(resizeModeValue)) { - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸 - // 这样图片完全覆盖甚至超出容器,容器中不留任何空白 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_CROP); - } else if ("center".equals(resizeModeValue)) { - // 居中不拉伸 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER); - } else if ("origin".equals(resizeModeValue)) { - // 不拉伸,居左上 - hippyImageView.setScaleType(HippyImageView.ScaleType.ORIGIN); - } else if ("repeat".equals(resizeModeValue)) { - hippyImageView.setScaleType(HippyImageView.ScaleType.REPEAT); - } else { - // stretch and other mode - // 拉伸图片且不维持宽高比,直到宽高都刚好填满容器 - hippyImageView.setScaleType(HippyImageView.ScaleType.FIT_XY); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = NodeProps.BACKGROUND_COLOR, defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setBackgroundColor(HippyImageView view, int backgroundColor) { - view.setBackgroundColor(backgroundColor); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "defaultSource", defaultType = HippyControllerProps.STRING) - public void setDefaultSource(HippyImageView hippyImageView, String defaultSource) { - hippyImageView.setHippyViewDefaultSource( - getInnerPath((HippyInstanceContext) hippyImageView.getContext(), defaultSource)); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "capInsets", defaultType = HippyControllerProps.MAP) - public void setCapInsets(HippyImageView hippyImageView, HippyMap capInsetsMap) { - if (capInsetsMap == null) { - hippyImageView.setNinePatchCoordinate(true, 0, 0, 0, 0); - } else { - int topCoordinate = capInsetsMap.getInt("top"); - int leftCoordinate = capInsetsMap.getInt("left"); - int bottomCoordinate = capInsetsMap.getInt("bottom"); - int rightCoordinate = capInsetsMap.getInt("right"); - hippyImageView.setNinePatchCoordinate(false, leftCoordinate, topCoordinate, rightCoordinate, - bottomCoordinate); - } - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "onLoad", defaultType = HippyControllerProps.BOOLEAN) - public void setOnLoad(HippyImageView hippyImageView, boolean enable) { - hippyImageView.setImageEventEnable(HippyImageView.ImageEvent.ONLOAD.ordinal(), enable); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "onLoadEnd", defaultType = HippyControllerProps.BOOLEAN) - public void setOnLoadEnd(HippyImageView hippyImageView, boolean enable) { - hippyImageView.setImageEventEnable(HippyImageView.ImageEvent.ONLOAD_END.ordinal(), enable); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "onLoadStart", defaultType = HippyControllerProps.BOOLEAN) - public void setOnLoadStart(HippyImageView hippyImageView, boolean enable) { - hippyImageView.setImageEventEnable(HippyImageView.ImageEvent.ONLOAD_START.ordinal(), enable); - } - - @SuppressWarnings("unused") - @HippyControllerProps(name = "onError", defaultType = HippyControllerProps.BOOLEAN) - public void setOnError(HippyImageView hippyImageView, boolean enable) { - hippyImageView.setImageEventEnable(HippyImageView.ImageEvent.ONERROR.ordinal(), enable); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListAdapter.java deleted file mode 100644 index 45d13c9001b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListAdapter.java +++ /dev/null @@ -1,581 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.list; - -import android.view.View; -import android.view.ViewGroup; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.DiffUtils; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.uimanager.ListItemRenderNode; -import com.tencent.mtt.hippy.uimanager.PullFooterRenderNode; -import com.tencent.mtt.hippy.uimanager.PullHeaderRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.views.refresh.HippyPullFooterView; -import com.tencent.mtt.hippy.views.refresh.HippyPullHeaderView; -import com.tencent.mtt.supportui.views.recyclerview.*; - -import java.util.ArrayList; - -@SuppressWarnings("deprecation") -public class HippyListAdapter extends RecyclerAdapter implements IRecycleItemTypeChange { - - protected final HippyEngineContext mHippyContext; - private RecyclerViewBase.Recycler mRecycler; - private HippyViewEvent onEndReachedEvent; - private HippyViewEvent onLoadMoreEvent; - // --Commented out by Inspection (2021/5/4 20:54):private static final String TAG = "HippyListAdapter"; - // harryguo: 给hippy sdk提供API:设置提前预加载的条目数量,默认为0 - private int mPreloadItemNum = 0; - - public HippyListAdapter(RecyclerView recyclerView, HippyEngineContext HippyContext) { - super(recyclerView); - mHippyContext = HippyContext; - } - - @Override - public String getViewHolderReUseKey(int position) { - if (position < 0 || position > getItemCount()) { - return null; - } - - return String.valueOf(position); - } - - @Override - public RecyclerView.ViewHolderWrapper onCreateSuspendViewHolderWithPos(RecyclerViewBase parent, - int position, int viewType) { - return null; - } - - @Override - public ContentHolder onCreateContentViewWithPos(ViewGroup parent, int position, int viewType) { - NodeHolder contentHolder = new NodeHolder(); - //LogUtils.d("HippyListView", "onCreateContentViewWithPos start position " + position); - RenderNode contentViewRenderNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()).getChildAt(position); - contentViewRenderNode.setLazy(false); - View view = contentViewRenderNode.createViewRecursive(); - contentHolder.mContentView = view; - if (view instanceof HippyPullHeaderView) { - ((HippyPullHeaderView) view).setParentView(mParentRecyclerView); - } - if (view instanceof HippyPullFooterView) { - ((HippyPullFooterView) view).setParentView(mParentRecyclerView); - } - contentHolder.mBindNode = contentViewRenderNode; - contentHolder.isCreated = true; - //LogUtils.d("HippyListView", "onCreateContentViewWithPos end position " + position); - //LogUtils.d("HippyListView", "onCreateContentViewWithPos" + contentViewRenderNode); - return contentHolder; - } - - - @Override - protected void onViewAbandon(RecyclerView.ViewHolderWrapper viewHolder) { - // set is lazy true the holder is delete so delete view - NodeHolder nodeHolder = (NodeHolder) viewHolder.mContentHolder; - - if (nodeHolder.mBindNode != null && !nodeHolder.mBindNode.isDelete()) { - //LogUtils.d("HippyListView", "onViewAbandon start " + nodeHolder.mBindNode.toString()); - nodeHolder.mBindNode.setLazy(true); - RenderNode parentNode = nodeHolder.mBindNode.getParent(); - if (parentNode != null) { - mHippyContext.getRenderManager().getControllerManager() - .deleteChild(parentNode.getId(), nodeHolder.mBindNode.getId()); - } - //LogUtils.d("HippyListView", "onViewAbandon end " + nodeHolder.mBindNode.toString()); - } - if (nodeHolder.mBindNode instanceof ListItemRenderNode) { - //LogUtils.d("HippyListView", "onViewAbandon start " + nodeHolder.mBindNode.toString()); - ((ListItemRenderNode) nodeHolder.mBindNode).setRecycleItemTypeChangeListener(null); - } - super.onViewAbandon(viewHolder); - } - - @Override - public void onBindContentView(ContentHolder holder, int position, int layoutType) { - NodeHolder contentHolder = (NodeHolder) holder; - //LogUtils.d("HippyListView", "onBindContentView : " + position); - if (contentHolder.isCreated) { - contentHolder.mBindNode.updateViewRecursive(); -// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG," onBindContentView updateViewRecursive"); - contentHolder.isCreated = false; - } else { - //step 1: diff - contentHolder.mBindNode.setLazy(true); - RenderNode toNode = null; - try { - toNode = mHippyContext.getRenderManager().getRenderNode(mParentRecyclerView.getId()) - .getChildAt(position); - } catch (Throwable e) { - LogUtils.d("HippyListAdapter", "onBindContentView: " + e.getMessage()); - } - //保护下 - if (toNode == null) { - return; - } - toNode.setLazy(false); - - //LogUtils.d("HippyListView", "toNode: " + toNode.toString()); -// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG, "toNode: " + toNode.toString()); - //LogUtils.d("HippyListView", "fromNode: " + contentHolder.mBindNode.toString()); -// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG,"fromNode: " + contentHolder.mBindNode.toString()); - - ArrayList patchTypes = DiffUtils.diff(contentHolder.mBindNode, toNode); - //LogUtils.d("HippyListView", " DiffUtils.diff position: " + position); - -// for (DiffUtils.PatchType patchType : patchTypes) -// { -// LogUtils.d("HippyListView", patchType.mPatch.toString()); -//// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG, patchType.mPatch.toString()); -// } - - //step:2 delete unUseful views - DiffUtils.deleteViews(mHippyContext.getRenderManager().getControllerManager(), patchTypes); - //LogUtils.d("HippyListView", " deleteViews position: " + position); -// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG, " deleteViews position: " + position); - //step:3 replace id - DiffUtils.replaceIds(mHippyContext.getRenderManager().getControllerManager(), patchTypes); - //LogUtils.d("HippyListView", " replaceIds position: " + position); -// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG, " replaceIds position: " + position); - //step:4 create view is do not reUse - DiffUtils.createView(patchTypes); - //LogUtils.d("HippyListView", " createView position: " + position); -// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG, " createView position: " + position); - //step:5 patch the dif result - DiffUtils.doPatch(mHippyContext.getRenderManager().getControllerManager(), patchTypes); - //LogUtils.d("HippyListView", " doPatch position: " + position); -// mHippyContext.getGlobalConfigs().getLogAdapter().log(TAG, " doPatch position: " + position); - - contentHolder.mBindNode = toNode; - } - if (contentHolder.mBindNode instanceof ListItemRenderNode) { - ((ListItemRenderNode) contentHolder.mBindNode).setRecycleItemTypeChangeListener(this); - } - } - - - @Override - public boolean hasCustomRecycler() { - return true; - } - - RecyclerViewBase.ViewHolder findBestHolderRecursive(int position, int targetType, - RecyclerViewBase.Recycler recycler) { - RecyclerViewBase.ViewHolder matchHolder = getScrapViewForPositionInner(position, targetType, - recycler); - if (matchHolder == null) { - matchHolder = recycler.getViewHolderForPosition(position); - } - - if (matchHolder != null && ((NodeHolder) matchHolder.mContentHolder).mBindNode.isDelete()) { - matchHolder = findBestHolderRecursive(position, targetType, recycler); - } - - return matchHolder; - } - - ArrayList mListViewHolder; - - public int getRecyclerItemCount() { - mListViewHolder = new ArrayList<>(); - - RecyclerViewBase.Recycler recycler = mParentRecyclerView.getRecycler(); - - mListViewHolder.addAll(recycler.mAttachedScrap); - - mListViewHolder.addAll(recycler.mCachedViews); - - for (int i = 0; i < recycler.getRecycledViewPool().mScrap.size(); i++) { - mListViewHolder.addAll(recycler.getRecycledViewPool().mScrap.valueAt(i)); - } - return mListViewHolder.size() + mParentRecyclerView.getChildCount(); - } - - View getRecyclerItemView(int index) { - if (index < mListViewHolder.size()) { - return mListViewHolder.get(index).mContent; - } else { - return mParentRecyclerView.getChildAt(index - mListViewHolder.size()); - } - - } - - @Override - public RecyclerViewBase.ViewHolder findBestHolderForPosition(int position, - RecyclerViewBase.Recycler recycler) { - LogUtils.d("HippyListView", "findBestHolderForPosition start : " + position); - mRecycler = recycler; - int targetType = getItemViewType(position); - RecyclerViewBase.ViewHolder matchHolder = findBestHolderRecursive(position, targetType, - recycler); - LogUtils.d("HippyListView", "findBestHolderForPosition end : " + position); - return matchHolder; - } - - @Override - public RecyclerViewBase.ViewHolder findSuspendHolderForPosition(int position, - RecyclerViewBase.Recycler recycler) { - mRecycler = recycler; - int targetType = getItemViewType(position); - RecyclerViewBase.ViewHolder matchHolder = getScrapViewForPositionInner(position, targetType, - recycler); - if (matchHolder != null && ((NodeHolder) matchHolder.mContentHolder).mBindNode.isDelete()) { - return null; - } - return matchHolder; - } - - private RecyclerViewBase.ViewHolder getScrapViewForPositionInner(int position, int type, - RecyclerViewBase.Recycler recycler) { - if (mHippyContext.getRenderManager().getRenderNode(mParentRecyclerView.getId()) == null - || - mHippyContext.getRenderManager().getRenderNode(mParentRecyclerView.getId()).getChildCount() - <= position) { - return null; - } - final int scrapCount = recycler.mAttachedScrap.size(); - // Try first for an exact, non-invalid match from scrap. - for (int i = 0; i < scrapCount; i++) { - final RecyclerViewBase.ViewHolder holder = recycler.mAttachedScrap.get(i); - if (holder.getPosition() == position && !holder.isInvalid() && (!holder.isRemoved())) { - if (holder.getItemViewType() == type && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - RenderNode toNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()).getChildAt(position); - if (holderNode == toNode) { - recycler.mAttachedScrap.remove(i); - holder.setScrapContainer(null); - return holder; - } - } - } - } - // Search in our first-level recycled view cache. - final int cacheSize = recycler.mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) { - final RecyclerViewBase.ViewHolder holder = recycler.mCachedViews.get(i); - if (holder.getPosition() == position && holder.getItemViewType() == type && !holder - .isInvalid() - && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - RenderNode toNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()).getChildAt(position); - if (holderNode == toNode) { - recycler.mCachedViews.remove(i); - return holder; - } - } - } - // Give up. Head to the shared pool. - return this.getRecycledViewFromPoolInner(recycler.getRecycledViewPool(), type, position); - } - - private RecyclerViewBase.ViewHolder getRecycledViewFromPoolInner( - RecyclerViewBase.RecycledViewPool pool, int viewType, int position) { - if (pool != null) { - final ArrayList scrapHeap = pool.mScrap.get(viewType); - if (scrapHeap != null && !scrapHeap.isEmpty()) { - // traverse all scrap - for (RecyclerViewBase.ViewHolder holder : scrapHeap) { - if (holder.getItemViewType() == viewType && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - RenderNode toNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()).getChildAt(position); - if (holderNode == toNode) { - scrapHeap.remove(holder); - return holder; - } - } - } - } - } - return null; - } - - private void checkHolderType(int oldType, int newType, ListItemRenderNode listItemRenderNode) { - //do checkHolderType onScreen - int count = mParentRecyclerView.getChildCount(); - for (int i = 0; i < count; i++) { - final RecyclerViewBase.ViewHolder holder = mParentRecyclerView - .getChildViewHolder(mParentRecyclerView.getChildAt(i)); - if (holder.getItemViewType() == oldType && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - return; - } - } - } - - //do checkHolderType inCache - final int scrapCount = mRecycler.mAttachedScrap.size(); - // Try first for an exact, non-invalid match from scrap. - for (int i = 0; i < scrapCount; i++) { - final RecyclerViewBase.ViewHolder holder = mRecycler.mAttachedScrap.get(i); - - if (holder.getItemViewType() == oldType && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - return; - } - } - } - - // Search in our first-level recycled view cache. - final int cacheSize = mRecycler.mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) { - final RecyclerViewBase.ViewHolder holder = mRecycler.mCachedViews.get(i); - if (holder.getItemViewType() == oldType && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - return; - } - } - } - - // Give up. Head to the shared pool. - if (mRecycler.getRecycledViewPool() != null) { - final ArrayList scrapHeap = mRecycler - .getRecycledViewPool().mScrap.get(oldType); - if (scrapHeap != null && !scrapHeap.isEmpty()) { - // traverse all scrap - for (RecyclerViewBase.ViewHolder holder : scrapHeap) { - if (holder.getItemViewType() == oldType && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - scrapHeap.remove(holder); - mRecycler.getRecycledViewPool().getScrapHeapForType(newType).add(holder); - return; - } - } - } - } - } - } - - @Override - public int getCustomHeaderViewWidth() { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > 0) { - RenderNode listItemNode = listNode.getChildAt(0); - if (listItemNode instanceof PullHeaderRenderNode) { - return listItemNode.getWidth(); - } - } - - return 0; - } - - @Override - public int getCustomFooterViewWidth() { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > 0) { - RenderNode listItemNode = listNode.getChildAt(listNode.getChildCount() - 1); - if (listItemNode instanceof PullFooterRenderNode) { - return listItemNode.getWidth(); - } - } - - return 0; - } - - @Override - public int getCustomHeaderViewHeight() { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > 0) { - RenderNode listItemNode = listNode.getChildAt(0); - if (listItemNode instanceof PullHeaderRenderNode) { - return listItemNode.getHeight(); - } - } - - return 0; - } - - @Override - public int getCustomFooterViewHeight() { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > 0) { - RenderNode listItemNode = listNode.getChildAt(listNode.getChildCount() - 1); - if (listItemNode instanceof PullFooterRenderNode) { - return listItemNode.getHeight(); - } - } - - return 0; - } - - @Override - public int getItemHeight(int index) { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > index && index >= 0) { - RenderNode listItemNode = listNode.getChildAt(index); - if (listItemNode != null) { - return listItemNode.getHeight(); - } - } - return 0; - } - - @Override - public int getItemWidth(int index) { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > index && index >= 0) { - RenderNode listItemNode = listNode.getChildAt(index); - if (listItemNode != null) { - return listItemNode.getWidth(); - } - } - return 0; - } - - @Override - public int getTotalHeight() { - if (isAutoCalculateItemHeight()) { - mContentHeight = -1; - } - if (mContentHeight == -1) { - int itemCount = getItemCount(); - mContentHeight = 0; - - if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_LIST) { - for (int i = 0; i < itemCount; i++) { - if (mParentRecyclerView.mLayout.canScrollHorizontally()) { - mContentHeight += getItemWidth(i); - mContentHeight += getItemMaigin(LOCATION_LEFT, i); - mContentHeight += getItemMaigin(LOCATION_RIGHT, i); - } else { - mContentHeight += getItemHeight(i); - mContentHeight += getItemMaigin(LOCATION_TOP, i); - mContentHeight += getItemMaigin(LOCATION_BOTTOM, i); - } - } - } - } - - int footerViewSize = mParentRecyclerView.mLayout.canScrollHorizontally() ? - getCustomFooterViewWidth() : getCustomFooterViewHeight(); - return mContentHeight - footerViewSize; - } - - @Override - public int getItemCount() { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null) { - return listNode.getChildCount(); - } - return super.getItemCount(); - } - - @Override - public int getItemViewType(int index) { - RenderNode listViewNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listViewNode != null && listViewNode.getChildCount() > index) { - RenderNode listItemNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()).getChildAt(index); - if (listItemNode != null) { - if (listItemNode instanceof PullFooterRenderNode) { - return RecyclerViewBase.ViewHolder.TYPE_CUSTOM_FOOTER; - } - - if (listItemNode instanceof PullHeaderRenderNode) { - return RecyclerViewBase.ViewHolder.TYPE_CUSTOM_HEADERE; - } - - if (listItemNode.getProps() != null) { - HippyMap listItemProps = listItemNode.getProps(); - if (listItemProps.get(ListItemRenderNode.ITEM_VIEW_TYPE) != null) { - return listItemProps.getInt(ListItemRenderNode.ITEM_VIEW_TYPE); - } - } - } - } - return super.getItemViewType(index); - } - - @Override - public boolean isSuspentedItem(int pos) { - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > pos) { - RenderNode listItemNode = listNode.getChildAt(pos); - if (listItemNode instanceof ListItemRenderNode) { - return ((ListItemRenderNode) listItemNode).shouldSticky(); - } - } - return super.isSuspentedItem(pos); - } - - @Override - public boolean isAutoCalculateItemHeight() { - return true; - } - - @Override - public void onRecycleItemTypeChanged(int oldType, int newType, ListItemRenderNode listItemNode) { - checkHolderType(oldType, newType, listItemNode); - } - - @Override - public void notifyEndReached() { - getOnEndReachedEvent().send(mParentRecyclerView, null); - getOnLoadMoreEvent().send(mParentRecyclerView, null); - } - - @Override - public int getPreloadThresholdInItemNumber() { - return mPreloadItemNum; - } - - @Override - public void onPreload() { - getOnEndReachedEvent().send(mParentRecyclerView, null); - getOnLoadMoreEvent().send(mParentRecyclerView, null); - } - - protected void setPreloadItemNumber(int preloadItemNum) { - mPreloadItemNum = preloadItemNum; - } - - protected HippyViewEvent getOnEndReachedEvent() { - if (onEndReachedEvent == null) { - onEndReachedEvent = new HippyViewEvent("onEndReached"); - } - return onEndReachedEvent; - } - - protected HippyViewEvent getOnLoadMoreEvent() { - if (onLoadMoreEvent == null) { - onLoadMoreEvent = new HippyViewEvent("onLoadMore"); - } - return onLoadMoreEvent; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListItemView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListItemView.java deleted file mode 100644 index 84503edd86d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListItemView.java +++ /dev/null @@ -1,139 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.list; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.view.View; -import android.view.ViewGroup; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.view.HippyViewGroup; - -public class HippyListItemView extends HippyViewGroup { - - private static final boolean VIEW_LEVEL_MONITOR_ENABLE = false; - private Paint mPaint; - - public final static int EXPOSURE_STATE_WILL_APPEAR = 0; - public final static int EXPOSURE_STATE_APPEAR = 1; - public final static int EXPOSURE_STATE_DISAPPEAR = 2; - public final static int EXPOSURE_STATE_WILL_DISAPPEAR = 3; - - public final static String EXPOSURE_EVENT_WILL_APPEAR = "onWillAppear"; - public final static String EXPOSURE_EVENT_APPEAR = "onAppear"; - public final static String EXPOSURE_EVENT_DISAPPEAR = "onDisAppear"; - public final static String EXPOSURE_EVENT_WILL_DISAPPEAR = "onWillDisappear"; - - private int mExposureState = EXPOSURE_STATE_DISAPPEAR; - - public int getExposureState() { - return mExposureState; - } - - public void setExposureState(int state) { - mExposureState = state; - } - - public HippyListItemView(Context context) { - super(context); - - if (VIEW_LEVEL_MONITOR_ENABLE) { - mPaint = new Paint(); - mPaint.setColor(Color.RED); - mPaint.setTextSize(PixelUtil.dp2px(16)); - mPaint.setTextAlign(Paint.Align.CENTER); - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - if (VIEW_LEVEL_MONITOR_ENABLE) { - canvas.save(); - int selfLevel = calculateSelfLevel(); - int hippyLevel = calculateHippyLevel(); - int childLevel = calculateChildLevel(this); - canvas.drawText( - "总:" + (selfLevel + childLevel) + " , HP:" + (hippyLevel + childLevel) + " , 子:" - + childLevel, getWidth() / 2.0f, - getHeight() / 2.0f, mPaint); - canvas.restore(); - } - } - - private int calculateSelfLevel() { - int level = 0; - View view = this; - while (true) { - if (view.getParent() != null && view.getParent() instanceof View) { - view = (View) view.getParent(); - ++level; - } else { - break; - } - } - return level; - } - - private int calculateHippyLevel() { - int level = 0; - View view = this; - while (true) { - if (view.getParent() != null && view.getParent() instanceof View && !(view - .getParent() instanceof HippyRootView)) { - view = (View) view.getParent(); - ++level; - } else if (view.getParent() instanceof HippyRootView) { - ++level; - break; - } else { - break; - } - } - return level; - } - - private int calculateChildLevel(View view) { - int level = 1; - if (view instanceof ViewGroup) { - int count = this.getChildCount(); - if (count != 0) { - int maxLevel = 0; - int currentLevel; - for (int i = 0; i < count; i++) { - currentLevel = calculateChildLevel(((ViewGroup) view).getChildAt(i)); - maxLevel = Math.max(maxLevel, currentLevel); - } - level = maxLevel + level; - } - } - return level; - } - - // public void setType(int type) - // { - // mType = type; - // } - - // public int getType() - // { - // return mType; - // } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListItemViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListItemViewController.java deleted file mode 100644 index bc2364a23e9..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListItemViewController.java +++ /dev/null @@ -1,45 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.list; - -import android.content.Context; -import android.view.View; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.ListItemRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyListItemViewController.CLASS_NAME, isLazyLoad = true) -public class HippyListItemViewController extends HippyViewController { - - public static final String CLASS_NAME = "ListViewItem"; - - @Override - protected View createViewImpl(Context context) { - return new HippyListItemView(context); - } - - @Override - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, ControllerManager controllerManager, boolean lazy) { - return new ListItemRenderNode(id, props, className, hippyRootView, controllerManager, lazy); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListView.java deleted file mode 100644 index b888001e64f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListView.java +++ /dev/null @@ -1,815 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.list; - -import android.view.ViewConfiguration; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.refresh.HippyPullFooterView; -import com.tencent.mtt.hippy.views.refresh.HippyPullHeaderView; -import com.tencent.mtt.hippy.views.scroll.HippyScrollViewEventHelper; -import com.tencent.mtt.supportui.views.recyclerview.BaseLayoutManager; -import com.tencent.mtt.supportui.views.recyclerview.LinearLayoutManager; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerAdapter; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerView; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewItem; - -import android.content.Context; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewTreeObserver; - -@SuppressWarnings({"deprecation", "unused"}) -public class HippyListView extends RecyclerView implements HippyViewBase { - - public final static int REFRESH_STATE_IDLE = 0; - public final static int REFRESH_STATE_LOADING = 1; - - public static final String EVENT_TYPE_HEADER_RELEASED = "onHeaderReleased"; - public static final String EVENT_TYPE_HEADER_PULLING = "onHeaderPulling"; - - public static final String EVENT_TYPE_FOOTER_RELEASED = "onFooterReleased"; - public static final String EVENT_TYPE_FOOTER_PULLING = "onFooterPulling"; - - protected int mHeaderRefreshState = REFRESH_STATE_IDLE; - protected int mFooterRefreshState = REFRESH_STATE_IDLE; - protected final boolean mEnableRefresh = true; - - private RecyclerAdapter mListAdapter; - - private HippyEngineContext mHippyContext; - - private NativeGestureDispatcher mGestureDispatcher; - - protected boolean mScrollBeginDragEventEnable = false; - - protected boolean mScrollEndDragEventEnable = false; - - protected boolean mMomentumScrollBeginEventEnable = false; - - protected boolean mMomentumScrollEndEventEnable = false; - - protected boolean mScrollEventEnable = true; - - protected boolean mScrollEnable = true; - - protected boolean mExposureEventEnable = false; - - private float touchDownY; - private float touchDownX; - private int touchSlop; - private int initialContentOffset = 0; - private boolean hasCompleteFirstBatch = false; - - protected int mScrollEventThrottle = 400; // 400ms最多回调一次 - protected int mLastOffsetX = Integer.MIN_VALUE; - protected int mLastOffsetY = Integer.MIN_VALUE; - protected long mLastScrollEventTimeStamp = -1; - - private boolean mHasRemovePreDraw = false; - private ViewTreeObserver.OnPreDrawListener mPreDrawListener = null; - private ViewTreeObserver mViewTreeObserver = null; - private OnInitialListReadyEvent mOnInitialListReadyEvent; - - private OnScrollDragStartedEvent mOnScrollDragStartedEvent; - private OnScrollDragEndedEvent mOnScrollDragEndedEvent; - private OnScrollFlingStartedEvent mOnScrollFlingStartedEvent; - private OnScrollFlingEndedEvent mOnScrollFlingEndedEvent; - private OnScrollEvent mOnScrollEvent; - - private void init(Context context, int orientation) { - mHippyContext = ((HippyInstanceContext) context).getEngineContext(); - this.setLayoutManager(new LinearLayoutManager(context, orientation, false)); - setRepeatableSuspensionMode(false); - mListAdapter = createAdapter(this, mHippyContext); - setAdapter(mListAdapter); - - final ViewConfiguration configuration = ViewConfiguration.get(context); - touchSlop = configuration.getScaledTouchSlop(); - } - - public HippyListView(Context context, int orientation) { - super(context); - init(context, orientation); - } - - public HippyListView(Context context) { - super(context); - init(context, BaseLayoutManager.VERTICAL); - } - - protected RecyclerAdapter createAdapter(RecyclerView hippyRecyclerView, - HippyEngineContext hippyEngineContext) { - return new HippyListAdapter(hippyRecyclerView, hippyEngineContext); - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return mGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - this.mGestureDispatcher = dispatcher; - } - - @Override - public boolean onTouchEvent(MotionEvent motionEvent) { - if (!mScrollEnable) { - return false; - } - return super.onTouchEvent(motionEvent); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent motionEvent) { - if (!mScrollEnable) { - return false; - } - - if (mLayout.canScrollVertically()) { - int action = motionEvent.getAction(); - float y = motionEvent.getY(); - float x = motionEvent.getX(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - touchDownY = y; - touchDownX = x; - break; - } - case MotionEvent.ACTION_MOVE: { - if (Math.abs(x - touchDownX) / Math.abs(y - touchDownY) > 1 && Math.abs(x - touchDownX) > touchSlop) { - return false; - } - break; - } - } - } - - return super.onInterceptTouchEvent(motionEvent); - } - - - public void setListData() { - LogUtils.d("hippylistview", "setListData"); - mListAdapter.notifyDataSetChanged(); - dispatchLayout(); - if (!hasCompleteFirstBatch && getChildCount() > 0) { - if (initialContentOffset > 0) { - scrollToInitContentOffset(); - } - - hasCompleteFirstBatch = true; - } - } - - private void scrollToInitContentOffset() { - int position = 0; - int itemHeight = 0; - if (mListAdapter == null) { - return; - } - - int itemCount = mListAdapter.getItemCount(); - for (; itemHeight < initialContentOffset && position < itemCount; position++) { - itemHeight += mListAdapter.getItemHeight(position); - } - - final int lastIndex = itemCount - 1; - int offset = itemHeight - initialContentOffset; - - //设置的offset超过边界,跳转到最后一个Item上去 - if (position >= lastIndex) { - position = lastIndex; - //不能划出内容高度 - if (offset < 0) { - offset = 0; - } - } - - scrollToPosition(position, offset); - } - - public void setInitialContentOffset(int offset) { - initialContentOffset = offset; - } - - public void setScrollBeginDragEventEnable(boolean enable) { - mScrollBeginDragEventEnable = enable; - } - - public void setScrollEndDragEventEnable(boolean enable) { - mScrollEndDragEventEnable = enable; - } - - public void setMomentumScrollBeginEventEnable(boolean enable) { - mMomentumScrollBeginEventEnable = enable; - } - - public void setMomentumScrollEndEventEnable(boolean enable) { - mMomentumScrollEndEventEnable = enable; - } - - public void setOnScrollEventEnable(boolean enable) { - mScrollEventEnable = enable; - } - - protected HippyMap generateScrollEvent() { - float value; - HippyMap contentOffset = new HippyMap(); - if (mLayout.canScrollHorizontally()) { - value = (mOffsetX - mState.mCustomHeaderWidth)/PixelUtil.getDensity(); - contentOffset.pushDouble("x", value); - contentOffset.pushDouble("y", 0.0f); - } else { - value = (mOffsetY - mState.mCustomHeaderHeight)/PixelUtil.getDensity(); - contentOffset.pushDouble("x", 0.0f); - contentOffset.pushDouble("y", value); - } - - HippyMap event = new HippyMap(); - event.pushMap("contentOffset", contentOffset); - return event; - } - - public void setScrollEnable(boolean enable) { - mScrollEnable = enable; - } - - public void setExposureEventEnable(boolean enable) { - mExposureEventEnable = enable; - } - - public void setScrollEventThrottle(int scrollEventThrottle) { - mScrollEventThrottle = scrollEventThrottle; - } - - public View getCustomHeaderView() { - if (getChildCount() > 0) { - View firstChild = getChildAt(0); - final ViewHolder holder = getChildViewHolderInt(firstChild); - if (holder != null) { - return holder.mContent; - } - } - - return null; - } - - public View getCustomFooterView() { - if (getChildCount() > 0) { - View lastChild = getChildAt(getChildCount() - 1); - final ViewHolder holder = getChildViewHolderInt(lastChild); - if (holder != null) { - return holder.mContent; - } - } - - return null; - } - - public void onHeaderRefreshFinish() { - if (mHeaderRefreshState == REFRESH_STATE_LOADING) { - if (mLayout.canScrollHorizontally()) { - if (mOffsetX < mState.mCustomHeaderWidth) { - smoothScrollBy(-mOffsetX + mState.mCustomHeaderWidth, 0, false, true); - } - } else { - if (mOffsetY < mState.mCustomHeaderHeight) { - smoothScrollBy(0, -mOffsetY + mState.mCustomHeaderHeight, false, true); - } - } - - mHeaderRefreshState = REFRESH_STATE_IDLE; - } - } - - public void onFooterRefreshFinish() { - if (mFooterRefreshState == REFRESH_STATE_LOADING) { - if (mLayout.canScrollHorizontally()) { - int contentOffsetX = getTotalHeight() - getWidth(); - if (mOffsetX > contentOffsetX) { - smoothScrollBy(contentOffsetX - mOffsetX, 0, false, true); - } - } else { - int contentOffsetY = getTotalHeight() - getHeight(); - if (mOffsetY > contentOffsetY) { - smoothScrollBy(0, contentOffsetY - mOffsetY, false, true); - } - } - mFooterRefreshState = REFRESH_STATE_IDLE; - } - } - - public void onHeaderRefresh() { - if (mHeaderRefreshState == REFRESH_STATE_IDLE) { - if (mLayout.canScrollHorizontally()) { - smoothScrollBy(-mOffsetX, 0, false, true); - } else { - smoothScrollBy(0, -mOffsetY, false, true); - } - } - } - - protected void onTouchMove(int x, int y) { - int totalHeight = mAdapter.getTotalHeight(); - HippyMap param = new HippyMap(); - float contentOffset = 0; - String eventName = ""; - - if (mLayout.canScrollHorizontally()) { - if (mOffsetX < mState.mCustomHeaderWidth) { - contentOffset = Math.abs((mOffsetX - mState.mCustomHeaderWidth)); - eventName = EVENT_TYPE_HEADER_PULLING; - } else if (mOffsetX > totalHeight - getWidth()) { - contentOffset = Math.abs((mOffsetX - totalHeight - getWidth())); - eventName = EVENT_TYPE_FOOTER_PULLING; - } - } else { - if (getOffsetY() < mState.mCustomHeaderHeight) { - contentOffset = Math.abs((getOffsetY() - mState.mCustomHeaderHeight)); - eventName = EVENT_TYPE_HEADER_PULLING; - } else if (getOffsetY() > totalHeight - getHeight()) { - contentOffset = Math.abs((getOffsetY() - totalHeight - getHeight())); - eventName = EVENT_TYPE_FOOTER_PULLING; - } - } - - param.pushDouble("contentOffset", PixelUtil.px2dp(contentOffset)); - switch (eventName) { - case EVENT_TYPE_HEADER_PULLING: - sendPullHeaderEvent(eventName, param); - break; - case EVENT_TYPE_FOOTER_PULLING: - sendPullFooterEvent(eventName, param); - break; - } - } - - private boolean shouldStopReleaseGlowsForHorizontal(boolean fromTouch) { - int totalHeight = mAdapter.getTotalHeight(); - if (mOffsetX <= 0 || getWidth() > (totalHeight - mState.mCustomHeaderWidth)) { - if (mHeaderRefreshState == REFRESH_STATE_IDLE && fromTouch) { - sendPullHeaderEvent(EVENT_TYPE_HEADER_RELEASED, new HippyMap()); - mHeaderRefreshState = REFRESH_STATE_LOADING; - } - - if (mOffsetX < 0) { - smoothScrollBy(-mOffsetX, 0, false, true); - } - return true; - } else { - int refreshEnableOffsetX = totalHeight - getWidth() + mState.mCustomFooterWidth; - if ((totalHeight - mState.mCustomHeaderWidth) < getWidth() - || mOffsetX >= refreshEnableOffsetX) { - if (mFooterRefreshState == REFRESH_STATE_IDLE) { - sendPullFooterEvent(EVENT_TYPE_FOOTER_RELEASED, new HippyMap()); - mFooterRefreshState = REFRESH_STATE_LOADING; - } - - View footerView = getCustomFooterView(); - if (footerView instanceof HippyPullFooterView) { - boolean stickEnabled = ((HippyPullFooterView) footerView).getStickEnabled(); - if (stickEnabled) { - smoothScrollBy(refreshEnableOffsetX - mOffsetX, 0, false, true); - return true; - } - } - } - } - - return false; - } - - private boolean shouldStopReleaseGlowsForVertical(boolean fromTouch) { - int totalHeight = mAdapter.getTotalHeight(); - if (getOffsetY() <= 0 || getHeight() > (totalHeight - mState.mCustomHeaderHeight)) { - if (mHeaderRefreshState == REFRESH_STATE_IDLE && fromTouch) { - sendPullHeaderEvent(EVENT_TYPE_HEADER_RELEASED, new HippyMap()); - mHeaderRefreshState = REFRESH_STATE_LOADING; - } - if (getOffsetY() < 0) { - smoothScrollBy(0, -mOffsetY, false, true); - } - return true; - } else { - int refreshEnableOffsetY = totalHeight - getHeight() + mState.mCustomFooterHeight; - if ((totalHeight - mState.mCustomHeaderHeight) < getHeight() - || getOffsetY() >= refreshEnableOffsetY) { - if (mFooterRefreshState == REFRESH_STATE_IDLE) { - sendPullFooterEvent(EVENT_TYPE_FOOTER_RELEASED, new HippyMap()); - mFooterRefreshState = REFRESH_STATE_LOADING; - } - - View footerView = getCustomFooterView(); - if (footerView instanceof HippyPullFooterView) { - boolean stickEnabled = ((HippyPullFooterView) footerView).getStickEnabled(); - if (stickEnabled) { - smoothScrollBy(0, refreshEnableOffsetY - mOffsetY, false, true); - return true; - } - } - } - } - - return false; - } - - @Override - protected boolean shouldStopReleaseGlows(boolean canGoRefresh, boolean fromTouch) { - if (mEnableRefresh) { -// Scroller scroller = mViewFlinger.getScroller(); -// if (scroller.isFinished() && scroller.isFling() && getOffsetY() < 0) { -// canGoRefresh = true; -// } - - if (!canGoRefresh) { - return false; - } - - if (mLayout.canScrollHorizontally()) { - return shouldStopReleaseGlowsForHorizontal(fromTouch); - } else { - return shouldStopReleaseGlowsForVertical(fromTouch); - } - } - - return false; - } - - @Override - protected void onScrollDragStarted() { - if (mScrollBeginDragEventEnable) { - getOnScrollDragStartedEvent().send(this, generateScrollEvent()); - } - } - - @Override - protected void onScrollDragEnded() { - if (mScrollEndDragEventEnable) { - getOnScrollDragEndedEvent().send(this, generateScrollEvent()); - } - } - - @Override - protected void onScrollFlingStarted() { - if (mMomentumScrollBeginEventEnable) { - getOnScrollFlingStartedEvent().send(this, generateScrollEvent()); - } - } - - @Override - protected void onScrollFlingEnded() { - if (mMomentumScrollEndEventEnable) { - getOnScrollFlingEndedEvent().send(this, generateScrollEvent()); - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - if (changed && mExposureEventEnable) { - dispatchExposureEvent(); - } - } - - @Override - public void onScrolled(int x, int y) { - super.onScrolled(x, y); - sendOnScrollEvent(); - if (mExposureEventEnable) { - dispatchExposureEvent(); - } - } - - protected void sendExposureEvent(View view, String eventName, HippyMap props) { - if (props.containsKey(eventName)) { - new HippyViewEvent(eventName).send(view, null); - } - } - - private HippyMap getItemViewProps(int id) { - if (mHippyContext == null) { - return null; - } - RenderNode node = mHippyContext.getRenderManager().getRenderNode(id); - if (node == null) { - return null; - } - - return node.getProps(); - } - - protected void checkExposureView(View view, int visibleStart, int visibleEnd, int parentStart, - int parentEnd) { - if (!(view instanceof HippyListItemView)) { - return; - } - - int myStart = (mLayout.canScrollHorizontally()) ? view.getLeft() : view.getTop(); - int myEnd = (mLayout.canScrollHorizontally()) ? view.getRight() : view.getBottom(); - myStart += parentStart; - myEnd += parentStart; - - HippyListItemView itemView = (HippyListItemView) view; - HippyMap props = getItemViewProps(itemView.getId()); - if (props == null) { - return; - } - - int currentExposureState = itemView.getExposureState(); - int viewSize = (mLayout.canScrollHorizontally()) ? view.getWidth() : view.getHeight(); - int correctingValueForDisappear = (int) Math.ceil(viewSize * 0.1f); - - if (myEnd <= (visibleStart + correctingValueForDisappear) || myStart >= (visibleEnd - - correctingValueForDisappear)) { - if (itemView.getExposureState() != HippyListItemView.EXPOSURE_STATE_DISAPPEAR) { - if (itemView.getExposureState() == HippyListItemView.EXPOSURE_STATE_APPEAR) { - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_WILL_DISAPPEAR, props); - } - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_DISAPPEAR, props); - itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_DISAPPEAR); - } - } else if ((myStart < visibleStart && myEnd > visibleStart) || (myStart < visibleEnd - && myEnd > visibleEnd)) { - if (currentExposureState == HippyListItemView.EXPOSURE_STATE_APPEAR) { - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_WILL_DISAPPEAR, props); - itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_WILL_DISAPPEAR); - } else if (currentExposureState == HippyListItemView.EXPOSURE_STATE_DISAPPEAR) { - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_WILL_APPEAR, props); - itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_WILL_APPEAR); - } - } else if ((myStart >= visibleStart && myEnd <= visibleEnd) || (myStart <= visibleStart - && myEnd > visibleEnd)) { - if (itemView.getExposureState() != HippyListItemView.EXPOSURE_STATE_APPEAR) { - if (itemView.getExposureState() == HippyListItemView.EXPOSURE_STATE_DISAPPEAR) { - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_WILL_APPEAR, props); - } - sendExposureEvent(view, HippyListItemView.EXPOSURE_EVENT_APPEAR, props); - itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_APPEAR); - } - } - } - - private void dispatchExposureEvent() { - if (mLayout instanceof BaseLayoutManager) { - BaseLayoutManager.OrientationHelper layoutHelper = ((BaseLayoutManager) mLayout).mOrientationHelper; - int count = getChildCount(); - int fixOffset = (mLayout.canScrollHorizontally()) ? mState.mCustomHeaderWidth - : mState.mCustomHeaderHeight; - int start = layoutHelper.getStartAfterPadding() + fixOffset; - int end = layoutHelper.getEndAfterPadding() - fixOffset; - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - final int childStart = layoutHelper.getDecoratedStart(child); - final int childEnd = layoutHelper.getDecoratedEnd(child); - if (child instanceof RecyclerViewItem) { - RecyclerViewItem itemView = (RecyclerViewItem) child; - if (itemView.getChildCount() > 0) { - checkExposureView(itemView.getChildAt(0), start, end, childStart, childEnd); - } - } - } - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (!mHasRemovePreDraw) { - mViewTreeObserver = getViewTreeObserver(); - if (mPreDrawListener == null) { - mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - if (mAdapter.getItemCount() > 0 && HippyListView.this.getChildCount() > 0) { - mViewTreeObserver.removeOnPreDrawListener(this); - mHasRemovePreDraw = true; - - post(new Runnable() { - @Override - public void run() { - HippyListView.this.onInitialListReady(); - getOnInitialListReadyEvent().send(HippyListView.this, null); - } - }); - - } - return true; - } - }; - } - mViewTreeObserver.removeOnPreDrawListener(mPreDrawListener); - mViewTreeObserver.addOnPreDrawListener(mPreDrawListener); - - } - } - - @Override - protected void onDetachedFromWindow() { - if (mPreDrawListener != null && mViewTreeObserver != null) { - mViewTreeObserver.removeOnPreDrawListener(mPreDrawListener); - } - super.onDetachedFromWindow(); - } - - public void scrollToIndex(int xIndex, int yIndex, boolean animated, int duration) { - if (animated) { - int scrollToYPos = getHeightBefore(yIndex) - getOffsetY(); - if (duration != 0) //如果用户设置了duration - { - if (scrollToYPos != 0) { - if (!mState.didStructureChange()) { - mViewFlinger.smoothScrollBy(0, scrollToYPos, duration, true); - } - } - } else { - smoothScrollBy(0, scrollToYPos); - } - } else { - scrollToPosition(yIndex, 0); - post(new Runnable() { - @Override - public void run() { - dispatchLayout(); - } - }); - } - } - - public void scrollToContentOffset(double xOffset, double yOffset, boolean animated, - int duration) { - int scrollToYPos = (int)PixelUtil.dp2px(yOffset) - mOffsetY; - int scrollToXPos = (int)PixelUtil.dp2px(xOffset) - mOffsetX; - if (animated) { - if (duration != 0){ - if ((scrollToYPos != 0 || scrollToXPos != 0) && !mState.didStructureChange()) { - mViewFlinger.smoothScrollBy(scrollToXPos, scrollToYPos, duration, true); - } - } else { - smoothScrollBy(scrollToXPos, scrollToYPos); - } - } else { - scrollBy(scrollToXPos, scrollToYPos); - post(new Runnable() { - @Override - public void run() { - dispatchLayout(); - } - }); - } - } - - protected void sendOnScrollEvent() { - if (mScrollEventEnable) { - long currTime = System.currentTimeMillis(); - if (currTime - mLastScrollEventTimeStamp < mScrollEventThrottle) { - return; - } - - mLastScrollEventTimeStamp = currTime; - getOnScrollEvent().send(this, generateScrollEvent()); - } - } - - // start drag event - protected OnScrollDragStartedEvent getOnScrollDragStartedEvent() { - if (mOnScrollDragStartedEvent == null) { - mOnScrollDragStartedEvent = new OnScrollDragStartedEvent( - HippyScrollViewEventHelper.EVENT_TYPE_BEGIN_DRAG); - } - return mOnScrollDragStartedEvent; - } - - protected static class OnScrollDragStartedEvent extends HippyViewEvent { - - public OnScrollDragStartedEvent(String eventName) { - super(eventName); - } - } - - // end drag event - protected OnScrollDragEndedEvent getOnScrollDragEndedEvent() { - if (mOnScrollDragEndedEvent == null) { - mOnScrollDragEndedEvent = new OnScrollDragEndedEvent( - HippyScrollViewEventHelper.EVENT_TYPE_END_DRAG); - } - return mOnScrollDragEndedEvent; - } - - protected static class OnScrollDragEndedEvent extends HippyViewEvent { - - public OnScrollDragEndedEvent(String eventName) { - super(eventName); - } - } - - // start fling - protected OnScrollFlingStartedEvent getOnScrollFlingStartedEvent() { - if (mOnScrollFlingStartedEvent == null) { - mOnScrollFlingStartedEvent = new OnScrollFlingStartedEvent( - HippyScrollViewEventHelper.EVENT_TYPE_MOMENTUM_BEGIN); - } - return mOnScrollFlingStartedEvent; - } - - protected static class OnScrollFlingStartedEvent extends HippyViewEvent { - - public OnScrollFlingStartedEvent(String eventName) { - super(eventName); - } - } - - // end fling - protected OnScrollFlingEndedEvent getOnScrollFlingEndedEvent() { - if (mOnScrollFlingEndedEvent == null) { - mOnScrollFlingEndedEvent = new OnScrollFlingEndedEvent( - HippyScrollViewEventHelper.EVENT_TYPE_MOMENTUM_END); - } - return mOnScrollFlingEndedEvent; - } - - protected static class OnScrollFlingEndedEvent extends HippyViewEvent { - - public OnScrollFlingEndedEvent(String eventName) { - super(eventName); - } - } - - // scroll - protected OnScrollEvent getOnScrollEvent() { - if (mOnScrollEvent == null) { - mOnScrollEvent = new OnScrollEvent(HippyScrollViewEventHelper.EVENT_TYPE_SCROLL); - } - return mOnScrollEvent; - } - - protected static class OnScrollEvent extends HippyViewEvent { - - public OnScrollEvent(String eventName) { - super(eventName); - } - } - - private OnInitialListReadyEvent getOnInitialListReadyEvent() { - if (mOnInitialListReadyEvent == null) { - mOnInitialListReadyEvent = new OnInitialListReadyEvent("initialListReady"); - } - return mOnInitialListReadyEvent; - } - - private static class OnInitialListReadyEvent extends HippyViewEvent { - - public OnInitialListReadyEvent(String eventName) { - super(eventName); - } - } - - @SuppressWarnings("EmptyMethod") - protected void onInitialListReady() { - - } - - protected static class PullElementEvent extends HippyViewEvent { - - public PullElementEvent(String eventName) { - super(eventName); - } - } - - protected void sendPullHeaderEvent(String eventName, HippyMap param) { - PullElementEvent event = new PullElementEvent(eventName); - View headerView = getCustomHeaderView(); - if (headerView instanceof HippyPullHeaderView) { - event.send(headerView, param); - } - } - - protected void sendPullFooterEvent(String eventName, HippyMap param) { - PullElementEvent event = new PullElementEvent(eventName); - View footerView = getCustomFooterView(); - if (footerView instanceof HippyPullFooterView) { - event.send(footerView, param); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListViewController.java deleted file mode 100644 index c7797ccddcb..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyListViewController.java +++ /dev/null @@ -1,196 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.list; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.ListViewRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.supportui.views.recyclerview.BaseLayoutManager; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewItem; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyListViewController.CLASS_NAME) -public class HippyListViewController extends HippyViewController { - - public static final String CLASS_NAME = "ListView"; - - @Override - public void onViewDestroy(HippyListView hippyListView) { - super.onViewDestroy(hippyListView); - if (hippyListView != null && hippyListView.mListScrollListeners != null) { - hippyListView.mListScrollListeners.clear(); - } - } - - @Override - protected void addView(ViewGroup parentView, View view, int index) { - // super.addView(parentView, view, index); - } - - @Override - protected void deleteChild(ViewGroup parentView, View childView, int childIndex) { - // List的childView是RecyclerViewItem类型,不是由Hippy构建的,所以这里需要提前删除RecyclerViewItem的child - if (childView instanceof RecyclerViewItem) { - ((RecyclerViewItem) childView).removeAllViews(); - } - // list里,删掉某个条目后,它后面的条目的位置都要减1 - if (childIndex >= 0 && parentView instanceof HippyListView) { - HippyListView listView = (HippyListView) parentView; - listView.getRecycler().updateHolderPositionWhenDelete(childIndex); - } - } - - @Override - public int getChildCount(HippyListView viewGroup) { - return ((HippyListAdapter) viewGroup.getAdapter()).getRecyclerItemCount(); - } - - @Override - public View getChildAt(HippyListView viewGroup, int i) { - return ((HippyListAdapter) viewGroup.getAdapter()).getRecyclerItemView(i); - } - - @Override - public void onBatchComplete(HippyListView view) { - super.onBatchComplete(view); - view.setListData(); - } - - @Override - protected View createViewImpl(Context context) { - return new HippyListView(context, BaseLayoutManager.VERTICAL); - } - - @Override - protected View createViewImpl(Context context, HippyMap iniProps) { - if (iniProps != null && iniProps.containsKey("horizontal")) { - return new HippyListView(context, BaseLayoutManager.HORIZONTAL); - } else { - return new HippyListView(context, BaseLayoutManager.VERTICAL); - } - } - - @Override - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, ControllerManager controllerManager, - boolean lazy) { - return new ListViewRenderNode(id, props, className, hippyRootView, controllerManager, lazy); - } - - @HippyControllerProps(name = "rowShouldSticky") - public void setRowShouldSticky(HippyListView view, boolean enable) { - view.setHasSuspentedItem(enable); - } - - @HippyControllerProps(name = "onScrollBeginDrag", defaultType = HippyControllerProps.BOOLEAN) - public void setScrollBeginDragEventEnable(HippyListView view, boolean flag) { - view.setScrollBeginDragEventEnable(flag); - } - - @HippyControllerProps(name = "onScrollEndDrag", defaultType = HippyControllerProps.BOOLEAN) - public void setScrollEndDragEventEnable(HippyListView view, boolean flag) { - view.setScrollEndDragEventEnable(flag); - } - - @HippyControllerProps(name = "onMomentumScrollBegin", defaultType = HippyControllerProps.BOOLEAN) - public void setMomentumScrollBeginEventEnable(HippyListView view, boolean flag) { - view.setMomentumScrollBeginEventEnable(flag); - } - - @HippyControllerProps(name = "onMomentumScrollEnd", defaultType = HippyControllerProps.BOOLEAN) - public void setMomentumScrollEndEventEnable(HippyListView view, boolean flag) { - view.setMomentumScrollEndEventEnable(flag); - } - - @HippyControllerProps(name = "onScrollEnable", defaultType = HippyControllerProps.BOOLEAN) - public void setOnScrollEventEnable(HippyListView view, boolean flag) { - view.setOnScrollEventEnable(flag); - } - - @HippyControllerProps(name = "exposureEventEnabled", defaultType = HippyControllerProps.BOOLEAN) - public void setExposureEventEnable(HippyListView view, boolean flag) { - view.setExposureEventEnable(flag); - } - - @HippyControllerProps(name = "scrollEnabled", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void setScrollEnable(HippyListView view, boolean flag) { - view.setScrollEnable(flag); - } - - @HippyControllerProps(name = "scrollEventThrottle", defaultType = HippyControllerProps.NUMBER, defaultNumber = 30.0D) - public void setscrollEventThrottle(HippyListView view, int scrollEventThrottle) { - view.setScrollEventThrottle(scrollEventThrottle); - } - - @HippyControllerProps(name = "preloadItemNumber") - public void setPreloadItemNumber(HippyListView view, int preloadItemNumber) { - RecyclerViewBase.Adapter adapter = view.getAdapter(); - if (adapter instanceof HippyListAdapter) { - ((HippyListAdapter) adapter).setPreloadItemNumber(preloadItemNumber); - } - } - - @HippyControllerProps(name = "overScrollEnabled", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void setOverScrollEnabled(HippyListView view, boolean flag) { - view.setOverScrollEnabled(flag); - } - - @HippyControllerProps(name = "initialContentOffset", defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setInitialContentOffset(HippyListView view, int offset) { - view.setInitialContentOffset((int)PixelUtil.dp2px(offset)); - } - - @Override - public void dispatchFunction(HippyListView view, String functionName, HippyArray dataArray) { - super.dispatchFunction(view, functionName, dataArray); - switch (functionName) { - case "scrollToIndex": { - // list滑动到某个item - int xIndex = dataArray.getInt(0); - int yIndex = dataArray.getInt(1); - boolean animated = dataArray.getBoolean(2); - int duration = dataArray.getInt(3); //1.2.7 增加滚动时间 ms,animated==true时生效 - view.scrollToIndex(xIndex, yIndex, animated, duration); - break; - } - case "scrollToContentOffset": { - // list滑动到某个距离 - double xOffset = dataArray.getDouble(0); - double yOffset = dataArray.getDouble(1); - boolean animated = dataArray.getBoolean(2); - int duration = dataArray.getInt(3); //1.2.7 增加滚动时间 ms,animated==true时生效 - view.scrollToContentOffset(xOffset, yOffset, animated, duration); - break; - } - case "scrollToTop": { - view.scrollToTop(null); - break; - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyRecycler.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyRecycler.java deleted file mode 100644 index 2e134952cc0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/HippyRecycler.java +++ /dev/null @@ -1,26 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.list; - -@SuppressWarnings({"unused"}) -public interface HippyRecycler { - - //恢复默认的时候使用 - void resetProps(); - - //replace id 的时候清除不需要的属性 - void clear(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/NodeHolder.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/NodeHolder.java deleted file mode 100644 index 9e0e2be552b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/list/NodeHolder.java +++ /dev/null @@ -1,34 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.list; - -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.supportui.views.recyclerview.ContentHolder; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase; - -public class NodeHolder extends ContentHolder { - - public RenderNode mBindNode; - public boolean isCreated = true; - - @Override - public void inTraversals(int traversalPurpose, int position, RecyclerViewBase recyclerView) { - super.inTraversals(traversalPurpose, position, recyclerView); - if (recyclerView != null) { - recyclerView.handleInTraversal(traversalPurpose, position, mContentView); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/HippyModalHostManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/HippyModalHostManager.java deleted file mode 100644 index 108464751b6..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/HippyModalHostManager.java +++ /dev/null @@ -1,93 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.modal; - -import android.content.Context; -import android.content.DialogInterface; -import android.view.View; - -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.uimanager.HippyGroupController; - -@SuppressWarnings("unused") -@HippyController(name = HippyModalHostManager.HIPPY_CLASS) -public class HippyModalHostManager extends HippyGroupController { - - public static final String HIPPY_CLASS = "Modal"; - - @Override - protected View createViewImpl(Context context) { - final HippyModalHostView hippyModalHostView = createModalHostView(context); - - hippyModalHostView.setOnRequestCloseListener(new HippyModalHostView.OnRequestCloseListener() { - @Override - public void onRequestClose(DialogInterface dialog) { - new RequestCloseEvent().send(hippyModalHostView, null); - } - }); - hippyModalHostView.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - new ShowEvent().send(hippyModalHostView, null); - } - }); - return hippyModalHostView; - } - - protected HippyModalHostView createModalHostView(Context context) { - return new HippyModalHostView(context); - } - - @Override - protected StyleNode createNode(boolean isVirtual) { - return new ModalStyleNode(); - } - - @Override - public void onViewDestroy(HippyModalHostView hippyModalHostView) { - super.onViewDestroy(hippyModalHostView); - hippyModalHostView.onInstanceDestroy(hippyModalHostView.getId()); - } - - @HippyControllerProps(name = "animationType", defaultType = HippyControllerProps.STRING, defaultString = "none") - public void setAnimationType(HippyModalHostView view, String animationType) { - view.setAnimationType(animationType); - } - - @HippyControllerProps(name = "immersionStatusBar", defaultType = HippyControllerProps.BOOLEAN) - public void setEnterImmersionStatusBar(HippyModalHostView view, boolean fullScreen) { - view.setEnterImmersionStatusBar(fullScreen); - } - - @HippyControllerProps(name = "darkStatusBarText", defaultType = HippyControllerProps.BOOLEAN) - public void setImmersionStatusBarTextDarkColor(HippyModalHostView view, boolean fullScreen) { - view.setImmersionStatusBarTextDarkColor(fullScreen); - } - - @HippyControllerProps(name = "transparent", defaultType = HippyControllerProps.BOOLEAN) - public void setTransparent(HippyModalHostView view, boolean transparent) { - view.setTransparent(transparent); - } - - @Override - public void onAfterUpdateProps(HippyModalHostView v) { - super.onAfterUpdateProps(v); - v.showOrUpdate(); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/HippyModalHostView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/HippyModalHostView.java deleted file mode 100644 index c56218eac25..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/HippyModalHostView.java +++ /dev/null @@ -1,531 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.modal; - -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.graphics.Canvas; -import android.graphics.Color; -import android.os.Build; -import android.text.TextUtils; -import android.view.Display; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityEvent; -import android.widget.FrameLayout; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.HippyInstanceLifecycleEventListener; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.views.view.HippyViewGroup; - -import java.lang.reflect.Field; -import java.util.ArrayList; - -@SuppressWarnings({"unused"}) -public class HippyModalHostView extends HippyViewGroup implements - HippyInstanceLifecycleEventListener { - - @Override - public void onInstanceLoad(int instanceId) { - showOrUpdate(); - } - - @Override - public void onInstanceResume(int instanceId) { - showOrUpdate(); - } - - @Override - public void onInstancePause(int instanceId) { - dismiss(); - } - - @Override - public void onInstanceDestroy(int instanceId) { - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) getContext(); - hippyInstanceContext.getEngineContext().removeInstanceLifecycleEventListener(this); - dismiss(); - } - - public interface OnRequestCloseListener { - - void onRequestClose(DialogInterface dialog); - } - - private final int STYLE_THEME_FULL_SCREEN_DIALOG = 0; - private final int STYLE_THEME_ANIMATED_FADE_DIALOG = 1; - private final int STYLE_THEME_ANIMATED_SLIDE_DIALOG = 2; - private final int STYLE_THEME_ANIMATED_SLIDE_FADE_DIALOG = 3; - - private final DialogRootViewGroup mHostView; - private Dialog mDialog; - private View mContentView; - private boolean mTransparent = true; - private boolean mPropertyRequiresNewDialog; - private DialogInterface.OnShowListener mOnShowListener; - OnRequestCloseListener mOnRequestCloseListener; - private String mAnimationType; - private int mAniType; - private boolean mEnterImmersionStatusBar = false; - private boolean mStatusBarTextDarkColor = false; - - public HippyModalHostView(Context context) { - super(context); - mAniType = STYLE_THEME_FULL_SCREEN_DIALOG; - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) context; - hippyInstanceContext.getEngineContext().addInstanceLifecycleEventListener(this); - mHostView = new DialogRootViewGroup(context); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - - } - - @Override - public void addView(View child, int index) { - mHostView.addView(child, index); - } - - @Override - public int getChildCount() { - return mHostView.getChildCount(); - } - - @Override - public View getChildAt(int index) { - return mHostView.getChildAt(index); - } - - @Override - public void removeView(View child) { - mHostView.removeView(child); - } - - @Override - public void removeViewAt(int index) { - View child = getChildAt(index); - mHostView.removeView(child); - } - - public void addChildrenForAccessibility(ArrayList outChildren) { - - } - - @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - return false; - } - - private void dismiss() { - if (isActivityFinishing()) { - return; - } - - if (mDialog != null) { - mDialog.dismiss(); - mDialog = null; - ViewGroup parent = (ViewGroup) mHostView.getParent(); - parent.removeViewAt(0); - } - } - - public void setOnRequestCloseListener(OnRequestCloseListener listener) { - mOnRequestCloseListener = listener; - } - - public void requestClose() { - if (mOnRequestCloseListener != null) { - mOnRequestCloseListener.onRequestClose(mDialog); - } - } - - public void setOnShowListener(DialogInterface.OnShowListener listener) { - mOnShowListener = listener; - } - - protected void setTransparent(boolean transparent) { - mTransparent = transparent; - } - - protected void setAnimationType(String animationType) { - if (!TextUtils.isEmpty(animationType)) { - switch (animationType) { - case "fade": - mAniType = STYLE_THEME_ANIMATED_FADE_DIALOG; - break; - case "slide": - mAniType = STYLE_THEME_ANIMATED_SLIDE_DIALOG; - break; - case "slide_fade": - mAniType = STYLE_THEME_ANIMATED_SLIDE_FADE_DIALOG; - break; - default: - mAniType = STYLE_THEME_FULL_SCREEN_DIALOG; - } - } - - mAnimationType = animationType; - mPropertyRequiresNewDialog = true; - } - - protected String getAnimationType() { - return mAnimationType; - } - - protected void setEnterImmersionStatusBar(boolean fullScreen) { - mEnterImmersionStatusBar = fullScreen; - } - - protected void setImmersionStatusBarTextDarkColor(boolean darkColor) { - mStatusBarTextDarkColor = darkColor; - } - - public Dialog getDialog() { - return mDialog; - } - - static int mStatusBarHeight = -1; - static boolean hasCheckStatusBarHeight = false; - - public int getStatusBarHeightFixed() { - if (mStatusBarHeight == -1) { - mStatusBarHeight = getStatusBarHeightFromSystem(); - - hasCheckStatusBarHeight = true; - } - return mStatusBarHeight; - } - - private static int statusBarHeight = -1; - - @SuppressWarnings("ConstantConditions") - public static int getStatusBarHeightFromSystem() { - if (statusBarHeight > 0) { - return statusBarHeight; - } - - Class c; - Object obj; - Field field; - int x; - try { - c = Class.forName("com.android.internal.R$dimen"); - obj = c.newInstance(); - field = c.getField("status_bar_height"); - x = Integer.parseInt(field.get(obj).toString()); - statusBarHeight = ContextHolder.getAppContext().getResources().getDimensionPixelSize(x); - } catch (Exception e1) { - statusBarHeight = -1; - e1.printStackTrace(); - } - - if (statusBarHeight < 1) { - try { - int statebarH_id = ContextHolder.getAppContext().getResources() - .getIdentifier("statebar_height", "dimen", - ContextHolder.getAppContext().getPackageName()); - statusBarHeight = Math - .round(ContextHolder.getAppContext().getResources().getDimension(statebarH_id)); - } catch (NotFoundException e) { - LogUtils.d("HippyModalHostView", "getStatusBarHeightFromSystem: " + e.getMessage()); - statusBarHeight = 0; - } - } - return statusBarHeight; - } - - public void setDialogBar(boolean isDarkIcon) { - try { - Window window = mDialog.getWindow(); - int sysUI = window.getDecorView().getSystemUiVisibility(); - sysUI = sysUI & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - sysUI = sysUI & ~View.SYSTEM_UI_FLAG_LAYOUT_STABLE; - int extra; - if (isDarkIcon) { - extra = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } else { - extra = View.SYSTEM_UI_FLAG_LAYOUT_STABLE; - } - window.getDecorView().setSystemUiVisibility(sysUI | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | extra); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - window.setStatusBarColor(Color.TRANSPARENT); - } else { - window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - } - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - private boolean isActivityFinishing() { - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) getContext(); - if (hippyInstanceContext == null) { - return true; - } - - Context context = hippyInstanceContext.getBaseContext(); - if (!(context instanceof Activity)) { - return true; - } - - Activity currentActivity = (Activity) context; - return currentActivity.isFinishing(); - } - - protected void showOrUpdate() { - if (isActivityFinishing()) { - return; - } - - if (mDialog != null) { - if (mPropertyRequiresNewDialog) { - dismiss(); - } else { - updateProperties(); - return; - } - } - - mPropertyRequiresNewDialog = false; - Context currentContext = getContext(); - mDialog = createDialog(currentContext); - mContentView = createContentView(mHostView); - mDialog.setContentView(mContentView); - updateProperties(); - if (mDialog != null && mDialog.getWindow() != null && mEnterImmersionStatusBar) { - setDialogBar(mStatusBarTextDarkColor); - } - - assert mDialog != null; - mDialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialogInterface) { - mOnShowListener.onShow(dialogInterface); - ObjectAnimator alphaAnimation = null; - switch (mAniType) { - case STYLE_THEME_ANIMATED_FADE_DIALOG: - alphaAnimation = ObjectAnimator.ofFloat(mContentView, "alpha", 0.0f, 1.0f); - break; - case STYLE_THEME_ANIMATED_SLIDE_DIALOG: - alphaAnimation = ObjectAnimator.ofFloat(mContentView, "translationY", 0); - break; - case STYLE_THEME_ANIMATED_SLIDE_FADE_DIALOG: - PropertyValuesHolder fadeValuesHolder = PropertyValuesHolder - .ofFloat("alpha", 0.0f, 1.0f); - PropertyValuesHolder slideValuesHolder = PropertyValuesHolder - .ofFloat("translationY", 0); - alphaAnimation = ObjectAnimator - .ofPropertyValuesHolder(mContentView, fadeValuesHolder, slideValuesHolder); - break; - default: - } - - if (alphaAnimation != null) { - alphaAnimation.setDuration(200); - alphaAnimation.start(); - } - } - }); - mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialogInterface) { - } - }); - mDialog.setOnKeyListener(new DialogInterface.OnKeyListener() { - @Override - public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_UP) { - - if (keyCode == KeyEvent.KEYCODE_BACK) { - mOnRequestCloseListener.onRequestClose(dialog); - return true; - } else { - if (((HippyInstanceContext) getContext()).getBaseContext() instanceof Activity) { - Activity currentActivity = (Activity) ((HippyInstanceContext) getContext()) - .getBaseContext(); - if (currentActivity != null) { - return currentActivity.onKeyUp(keyCode, event); - } - } - } - } - return false; - } - }); - - mDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - mDialog.show(); - - int nScreenHeight = getScreenHeight(); - switch (mAniType) { - case STYLE_THEME_ANIMATED_FADE_DIALOG: - mContentView.setAlpha(0); - break; - case STYLE_THEME_ANIMATED_SLIDE_DIALOG: - if (nScreenHeight != -1) { - mContentView.setTranslationY(nScreenHeight); - } - break; - case STYLE_THEME_ANIMATED_SLIDE_FADE_DIALOG: - mContentView.setAlpha(0); - if (nScreenHeight != -1) { - mContentView.setTranslationY(nScreenHeight); - } - break; - default: - } - } - - private int getScreenHeight() { - try { - Context context = ContextHolder.getAppContext(); - android.view.WindowManager manager = (android.view.WindowManager) context - .getSystemService(Context.WINDOW_SERVICE); - Display display = manager.getDefaultDisplay(); - if (display != null) { - //noinspection deprecation - return manager.getDefaultDisplay().getHeight(); - } - } catch (SecurityException e) { - LogUtils.d("HippyModalHostView", "getScreenHeight: " + e.getMessage()); - } - return -1; - } - - @SuppressWarnings("SameReturnValue") - protected int getThemeResId() { - return 0; - } - - protected Dialog createDialog(Context context) { - int themeResId = getThemeResId(); - if (context != null) { - Resources res = context.getResources(); - themeResId = res.getIdentifier("HippyFullScreenDialog", "style", context.getPackageName()); - } - - assert context != null; - Dialog dialog = new Dialog(context, themeResId); - if (themeResId == 0) { - Window window = dialog.getWindow(); - if (window != null) { - window.requestFeature(Window.FEATURE_NO_TITLE); - window.setBackgroundDrawableResource(android.R.color.transparent); - window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams - .MATCH_PARENT); - } - } - - return dialog; - } - - protected View createContentView(View hostView) { - FrameLayout frameLayout = new FrameLayout(getContext()) { - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - if (mEnterImmersionStatusBar && mStatusBarHeight != -1 - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT - && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - canvas.save(); - canvas.clipRect(0, 0, getMeasuredWidth(), mStatusBarHeight); - canvas.drawColor(0x40000000); - canvas.restore(); - } - } - }; - if (mEnterImmersionStatusBar && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - params.topMargin = -1 * getStatusBarHeightFixed(); - frameLayout.addView(hostView, params); - } else { - frameLayout.addView(hostView); - } - frameLayout.setFitsSystemWindows(false); - return frameLayout; - } - - private void updateProperties() { - if (mTransparent) { - mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); - } else { - mDialog.getWindow().setDimAmount(0.5f); - mDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, - WindowManager.LayoutParams.FLAG_DIM_BEHIND); - } - } - - static class DialogRootViewGroup extends HippyViewGroup { - - public DialogRootViewGroup(Context context) { - super(context); - setFitsSystemWindows(false); - } - - @Override - protected void onSizeChanged(final int w, final int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - if (getChildCount() > 0) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - getChildAt(0) - .layout(getChildAt(0).getLeft(), getChildAt(0).getTop(), getChildAt(0).getLeft() + w, - getChildAt(0).getTop() + h); - } - - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) getContext(); - if (hippyInstanceContext != null && hippyInstanceContext.getEngineContext() != null) { - final HippyEngineContext engineContext = hippyInstanceContext.getEngineContext(); - if (engineContext.getThreadExecutor() != null) { - final int id = getChildAt(0).getId(); - engineContext.getThreadExecutor().postOnDomThread(new Runnable() { - @Override - public void run() { - if (engineContext.getDomManager() != null) { - engineContext.getDomManager().updateNodeSize(id, w, h); - } - } - }); - - } - - } - } - } - - @Override - public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { - - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ModalHostHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ModalHostHelper.java deleted file mode 100644 index 1f78c2f45bd..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ModalHostHelper.java +++ /dev/null @@ -1,46 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.modal; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Point; -import android.os.Build; -import android.view.Display; -import android.view.WindowManager; - -/*package*/ class ModalHostHelper { - - private static final Point MIN_POINT = new Point(); - private static final Point MAX_POINT = new Point(); - private static final Point SIZE_POINT = new Point(); - - - @TargetApi(16) - public static Point getModalHostSize(Context context) { - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - Display display = wm.getDefaultDisplay(); - if (Build.VERSION.SDK_INT >= 16) { - display.getCurrentSizeRange(MIN_POINT, MAX_POINT); - } - display.getSize(SIZE_POINT); - if (SIZE_POINT.x < SIZE_POINT.y) { - return new Point(MIN_POINT.x, MAX_POINT.y); - } else { - return new Point(MAX_POINT.x, MIN_POINT.y); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ModalStyleNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ModalStyleNode.java deleted file mode 100644 index c7a919d5f37..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ModalStyleNode.java +++ /dev/null @@ -1,34 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.modal; - -import android.graphics.Point; - -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.smtt.flexbox.FlexNode; - -@SuppressWarnings({"unused"}) -class ModalStyleNode extends StyleNode { - - @Override - public void addChildAt(FlexNode child, int i) { - super.addChildAt(child, i); - Point modalSize = ModalHostHelper.getModalHostSize(ContextHolder.getAppContext()); - child.setStyleWidth(modalSize.x); - child.setStyleHeight(modalSize.y); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/RequestCloseEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/RequestCloseEvent.java deleted file mode 100644 index 4d24179eb54..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/RequestCloseEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.modal; - -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; - -/** - * - */ -public class RequestCloseEvent extends HippyViewEvent { - - public static final String EVENT_NAME = "onRequestClose"; - - public RequestCloseEvent() { - super(EVENT_NAME); - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ShowEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ShowEvent.java deleted file mode 100644 index e4df7b160cb..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/modal/ShowEvent.java +++ /dev/null @@ -1,31 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.modal; - -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; - -/** - * - */ -public class ShowEvent extends HippyViewEvent { - - public static final String EVENT_NAME = "onShow"; - - public ShowEvent() { - super(EVENT_NAME); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/navigator/Navigator.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/navigator/Navigator.java deleted file mode 100644 index 734ed457f17..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/navigator/Navigator.java +++ /dev/null @@ -1,126 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.navigator; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.view.View; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.views.view.HippyViewGroup; - -public class Navigator extends HippyViewGroup { - - private final static String DIRECTION_LEFT = "left"; - private final static String DIRECTION_RIGHT = "right"; - private final static String DIRECTION_TOP = "top"; - private final static String DIRECTION_BOTTOM = "bottom"; - - public Navigator(Context context) { - super(context); - } - - public void push(HippyRootView hippyRootView, boolean animated, String fromDirection) { - addView(hippyRootView); - hippyRootView.layout(0, 0, getWidth(), getHeight()); - - if (animated) { - Animator animator; - switch (fromDirection == null ? "" : fromDirection) { - case DIRECTION_TOP: - animator = ObjectAnimator.ofFloat(hippyRootView, "translationY", -getHeight(), 0); - break; - case DIRECTION_BOTTOM: - animator = ObjectAnimator.ofFloat(hippyRootView, "translationY", getHeight(), 0); - break; - case DIRECTION_LEFT: - animator = ObjectAnimator.ofFloat(hippyRootView, "translationX", -getWidth(), 0); - break; - case DIRECTION_RIGHT: - default: - // 默认值就是"right" - animator = ObjectAnimator.ofFloat(hippyRootView, "translationX", getWidth(), 0); - break; - } - if (animator != null) { - animator.start(); - } - } - } - - - @Override - protected void onLayout(boolean change, int l, int t, int r, int b) { - // super.onLayout(b, i, i1, i2, i3); - - int childCount = getChildCount(); - - for (int i = 0; i < childCount; i++) { - getChildAt(i).layout(0, 0, getWidth(), getHeight()); - } - } - - public void init(HippyRootView hippyRootView) { - addView(hippyRootView); - } - - - @Override - public void onAnimationEnd(Animator animator) { - super.onAnimationEnd(animator); - - final View chileView = (View) ((ObjectAnimator) animator).getTarget(); - NavigatorController.destroyInstance(chileView); - animator.removeAllListeners(); - - post(new Runnable() { - @Override - public void run() { - removeView(chileView); - } - }); - } - - public void pop(boolean animated, String toDirection) { - final View childView = getChildAt(getChildCount() - 1); - if (animated) { - Animator animator; - switch (toDirection == null ? "" : toDirection) { - case DIRECTION_TOP: - animator = ObjectAnimator.ofFloat(childView, "translationY", 0, -getHeight()); - break; - case DIRECTION_BOTTOM: - animator = ObjectAnimator.ofFloat(childView, "translationY", 0, getHeight()); - break; - case DIRECTION_LEFT: - animator = ObjectAnimator.ofFloat(childView, "translationX", 0, -getWidth()); - break; - case DIRECTION_RIGHT: - default: - // 默认值就是"right" - animator = ObjectAnimator.ofFloat(childView, "translationX", 0, getWidth()); - break; - } - if (animator != null) { - animator.addListener(this); - animator.start(); - } - } else { - NavigatorController.destroyInstance(childView); - removeView(childView); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/navigator/NavigatorController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/navigator/NavigatorController.java deleted file mode 100644 index 9ecc8bc00c8..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/navigator/NavigatorController.java +++ /dev/null @@ -1,120 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.navigator; - -import android.content.Context; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; - -import com.tencent.mtt.hippy.HippyEngine; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyGroupController; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = NavigatorController.CLASS) -public class NavigatorController extends HippyGroupController { - - public static final String CLASS = "Navigator"; - - private final static String PUSH = "push"; - private final static String POP = "pop"; - - @Override - protected View createViewImpl(Context context) { - return new Navigator(context); - } - - @Override - protected void addView(ViewGroup parentView, View view, int index) { - // super.addView(parentView, view, index); - Log.d(CLASS, "addView"); - } - - @Override - public void dispatchFunction(Navigator view, String functionName, HippyArray var) { - super.dispatchFunction(view, functionName, var); - - switch (functionName) { - case POP: - boolean animated = false; - String toDirection = null; - if (var != null) { - HippyMap hippyMap = var.getMap(0); - if (hippyMap != null) { - animated = hippyMap.getBoolean("animated"); - toDirection = hippyMap.getString("toDirection"); - } - } - view.pop(animated, toDirection); - break; - case PUSH: - if (var != null) { - HippyMap hippyMap = var.getMap(0); - if (hippyMap != null) { - String component = hippyMap.getString("routeName"); - HippyMap initProps = hippyMap.getMap("initProps"); - animated = hippyMap.getBoolean("animated"); - String fromDirection = hippyMap.getString("fromDirection"); - HippyRootView hippyRootView = loadNavPage(view, component, initProps); - view.push(hippyRootView, animated, fromDirection); - } - } - break; - } - } - - private HippyRootView loadNavPage(Navigator view, String component, HippyMap initProps) { - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) view.getContext(); - HippyEngine.ModuleLoadParams moduleParams = new HippyEngine.ModuleLoadParams( - hippyInstanceContext.getModuleParams()); - moduleParams.componentName = component; - moduleParams.jsParams = initProps; - return hippyInstanceContext.getEngineManager().loadModule(moduleParams); - } - - @HippyControllerProps(name = "initialRoute", defaultType = HippyControllerProps.MAP) - public void initPage(Navigator navigator, HippyMap hippyMap) { - String component = hippyMap.getString("routeName"); - HippyMap initProps = hippyMap.getMap("initProps"); - - HippyRootView hippyRootView = loadNavPage(navigator, component, initProps); - - navigator.init(hippyRootView); - } - - public static void destroyInstance(View view) { - if (view instanceof HippyRootView) { - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) view.getContext(); - HippyRootView hippyRootView = (HippyRootView) view; - hippyInstanceContext.getEngineManager().destroyModule(hippyRootView); - } - } - - @Override - protected void deleteChild(ViewGroup parentView, View childView) { - // super.deleteChild(parentView, childView); - - destroyInstance(childView); - - Log.d(CLASS, "deleteChild"); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/FooterUtil.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/FooterUtil.java deleted file mode 100644 index 37d42f361c2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/FooterUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.refresh; - -import android.view.View; - -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.uimanager.PullFooterRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.HippyViewUtil; -import com.tencent.mtt.hippy.views.list.HippyListView; -import com.tencent.mtt.hippy.views.waterfalllist.HippyWaterfallView; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase; - -public class FooterUtil { - - public static boolean isFooterView(View view) { - RenderNode renderNode = HippyViewUtil.getRenderNode(view); - return renderNode instanceof PullFooterRenderNode; - } - - public static void sendFooterReleasedEvent(HippyPullFooterView footerView) { - IFooterContainer footerContainer = null; - if (footerView.getParentView() instanceof IFooterContainer) { - footerContainer = (IFooterContainer) footerView.getParentView(); - } - int curState = footerContainer != null - ? footerContainer.getFooterState() : HippyListView.REFRESH_STATE_IDLE; - - if (curState == HippyListView.REFRESH_STATE_IDLE) { - if (footerContainer != null) { - footerContainer.setFooterState(HippyListView.REFRESH_STATE_LOADING); - } - new HippyViewEvent(HippyListView.EVENT_TYPE_FOOTER_RELEASED).send(footerView, null); - } - - if (footerContainer instanceof HippyWaterfallView) { - ((HippyWaterfallView) footerContainer).startLoadMore(); - } - } - - public static void checkFooterBinding(RecyclerViewBase list, View view) { - if (view instanceof HippyPullFooterView) { - ((HippyPullFooterView) view).setParentView(list); - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullFooterView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullFooterView.java deleted file mode 100644 index 84d272b8097..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullFooterView.java +++ /dev/null @@ -1,47 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.refresh; - -import android.content.Context; -import android.view.View; - -import com.tencent.mtt.hippy.views.view.HippyViewGroup; - -public class HippyPullFooterView extends HippyViewGroup { - - private View mParentView; - private boolean mStickEnabled = false; - - public HippyPullFooterView(Context context) { - super(context); - } - - public void setParentView(View parentView) { - mParentView = parentView; - } - - public View getParentView() { - return mParentView; - } - - public void setStickEnabled(boolean enabled) { - mStickEnabled = enabled; - } - - public boolean getStickEnabled() { - return mStickEnabled; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullFooterViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullFooterViewController.java deleted file mode 100644 index 3b585251045..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullFooterViewController.java +++ /dev/null @@ -1,69 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.refresh; - -import android.content.Context; -import android.view.View; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.PullFooterRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.views.list.HippyListView; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyPullFooterViewController.CLASS_NAME, isLazyLoad = true) -public class HippyPullFooterViewController extends HippyViewController { - - public static final String CLASS_NAME = "PullFooterView"; - - @Override - protected View createViewImpl(Context context) { - return new HippyPullFooterView(context); - } - - @Override - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, ControllerManager controllerManager, boolean lazy) { - return new PullFooterRenderNode(id, props, className, hippyRootView, controllerManager, lazy); - } - - @HippyControllerProps(name = "sticky", defaultType = HippyControllerProps.BOOLEAN) - public void setStickEnabled(HippyPullFooterView view, boolean flag) { - view.setStickEnabled(flag); - } - - @Override - public void dispatchFunction(HippyPullFooterView view, String functionName, HippyArray dataArray) { - super.dispatchFunction(view, functionName, dataArray); - View parent = view.getParentView(); - switch (functionName) { - case "collapsePullFooter": { - if (parent instanceof HippyListView) { - ((HippyListView) parent).onFooterRefreshFinish(); - } else if (parent instanceof IFooterContainer) { - ((IFooterContainer) parent).onFooterRefreshFinish(); - } - break; - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderView.java deleted file mode 100644 index 969835b7338..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderView.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.refresh; - -import android.content.Context; -import android.view.View; - -import com.tencent.mtt.hippy.views.view.HippyViewGroup; - -public class HippyPullHeaderView extends HippyViewGroup { - - private View mParentView; - - public HippyPullHeaderView(Context context) { - super(context); - } - - public void setParentView(View parentView) { - mParentView = parentView; - } - - public View getParentView() { - return mParentView; - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderViewController.java deleted file mode 100644 index 73a0389e8f0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/HippyPullHeaderViewController.java +++ /dev/null @@ -1,104 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.refresh; - -import android.content.Context; -import android.view.View; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.PullHeaderRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.views.hippylist.HippyRecyclerView; -import com.tencent.mtt.hippy.views.hippylist.PullHeaderEventHelper; -import com.tencent.mtt.hippy.views.list.HippyListView; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyPullHeaderViewController.CLASS_NAME, isLazyLoad = true) -public class HippyPullHeaderViewController extends HippyViewController { - - public static final String CLASS_NAME = "PullHeaderView"; - public static final String COLLAPSE_PULL_HEADER = "collapsePullHeader"; - public static final String EXPAND_PULL_HEADER = "expandPullHeader"; - - @Override - protected View createViewImpl(Context context) { - return new HippyPullHeaderView(context); - } - - @Override - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, - ControllerManager controllerManager, boolean lazy) { - return new PullHeaderRenderNode(id, props, className, hippyRootView, controllerManager, lazy); - } - - private void execListViewFunction(HippyListView listView, String functionName) { - switch (functionName) { - case COLLAPSE_PULL_HEADER: { - listView.onHeaderRefreshFinish(); - break; - } - case EXPAND_PULL_HEADER: { - listView.onHeaderRefresh(); - break; - } - default: { - LogUtils - .d("HippyPullHeaderViewController", "execListViewFunction: unknown function name!!"); - } - } - } - - private void execRecyclerViewFunction(HippyRecyclerView recyclerView, String functionName) { - PullHeaderEventHelper headerEventHelper = recyclerView.getAdapter() - .getHeaderEventHelper(); - if (headerEventHelper != null) { - switch (functionName) { - case COLLAPSE_PULL_HEADER: { - headerEventHelper.onHeaderRefreshFinish(); - break; - } - case EXPAND_PULL_HEADER: { - headerEventHelper.onHeaderRefresh(); - break; - } - default: { - LogUtils.d("HippyPullHeaderViewController", - "execRecyclerViewFunction: unknown function name!!"); - } - } - } - } - - @Override - public void dispatchFunction(HippyPullHeaderView view, String functionName, - HippyArray dataArray) { - super.dispatchFunction(view, functionName, dataArray); - View parent = view.getParentView(); - if (parent instanceof HippyListView) { - execListViewFunction((HippyListView)parent, functionName); - } else if (parent instanceof HippyRecyclerView) { - execRecyclerViewFunction((HippyRecyclerView)parent, functionName); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/RefreshWrapper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/RefreshWrapper.java deleted file mode 100644 index ed4d30a36ba..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/RefreshWrapper.java +++ /dev/null @@ -1,237 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.refresh; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.content.Context; -import android.view.MotionEvent; -import android.view.View; -import android.view.animation.AccelerateInterpolator; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.view.HippyViewGroup; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase; - -@SuppressWarnings({"deprecation", "unused"}) -public class RefreshWrapper extends HippyViewGroup { - - RefreshWrapperItemView mRefreshWrapperItemView; - View mContentView; - - float mTansY = -1; - float mStartTransY = 0; - float mStartY = 0; - float mStartDownY = -1; - float mStartX = 0; - - RefreshState mState = RefreshState.Init; - - int mBounceTime = 300; - protected boolean mScrollEventEnable = true; - protected int mScrollEventThrottle = 400; // 400ms最多回调一次 - private long mLastScrollEventTimeStamp = -1; - - public void refreshComplected() { - bounceToHead(0); - mState = RefreshState.Init; - } - - public void setTime(int time) { - this.mBounceTime = time; - } - - enum RefreshState { - Init, - Loading, - } - - public RefreshWrapper(Context context) { - super(context); - } - - - void setSTranslationY(float y) { - if (mRefreshWrapperItemView != null) { - mRefreshWrapperItemView.setTranslationY(y > 0 ? y : 0); - } - if (mContentView != null) { - mContentView.setTranslationY(y > 0 ? y : 0); - } - } - - public void setOnScrollEventEnable(boolean enable) { - mScrollEventEnable = enable; - } - - public void setScrollEventThrottle(int scrollEventThrottle) { - mScrollEventThrottle = scrollEventThrottle; - } - - void bounceToHead(float toTransY) { - if (mContentView != null && mRefreshWrapperItemView != null) { - Animator contentAnimator = ObjectAnimator - .ofFloat(mContentView, "TranslationY", mContentView.getTranslationY(), toTransY); - contentAnimator.setDuration(mBounceTime); - contentAnimator.setInterpolator(new AccelerateInterpolator()); - Animator wrapperAnimator = ObjectAnimator.ofFloat(mRefreshWrapperItemView, "TranslationY", - mRefreshWrapperItemView.getTranslationY(), - toTransY); - wrapperAnimator.setInterpolator(new AccelerateInterpolator()); - wrapperAnimator.setDuration(mBounceTime); - contentAnimator.start(); - wrapperAnimator.start(); - } - } - - - float getCompactScrollY() { - if (mContentView instanceof RecyclerViewBase) { - return ((RecyclerViewBase) mContentView).getOffsetY(); - } - return mContentView.getScrollY(); - } - - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - float nowMoveY = event.getRawY(); - float nowMoveX = event.getRawX(); - if (mContentView != null && mRefreshWrapperItemView != null) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mStartY = event.getRawY(); - mStartX = event.getRawX(); //记录首次DOWN的位置 - mStartTransY = mRefreshWrapperItemView.getTranslationY(); - - break; - case MotionEvent.ACTION_MOVE: - - if (nowMoveY - mStartY > 0) { - float scrollY = getCompactScrollY(); - - if (scrollY == 0) { - if (mStartDownY == -1) { - mStartDownY = nowMoveY; - } else { - mTansY = (nowMoveY - mStartDownY) / 3; - setSTranslationY(mTansY + mStartTransY); - //把y的偏移值返回给js侧,这里把偏移值转换为负数,方便前端理解 - sendOnScrollEvent(-mTansY); - } - - //如果垂直滚动得比水平滚动得多,就认为当前用户手势是一个上下拉,RefreshWrapper就把事件吃掉,RefreshWrapper里面的孩子就收不到事件了 - //否则RefreshWrapper里面的孩子能收到事件,ViewPager还能继续处理左右滚动事件。 - if (Math.abs(nowMoveX - mStartX) < Math.abs((nowMoveY - mStartY))) { - return true; - } - } - } else { - if (mState == RefreshState.Loading) { - float dis = nowMoveY - mStartY; - if (mRefreshWrapperItemView.getTranslationY() > 0) { - setSTranslationY(mStartTransY + dis); - //如果垂直滚动得比水平滚动得多,就认为当前用户手势是一个上下拉,RefreshWrapper就把事件吃掉,RefreshWrapper里面的孩子就收不到事件了 - //否则RefreshWrapper里面的孩子能收到事件,ViewPager还能继续处理左右滚动事件。 - if (Math.abs(nowMoveX - mStartX) < Math.abs(dis)) { - return true; - } - } - } - } - break; - case MotionEvent.ACTION_UP: - if (mState == RefreshState.Init) { - if (mTansY < mRefreshWrapperItemView.getHeight() - && mRefreshWrapperItemView.getTranslationY() > 0) { - bounceToHead(0); - //如果是水平滚动,不发送cancle事件。 - if (Math.abs(nowMoveX - mStartX) < Math.abs((nowMoveY - mStartY))) { - sendCancelEvent(event); - } - } else if (mTansY > mRefreshWrapperItemView.getHeight()) { - startRefresh(); - //如果是水平滚动,不发送cancle事件。 - if (Math.abs(nowMoveX - mStartX) < Math.abs((nowMoveY - mStartY))) { - sendCancelEvent(event); - } - } - } else if (mState == RefreshState.Loading) { - if (mRefreshWrapperItemView.getTranslationY() > mRefreshWrapperItemView.getHeight()) { - startRefresh(); - //如果是水平滚动,不发送cancle事件。 - if (Math.abs(nowMoveX - mStartX) < Math.abs((nowMoveY - mStartY))) { - sendCancelEvent(event); - } - } - } - - mStartDownY = -1; - break; - } - - } - - return super.dispatchTouchEvent(event); - } - - public void sendCancelEvent(MotionEvent event) { - MotionEvent motionEvent = MotionEvent.obtain(event); - motionEvent.setAction(MotionEvent.ACTION_CANCEL); - mContentView.dispatchTouchEvent(motionEvent); - } - - - public void startRefresh() { - mTansY = -1; - bounceToHead(mRefreshWrapperItemView.getHeight()); - mState = RefreshState.Loading; - new HippyViewEvent("onRefresh").send(this, null); - } - - public void sendOnScrollEvent(float y) { - if (mScrollEventEnable) { - long currTime = System.currentTimeMillis(); - if (currTime - mLastScrollEventTimeStamp < mScrollEventThrottle) { - return; - } - new HippyViewEvent("onScroll").send(this, generateScrollEvent(y)); - mLastScrollEventTimeStamp = currTime; - } - } - - private HippyMap generateScrollEvent(float y) { - HippyMap contentOffset = new HippyMap(); - contentOffset.pushDouble("x", PixelUtil.px2dp(0)); - contentOffset.pushDouble("y", PixelUtil.px2dp(y)); - HippyMap event = new HippyMap(); - event.pushMap("contentOffset", contentOffset); - return event; - } - - @Override - public void addView(View child, int index) { - if (child instanceof RefreshWrapperItemView) { - mRefreshWrapperItemView = (RefreshWrapperItemView) child; - } else { - mContentView = child; - } - super.addView(child, index); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/RefreshWrapperController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/RefreshWrapperController.java deleted file mode 100644 index db33fd06a39..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/refresh/RefreshWrapperController.java +++ /dev/null @@ -1,62 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.refresh; - -import android.content.Context; -import android.view.View; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.uimanager.HippyGroupController; - -@SuppressWarnings({"unused"}) -@HippyController(name = "RefreshWrapper") -public class RefreshWrapperController extends HippyGroupController { - - final String RefreshComplected = "refreshComplected"; - final String StartRefresh = "startRefresh"; - - @Override - protected View createViewImpl(Context context) { - return new RefreshWrapper(context); - } - - @HippyControllerProps(name = "bounceTime", defaultType = HippyControllerProps.NUMBER, defaultNumber = 300) - public void bounceTime(RefreshWrapper wrapper, int time) { - wrapper.setTime(time); - } - - @HippyControllerProps(name = "onScrollEnable", defaultType = HippyControllerProps.BOOLEAN) - public void setOnScrollEventEnable(RefreshWrapper wrapper, boolean flag) { - wrapper.setOnScrollEventEnable(flag); - } - - @HippyControllerProps(name = "scrollEventThrottle", defaultType = HippyControllerProps.NUMBER, defaultNumber = 30.0D) - public void setscrollEventThrottle(RefreshWrapper wrapper, int scrollEventThrottle) { - wrapper.setScrollEventThrottle(scrollEventThrottle); - } - - @Override - public void dispatchFunction(RefreshWrapper view, String functionName, HippyArray var) { - super.dispatchFunction(view, functionName, var); - - if (RefreshComplected.equals(functionName)) { - view.refreshComplected(); - } else if (StartRefresh.equals(functionName)) { - view.startRefresh(); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyHorizontalScrollView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyHorizontalScrollView.java deleted file mode 100644 index 56c612ea828..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyHorizontalScrollView.java +++ /dev/null @@ -1,384 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.scroll; - -import android.animation.ValueAnimator; -import android.content.Context; -import android.os.Build; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.widget.HorizontalScrollView; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.utils.I18nUtil; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.supportui.views.ScrollChecker; -import java.util.HashMap; - -@SuppressWarnings("deprecation") -public class HippyHorizontalScrollView extends HorizontalScrollView implements HippyViewBase, - HippyScrollView, ScrollChecker.IScrollCheck { - - private NativeGestureDispatcher mGestureDispatcher; - - private boolean mScrollEnabled = true; - - private boolean mDoneFlinging; - - private boolean mDragging; - - private final HippyOnScrollHelper mHippyOnScrollHelper; - - private boolean mScrollEventEnable = true; - - private boolean mScrollBeginDragEventEnable = false; - - private boolean mScrollEndDragEventEnable = false; - - private boolean mMomentumScrollBeginEventEnable = false; - - private boolean mMomentumScrollEndEventEnable = false; - - private boolean mFlingEnabled = true; - - private boolean mPagingEnabled = false; - - protected int mScrollEventThrottle = 400; // 400ms最多回调一次 - private long mLastScrollEventTimeStamp = -1; - - protected int mScrollMinOffset = 0; - private int startScrollX = 0; - private int mLastX = 0; - private int initialContentOffset = 0; - private boolean hasCompleteFirstBatch = false; - - private HashMap scrollOffsetForReuse = new HashMap<>(); - - public HippyHorizontalScrollView(Context context) { - super(context); - mHippyOnScrollHelper = new HippyOnScrollHelper(); - setHorizontalScrollBarEnabled(false); - - if (I18nUtil.isRTL()) { - setRotationY(180f); - } - } - - @Override - public void onViewAdded(View child) { - if (I18nUtil.isRTL()) { - child.setRotationY(180f); - } - super.onViewAdded(child); - } - - public void setScrollEnabled(boolean enabled) { - this.mScrollEnabled = enabled; - } - - @Override - public void showScrollIndicator(boolean showScrollIndicator) { - setHorizontalScrollBarEnabled(showScrollIndicator); - } - - public void setScrollEventThrottle(int scrollEventThrottle) { - mScrollEventThrottle = scrollEventThrottle; - } - - @Override - public void callSmoothScrollTo(int x, final int y, int duration) { - if (duration > 0) { - ValueAnimator realSmoothScrollAnimation = - ValueAnimator.ofInt(getScrollX(), x); - realSmoothScrollAnimation.setDuration(duration); - realSmoothScrollAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int scrollTo = (Integer) animation.getAnimatedValue(); - HippyHorizontalScrollView.this.scrollTo(scrollTo, y); - } - }); - realSmoothScrollAnimation.start(); - } else { - smoothScrollTo(x, y); - } - } - - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), - MeasureSpec.getSize(heightMeasureSpec)); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - // Call with the present values in order to re-layout if necessary - scrollTo(getScrollX(), getScrollY()); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_DOWN && !mDragging) { - mDragging = true; - if (mScrollBeginDragEventEnable) { - LogUtils.d("HippyHorizontalScrollView", "emitScrollBeginDragEvent"); - HippyScrollViewEventHelper.emitScrollBeginDragEvent(this); - } - } else if (action == MotionEvent.ACTION_UP && mDragging) { - if (mScrollEndDragEventEnable) { - LogUtils.d("HippyHorizontalScrollView", "emitScrollEndDragEvent"); - HippyScrollViewEventHelper.emitScrollEndDragEvent(this); - } - - if(mPagingEnabled) { - post(new Runnable() { - @Override - public void run() { - doPageScroll(); - } - } - ); - } - - mDragging = false; - } - - boolean result = mScrollEnabled && super.onTouchEvent(event); - if (mGestureDispatcher != null) { - result |= mGestureDispatcher.handleTouchEvent(event); - } - return result; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - if (!mScrollEnabled) { - return false; - } - - int action = event.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_DOWN) { - startScrollX = getScrollX(); - } - - if (super.onInterceptTouchEvent(event)) { - if (mScrollBeginDragEventEnable) { - LogUtils.d("HippyHorizontalScrollView", "emitScrollBeginDragEvent"); - HippyScrollViewEventHelper.emitScrollBeginDragEvent(this); - } - mDragging = true; - return true; - } - return false; - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return mGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - mGestureDispatcher = dispatcher; - } - - @Override - protected void onScrollChanged(int x, int y, int oldX, int oldY) { - super.onScrollChanged(x, y, oldX, oldY); - - Integer id = getId(); - Integer scrollX = getScrollX(); - scrollOffsetForReuse.put(id, scrollX); - - if (mHippyOnScrollHelper.onScrollChanged(x, y)) { - if (mScrollEventEnable) { - long currTime = System.currentTimeMillis(); - int offsetX = Math.abs(x - mLastX); - if (mScrollMinOffset > 0 && offsetX >= mScrollMinOffset) { - mLastX = x; - } else if ((mScrollMinOffset == 0) && (currTime - mLastScrollEventTimeStamp - >= mScrollEventThrottle)) { - mLastScrollEventTimeStamp = currTime; - } else { - return; - } - - HippyScrollViewEventHelper.emitScrollEvent(this); - } - mDoneFlinging = false; - } - - } - - protected void doPageScroll() { - if (mMomentumScrollBeginEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumBeginEvent(this); - } - - smoothScrollToPage(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - if (mDoneFlinging) { - if (mMomentumScrollEndEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumEndEvent(HippyHorizontalScrollView.this); - } - } else { - mDoneFlinging = true; - postOnAnimationDelayed(this, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - } - }; - - postOnAnimationDelayed(runnable, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - - @Override - public void fling(int velocityX) { - if (!mFlingEnabled || mPagingEnabled) { - return; - } - - super.fling(velocityX); - - if (mMomentumScrollBeginEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumBeginEvent(this); - } - Runnable runnable = new Runnable() { - @Override - public void run() { - if (mDoneFlinging) { - if (mMomentumScrollEndEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumEndEvent(HippyHorizontalScrollView.this); - } - } else { - mDoneFlinging = true; - postOnAnimationDelayed(this, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - } - }; - - postOnAnimationDelayed(runnable, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - - private void smoothScrollToPage() { - int width = getWidth(); - if (width <= 0) { - return; - } - int maxPage = getChildAt(0).getWidth()/width; - int page = startScrollX / width; - int offset = getScrollX() - startScrollX; - if (offset == 0) { - return; - } - - if ((page == maxPage - 1) && offset > 0) { - page = page + 1; - } else if (Math.abs(offset) > width/5) { - page = (offset > 0) ? page + 1 : page - 1; - } - - if (page < 0) { - page = 0; - } - - smoothScrollTo(page * width, getScrollY()); - } - - public void setScrollEventEnable(boolean enable) { - this.mScrollEventEnable = enable; - } - - public void setScrollBeginDragEventEnable(boolean enable) { - this.mScrollBeginDragEventEnable = enable; - } - - public void setScrollEndDragEventEnable(boolean enable) { - this.mScrollEndDragEventEnable = enable; - } - - public void setMomentumScrollBeginEventEnable(boolean enable) { - this.mMomentumScrollBeginEventEnable = enable; - } - - public void setMomentumScrollEndEventEnable(boolean enable) { - this.mMomentumScrollEndEventEnable = enable; - } - - public void setFlingEnabled(boolean flag) { - this.mFlingEnabled = flag; - } - - @Override - public void setContentOffset4Reuse(HippyMap offsetMap) { - double offset = offsetMap.getDouble("x"); - scrollTo((int) PixelUtil.dp2px(offset), 0); - } - - public void setContentOffset4Reuse() { - Integer offset = scrollOffsetForReuse.get(getId()); - if (offset != null) { - scrollTo(offset, 0); - } else { - scrollTo(0, 0); - } - } - - public void setPagingEnabled(boolean pagingEnabled) { - this.mPagingEnabled = pagingEnabled; - } - - @Override - public boolean verticalCanScroll(int i) { - return false; - } - - @Override - public boolean horizontalCanScroll(int i) { - return true; - } - - @Override - public void setScrollMinOffset(int scrollMinOffset) { - scrollMinOffset = Math.max(5, scrollMinOffset); - mScrollMinOffset = (int) PixelUtil.dp2px(scrollMinOffset); - } - - @Override - public void setInitialContentOffset(int offset) { - initialContentOffset = offset; - } - - @Override - public void scrollToInitContentOffset() { - if (hasCompleteFirstBatch) { - return; - } - - if (initialContentOffset > 0) { - scrollTo(initialContentOffset, 0); - } - - hasCompleteFirstBatch = true; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyOnScrollHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyOnScrollHelper.java deleted file mode 100644 index 2812437943d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyOnScrollHelper.java +++ /dev/null @@ -1,39 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.scroll; - -import android.os.SystemClock; - -public class HippyOnScrollHelper { - - private static final int MIN_EVENT_SEPARATION_MS = 10; - - private int mPrevX = Integer.MIN_VALUE; - private int mPrevY = Integer.MIN_VALUE; - private long mLastScrollEventTimeMs = -(MIN_EVENT_SEPARATION_MS + 1); - - public boolean onScrollChanged(int x, int y) { - long eventTime = SystemClock.uptimeMillis(); - boolean shouldDispatch = - eventTime - mLastScrollEventTimeMs > MIN_EVENT_SEPARATION_MS || mPrevX != x || mPrevY != y; - - mLastScrollEventTimeMs = eventTime; - mPrevX = x; - mPrevY = y; - - return shouldDispatch; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollView.java deleted file mode 100644 index 3804dfcd709..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollView.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.tencent.mtt.hippy.views.scroll; - -import com.tencent.mtt.hippy.common.HippyMap; - -@SuppressWarnings("deprecation") -public interface HippyScrollView { - - void setScrollEnabled(boolean enabled); - - void showScrollIndicator(boolean showScrollIndicator); - - void setScrollEventEnable(boolean enable); - - void setScrollBeginDragEventEnable(boolean enable); - - void setScrollEndDragEventEnable(boolean enable); - - void setMomentumScrollBeginEventEnable(boolean enable); - - void setMomentumScrollEndEventEnable(boolean enable); - - void setFlingEnabled(boolean flag); - - void setContentOffset4Reuse(HippyMap offsetMap); - - void setPagingEnabled(boolean pagingEnabled); - - void setScrollEventThrottle(int scrollEventThrottle); - - void callSmoothScrollTo(int x, int y, int duration); - - void setScrollMinOffset(int scrollMinOffset); - - void setInitialContentOffset(int offset); - - void scrollToInitContentOffset(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollViewController.java deleted file mode 100644 index dd78d000c47..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollViewController.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.tencent.mtt.hippy.views.scroll; - -import android.content.Context; -import android.text.TextUtils; -import android.view.View; -import android.view.ViewGroup; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyGroupController; -import com.tencent.mtt.hippy.utils.PixelUtil; - -@SuppressWarnings({"deprecation", "unused", "rawtypes"}) -@HippyController(name = HippyScrollViewController.CLASS_NAME) -public class HippyScrollViewController extends - HippyGroupController { - - protected static final String SCROLL_TO = "scrollTo"; - private static final String SCROLL_TO_WITHOPTIONS = "scrollToWithOptions"; - - public static final String CLASS_NAME = "ScrollView"; - - - @Override - protected View createViewImpl(Context context, HippyMap iniProps) { - - if (iniProps != null && iniProps.containsKey("horizontal") && iniProps - .getBoolean("horizontal")) { - return new HippyHorizontalScrollView(context); - } else { - return new HippyVerticalScrollView(context); - } - - // return super.createViewImpl(context, iniProps); - } - - @Override - protected View createViewImpl(Context context) { - return null; - // return new HippyScrollView(context); - } - - @HippyControllerProps(name = "scrollEnabled", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void setScrollEnabled(HippyScrollView view, boolean flag) { - view.setScrollEnabled(flag); - } - - @HippyControllerProps(name = "showScrollIndicator", defaultType = HippyControllerProps.BOOLEAN) - public void setShowScrollIndicator(HippyScrollView view, boolean flag) { - view.showScrollIndicator(flag); - } - - @HippyControllerProps(name = "onScrollEnable", defaultType = HippyControllerProps.BOOLEAN) - public void setScrollEventEnable(HippyScrollView view, boolean flag) { - view.setScrollEventEnable(flag); - } - - @HippyControllerProps(name = "onScrollBeginDrag", defaultType = HippyControllerProps.BOOLEAN) - public void setScrollBeginDragEventEnable(HippyScrollView view, boolean flag) { - view.setScrollBeginDragEventEnable(flag); - } - - @HippyControllerProps(name = "onScrollEndDrag", defaultType = HippyControllerProps.BOOLEAN) - public void setScrollEndDragEventEnable(HippyScrollView view, boolean flag) { - view.setScrollEndDragEventEnable(flag); - } - - @HippyControllerProps(name = "onMomentumScrollBegin", defaultType = HippyControllerProps.BOOLEAN) - public void setMomentumScrollBeginEventEnable(HippyScrollView view, boolean flag) { - view.setMomentumScrollBeginEventEnable(flag); - } - - @HippyControllerProps(name = "onMomentumScrollEnd", defaultType = HippyControllerProps.BOOLEAN) - public void setMomentumScrollEndEventEnable(HippyScrollView view, boolean flag) { - view.setMomentumScrollEndEventEnable(flag); - } - - @HippyControllerProps(name = "flingEnabled", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void setFlingEnabled(HippyScrollView view, boolean flag) { - view.setFlingEnabled(flag); - } - - @HippyControllerProps(name = "contentOffset4Reuse") - public void setContentOffset4Reuse(HippyScrollView view, HippyMap offsetMap) { - view.setContentOffset4Reuse(offsetMap); - } - - @HippyControllerProps(name = "pagingEnabled", defaultType = HippyControllerProps.BOOLEAN) - public void setPagingEnabled(HippyScrollView view, boolean pagingEnabled) { - view.setPagingEnabled(pagingEnabled); - } - - @HippyControllerProps(name = "scrollEventThrottle", defaultType = HippyControllerProps.NUMBER, defaultNumber = 30.0D) - public void setScrollEventThrottle(HippyScrollView view, int scrollEventThrottle) { - view.setScrollEventThrottle(scrollEventThrottle); - } - - @HippyControllerProps(name = "scrollMinOffset", defaultType = HippyControllerProps.NUMBER, defaultNumber = 5) - public void setScrollMinOffset(HippyScrollView view, int scrollMinOffset) { - view.setScrollMinOffset(scrollMinOffset); - } - - @HippyControllerProps(name = "initialContentOffset", defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setInitialContentOffset(HippyScrollView view, int offset) { - view.setInitialContentOffset((int)PixelUtil.dp2px(offset)); - } - - @Override - public void onBatchComplete(View view) { - super.onBatchComplete(view); - - if (view instanceof HippyScrollView) { - ((HippyScrollView)view).scrollToInitContentOffset(); - } - } - - @Override - public void dispatchFunction(View view, String functionName, HippyArray args) { - //noinspection unchecked - super.dispatchFunction(view, functionName, args); - if (view instanceof HippyScrollView) { - - if (TextUtils.equals(SCROLL_TO, functionName)) { - int destX = Math.round(PixelUtil.dp2px(args.getDouble(0))); - int destY = Math.round(PixelUtil.dp2px(args.getDouble(1))); - boolean animated = args.getBoolean(2); - - if (animated) { - ((HippyScrollView) view).callSmoothScrollTo(destX, destY, 0);//用默认的动画事件 - } else { - view.scrollTo(destX, destY); - } - } - if (TextUtils.equals(SCROLL_TO_WITHOPTIONS, functionName) && args != null - && args.size() > 0) { - HippyMap hippyMap = args.getMap(0); //取第一个元素 - int destX = Math.round(PixelUtil.dp2px(hippyMap.getInt("x"))); - int destY = Math.round(PixelUtil.dp2px(hippyMap.getInt("y"))); - int duration = hippyMap.getInt("duration"); - if (duration > 0) { - ((HippyScrollView) view).callSmoothScrollTo(destX, destY, duration);//用默认的动画事件 - } else { - view.scrollTo(destX, destY); - } - } - } - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollViewEventHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollViewEventHelper.java deleted file mode 100644 index 4209586d1b3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyScrollViewEventHelper.java +++ /dev/null @@ -1,92 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.scroll; - -import android.view.ViewGroup; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.utils.PixelUtil; - -@SuppressWarnings({"deprecation", "unused"}) -public class HippyScrollViewEventHelper { - public static final long MOMENTUM_DELAY = 20; - public static final String EVENT_TYPE_BEGIN_DRAG = "onScrollBeginDrag"; - public static final String EVENT_TYPE_END_DRAG = "onScrollEndDrag"; - public static final String EVENT_TYPE_SCROLL = "onScroll"; - public static final String EVENT_TYPE_MOMENTUM_BEGIN = "onMomentumScrollBegin"; - public static final String EVENT_TYPE_MOMENTUM_END = "onMomentumScrollEnd"; - public static final String EVENT_TYPE_ANIMATION_END = "onScrollAnimationEnd"; - - public static void emitScrollEvent(ViewGroup view) { - emitScrollEvent(view, EVENT_TYPE_SCROLL); - } - - public static void emitScrollBeginDragEvent(ViewGroup view) { - emitScrollEvent(view, EVENT_TYPE_BEGIN_DRAG); - } - - public static void emitScrollEndDragEvent(ViewGroup view) { - emitScrollEvent(view, EVENT_TYPE_END_DRAG); - } - - public static void emitScrollMomentumBeginEvent(ViewGroup view) { - emitScrollEvent(view, EVENT_TYPE_MOMENTUM_BEGIN); - } - - public static void emitScrollMomentumEndEvent(ViewGroup view) { - emitScrollEvent(view, EVENT_TYPE_MOMENTUM_END); - } - - protected static void emitScrollEvent(ViewGroup view, String scrollEventType) { - if (view == null) { - return; - } - HippyMap contentInset = new HippyMap(); - contentInset.pushDouble("top", 0); - contentInset.pushDouble("bottom", 0); - contentInset.pushDouble("left", 0); - contentInset.pushDouble("right", 0); - - HippyMap contentOffset = new HippyMap(); - contentOffset.pushDouble("x", PixelUtil.px2dp(view.getScrollX())); - contentOffset.pushDouble("y", PixelUtil.px2dp(view.getScrollY())); - - HippyMap contentSize = new HippyMap(); - contentSize.pushDouble("width", PixelUtil - .px2dp(view.getChildCount() > 0 ? view.getChildAt(0).getWidth() : view.getWidth())); - contentSize.pushDouble("height", PixelUtil - .px2dp(view.getChildCount() > 0 ? view.getChildAt(0).getHeight() : view.getHeight())); - - HippyMap layoutMeasurement = new HippyMap(); - layoutMeasurement.pushDouble("width", PixelUtil.px2dp(view.getWidth())); - layoutMeasurement.pushDouble("height", PixelUtil.px2dp(view.getHeight())); - - HippyMap event = new HippyMap(); - event.pushMap("contentInset", contentInset); - event.pushMap("contentOffset", contentOffset); - event.pushMap("contentSize", contentSize); - event.pushMap("layoutMeasurement", layoutMeasurement); - - if (view.getContext() instanceof HippyInstanceContext) { - HippyEngineContext context = ((HippyInstanceContext) view.getContext()).getEngineContext(); - context.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(view.getId(), scrollEventType, event); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyVerticalScrollView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyVerticalScrollView.java deleted file mode 100644 index 54fa1108178..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/scroll/HippyVerticalScrollView.java +++ /dev/null @@ -1,349 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.scroll; - -import android.animation.ValueAnimator; -import android.content.Context; -import android.os.Build; -import android.view.MotionEvent; -import android.widget.ScrollView; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.utils.PixelUtil; - -@SuppressWarnings("deprecation") -public class HippyVerticalScrollView extends ScrollView implements HippyViewBase, HippyScrollView { - - private NativeGestureDispatcher mGestureDispatcher; - - private boolean mScrollEnabled = true; - - private boolean mDoneFlinging; - - private boolean mDragging; - - private final HippyOnScrollHelper mHippyOnScrollHelper; - - private boolean mScrollEventEnable = true; - - private boolean mScrollBeginDragEventEnable = false; - - private boolean mScrollEndDragEventEnable = false; - - private boolean mMomentumScrollBeginEventEnable = false; - - private boolean mMomentumScrollEndEventEnable = false; - - private boolean mFlingEnabled = true; - - private boolean mPagingEnabled = false; - - protected int mScrollEventThrottle = 400; // 400ms最多回调一次 - private long mLastScrollEventTimeStamp = -1; - - protected int mScrollMinOffset = 0; - private int startScrollY = 0; - private int mLastY = 0; - private int initialContentOffset = 0; - private boolean hasCompleteFirstBatch = false; - - public HippyVerticalScrollView(Context context) { - super(context); - mHippyOnScrollHelper = new HippyOnScrollHelper(); - setVerticalScrollBarEnabled(false); - } - - public void setScrollEnabled(boolean enabled) { - this.mScrollEnabled = enabled; - } - - @Override - public void showScrollIndicator(boolean showScrollIndicator) { - this.setVerticalScrollBarEnabled(showScrollIndicator); - } - - public void setScrollEventThrottle(int scrollEventThrottle) { - mScrollEventThrottle = scrollEventThrottle; - } - - @Override - public void callSmoothScrollTo(final int x, final int y, int duration) { - if (duration > 0) { - ValueAnimator realSmoothScrollAnimation = - ValueAnimator.ofInt(getScrollY(), y); - realSmoothScrollAnimation.setDuration(duration); - realSmoothScrollAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int scrollTo = (Integer) animation.getAnimatedValue(); - HippyVerticalScrollView.this.scrollTo(x, scrollTo); - } - }); - realSmoothScrollAnimation.start(); - } else { - smoothScrollTo(x, y); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension( - MeasureSpec.getSize(widthMeasureSpec), - MeasureSpec.getSize(heightMeasureSpec)); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - // Call with the present values in order to re-layout if necessary - scrollTo(getScrollX(), getScrollY()); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_DOWN && !mDragging) { - mDragging = true; - if (mScrollBeginDragEventEnable) { - HippyScrollViewEventHelper.emitScrollBeginDragEvent(this); - } - // 当手指触摸listview时,让父控件交出ontouch权限,不能滚动 - setParentScrollableIfNeed(false); - } else if (action == MotionEvent.ACTION_UP && mDragging) { - if (mScrollEndDragEventEnable) { - HippyScrollViewEventHelper.emitScrollEndDragEvent(this); - } - - if(mPagingEnabled) { - post(new Runnable() { - @Override - public void run() { - doPageScroll(); - } - } - ); - } - // 当手指松开时,让父控件重新获取onTouch权限 - setParentScrollableIfNeed(true); - mDragging = false; - } - - boolean result = mScrollEnabled && super.onTouchEvent(event); - if (mGestureDispatcher != null) { - result |= mGestureDispatcher.handleTouchEvent(event); - } - return result; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - if (!mScrollEnabled) { - return false; - } - - int action = event.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_DOWN) { - startScrollY = getScrollY(); - } - - if (super.onInterceptTouchEvent(event)) { - if (mScrollBeginDragEventEnable) { - HippyScrollViewEventHelper.emitScrollBeginDragEvent(this); - } - mDragging = true; - return true; - } - return false; - } - - // 设置父控件是否可以获取到触摸处理权限 - private void setParentScrollableIfNeed(boolean flag) { - // 若自己能上下滚动 - if (canScrollVertically(-1) || canScrollVertically(1)) { - getParent().requestDisallowInterceptTouchEvent(!flag); - } - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return mGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - mGestureDispatcher = dispatcher; - } - - @Override - protected void onScrollChanged(int x, int y, int oldX, int oldY) { - super.onScrollChanged(x, y, oldX, oldY); - if (mHippyOnScrollHelper.onScrollChanged(x, y)) { - if (mScrollEventEnable) { - long currTime = System.currentTimeMillis(); - int offsetY = Math.abs(y - mLastY); - if (mScrollMinOffset > 0 && offsetY >= mScrollMinOffset) { - mLastY = y; - } else if ((mScrollMinOffset == 0) && (currTime - mLastScrollEventTimeStamp - >= mScrollEventThrottle)) { - mLastScrollEventTimeStamp = currTime; - } else { - return; - } - - HippyScrollViewEventHelper.emitScrollEvent(this); - } - - mDoneFlinging = false; - } - - } - - protected void doPageScroll() { - if (mMomentumScrollBeginEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumBeginEvent(this); - } - - smoothScrollToPage(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - if (mDoneFlinging) { - if (mMomentumScrollEndEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumEndEvent(HippyVerticalScrollView.this); - } - } else { - mDoneFlinging = true; - postOnAnimationDelayed(this, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - } - }; - - postOnAnimationDelayed(runnable, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - - @Override - public void fling(int velocityY) { - if (!mFlingEnabled || mPagingEnabled) { - return; - } - - super.fling(velocityY); - - if (mMomentumScrollBeginEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumBeginEvent(this); - } - Runnable runnable = new Runnable() { - @Override - public void run() { - if (mDoneFlinging) { - if (mMomentumScrollEndEventEnable) { - HippyScrollViewEventHelper.emitScrollMomentumEndEvent(HippyVerticalScrollView.this); - } - } else { - mDoneFlinging = true; - postOnAnimationDelayed(this, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - } - }; - - postOnAnimationDelayed(runnable, HippyScrollViewEventHelper.MOMENTUM_DELAY); - } - - private void smoothScrollToPage() { - int height = getHeight(); - if (height <= 0) { - return; - } - int maxPage = getChildAt(0).getHeight()/height; - int page = startScrollY / height; - int offset = getScrollY() - startScrollY; - if (offset == 0) { - return; - } - - if ((page == maxPage - 1) && offset > 0) { - page = page + 1; - } else if (Math.abs(offset) > height/5) { - page = (offset > 0) ? page + 1 : page - 1; - } - - if (page < 0) { - page = 0; - } - - smoothScrollTo(getScrollX(), page * height); - } - - public void setScrollEventEnable(boolean enable) { - this.mScrollEventEnable = enable; - } - - public void setScrollBeginDragEventEnable(boolean enable) { - this.mScrollBeginDragEventEnable = enable; - } - - public void setScrollEndDragEventEnable(boolean enable) { - this.mScrollEndDragEventEnable = enable; - } - - public void setMomentumScrollBeginEventEnable(boolean enable) { - this.mMomentumScrollBeginEventEnable = enable; - } - - public void setMomentumScrollEndEventEnable(boolean enable) { - this.mMomentumScrollEndEventEnable = enable; - } - - public void setFlingEnabled(boolean flag) { - this.mFlingEnabled = flag; - } - - @Override - public void setContentOffset4Reuse(HippyMap offsetMap) { - double offset = offsetMap.getDouble("y"); - scrollTo(0, (int) PixelUtil.dp2px(offset)); - } - - @Override - public void setPagingEnabled(boolean pagingEnabled) { - mPagingEnabled = pagingEnabled; - } - - @Override - public void setScrollMinOffset(int scrollMinOffset) { - scrollMinOffset = Math.max(5, scrollMinOffset); - mScrollMinOffset = (int) PixelUtil.dp2px(scrollMinOffset); - } - - @Override - public void setInitialContentOffset(int offset) { - initialContentOffset = offset; - } - - @Override - public void scrollToInitContentOffset() { - if (hasCompleteFirstBatch) { - return; - } - - if (initialContentOffset > 0) { - scrollTo(0, initialContentOffset); - } - - hasCompleteFirstBatch = true; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/text/HippyTextView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/text/HippyTextView.java deleted file mode 100644 index 41d4e909f18..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/text/HippyTextView.java +++ /dev/null @@ -1,363 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.text; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.text.*; -import android.text.style.AbsoluteSizeSpan; -import android.text.style.ForegroundColorSpan; -import android.view.MotionEvent; -import android.view.View; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.adapter.exception.HippyExceptionHandlerAdapter; -import com.tencent.mtt.hippy.dom.node.DomNode; -import com.tencent.mtt.hippy.dom.node.HippyNativeGestureSpan; -import com.tencent.mtt.hippy.dom.node.TextNode; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.views.common.CommonBackgroundDrawable; -import com.tencent.mtt.hippy.views.common.CommonBorder; -import com.tencent.mtt.hippy.views.list.HippyRecycler; - -@SuppressWarnings({"unused"}) -public class HippyTextView extends View implements CommonBorder, HippyViewBase, HippyRecycler { - - private CommonBackgroundDrawable mBGDrawable; - - private boolean mNativeGestureEnable = false; - - private HippyNativeGestureSpan mNativeGestureSpan; - - private NativeGestureDispatcher mGestureDispatcher; - - protected Layout mLayout = null; - - private boolean mTextBold = false; - - private int mNativeTextColor = 0; - private boolean mHasSetNativeTextColor = false; - - - @Override - public void resetProps() { - setPadding(0, 0, 0, 0); - mNativeGestureEnable = false; - mBGDrawable = null; - //noinspection deprecation - setBackgroundDrawable(null); - mTextBold = false; - mGestureDispatcher = null; - mNativeGestureSpan = null; - mNativeTextColor = 0; - mHasSetNativeTextColor = false; - mLayout = null; - } - - @Override - public void clear() { - mLayout = null; - } - - @Override - public void setId(int id) { - super.setId(id); - - Context context = getContext(); - if (context instanceof HippyInstanceContext) { - HippyEngineContext engineContext = ((HippyInstanceContext) context).getEngineContext(); - if (engineContext != null) { - DomNode node = engineContext.getDomManager().getNode(id); - if (node instanceof TextNode) { - ((TextNode) node).setTextView(this); - } - } - } - } - - public HippyTextView(Context context) { - super(context); - } - - public void setTextBold(boolean bold) { - mTextBold = bold; - postInvalidate(); - } - - - public void setLayout(Layout layout) { - if (mLayout != null) { - invalidate(); - } - mLayout = layout; - if (mHasSetNativeTextColor && mNativeTextColor != 0) { - setTextColor(mNativeTextColor); - } - - } - - //user in tabHost - public void setCustomColor(int color) { - mHasSetNativeTextColor = true; - mNativeTextColor = color; - setTextColor(color); - } - - @Override - protected void onDraw(Canvas canvas) { - try { - super.onDraw(canvas); - if (mLayout != null) { - LogUtils.d("HippyText", - "id: " + getId() + " mExtra : " + mLayout.getText() + "layout : w:" + mLayout.getWidth() - + " h:" + mLayout.getHeight() - + " view : w:" + getWidth() + " h:" + getHeight() + " textColor:" + mLayout - .getPaint().getColor()); - canvas.save(); - switch (mLayout.getAlignment()) { - case ALIGN_CENTER: - int totalHeight = - getHeight() + getPaddingTop() + getPaddingBottom() - mLayout.getHeight(); - int width = (getWidth() - mLayout.getWidth()) / 2; - canvas.translate((float) width, totalHeight / 2.0f); - break; - case ALIGN_OPPOSITE: - int x = getWidth() - getPaddingRight() - mLayout.getWidth(); - canvas.translate(x, 0); - break; - default: - canvas.translate(getPaddingLeft(), getPaddingTop()); - break; - } - Paint paint = mLayout.getPaint(); - if (paint != null) { - paint.setFakeBoldText(mTextBold); - } - - mLayout.draw(canvas); - - canvas.restore(); - } else { - LogUtils.d("HippyText", "id: " + getId() + " mExtra : is null "); - } - } catch (Throwable e) { - Context context = getContext(); - if (context instanceof HippyInstanceContext) { - HippyInstanceContext hippyInstanceContext = (HippyInstanceContext) context; - HippyExceptionHandlerAdapter defaultExceptionHandler = hippyInstanceContext - .getEngineContext().getGlobalConfigs() - .getExceptionHandler(); - if (defaultExceptionHandler != null) { - defaultExceptionHandler - .handleNativeException(new RuntimeException("hippyTextView onDraw" + e.getMessage()), - true); - } - } - } - } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - } - - public void setBorderRadius(float radius, int position) { - getBackGround().setBorderRadius(radius, position); - } - - public void setBorderWidth(float width, int position) { - getBackGround().setBorderWidth(width, position); - } - - public void setBorderColor(int color, int position) { - getBackGround().setBorderColor(color, position); - } - - @Override - public void setBorderStyle(int borderStyle) { - } - - @Override - public void setBackgroundColor(int color) { - getBackGround().setBackgroundColor(color); - } - - private CommonBackgroundDrawable getBackGround() { - if (mBGDrawable == null) { - mBGDrawable = new CommonBackgroundDrawable(); - Drawable currBGDrawable = getBackground(); - //noinspection deprecation - super.setBackgroundDrawable(null); - if (currBGDrawable == null) { - //noinspection deprecation - super.setBackgroundDrawable(mBGDrawable); - } else { - LayerDrawable layerDrawable = new LayerDrawable( - new Drawable[]{mBGDrawable, currBGDrawable}); - //noinspection deprecation - super.setBackgroundDrawable(layerDrawable); - } - } - return mBGDrawable; - } - - protected void setTextColor(int textColor) { - if (mLayout != null && mLayout.getText() instanceof SpannableStringBuilder) { - SpannableStringBuilder textSpan = (SpannableStringBuilder) mLayout.getText(); - ForegroundColorSpan[] spans = textSpan - .getSpans(0, mLayout.getText().length(), ForegroundColorSpan.class); - boolean hasSpans = false; - if (spans != null) { - for (ForegroundColorSpan span : spans) { - int start = textSpan.getSpanStart(span); - int end = textSpan.getSpanEnd(span); - textSpan.removeSpan(span); - int spanFlags = Spannable.SPAN_EXCLUSIVE_INCLUSIVE; - if (start == 0) { - spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE; - } - textSpan.setSpan(new ForegroundColorSpan(textColor), start, end, spanFlags); - } - } - if (spans == null || spans.length == 0) { - textSpan.setSpan(new ForegroundColorSpan(textColor), 0, textSpan.toString().length(), - Spannable.SPAN_EXCLUSIVE_INCLUSIVE); - } - } - - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return mGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - mGestureDispatcher = dispatcher; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - - if (!mNativeGestureEnable) { - return super.dispatchTouchEvent(event); - } - int action = event.getAction(); - - if (action == MotionEvent.ACTION_DOWN) { - mNativeGestureSpan = findNativeGestureSpanForTouch(event); - } - if (mNativeGestureSpan != null) { - boolean flag = mNativeGestureSpan.handleDispatchTouchEvent(this, event); - if (flag) { - super.dispatchTouchEvent(event); - return true; - } else { - return super.dispatchTouchEvent(event); - } - } - return super.dispatchTouchEvent(event); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean result = super.onTouchEvent(event); - if (mNativeGestureSpan != null) { - result |= mNativeGestureSpan.handleTouchEvent(this, event); - } - return result; - } - - public void setNativeGestureEnable(boolean nativeGestureEnable) { - this.mNativeGestureEnable = nativeGestureEnable; - } - - - private HippyNativeGestureSpan findNativeGestureSpanForTouch(MotionEvent event) { - HippyNativeGestureSpan span = null; - if (mLayout == null) { - return null; - } - - int x = (int) event.getX(); - int y = (int) event.getY(); - - switch (mLayout.getAlignment()) { - case ALIGN_CENTER: { - int totalHeight = getHeight() + getPaddingTop() + getPaddingBottom() - mLayout.getHeight(); - int width = (getWidth() - mLayout.getWidth()) / 2; - x -= width; - y -= totalHeight / 2; - } - break; - case ALIGN_OPPOSITE: { - int width = getWidth() - getPaddingRight() - mLayout.getWidth(); - x -= width; - } - - } - Layout layout = mLayout; - int line = layout.getLineForVertical(y); - - int lineStartX = (int) layout.getLineLeft(line); - int lineEndX = (int) layout.getLineRight(line); - - CharSequence charSequence = layout.getText(); - if (charSequence instanceof Spanned && x >= lineStartX && x <= lineEndX) { - Spanned spannedText = (Spanned) charSequence; - int index = mLayout.getOffsetForHorizontal(line, x); - - HippyNativeGestureSpan[] spans = spannedText - .getSpans(index, index, HippyNativeGestureSpan.class); - - if (spans != null && spans.length > 0) { - int targetSpanTextLength = charSequence.length(); - for (HippyNativeGestureSpan hippyNativeGestureSpan : spans) { - int spanStart = spannedText.getSpanStart(hippyNativeGestureSpan); - int spanEnd = spannedText.getSpanEnd(hippyNativeGestureSpan); - if (spanEnd > index && (spanEnd - spanStart) <= targetSpanTextLength) { - span = hippyNativeGestureSpan; - targetSpanTextLength = (spanEnd - spanStart); - } - } - } - } - //extend touch area ,if there is no touch event on the text ,use the first node ,it must be the real node - if (span == null && charSequence instanceof Spanned) { - Spanned spanned = (Spanned) charSequence; - HippyNativeGestureSpan[] spans = spanned - .getSpans(0, spanned.length(), HippyNativeGestureSpan.class); - if (spans.length == 1) //only support one text node - { - AbsoluteSizeSpan[] absoluteSizeSpan = spanned - .getSpans(0, spanned.length(), AbsoluteSizeSpan.class); - if (!spans[0].isVirtual() && absoluteSizeSpan.length == 1) { - span = spans[0]; - } - } - } - return span; - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/text/HippyTextViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/text/HippyTextViewController.java deleted file mode 100644 index 1789dbc3f59..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/text/HippyTextViewController.java +++ /dev/null @@ -1,73 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.text; - -import android.content.Context; -import android.text.Layout; -import android.text.Spannable; -import android.view.View; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.dom.node.HippyNativeGestureSpan; -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.dom.node.TextExtra; -import com.tencent.mtt.hippy.dom.node.TextNode; -import com.tencent.mtt.hippy.uimanager.HippyViewController; - -@SuppressWarnings({"unused"}) -@HippyController(name = HippyTextViewController.CLASS_NAME) -public class HippyTextViewController extends HippyViewController { - - public static final String CLASS_NAME = "Text"; - - @Override - protected View createViewImpl(Context context) { - return new HippyTextView(context); - } - - @Override - protected void updateExtra(View view, Object object) { - TextExtra textExtra = (TextExtra) object; - if (textExtra != null && textExtra.mExtra instanceof Layout && view instanceof HippyTextView) { - HippyTextView hippyTextView = (HippyTextView) view; - Layout layout = (Layout) textExtra.mExtra; - CharSequence textSequence = layout.getText(); - if (textSequence instanceof Spannable) { - Spannable spannable = (Spannable) textSequence; - HippyNativeGestureSpan[] spans = spannable - .getSpans(0, spannable.length(), HippyNativeGestureSpan.class); - hippyTextView.setNativeGestureEnable(spans != null && spans.length > 0); - } - hippyTextView.setPadding((int) Math.floor(textExtra.mLeftPadding), - (int) Math.floor(textExtra.mTopPadding), - (int) Math.floor(textExtra.mRightPadding), (int) Math.floor(textExtra.mBottomPadding)); - - hippyTextView.setLayout(layout); - hippyTextView.postInvalidate(); - } - - - } - - @Override - protected StyleNode createNode(boolean virtual) { - return new TextNode(virtual); - } - - @Override - protected boolean handleGestureBySelf() { - return true; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/HippyTextInput.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/HippyTextInput.java deleted file mode 100644 index c3111bf6b73..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/HippyTextInput.java +++ /dev/null @@ -1,668 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.textinput; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.modules.javascriptmodules.EventDispatcher; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.views.common.CommonBackgroundDrawable; -import com.tencent.mtt.hippy.views.common.CommonBorder; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.os.Build; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.Display; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; -import android.widget.TextView; - -import java.lang.reflect.Field; - -@SuppressWarnings({"deprecation", "unused"}) -public class HippyTextInput extends EditText implements HippyViewBase, CommonBorder, - TextView.OnEditorActionListener, View.OnFocusChangeListener { - - private CommonBackgroundDrawable mReactBackgroundDrawable; - final HippyEngineContext mHippyContext; - boolean mHasAddWatcher = false; - private String mPreviousText; - TextWatcher mTextWatcher = null; - boolean mHasSetOnSelectListener = false; - - private final int mDefaultGravityHorizontal; - private final int mDefaultGravityVertical; - //输入法键盘的相关方法 - private final Rect mRect = new Rect(); //获取当前RootView的大小位置信息 - private int mLastRootViewVisibleHeight = -1; //当前RootView的上一次大小 - private boolean mIsKeyBoardShow = false; //键盘是否在显示 - private ReactContentSizeWatcher mReactContentSizeWatcher = null; - - public HippyTextInput(Context context) { - super(context); - mHippyContext = ((HippyInstanceContext) context).getEngineContext(); - setFocusable(true); - setFocusableInTouchMode(true); - setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS); - - mDefaultGravityHorizontal = - getGravity() & (Gravity.HORIZONTAL_GRAVITY_MASK | Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK); - mDefaultGravityVertical = getGravity() & Gravity.VERTICAL_GRAVITY_MASK; - // 临时规避一下EditTextView重设hint不生效的问题 - setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - setPadding(0, 0, 0, 0); - } - - @Override - public void onEditorAction(int actionCode) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushInt("actionCode", actionCode); - hippyMap.pushString("text", getText().toString()); - switch (actionCode) { - case EditorInfo.IME_ACTION_GO: - hippyMap.pushString("actionName", "go"); - break; - case EditorInfo.IME_ACTION_NEXT: - hippyMap.pushString("actionName", "next"); - break; - case EditorInfo.IME_ACTION_NONE: - hippyMap.pushString("actionName", "none"); - break; - case EditorInfo.IME_ACTION_PREVIOUS: - hippyMap.pushString("actionName", "previous"); - break; - case EditorInfo.IME_ACTION_SEARCH: - hippyMap.pushString("actionName", "search"); - break; - case EditorInfo.IME_ACTION_SEND: - hippyMap.pushString("actionName", "send"); - break; - case EditorInfo.IME_ACTION_DONE: - hippyMap.pushString("actionName", "done"); - break; - default: - hippyMap.pushString("actionName", "unknown"); - break; - } - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), - "onEditorAction", hippyMap); - super.onEditorAction(actionCode); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - //监听RootView的布局变化,来判断键盘是否弹起 - if (getRootView() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - getRootView().getViewTreeObserver().addOnGlobalLayoutListener(globaListener); - } - - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - //监听RootView的布局变化,Listern去掉 - if (getRootView() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - getRootView().getViewTreeObserver().removeOnGlobalLayoutListener(globaListener); - } - } - - void setGravityHorizontal(int gravityHorizontal) { - if (gravityHorizontal == 0) { - gravityHorizontal = mDefaultGravityHorizontal; - } - setGravity((getGravity() & ~Gravity.HORIZONTAL_GRAVITY_MASK - & ~Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) | gravityHorizontal); - } - - void setGravityVertical(int gravityVertical) { - if (gravityVertical == 0) { - gravityVertical = mDefaultGravityVertical; - } - setGravity((getGravity() & ~Gravity.VERTICAL_GRAVITY_MASK) | gravityVertical); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (mReactContentSizeWatcher != null) { - mReactContentSizeWatcher.onLayout(); - } - } - - @Override - protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { - super.onTextChanged(text, start, lengthBefore, lengthAfter); - if (mReactContentSizeWatcher != null) { - mReactContentSizeWatcher.onLayout(); - } - } - - public class ReactContentSizeWatcher { - - private final EditText mEditText; - final HippyEngineContext mHippyContext; - private int mPreviousContentWidth = 0; - private int mPreviousContentHeight = 0; - - public ReactContentSizeWatcher(EditText editText, HippyEngineContext hippyContext) { - mEditText = editText; - mHippyContext = hippyContext; - } - - public void onLayout() { - int contentWidth = mEditText.getWidth(); - int contentHeight = mEditText.getHeight(); - - // Use instead size of text content within EditText when available - if (mEditText.getLayout() != null) { - contentWidth = mEditText.getCompoundPaddingLeft() + mEditText.getLayout().getWidth() < 0 ? 0 - : mEditText.getLayout().getWidth() + - mEditText.getCompoundPaddingRight(); - contentHeight = - mEditText.getCompoundPaddingTop() + mEditText.getLayout().getHeight() < 0 ? 0 - : mEditText.getLayout().getHeight() + - mEditText.getCompoundPaddingBottom(); - } - - if (contentWidth != mPreviousContentWidth || contentHeight != mPreviousContentHeight) { - mPreviousContentHeight = contentHeight; - mPreviousContentWidth = contentWidth; - HippyMap contentSize = new HippyMap(); - contentSize.pushDouble("width", mPreviousContentWidth); - contentSize.pushDouble("height", mPreviousContentWidth); - HippyMap eventData = new HippyMap(); - eventData.pushMap("contentSize", contentSize); - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), "onContentSizeChange", eventData); - - } - } - } - - public void setOnContentSizeChange(boolean contentSizeChange) { - if (contentSizeChange) { - mReactContentSizeWatcher = new ReactContentSizeWatcher(this, mHippyContext); - } else { - mReactContentSizeWatcher = null; - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - // if (handleTouch) -// { -// if (getParent() != null) -// { -// getParent().requestDisallowInterceptTouchEvent(true); -// } -// } - return super.onTouchEvent(event); - } - - public InputMethodManager getInputMethodManager() { - return (InputMethodManager) this.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - } - - public void hideInputMethod() { - InputMethodManager imm = this.getInputMethodManager(); - if (imm != null && imm.isActive(this)) { - try { - imm.hideSoftInputFromWindow(this.getWindowToken(), 0); - } catch (Exception e) { - e.printStackTrace(); - } - } - - } - - //成功的話返回手機屏幕的高度,失敗返回-1 - private int getScreenHeight() { - try { - Context context = ContextHolder.getAppContext(); - android.view.WindowManager manager = (android.view.WindowManager) context - .getSystemService(Context.WINDOW_SERVICE); - Display display = manager.getDefaultDisplay(); - - if (display != null) { - int width = manager.getDefaultDisplay().getWidth(); - int height = manager.getDefaultDisplay().getHeight(); - return Math.max(width, height); - } - - } catch (SecurityException e) { - LogUtils.d("HippyTextInput", "getScreenHeight: " + e.getMessage()); - } - return -1; - } - - /** - * 返回RootView的高度,要注意即使全屏,他應該也少了一個狀態欄的高度 - */ - private int getRootViewHeight() { - int height = -1; - View rootView = getRootView(); - if (rootView == null) { - return height; - } - // 问题ID: 106874510 某些奇葩手机ROM调用此方法会报错,做下捕获吧 - try { - rootView.getWindowVisibleDisplayFrame(mRect); - } catch (Throwable e) { - LogUtils.d("InputMethodStatusMonitor:", "getWindowVisibleDisplayFrame failed !" + e); - e.printStackTrace(); - } - - int visibleHeight = mRect.bottom - mRect.top; - if (visibleHeight < 0) { - return -1; - } - return visibleHeight; - } - - //监听RootView布局变化的listener - final ViewTreeObserver.OnGlobalLayoutListener globaListener = new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - int rootViewVisibleHeight = getRootViewHeight(); //RootView的高度 - int screenHeight = getScreenHeight(); //屏幕高度 - if (rootViewVisibleHeight == -1 || screenHeight == -1) //如果有失败直接返回 //TODO...仔细检查下这里的逻辑 - { - mLastRootViewVisibleHeight = rootViewVisibleHeight; - return; - } - if (mLastRootViewVisibleHeight == -1) // 首次 - { - //假设输入键盘的高度位屏幕高度20% - if (rootViewVisibleHeight > screenHeight * 0.8f) { - - mIsKeyBoardShow = false; //键盘没有显示 - } else { - if (!mIsKeyBoardShow) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushInt("keyboardHeight", Math.abs( - screenHeight - rootViewVisibleHeight)); //TODO 首次输入这里需要减去一个statusbar的高度,但是又要当心全屏模式 - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), - "onKeyboardWillShow", hippyMap); - } - mIsKeyBoardShow = true; //键盘显示 ----s首次需要通知 - } - } else { - //假设输入键盘的高度位屏幕高度20% - if (rootViewVisibleHeight > screenHeight * 0.8f) { - if (mIsKeyBoardShow) { - HippyMap hippyMap = new HippyMap(); - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), - "onKeyboardWillHide", hippyMap); - } - mIsKeyBoardShow = false; //键盘没有显示 - } else { - if (!mIsKeyBoardShow) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushInt("keyboardHeight", - Math.abs(mLastRootViewVisibleHeight - rootViewVisibleHeight)); - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), - "onKeyboardWillShow", hippyMap); - } - mIsKeyBoardShow = true; //键盘显示 ----s首次需要通知 - } - } - - mLastRootViewVisibleHeight = rootViewVisibleHeight; - } - }; - - public void showInputMethodManager() { - - InputMethodManager imm = this.getInputMethodManager(); - - try { - imm.showSoftInput(this, 0, null); - } catch (Exception e) { - e.printStackTrace(); - } - - } - - - private String mValidator = ""; //这则表达式,前端传入,要比较小心导致的crash - private String sRegrexValidBefore = ""; - private String sRegrexValidRepeat = ""; //如果有无效的正则输入,会设置. - private boolean mTextInputed = false; //文本是否输入过 - - public void setValidator(String validator) { - mValidator = validator; - } - - //changeListener == true 代表前端监听了 onTextChagne. - //所以如果 - public void setOnChangeListener(boolean changeListener) { - if (changeListener) //需要监听文字的通知 - { - if (mHasAddWatcher) //如果已经注册过了,直接退出。 - { - return; - } - //第一次才注册。 - mTextWatcher = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - sRegrexValidBefore = s.toString();//在文本变化前,记录一下当前输入框的文本值.也就是说现在肯定是符合正则表达式的. - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { - HippyTextInput.this.layout(HippyTextInput.this.getLeft(), HippyTextInput.this.getTop(), - HippyTextInput.this.getRight(), - HippyTextInput.this.getBottom()); - - if (TextUtils.isEmpty((mValidator))) //如果没有正则匹配 - { - //如果文本输入过,判断是否两次相同 - if (mTextInputed && TextUtils.equals(s.toString(), mPreviousText)) { - return; - } - //这里为什么不用sRegrexValidBefore,sRegrexValidBefore是每次有词汇变化就会被回调设置. - mPreviousText = s.toString(); - mTextInputed = true; - if (!bUserSetValue) //如果是前端设置下来的值,不再需要回调给前端. - { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushString("text", s.toString()); - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), - "onChangeText", hippyMap); - LogUtils.d("robinsli", "afterTextChanged 通知前端文本变化=" + s.toString()); - } - } else //如果设置了正则表达式 - { - try { - //如果当前的内容不匹配正则表达式 - if (!s.toString().matches(mValidator) && !"".equals(s.toString())) { - LogUtils.d("robinsli", "afterTextChanged 不符合正则表达式,需要设置回去=" + s.toString()); - //丢弃当前的内容,回退到上一次的值.上一次的值检查过,肯定是符合正则表达式的. - setText(sRegrexValidBefore); - //上一步的setText,将触发新一轮的beforeTextChanged,onTextChanged,afterTextChanged - //为了避免前端收到两次内容同样的通知.记录一下正则匹配设置回去的值. - sRegrexValidRepeat = sRegrexValidBefore; - setSelection(getText().toString().length()); // TODO这里不应该通知 - mTextInputed = true; - } else { - //如果文本输入过,判断是否两次相同 - if (mTextInputed && TextUtils.equals(s.toString(), mPreviousText)) { - return; - } - mTextInputed = true; - mPreviousText = s.toString(); - if (!bUserSetValue //如果是前端设置的一定不通知 - && (TextUtils.isEmpty(sRegrexValidRepeat) //如果没有,输入过无效的内容 - || !TextUtils.equals(sRegrexValidRepeat, mPreviousText) //如果本次输入的内容是上一次重复的蓉蓉 - )) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushString("text", s.toString()); - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), - "onChangeText", hippyMap); - LogUtils.d("robinsli", "afterTextChanged 通知前端文本变化=" + s.toString()); - sRegrexValidRepeat = ""; - } - } - } catch (Throwable error) { - // 不知道外部的正则表达式,最好保护住 - } - - } - - } - }; - - //注册。并标记 - mHasAddWatcher = true; - addTextChangedListener(mTextWatcher); - - } else //不需要需要监听文字的通知 - { - mHasAddWatcher = false; - removeTextChangedListener(mTextWatcher); - } - } - - @Override - public void setBackgroundColor(int color) { - int paddingBottom = getPaddingBottom(); - int paddingTop = getPaddingTop(); - int paddingLeft = getPaddingLeft(); - int paddingRight = getPaddingRight(); - - if (color == Color.TRANSPARENT && mReactBackgroundDrawable == null) { - // don't do anything, no need to allocate ReactBackgroundDrawable for transparent background - LogUtils.d("HippyTextInput", - "don't do anything, no need to allocate ReactBackgroundDrawable for transparent background"); - } else { - getOrCreateReactViewBackground().setBackgroundColor(color); - } - // Android这个EditText控件默认带有内边距,设置背景时系统也可能会再把它默认的内边距给加上去。这里强制去掉内边距 - setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); - } - - public void setBorderColor(int color, int position) { - getOrCreateReactViewBackground().setBorderColor(color, position); - } - - public void setBorderRadius(float borderRadius, int position) { - getOrCreateReactViewBackground().setBorderRadius(borderRadius, position); - } - - @Override - public void setBorderStyle(int borderStyle) { - } - - @Override - public void setBorderWidth(float width, int position) { - getOrCreateReactViewBackground().setBorderWidth(width, position); - } - - private CommonBackgroundDrawable getOrCreateReactViewBackground() { - if (mReactBackgroundDrawable == null) { - mReactBackgroundDrawable = new CommonBackgroundDrawable(); - Drawable backgroundDrawable = getBackground(); - super.setBackgroundDrawable( - null); // required so that drawable callback is cleared before we add the - // drawable back as a part of LayerDrawable - if (backgroundDrawable == null) { - super.setBackgroundDrawable(mReactBackgroundDrawable); - } else { - LayerDrawable layerDrawable = new LayerDrawable( - new Drawable[]{mReactBackgroundDrawable, backgroundDrawable}); - super.setBackgroundDrawable(layerDrawable); - } - } - return mReactBackgroundDrawable; - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return null; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - - } - - - public void setOnEndEditingListener(boolean onEndEditingLIstener) { - if (onEndEditingLIstener) { - setOnEditorActionListener(this); - } else { - setOnEditorActionListener(null); - } - } - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if ((actionId & EditorInfo.IME_MASK_ACTION) > 0 || actionId == EditorInfo.IME_NULL) { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushString("text", getText().toString()); - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), "onEndEditing", hippyMap); - } - return false; - } - - public void setBlurOrOnFocus(boolean blur) { - if (blur) { - setOnFocusChangeListener(this); - } else { - setOnFocusChangeListener(null); - } - } - - @Override - public void onFocusChange(View v, boolean hasFocus) { - - HippyMap hippyMap = new HippyMap(); - hippyMap.pushString("text", getText().toString()); - if (hasFocus) { - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), "onFocus", hippyMap); - } else { - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), "onBlur", hippyMap); - // harryguo: 屏蔽这里的onEndEditing事件。理由:失去焦点时,就只发onBlur就够了。onEndEditing不可再发,否则和那个地方(哪个地方?键盘回车或点击软键盘send、search、next...时的)的onEditorAction重复 - // mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class).receiveUIComponentEvent(getId(), "onEndEditing", hippyMap); - } - } - - - @Override - protected void onSelectionChanged(int selStart, int selEnd) { - super.onSelectionChanged(selStart, selEnd); - if (mHasSetOnSelectListener) { - HippyMap selection = new HippyMap(); - selection.pushInt("start", selStart); - selection.pushInt("end", selEnd); - HippyMap hippyMap = new HippyMap(); - hippyMap.pushMap("selection", selection); - mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) - .receiveUIComponentEvent(getId(), "onSelectionChange", hippyMap); - } - } - - public HippyMap jsGetValue() { - HippyMap hippyMap = new HippyMap(); - hippyMap.pushString("text", getText().toString()); - return hippyMap; -// mHippyContext.getModuleManager().getJavaScriptModule(EventDispatcher.class) -// .receiveUIComponentEvent(getId(), "getValue", hippyMap); - } - - public boolean bUserSetValue = false; - - public void jsSetValue(String value, int pos) { - bUserSetValue = true; - setText(value); - if (value != null) { - if (pos < 0) { - pos = value.length(); - } - if (pos >= value.length()) { - pos = value.length(); - } - setSelection(pos); - } - bUserSetValue = false; - } - - public void setOnSelectListener(boolean change) { - mHasSetOnSelectListener = change; - } - - @SuppressWarnings("JavaReflectionMemberAccess") - public void setCursorColor(int color) { - try { - Field field = TextView.class.getDeclaredField("mCursorDrawableRes"); - field.setAccessible(true); - int drawableResId = field.getInt(this); - field = TextView.class.getDeclaredField("mEditor"); - field.setAccessible(true); - Object editor = field.get(this); - Drawable drawable = null; - final int version = Build.VERSION.SDK_INT; - if (version >= 21) { - drawable = this.getContext().getDrawable(drawableResId); - } else if (version >= 16) { - drawable = this.getContext().getResources().getDrawable(drawableResId); - } - if (drawable == null) { - return; - } - drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); - assert editor != null; - Class editorClass = editor - .getClass(); //有的ROM自己复写了,Editor类,所以之类里面没有mDrawableForCursor,这里需要遍历 - while (editorClass != null) { - try { - if (version >= 28) { - field = editorClass.getDeclaredField("mDrawableForCursor");//mCursorDrawable - field.setAccessible(true); - field.set(editor, drawable); - } else { - Drawable[] drawables = {drawable, drawable}; - field = editorClass.getDeclaredField("mCursorDrawable");//mCursorDrawable - field.setAccessible(true); - field.set(editor, drawables); - } - break; - } catch (Throwable e) { - LogUtils.d("HippyTextInput", "setCursorColor: " + e.getMessage()); - } - editorClass = editorClass.getSuperclass(); //继续往上反射父亲 - } - } catch (Throwable e) { - LogUtils.d("HippyTextInput", "setCursorColor: " + e.getMessage()); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/HippyTextInputController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/HippyTextInputController.java deleted file mode 100644 index 7aff62319cf..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/HippyTextInputController.java +++ /dev/null @@ -1,528 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.textinput; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.Typeface; -import android.os.Build; -import android.os.Looper; -import android.os.MessageQueue; -import android.text.Editable; -import android.text.InputFilter; -import android.text.InputType; -import android.text.TextUtils; -import android.text.method.PasswordTransformationMethod; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.inputmethod.EditorInfo; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.dom.node.StyleNode; -import com.tencent.mtt.hippy.dom.node.TextExtra; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; - -import java.util.LinkedList; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyTextInputController.CLASS_NAME) -public class HippyTextInputController extends HippyViewController { - - public static final String CLASS_NAME = "TextInput"; - private static final String TAG = "HippyTextInputControlle"; - - private static final int INPUT_TYPE_KEYBOARD_NUMBERED = - InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL - | InputType.TYPE_NUMBER_FLAG_SIGNED; - - private static final String KEYBOARD_TYPE_EMAIL_ADDRESS = "email"; - private static final String KEYBOARD_TYPE_NUMERIC = "numeric"; - private static final String KEYBOARD_TYPE_PHONE_PAD = "phone-pad"; - private static final String KEYBOARD_TYPE_PASS_WORD = "password"; - - private static final String CLEAR_FUNCTION = "clear"; - public static final String COMMAND_FOCUS = "focusTextInput"; - public static final String COMMAND_BLUR = "blurTextInput"; - public static final String COMMAND_getValue = "getValue"; - public static final String COMMAND_setValue = "setValue"; - public static final String COMMAND_KEYBOARD_DISMISS = "dissmiss"; - - @Override - protected View createViewImpl(Context context) { - return new HippyTextInput(context); - } - - @Override - protected StyleNode createNode(boolean isVirtual) { - return new TextInputNode(isVirtual); - } - - @Override - protected void updateExtra(View view, Object object) { - super.updateExtra(view, object); - - if (object instanceof TextExtra) { - TextExtra textExtra = (TextExtra) object; - HippyTextInput hippyTextInput = (HippyTextInput) view; - hippyTextInput.setPadding((int) Math.ceil(textExtra.mLeftPadding), - (int) Math.ceil(textExtra.mTopPadding), - (int) Math.ceil(textExtra.mRightPadding), (int) Math.ceil(textExtra.mBottomPadding)); - } - } - - @HippyControllerProps(name = NodeProps.FONT_SIZE, defaultType = HippyControllerProps.NUMBER, defaultNumber = 14) - public void setFontSize(HippyTextInput hippyTextInput, float fontSize) { - hippyTextInput - .setTextSize(TypedValue.COMPLEX_UNIT_PX, (int) Math.ceil(PixelUtil.dp2px(fontSize))); - } - - @HippyControllerProps(name = "defaultValue", defaultType = HippyControllerProps.STRING) - public void setDefaultValue(HippyTextInput hippyTextInput, String defaultValue) { - String strOld = hippyTextInput.getText().toString(); - if (!TextUtils.equals(strOld, defaultValue)) { - hippyTextInput.setText(defaultValue); - if (!TextUtils.isEmpty(defaultValue)) { - hippyTextInput.setSelection(defaultValue.length()); - } - } - } - - @HippyControllerProps(name = "validator", defaultType = HippyControllerProps.STRING) - public void setValidator(HippyTextInput hippyTextInput, String strValidator) { - hippyTextInput.setValidator(strValidator); - } - - @HippyControllerProps(name = "editable", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void setEditable(HippyTextInput hippyTextInput, boolean editable) { - hippyTextInput.setEnabled(editable); - } - - /** - * 设置输入光标颜色 - **///RN 语法 caret-color - @HippyControllerProps(name = "caret-color", defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setCaretColor(HippyTextInput hippyTextInput, int cursorColor) { - hippyTextInput.setCursorColor(cursorColor); - } - - /** - * 设置输入光标颜色 - **/ - //For Vue.vue的前端语法,会把caret-color转化成caretColor - @HippyControllerProps(name = "caretColor", defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setCaretColorAlias(HippyTextInput hippyTextInput, int cursorColor) { - hippyTextInput.setCursorColor(cursorColor); - } - - @HippyControllerProps(name = "multiline", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void multiLine(HippyTextInput hippyTextInput, boolean multiline) { - int inputType = hippyTextInput.getInputType(); - if (multiline) { - inputType = inputType | InputType.TYPE_TEXT_FLAG_MULTI_LINE; - } else { - inputType &= ~InputType.TYPE_TEXT_FLAG_MULTI_LINE; - } - hippyTextInput.setInputType(inputType); - if (multiline) { - hippyTextInput.setGravityVertical(Gravity.TOP); - } - } - - @HippyControllerProps(name = "returnKeyType") - public void setReturnKeyType(HippyTextInput view, String returnKeyType) { - - int returnKeyFlag = EditorInfo.IME_ACTION_DONE; - if (returnKeyType != null) { - switch (returnKeyType) { - case "go": - returnKeyFlag = EditorInfo.IME_ACTION_GO; - break; - case "next": - returnKeyFlag = EditorInfo.IME_ACTION_NEXT; - view.setSingleLine(true); - break; - case "none": - returnKeyFlag = EditorInfo.IME_ACTION_NONE; - break; - case "previous": - returnKeyFlag = EditorInfo.IME_ACTION_PREVIOUS; - view.setSingleLine(true); - break; - case "search": - returnKeyFlag = EditorInfo.IME_ACTION_SEARCH; - view.setSingleLine(true); - break; - case "send": - returnKeyFlag = EditorInfo.IME_ACTION_SEND; - view.setSingleLine(true); - break; - case "done": - returnKeyFlag = EditorInfo.IME_ACTION_DONE; - view.setSingleLine(true); - break; - } - } - view.setImeOptions(returnKeyFlag | EditorInfo.IME_FLAG_NO_FULLSCREEN); - } - - @HippyControllerProps(name = "keyboardType", defaultType = HippyControllerProps.STRING) - public void setKeyboardType(HippyTextInput hippyTextInput, String keyboardType) { - int flagsToSet = InputType.TYPE_CLASS_TEXT; - if (KEYBOARD_TYPE_NUMERIC.equalsIgnoreCase(keyboardType)) { - flagsToSet = INPUT_TYPE_KEYBOARD_NUMBERED; - } else if (KEYBOARD_TYPE_EMAIL_ADDRESS.equalsIgnoreCase(keyboardType)) { - flagsToSet = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_CLASS_TEXT; - } else if (KEYBOARD_TYPE_PHONE_PAD.equalsIgnoreCase(keyboardType)) { - flagsToSet = InputType.TYPE_CLASS_PHONE; - } else if (KEYBOARD_TYPE_PASS_WORD.equalsIgnoreCase(keyboardType)) { - flagsToSet = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; - hippyTextInput.setTransformationMethod(PasswordTransformationMethod.getInstance()); - } - - hippyTextInput.setInputType(flagsToSet); - } - - private static int parseFontWeight(String fontWeightString) { - // This should be much faster than using regex to verify input and Integer.parseInt - return fontWeightString.length() == 3 && fontWeightString.endsWith("00") - && fontWeightString.charAt(0) <= '9' - && fontWeightString.charAt(0) >= '1' ? 100 * (fontWeightString.charAt(0) - '0') : -1; - } - - @HippyControllerProps(name = NodeProps.FONT_STYLE, defaultType = HippyControllerProps.STRING, defaultString = "normal") - public void setFontStyle(HippyTextInput view, String fontStyleString) { - if (TextUtils.isEmpty(fontStyleString)) { - return; - } - int fontStyle = -1; - if ("italic".equals(fontStyleString)) { - fontStyle = Typeface.ITALIC; - } else if ("normal".equals(fontStyleString)) { - fontStyle = Typeface.NORMAL; - } - - Typeface currentTypeface = view.getTypeface(); - if (currentTypeface == null) { - currentTypeface = Typeface.DEFAULT; - } - if (fontStyle != currentTypeface.getStyle()) { - view.setTypeface(currentTypeface, fontStyle); - } - } - - @HippyControllerProps(name = NodeProps.FONT_WEIGHT, defaultType = HippyControllerProps.STRING, defaultString = "normal") - public void setFontWeight(HippyTextInput view, String fontWeightString) { - int fontWeightNumeric = fontWeightString != null ? parseFontWeight(fontWeightString) : -1; - int fontWeight = -1; - if (fontWeightNumeric >= 500 || "bold".equals(fontWeightString)) { - fontWeight = Typeface.BOLD; - } else //noinspection ConstantConditions - if ("normal".equals(fontWeightString) || (fontWeightNumeric != -1 - && fontWeightNumeric < 500)) { - fontWeight = Typeface.NORMAL; - } - Typeface currentTypeface = view.getTypeface(); - if (currentTypeface == null) { - currentTypeface = Typeface.DEFAULT; - } - if (fontWeight != currentTypeface.getStyle()) { - view.setTypeface(currentTypeface, fontWeight); - } - } - - @HippyControllerProps(name = NodeProps.FONT_FAMILY, defaultType = HippyControllerProps.STRING, defaultString = "normal") - public void setFontFamily(HippyTextInput view, String fontFamily) { - if (TextUtils.isEmpty(fontFamily)) { - return; - } - int style = Typeface.NORMAL; - if (view.getTypeface() != null) { - style = view.getTypeface().getStyle(); - } - Typeface newTypeface = Typeface.create(fontFamily, style); - view.setTypeface(newTypeface); - } - - private static final InputFilter[] EMPTY_FILTERS = new InputFilter[0]; - - @HippyControllerProps(name = "maxLength", defaultType = HippyControllerProps.NUMBER, defaultNumber = Integer.MAX_VALUE) - public void maxLength(HippyTextInput view, int maxLength) { - InputFilter[] currentFilters = view.getFilters(); - InputFilter[] newFilters = EMPTY_FILTERS; - - if (maxLength == -1) { - if (currentFilters.length > 0) { - LinkedList list = new LinkedList<>(); - for (InputFilter currentFilter : currentFilters) { - if (!(currentFilter instanceof InputFilter.LengthFilter)) { - list.add(currentFilter); - } - } - if (!list.isEmpty()) { - //noinspection ToArrayCallWithZeroLengthArrayArgument - newFilters = list.toArray(new InputFilter[list.size()]); - } - } - } else { - if (currentFilters.length > 0) { - newFilters = currentFilters; - boolean replaced = false; - for (int i = 0; i < currentFilters.length; i++) { - if (currentFilters[i] instanceof InputFilter.LengthFilter) { - currentFilters[i] = new InputFilter.LengthFilter(maxLength); - replaced = true; - } - } - if (!replaced) { - newFilters = new InputFilter[currentFilters.length + 1]; - System.arraycopy(currentFilters, 0, newFilters, 0, currentFilters.length); - newFilters[currentFilters.length] = new InputFilter.LengthFilter(maxLength); - } - } else { - newFilters = new InputFilter[1]; - newFilters[0] = new InputFilter.LengthFilter(maxLength); - } - } - - view.setFilters(newFilters); - } - - @HippyControllerProps(name = "onSelectionChange", defaultType = "boolean") - public void setOnSelectionChange(HippyTextInput hippyTextInput, boolean change) { - hippyTextInput.setOnSelectListener(change); - } - - @HippyControllerProps(name = "letterSpacing", defaultType = HippyControllerProps.NUMBER, defaultNumber = -1) - public void letterSpacing(HippyTextInput view, float letterSpacing) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && letterSpacing != -1) { - view.setLetterSpacing(PixelUtil.dp2px(letterSpacing)); - } - } - - @HippyControllerProps(name = "value", defaultType = HippyControllerProps.STRING) - public void value(HippyTextInput view, String value) { - int selectionStart = view.getSelectionStart(); - int selectionEnd = view.getSelectionEnd(); - LogUtils - .d(TAG, String.format("setText: selectionStart:%s sEnd:%s", selectionStart, selectionEnd)); - Editable editText = view.getEditableText(); - if (editText == null) { - return; - } - String oldValue = editText.toString(); - String sub1 = oldValue.substring(0, selectionStart); - String sub2 = oldValue.substring(selectionEnd); - LogUtils.d(TAG, String.format("setText: sub1:[%s] sub2:[%s]", sub1, sub2)); - - if (selectionStart == selectionEnd && value.length() > oldValue.length() && value - .startsWith(sub1) && value.endsWith(sub2)) { - // 未选中状态 && insert - String insertStr = value.substring(selectionStart, value.length() - sub2.length()); - LogUtils.d(TAG, String.format("setText: InsertStr: [%s]", insertStr)); - editText.insert(selectionStart, insertStr); - } else if (selectionStart < selectionEnd && value.startsWith(sub1) && value.endsWith(sub2)) { - // 选中状态 && replace选中部分 - String replaceStr = value.substring(selectionStart, value.length() - sub2.length()); - LogUtils.d(TAG, String.format("setText: ReplaceStr: [%s]", replaceStr)); - editText.replace(selectionStart, selectionEnd, replaceStr); - } else if (selectionStart == selectionEnd && value.length() < oldValue.length() && value - .endsWith(sub2) - && value - .startsWith(sub1.substring(0, selectionStart - (oldValue.length() - value.length())))) { - // 未选中状态 && delete - int delLen = oldValue.length() - value.length(); - editText.delete(selectionEnd - delLen, selectionEnd); - } else { - editText.replace(0, editText.length(), value); - } - } - - - @HippyControllerProps(name = "placeholder", defaultType = HippyControllerProps.STRING) - public void placeHolder(HippyTextInput view, String placeholder) { - view.setHint(placeholder); - } - - @HippyControllerProps(name = "placeholderTextColor", defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.GRAY) - public void setTextHitColor(HippyTextInput input, int color) { - input.setHintTextColor(color); - } - - @HippyControllerProps(name = "numberOfLines", defaultType = HippyControllerProps.NUMBER, defaultNumber = Integer.MAX_VALUE) - public void setMaxLines(HippyTextInput input, int numberOfLine) { - input.setMaxLines(numberOfLine); - } - - - @HippyControllerProps(name = "underlineColorAndroid", defaultType = HippyControllerProps.NUMBER, defaultNumber = Color.TRANSPARENT) - public void setUnderlineColor(HippyTextInput view, Integer underlineColor) { - if (underlineColor == null) { - view.getBackground().clearColorFilter(); - } else { - view.getBackground().setColorFilter(underlineColor, PorterDuff.Mode.SRC_IN); - } - } - - @HippyControllerProps(name = "onChangeText", defaultType = HippyControllerProps.BOOLEAN) - public void setOnChangeText(HippyTextInput hippyTextInput, boolean change) { - hippyTextInput.setOnChangeListener(change); - } - - @HippyControllerProps(name = "onEndEditing", defaultType = HippyControllerProps.BOOLEAN) - public void setEndEditing(HippyTextInput hippyTextInput, boolean change) { - hippyTextInput.setOnEndEditingListener(change); - } - - @HippyControllerProps(name = "onFocus", defaultType = HippyControllerProps.BOOLEAN) - public void setOnFocus(HippyTextInput hippyTextInput, boolean change) { - hippyTextInput.setBlurOrOnFocus(change); - } - - @HippyControllerProps(name = "onBlur", defaultType = HippyControllerProps.BOOLEAN) - public void setBlur(HippyTextInput hippyTextInput, boolean change) { - hippyTextInput.setBlurOrOnFocus(change); - } - - @HippyControllerProps(name = "onContentSizeChange", defaultType = HippyControllerProps.BOOLEAN) - public void setOnContentSizeChange(HippyTextInput hippyTextInput, boolean contentSizeChange) { - hippyTextInput.setOnContentSizeChange(contentSizeChange); - } - - @HippyControllerProps(name = NodeProps.COLOR, defaultType = HippyControllerProps.NUMBER) - public void setColor(HippyTextInput hippyTextInput, int change) { - hippyTextInput.setTextColor(change); - } - - - @HippyControllerProps(name = NodeProps.TEXT_ALIGN, defaultType = HippyControllerProps.STRING) - public void setTextAlign(HippyTextInput view, String textAlign) { - if (textAlign == null || "auto".equals(textAlign)) { - view.setGravityHorizontal(Gravity.NO_GRAVITY); - } else if ("left".equals(textAlign)) { - view.setGravityHorizontal(Gravity.LEFT); - } else if ("right".equals(textAlign)) { - view.setGravityHorizontal(Gravity.RIGHT); - } else if ("center".equals(textAlign)) { - view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL); - } else if ("justify".equals(textAlign)) { - view.setGravityHorizontal(Gravity.LEFT); - } - } - - @HippyControllerProps(name = NodeProps.TEXT_ALIGN_VERTICAL) - public void setTextAlignVertical(HippyTextInput view, String textAlignVertical) { - if (textAlignVertical == null || "auto".equals(textAlignVertical)) { - view.setGravityVertical(Gravity.NO_GRAVITY); - } else if ("top".equals(textAlignVertical)) { - view.setGravityVertical(Gravity.TOP); - } else if ("bottom".equals(textAlignVertical)) { - view.setGravityVertical(Gravity.BOTTOM); - } else if ("center".equals(textAlignVertical)) { - view.setGravityVertical(Gravity.CENTER_VERTICAL); - } - - } - - @Override - public void dispatchFunction(final HippyTextInput view, String functionName, HippyArray params, - Promise promise) { - if (COMMAND_getValue.equals(functionName)) { - if (promise != null) { - HippyMap resultMap = view.jsGetValue(); - promise.resolve(resultMap); - } - } - } - - @Override - public void dispatchFunction(final HippyTextInput view, String functionName, - final HippyArray var) { - switch (functionName) { - case COMMAND_setValue: - if (var != null && var.getString(0) != null) { - int pos = var.getInt(1); - if (var.size() < 2) { - pos = var.getString(0).length(); - } - view.jsSetValue(var.getString(0), pos); - } - break; - case CLEAR_FUNCTION: - view.jsSetValue("", 0); - break; - case COMMAND_FOCUS: - view.setFocusableInTouchMode(true); - //noinspection AccessStaticViaInstance - Looper.getMainLooper().myQueue().addIdleHandler(new MessageQueue.IdleHandler() { - @Override - public boolean queueIdle() { - boolean result = view.requestFocusFromTouch(); - LogUtils.d("InputText", " requestFocusFromTouch result:" + result); - if (!result) { - result = view.requestFocus(); - LogUtils.d("InputText", "requestFocus result:" + result); - } - if (var.getObject(0) == null || var.getBoolean(0)) { - view.showInputMethodManager(); - } - return false; - } - }); - break; - case COMMAND_KEYBOARD_DISMISS: - view.hideInputMethod(); - break; - case COMMAND_BLUR: - // view.setFocusableInTouchMode(false); - - //find the HippyRootView - ViewParent viewParent = view.getParent(); - while (viewParent != null) { - if (viewParent instanceof HippyRootView) { - break; - } - viewParent = viewParent.getParent(); - } - int oldFoucusAbaility = 0; - //noinspection ConstantConditions - if (viewParent instanceof HippyRootView) { - oldFoucusAbaility = ((ViewGroup) viewParent) - .getDescendantFocusability(); //Get the current value - ((ViewGroup) viewParent) - .setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);//Block the fouse. - } - view.hideInputMethod(); - view.clearFocus(); - //noinspection ConstantConditions - if (viewParent instanceof HippyRootView) { - ((ViewGroup) viewParent).setDescendantFocusability(oldFoucusAbaility); - } - break; - } - super.dispatchFunction(view, functionName, var); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/TextInputNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/TextInputNode.java deleted file mode 100644 index 9feb904951f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/textinput/TextInputNode.java +++ /dev/null @@ -1,115 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.textinput; - -import android.util.TypedValue; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; - -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.flex.FlexMeasureMode; -import com.tencent.mtt.hippy.dom.flex.FlexNodeAPI; -import com.tencent.mtt.hippy.dom.flex.FlexOutput; -import com.tencent.mtt.hippy.dom.flex.FlexSpacing; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.dom.node.TextNode; -import com.tencent.mtt.hippy.utils.ContextHolder; -import com.tencent.mtt.hippy.utils.PixelUtil; - -@SuppressWarnings({"deprecation", "unused"}) -public class TextInputNode extends TextNode implements FlexNodeAPI.MeasureFunction { - - private EditText mEditText; - private float[] mComputedPadding; - - - public TextInputNode(boolean isvurtla) { - super(isvurtla); - setMeasureFunction(this); - } - - @Override - public void updateProps(HippyMap props) { - - } - - @Override - public void layoutBefore(HippyEngineContext context) { - - if (mEditText == null) { - mEditText = new EditText(ContextHolder.getAppContext()); - mEditText.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - - setDefaultPadding(FlexSpacing.START, mEditText.getPaddingLeft()); - setDefaultPadding(FlexSpacing.TOP, mEditText.getPaddingTop()); - setDefaultPadding(FlexSpacing.END, mEditText.getPaddingRight()); - setDefaultPadding(FlexSpacing.BOTTOM, mEditText.getPaddingBottom()); - mComputedPadding = new float[]{getPadding(FlexSpacing.START), getPadding(FlexSpacing.TOP), - getPadding(FlexSpacing.END), getPadding(FlexSpacing.BOTTOM),}; - } - } - - @Override - public void layoutAfter(HippyEngineContext context) { - // 不能删 - } - - private int getMeasureSpec(float size, FlexMeasureMode mode) { - if (mode == FlexMeasureMode.EXACTLY) { - return View.MeasureSpec.makeMeasureSpec((int) size, View.MeasureSpec.EXACTLY); - } else if (mode == FlexMeasureMode.AT_MOST) { - return View.MeasureSpec.makeMeasureSpec((int) size, View.MeasureSpec.AT_MOST); - } else { - return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - } - } - - @Override - public void setPadding(int spacingType, float padding) { - super.setPadding(spacingType, padding); - mComputedPadding = new float[]{ - getPadding(FlexSpacing.START), - getPadding(FlexSpacing.TOP), - getPadding(FlexSpacing.END), - getPadding(FlexSpacing.BOTTOM), - }; - markUpdated(); - } - - @SuppressWarnings("rawtypes") - @Override - public long measure(FlexNodeAPI node, float width, FlexMeasureMode widthMode, float height, - FlexMeasureMode heightMode) { - mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, - mFontSize == UNSET ? (int) Math.ceil(PixelUtil.dp2px(NodeProps.FONT_SIZE_SP)) : mFontSize); - mComputedPadding = new float[]{getPadding(FlexSpacing.START), getPadding(FlexSpacing.TOP), - getPadding(FlexSpacing.END), getPadding(FlexSpacing.BOTTOM),}; - mEditText.setPadding((int) Math.floor(getPadding(FlexSpacing.START)), - (int) Math.floor(getPadding(FlexSpacing.TOP)), - (int) Math.floor(getPadding(FlexSpacing.END)), - (int) Math.floor(getPadding(FlexSpacing.BOTTOM))); - - if (mNumberOfLines != UNSET) { - mEditText.setLines(mNumberOfLines); - } - mEditText.measure(getMeasureSpec(width, widthMode), getMeasureSpec(height, heightMode)); - - return FlexOutput.make(mEditText.getMeasuredWidth(), mEditText.getMeasuredHeight()); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroup.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroup.java deleted file mode 100644 index 34cd33a4fa5..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroup.java +++ /dev/null @@ -1,323 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.view; - -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.uimanager.IHippyZIndexViewGroup; -import com.tencent.mtt.hippy.uimanager.ViewGroupDrawingOrderHelper; -import com.tencent.mtt.hippy.views.image.HippyImageView; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Path; -import android.graphics.RectF; -import android.os.Build; -import android.text.TextUtils; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; - -@SuppressWarnings({"unused"}) -public class HippyViewGroup extends HippyImageView implements IHippyZIndexViewGroup { - - private static final int LAYER_TYPE_NOT_SET = -1; - private final ViewGroupDrawingOrderHelper mDrawingOrderHelper; - float mDownX = 0; - float mDownY = 0; - boolean isHandlePullUp = false; - // private CommonBackgroundDrawable mBGDrawable; - // private NativeGestureDispatcher mGestureDispatcher; - private String mOverflow; - private Path mOverflowPath; - private RectF mOverflowRect; - private int mOldLayerType; - private ViewConfiguration mViewConfiguration; - - public HippyViewGroup(Context context) { - super(context); - mDrawingOrderHelper = new ViewGroupDrawingOrderHelper(this); - mOldLayerType = LAYER_TYPE_NOT_SET; - setScaleType(ScaleType.ORIGIN); - } - - // @Override - // protected void onLayout(boolean changed, int l, int t, int r, int b) - // { - // - // } - - // @Override - // public void requestLayout() - // { - // //super.requestLayout(); - // } - - @SuppressWarnings("SuspiciousNameCombination") - @Override - protected void dispatchDraw(Canvas canvas) { - if (mOverflow != null) { - switch (mOverflow) { - case "visible": - if (mOverflowPath != null) { - mOverflowPath.rewind(); - } - restoreLayerType(); - break; - case "hidden": - if (mBGDrawable != null) { - float left = 0f; - float top = 0f; - float right = getWidth(); - float bottom = getHeight(); - float borderWidth; - if (mBGDrawable.getBorderWidthArray() != null - && mBGDrawable.getBorderWidthArray()[0] != 0f) { - borderWidth = mBGDrawable.getBorderWidthArray()[0]; - left += borderWidth; - top += borderWidth; - right -= borderWidth; - bottom -= borderWidth; - } - float radius = - mBGDrawable.getBorderRadiusArray() != null ? mBGDrawable.getBorderRadiusArray()[0] - : 0f; - - if (radius > 0f) { - if (mOverflowPath == null) { - mOverflowPath = new Path(); - } - mOverflowPath.rewind(); - if (mOverflowRect == null) { - mOverflowRect = new RectF(); - } - mOverflowRect.set(left, top, right, bottom); - mOverflowPath.addRoundRect(mOverflowRect, radius, radius, Path.Direction.CW); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - if (mOldLayerType == LAYER_TYPE_NOT_SET) { - mOldLayerType = this.getLayerType(); - } - this.setLayerType(LAYER_TYPE_SOFTWARE, null); - } - try { - canvas.clipPath(mOverflowPath); - } catch (Throwable throwable) { - restoreLayerType(); - } - } - } - break; - default: - restoreLayerType(); - break; - } - } - super.dispatchDraw(canvas); - // String testString = "View ID:" + this.getId(); - // Paint mPaint = new Paint(); - // mPaint.setStrokeWidth(3); - // mPaint.setTextSize(40); - // mPaint.setColor(Color.RED); - // mPaint.setTextAlign(Paint.Align.LEFT); - // Rect bounds = new Rect(); - // mPaint.getTextBounds(testString, 0, testString.length(), bounds); - // Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); - // int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top; - // canvas.drawText(testString, getMeasuredWidth() / 2 - bounds.width() / 2, baseline, mPaint); - } - - private void restoreLayerType() { - if (mOldLayerType > LAYER_TYPE_NOT_SET) { - this.setLayerType(mOldLayerType, null); - } - } - - // public void setBorderRadius(float radius, int position) - // { - // getBackGround().setBorderRadius(radius, position); - // } - // - // public void setBorderWidth(float width, int position) - // { - // getBackGround().setBorderWidth(width, position); - // } - // - // public void setBorderColor(int color, int position) - // { - // getBackGround().setBorderColor(color, position); - // } - // - // private CommonBackgroundDrawable getBackGround() - // { - // if (mBGDrawable == null) - // { - // mBGDrawable = new CommonBackgroundDrawable(); - // Drawable currBGDrawable = getBackground(); - // super.setBackgroundDrawable(null); - // if (currBGDrawable == null) - // { - // super.setBackgroundDrawable(mBGDrawable); - // } - // else - // { - // LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] { mBGDrawable, currBGDrawable }); - // super.setBackgroundDrawable(layerDrawable); - // } - // } - // return mBGDrawable; - // } - - public void setOverflow(String overflow) { - mOverflow = overflow; - //robinsli Android 支持 overflow: visible,超出容器之外的属性节点也可以正常显示 - if (!TextUtils.isEmpty(mOverflow)) { - switch (mOverflow) { - case "visible": - setClipChildren(false); //可以超出父亲区域 - break; - case "hidden": { - setClipChildren(true); //默认值是false - break; - } - } - } - invalidate(); - } - - // @Override - // public void setBackgroundColor(int color) - // { - // getBackGround().setBackgroundColor(color); - // } - - // @Override - // public boolean onTouchEvent(MotionEvent event) - // { - // boolean result = super.onTouchEvent(event); - // if (mGestureDispatcher != null) - // { - // result |= mGestureDispatcher.handleTouchEvent(event); - // } - // return result; - // } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - int action = ev.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_DOWN) { - mDownX = ev.getX(); - mDownY = ev.getY(); - isHandlePullUp = false; - } - - boolean result = super.onInterceptTouchEvent(ev); - - if (mGestureDispatcher != null) { - result |= mGestureDispatcher.needHandle(NodeProps.ON_INTERCEPT_TOUCH_EVENT); - } - - if (!result && mGestureDispatcher != null && mGestureDispatcher - .needHandle(NodeProps.ON_INTERCEPT_PULL_UP_EVENT)) { - //noinspection SwitchStatementWithTooFewBranches - switch (action) { - case MotionEvent.ACTION_MOVE: { - if (isHandlePullUp) { - break; - } - if (mViewConfiguration == null) { - //noinspection deprecation - mViewConfiguration = new ViewConfiguration(); - } - float dx = ev.getX() - mDownX; - float dy = ev.getY() - mDownY; - if (dy < 0 && Math.abs(dx) < Math.abs(dy) && Math.abs(dy) > mViewConfiguration - .getScaledTouchSlop()) { - mGestureDispatcher.handle(NodeProps.ON_TOUCH_DOWN, mDownX, mDownY); - isHandlePullUp = true; - } - break; - } - } - result = isHandlePullUp; - } - return result; - } - - // @Override - // public NativeGestureDispatcher getGestureDispatcher() - // { - // return mGestureDispatcher; - // } - - // @Override - // public void setGestureDispatcher(NativeGestureDispatcher dispatcher) - // { - // mGestureDispatcher = dispatcher; - // } - - @Override - protected int getChildDrawingOrder(int childCount, int index) { - return mDrawingOrderHelper.getChildDrawingOrder(childCount, index); - } - - @Override - public int getZIndexMappedChildIndex(int index) { - if (mDrawingOrderHelper.shouldEnableCustomDrawingOrder()) { - return mDrawingOrderHelper.getChildDrawingOrder(getChildCount(), index); - } else { - return index; - } - } - - @Override - public void updateDrawingOrder() { - mDrawingOrderHelper.update(); - setChildrenDrawingOrderEnabled(mDrawingOrderHelper.shouldEnableCustomDrawingOrder()); - invalidate(); - } - - @Override - public void addView(View child, int index) { - super.addView(child, index); - mDrawingOrderHelper.handleAddView(child); - setChildrenDrawingOrderEnabled(mDrawingOrderHelper.shouldEnableCustomDrawingOrder()); - } - - @Override - public void removeView(View view) { - super.removeView(view); - mDrawingOrderHelper.handleRemoveView(view); - setChildrenDrawingOrderEnabled(mDrawingOrderHelper.shouldEnableCustomDrawingOrder()); - } - - @Override - public void resetProps() { - // HippyViewController.resetTransform(this); - - HippyViewGroupController.removeViewZIndex(this); - - // mBGDrawable = null; - // super.setBackgroundDrawable(null); - mOverflow = null; - setClipChildren(true); //默认值是false - // setAlpha(1.0f); - } - - // @Override - // public void clear() - // { - // - // } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroupController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroupController.java deleted file mode 100644 index e14a1868d7b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroupController.java +++ /dev/null @@ -1,99 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.view; - -import android.content.Context; -import android.view.View; - -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.uimanager.HippyGroupController; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.image.HippyImageView; - -import java.util.WeakHashMap; - -@SuppressWarnings({"unused"}) -@HippyController(name = HippyViewGroupController.CLASS_NAME) -public class HippyViewGroupController extends HippyGroupController { - - public static final String CLASS_NAME = "View"; - - public static final WeakHashMap mZIndexHash = new WeakHashMap<>(); - - - public static void setViewZIndex(View view, int zIndex) { - mZIndexHash.put(view, zIndex); - } - - public static void removeViewZIndex(View view) { - mZIndexHash.remove(view); - } - - public static Integer getViewZIndex(View view) { - return mZIndexHash.get(view); - } - - @Override - protected View createViewImpl(Context context) { - return new HippyViewGroup(context); - } - - @HippyControllerProps(name = NodeProps.OVERFLOW, defaultType = HippyControllerProps.STRING, defaultString = "visible") - public void setOverflow(HippyViewGroup hippyViewGroup, String overflow) { - hippyViewGroup.setOverflow(overflow); - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_IMAGE, defaultType = HippyControllerProps.STRING) - public void setBackgroundImage(HippyViewGroup hippyViewGroup, String url) { - hippyViewGroup.setUrl(getInnerPath((HippyInstanceContext)hippyViewGroup.getContext(), url)); - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_SIZE, defaultType = HippyControllerProps.STRING, defaultString = "origin") - public void setBackgroundImageSize(HippyImageView hippyImageView, String resizeModeValue) { - if ("contain".equals(resizeModeValue)) { - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸 - // 这样图片完全被包裹在容器中,容器中可能留有空白 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_INSIDE); - } else if ("cover".equals(resizeModeValue)) { - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸 - // 这样图片完全覆盖甚至超出容器,容器中不留任何空白 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_CROP); - } else if ("center".equals(resizeModeValue)) { - // 居中不拉伸 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER); - } else if ("origin".equals(resizeModeValue)) { - // 不拉伸,居左上 - hippyImageView.setScaleType(HippyImageView.ScaleType.ORIGIN); - } else { - // stretch and other mode - // 拉伸图片且不维持宽高比,直到宽高都刚好填满容器 - hippyImageView.setScaleType(HippyImageView.ScaleType.FIT_XY); - } - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_POSITION_X, defaultType = HippyControllerProps.NUMBER) - public void setBackgroundImagePositionX(HippyViewGroup hippyViewGroup, int positionX) { - hippyViewGroup.setImagePositionX((int) PixelUtil.dp2px(positionX)); - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_POSITION_Y, defaultType = HippyControllerProps.NUMBER) - public void setBackgroundImagePositionY(HippyViewGroup hippyViewGroup, int positionY) { - hippyViewGroup.setImagePositionY((int) PixelUtil.dp2px(positionY)); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java deleted file mode 100644 index 9482321701f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java +++ /dev/null @@ -1,261 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.viewpager; - -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.utils.I18nUtil; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.supportui.views.viewpager.ViewPager; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.text.TextUtils; -import android.view.MotionEvent; -import android.view.View; - -@SuppressWarnings({"unused"}) -public class HippyViewPager extends ViewPager implements HippyViewBase { - - private static final String TAG = "HippyViewPager"; - - private final Runnable mMeasureAndLayout = new Runnable() { - @Override - public void run() { - measure(View.MeasureSpec.makeMeasureSpec(getWidth(), View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(getHeight(), View.MeasureSpec.EXACTLY)); - layout(getLeft(), getTop(), getRight(), getBottom()); - } - }; - - - private NativeGestureDispatcher mGestureDispatcher; - private boolean mFirstUpdateChild = true; - private final boolean mReNotifyOnAttach = false; - private ViewPagerPageChangeListener mPageListener; - private final Handler mHandler = new Handler(Looper.getMainLooper()); - private Promise mCallBackPromise; - - private void init(Context context) { - setCallPageChangedOnFirstLayout(true); - setEnableReLayoutOnAttachToWindow(false); - - mPageListener = new ViewPagerPageChangeListener(this); - setOnPageChangeListener(mPageListener); - setAdapter(createAdapter(context)); - setLeftDragOutSizeEnabled(false); - setRightDragOutSizeEnabled(false); - - if (I18nUtil.isRTL()) { - setRotationY(180f); - } - } - - @Override - public void onViewAdded(View child) { - if (I18nUtil.isRTL()) { - child.setRotationY(180f); - } - super.onViewAdded(child); - } - - public HippyViewPager(Context context, boolean isVertical) { - super(context, isVertical); - init(context); - } - - public HippyViewPager(Context context) { - super(context); - init(context); - } - - public void setCallBackPromise(Promise promise) { - mCallBackPromise = promise; - } - - public Promise getCallBackPromise() { - return mCallBackPromise; - } - - protected HippyViewPagerAdapter createAdapter(Context context) { - return new HippyViewPagerAdapter((HippyInstanceContext) context, this); - } - - public void setInitialPageIndex(int index) { - getAdapter().setInitPageIndex(index); - } - - - public void setChildCountAndUpdate(final int childCount) { - LogUtils.d(TAG, "doUpdateInternal: " + hashCode() + ", childCount=" + childCount); - if (mFirstUpdateChild) { - setFirstLayoutParameter(true); - mFirstUpdateChild = false; - } - getAdapter().setChildSize(childCount); - //getWindowToken() == null执行这个操作,onAttachToWindow就不需要了。 - getAdapter().notifyDataSetChanged(); - triggerRequestLayout(); - } - - protected void addViewToAdapter(HippyViewPagerItem view, int postion) { - HippyViewPagerAdapter adapter = getAdapter(); - if (adapter != null) { - adapter.addView(view, postion); - } - } - - protected int getAdapterViewSize() { - HippyViewPagerAdapter adapter = getAdapter(); - if (adapter != null) { - return adapter.getItemViewSize(); - } - return 0; - } - - protected void removeViewFromAdapter(HippyViewPagerItem view) { - HippyViewPagerAdapter adapter = getAdapter(); - if (adapter != null) { - adapter.removeView(view); - } - } - - public View getViewFromAdapter(int currentItem) { - HippyViewPagerAdapter adapter = getAdapter(); - if (adapter != null) { - return adapter.getViewAt(currentItem); - } - return null; - } - - @Override - public HippyViewPagerAdapter getAdapter() { - return (HippyViewPagerAdapter) super.getAdapter(); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (!isScrollEnabled()) { - return false; - } - - return super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (!isScrollEnabled()) { - return false; - } - - return super.onTouchEvent(ev); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - LogUtils.d(TAG, "onAttachedToWindow: " + hashCode() + ", childCount=" + getChildCount() - + ", repopulate=" + mNeedRepopulate - + ", renotifyOnAttach=" + mReNotifyOnAttach); - - /* - * hippy 在setChildCountAndUpdate打开,执行了 - * if (mReNotifyOnAttach) - * { - * getAdapter().notifyDataSetChanged(); - * mReNotifyOnAttach = false; - * } - */ - // 9.6在supportui已经把windowToken的检查过滤去掉了,所以这里应该关掉 - /* - * if (mNeedRepopulate) //这个是是在supportUI工程里面poplate的时候设置的。再没有上树的情况下 - * { - * mNeedRepopulate = false; - * triggerRequestLayout(); - * postInvalidate(); - * } - */ - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - LogUtils.d(TAG, "onDetachedFromWindow: " + hashCode() + ", childCount=" + getChildCount() - + ", repopulate=" + mNeedRepopulate - + ", renotifyOnAttach=" + mReNotifyOnAttach); - } - - public void switchToPage(int item, boolean animated) { - LogUtils.d(TAG, - "switchToPage: " + hashCode() + ", item=" + item + ", animated=" + animated); - if (getAdapter().getCount() == 0) // viewpager的children没有初始化好的时候,直接设置mInitialPageIndex - { - LogUtils.d(TAG, "switchToPage: getAdapter().getCount() == 0"); - } else { - if (getCurrentItem() != item) // 如果和当前位置一样,就不进行switch - { - if (isSettling()) { - // 如果仍然在滑动中,重置一下状态 - setScrollingCacheEnabled(false); - mScroller.abortAnimation(); - int oldX = getScrollX(); - int oldY = getScrollY(); - int x = mScroller.getCurrX(); - int y = mScroller.getCurrY(); - if (oldX != x || oldY != y) { - scrollTo(x, y); - } - setScrollState(SCROLL_STATE_IDLE); - } - setCurrentItem(item, animated); - } else if (!isFirstLayout()) { - mPageListener.onPageSelected(item); - } - } - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return mGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher nativeGestureDispatcher) { - mGestureDispatcher = nativeGestureDispatcher; - } - - public void triggerRequestLayout() { - mHandler.post(mMeasureAndLayout); - } - - public void setOverflow(String overflow) { - if (!TextUtils.isEmpty(overflow)) { - switch (overflow) { - case "visible": - setClipChildren(false); //可以超出父亲区域 - break; - case "hidden": { - setClipChildren(true); //默认值是false - break; - } - } - } - invalidate(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java deleted file mode 100644 index aedee6604cc..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java +++ /dev/null @@ -1,211 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.viewpager; - -import android.util.Log; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.dom.node.NodeProps; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.hippy.utils.PixelUtil; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; - - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyViewPagerController.CLASS_NAME) -public class HippyViewPagerController extends HippyViewController { - - public static final String CLASS_NAME = "ViewPager"; - - private static final String TAG = "HippyViewPagerController"; - - private static final String FUNC_SET_PAGE = "setPage"; - private static final String FUNC_SET_PAGE_WITHOUT_ANIM = "setPageWithoutAnimation"; - - private static final String FUNC_SET_INDEX = "setIndex"; - private static final String FUNC_NEXT_PAGE = "next"; - private static final String FUNC_PREV_PAGE = "prev"; - - @Override - protected View createViewImpl(Context context) { - return new HippyViewPager(context); - } - - @Override - protected View createViewImpl(Context context, HippyMap iniProps) { - boolean isVertical = false; - if (iniProps != null) { - if ((iniProps.containsKey("direction") && iniProps.getString("direction") - .equals("vertical")) - || iniProps.containsKey("vertical")) { - isVertical = true; - } - } - - return new HippyViewPager(context, isVertical); - } - - @Override - public View getChildAt(HippyViewPager hippyViewPager, int i) { - return hippyViewPager.getViewFromAdapter(i); - } - - @Override - public int getChildCount(HippyViewPager hippyViewPager) { - return hippyViewPager.getAdapter().getCount(); - } - - @Override - protected void addView(ViewGroup parentView, View view, int index) { - LogUtils.d(TAG, "addView: " + parentView.hashCode() + ", index=" + index); - if (parentView instanceof HippyViewPager && view instanceof HippyViewPagerItem) { - HippyViewPager hippyViewPager = (HippyViewPager) parentView; - hippyViewPager.addViewToAdapter((HippyViewPagerItem) view, index); - } else { - LogUtils.e(TAG, "add view got invalid params"); - } - } - - @Override - protected void deleteChild(ViewGroup parentView, View childView) { - LogUtils.d(TAG, "deleteChild: " + parentView.hashCode()); - if (parentView instanceof HippyViewPager && childView instanceof HippyViewPagerItem) { - ((HippyViewPager) parentView).removeViewFromAdapter((HippyViewPagerItem) childView); - } else { - LogUtils.e(TAG, "delete view got invalid params"); - } - } - - @Override - protected void onManageChildComplete(HippyViewPager viewPager) { - viewPager.setChildCountAndUpdate(viewPager.getAdapter().getItemViewSize()); - } - - @HippyControllerProps(name = "initialPage", defaultNumber = 0, defaultType = HippyControllerProps.NUMBER) - public void setInitialPage(HippyViewPager parent, int initialPage) { - parent.setInitialPageIndex(initialPage); - } - - @HippyControllerProps(name = "scrollEnabled", defaultBoolean = true, defaultType = HippyControllerProps.BOOLEAN) - public void setScrollEnabled(HippyViewPager viewPager, boolean value) { - viewPager.setScrollEnabled(value); - } - - @HippyControllerProps(name = "pageMargin", defaultNumber = 0, defaultType = HippyControllerProps.NUMBER) - public void setPageMargin(HippyViewPager pager, float margin) { - pager.setPageMargin((int) PixelUtil.dp2px(margin)); - } - - @HippyControllerProps(name = NodeProps.OVERFLOW, defaultType = HippyControllerProps.STRING, defaultString = "visible") - public void setOverflow(HippyViewPager pager, String overflow) { - pager.setOverflow(overflow); - } - - @Override - public void dispatchFunction(HippyViewPager view, String functionName, HippyArray var) { - if (view == null) { - return; - } - - int curr = view.getCurrentItem(); - - switch (functionName) { - case FUNC_SET_PAGE: - if (var != null) { - Object selected = var.get(0); - if (selected instanceof Number) { - view.switchToPage(((Number)selected).intValue(), true); - } - } - break; - case FUNC_SET_PAGE_WITHOUT_ANIM: - if (var != null) { - Object selected = var.get(0); - if (selected instanceof Number) { - view.switchToPage(((Number)selected).intValue(), false); - } - } - break; - case FUNC_SET_INDEX: - if (var != null && var.size() > 0) { - HippyMap paramsMap = var.getMap(0); - if (paramsMap != null && paramsMap.size() > 0 && paramsMap - .containsKey("index")) { - int index = paramsMap.getInt("index"); - boolean animated = !paramsMap.containsKey("animated") || paramsMap - .getBoolean("animated"); - view.switchToPage(index, animated); - } - } - break; - case FUNC_NEXT_PAGE: - int total = view.getAdapter().getCount(); - if (curr < total - 1) { - view.switchToPage(curr + 1, true); - } - break; - case FUNC_PREV_PAGE: - if (curr > 0) { - view.switchToPage(curr - 1, true); - } - break; - default: - break; - } - } - - @SuppressWarnings("SwitchStatementWithTooFewBranches") - @Override - public void dispatchFunction(HippyViewPager view, String functionName, HippyArray params, - Promise promise) { - if (view == null) { - return; - } - - switch (functionName) { - case FUNC_SET_INDEX: - if (params != null && params.size() > 0) { - HippyMap paramsMap = params.getMap(0); - if (paramsMap != null && paramsMap.size() > 0 && paramsMap - .containsKey("index")) { - int index = paramsMap.getInt("index"); - boolean animated = !paramsMap.containsKey("animated") || paramsMap - .getBoolean("animated"); - view.setCallBackPromise(promise); - view.switchToPage(index, animated); - return; - } - } - - if (promise != null) { - String msg = "invalid parameter!"; - HippyMap resultMap = new HippyMap(); - resultMap.pushString("msg", msg); - promise.resolve(resultMap); - } - break; - default: - break; - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java deleted file mode 100644 index 8ba31980e0d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java +++ /dev/null @@ -1,114 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.viewpager; - -import android.view.View; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.modules.Promise; -import com.tencent.mtt.hippy.views.viewpager.event.HippyPageItemExposureEvent; -import com.tencent.mtt.hippy.views.viewpager.event.HippyPageScrollEvent; -import com.tencent.mtt.hippy.views.viewpager.event.HippyPageScrollStateChangedEvent; -import com.tencent.mtt.hippy.views.viewpager.event.HippyPageSelectedEvent; -import com.tencent.mtt.supportui.views.viewpager.ViewPager; - -@SuppressWarnings({"deprecation", "unused"}) -public class ViewPagerPageChangeListener implements ViewPager.OnPageChangeListener { - - private final HippyPageScrollEvent mPageScrollEmitter; - private final HippyPageScrollStateChangedEvent mPageScrollStateChangeEmitter; - private final HippyPageSelectedEvent mPageSelectedEmitter; - private int mLastPageIndex; - private int mCurrPageIndex; - private final HippyViewPager mPager; - - public ViewPagerPageChangeListener(HippyViewPager pager) { - mPager = pager; - mPageScrollEmitter = new HippyPageScrollEvent(pager); - mPageScrollStateChangeEmitter = new HippyPageScrollStateChangedEvent(pager); - mPageSelectedEmitter = new HippyPageSelectedEvent(pager); - mLastPageIndex = 0; - mCurrPageIndex = 0; - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - mPageScrollEmitter.send(position, positionOffset); - } - - @Override - public void onPageSelected(int position) { - mCurrPageIndex = position; - mPageSelectedEmitter.send(position); - if (mPager != null) { - View currView = mPager.getViewFromAdapter(mCurrPageIndex); - HippyPageItemExposureEvent eventWillAppear = new HippyPageItemExposureEvent( - HippyPageItemExposureEvent.EVENT_PAGER_ITEM_WILL_APPEAR); - eventWillAppear.send(currView, mCurrPageIndex); - - View lastView = mPager.getViewFromAdapter(mLastPageIndex); - HippyPageItemExposureEvent eventWillDisAppear = new HippyPageItemExposureEvent( - HippyPageItemExposureEvent.EVENT_PAGER_ITEM_WILL_DISAPPEAR); - eventWillDisAppear.send(lastView, mLastPageIndex); - } - } - - private void onScrollStateChangeToIdle() { - if (mPager != null && mCurrPageIndex != mLastPageIndex) { - Promise promise = mPager.getCallBackPromise(); - if (promise != null) { - String msg = "on set index successful!"; - HippyMap resultMap = new HippyMap(); - resultMap.pushString("msg", msg); - promise.resolve(resultMap); - mPager.setCallBackPromise(null); - } - - View currView = mPager.getViewFromAdapter(mCurrPageIndex); - HippyPageItemExposureEvent eventWillAppear = new HippyPageItemExposureEvent( - HippyPageItemExposureEvent.EVENT_PAGER_ITEM_DID_APPEAR); - eventWillAppear.send(currView, mCurrPageIndex); - - View lastView = mPager.getViewFromAdapter(mLastPageIndex); - HippyPageItemExposureEvent eventWillDisAppear = new HippyPageItemExposureEvent( - HippyPageItemExposureEvent.EVENT_PAGER_ITEM_DID_DISAPPEAR); - eventWillDisAppear.send(lastView, mLastPageIndex); - - mLastPageIndex = mCurrPageIndex; - } - } - - @Override - public void onPageScrollStateChanged(int oldState, int newState) { - String pageScrollState; - switch (newState) { - case ViewPager.SCROLL_STATE_IDLE: - pageScrollState = "idle"; - onScrollStateChangeToIdle(); - break; - case ViewPager.SCROLL_STATE_DRAGGING: - pageScrollState = "dragging"; - break; - case ViewPager.SCROLL_STATE_SETTLING: - pageScrollState = "settling"; - break; - default: - throw new IllegalStateException("Unsupported pageScrollState"); - } - - mPageScrollStateChangeEmitter.send(pageScrollState); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageItemExposureEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageItemExposureEvent.java deleted file mode 100644 index 50e234ba41d..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageItemExposureEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.viewpager.event; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; - -import android.view.View; - -@SuppressWarnings("deprecation") -public class HippyPageItemExposureEvent extends HippyViewEvent { - - public static final String EVENT_PAGER_ITEM_WILL_APPEAR = "onWillAppear"; - public static final String EVENT_PAGER_ITEM_DID_APPEAR = "onDidAppear"; - public static final String EVENT_PAGER_ITEM_WILL_DISAPPEAR = "onWillDisAppear"; - public static final String EVENT_PAGER_ITEM_DID_DISAPPEAR = "onDidDisAppear"; - - public HippyPageItemExposureEvent(String eventName) { - super(eventName); - } - - public void send(View view, int position) { - HippyMap map = new HippyMap(); - map.pushInt("position", position); - super.send(view, map); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageScrollEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageScrollEvent.java deleted file mode 100644 index be4417962ad..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageScrollEvent.java +++ /dev/null @@ -1,43 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.viewpager.event; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; - -import android.view.View; - -@SuppressWarnings("deprecation") -public class HippyPageScrollEvent extends HippyViewEvent { - - public static final String EVENT_NAME = "onPageScroll"; - - private final View mTarget; - - public HippyPageScrollEvent(View target) { - super(EVENT_NAME); - mTarget = target; - } - - public void send(int position, float offset) { - HippyMap map = new HippyMap(); - map.pushInt("position", position); - map.pushDouble("offset", offset); - super.send(mTarget, map); - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageScrollStateChangedEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageScrollStateChangedEvent.java deleted file mode 100644 index 0355a81c4e2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageScrollStateChangedEvent.java +++ /dev/null @@ -1,42 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.viewpager.event; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; - -import android.view.View; - -@SuppressWarnings("deprecation") -public class HippyPageScrollStateChangedEvent extends HippyViewEvent { - - public static final String EVENT_NAME = "onPageScrollStateChanged"; - - private final View mTarget; - - public HippyPageScrollStateChangedEvent(View target) { - super(EVENT_NAME); - mTarget = target; - } - - public void send(String pageScrollState) { - HippyMap map = new HippyMap(); - map.pushString("pageScrollState", pageScrollState); - super.send(mTarget, map); - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageSelectedEvent.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageSelectedEvent.java deleted file mode 100644 index 9611ef1b655..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/viewpager/event/HippyPageSelectedEvent.java +++ /dev/null @@ -1,42 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.viewpager.event; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; - -import android.view.View; - -@SuppressWarnings("deprecation") -public class HippyPageSelectedEvent extends HippyViewEvent { - - public static final String EVENT_NAME = "onPageSelected"; - - private final View mTarget; - - public HippyPageSelectedEvent(View target) { - super(EVENT_NAME); - mTarget = target; - } - - public void send(int position) { - HippyMap map = new HippyMap(); - map.pushInt("position", position); - super.send(mTarget, map); - } - - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemRenderNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemRenderNode.java deleted file mode 100644 index b40e3805b05..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemRenderNode.java +++ /dev/null @@ -1,69 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.RenderNode; - -public class HippyWaterfallItemRenderNode extends RenderNode { - - static final String TAG = "HippyWaterfallItemNode"; - IRecycleItemTypeChange mRecycleItemTypeChangeListener; - - public HippyWaterfallItemRenderNode(int mId, HippyMap mPropsToUpdate, String className, - HippyRootView mRootView, - ControllerManager componentManager, boolean isLazyLoad) { - super(mId, mPropsToUpdate, className, mRootView, componentManager, isLazyLoad); - } - - @Override - public String toString() { - return "[type:" + getType() + "]" + super.toString(); - } - - public int getType() { - int type = -1; - HippyMap props = getProps(); - if (props != null && props.containsKey("type")) { - type = props.getInt("type"); - } - return type; - } - - @Override - public void updateNode(HippyMap map) { - int oldType = getProps().getInt("type"); - int newType = map.getInt("type"); - if (mRecycleItemTypeChangeListener != null && oldType != newType) { - mRecycleItemTypeChangeListener.onRecycleItemTypeChanged(oldType, newType, this); - } - super.updateNode(map); - } - - public void setRecycleItemTypeChangeListener( - IRecycleItemTypeChange recycleItemTypeChangeListener) { - mRecycleItemTypeChangeListener = recycleItemTypeChangeListener; - } - - public interface IRecycleItemTypeChange { - - void onRecycleItemTypeChanged(int oldType, int newType, - HippyWaterfallItemRenderNode listItemNode); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemView.java deleted file mode 100644 index b634a2d14c0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemView.java +++ /dev/null @@ -1,38 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -import android.content.Context; -import com.tencent.mtt.hippy.views.view.HippyViewGroup; - -public class HippyWaterfallItemView extends HippyViewGroup { - - static final String TAG = "HippyWaterfallItemView"; - private int mType; - - public HippyWaterfallItemView(Context context) { - super(context); - } - - public void setType(int type) { - mType = type; - } - - public int getType() { - return mType; - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemViewController.java deleted file mode 100644 index 27e65b517d2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallItemViewController.java +++ /dev/null @@ -1,68 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.RenderNode; - -@HippyController(name = WaterFallComponentName.ITEM, isLazyLoad = true) -public class HippyWaterfallItemViewController extends - HippyViewController { - - static final String TAG = WaterFallComponentName.ITEM; - - @Override - protected View createViewImpl(Context context) { - return new HippyWaterfallItemView(context); - } - - @HippyControllerProps(name = "type", defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setListItemType(HippyWaterfallItemView listItemView, int type) { - listItemView.setType(type); - } - - @Override - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, ControllerManager controllerManager, - boolean lazy) { - return new HippyWaterfallItemRenderNode(id, props, className, hippyRootView, - controllerManager, lazy); - } - - @Override - protected boolean shouldInterceptLayout(View view, int x, int y, int width, int height) { - ViewParent vp = view.getParent(); - if (vp instanceof ViewGroup) { - ViewGroup vg = (ViewGroup) vp; - int leftPadding = vg.getPaddingLeft(); - if (leftPadding > 0) { - x += leftPadding; - view.layout(x, y, x + width, y + height); - return true; - } - } - return false; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallLayoutManager.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallLayoutManager.java deleted file mode 100644 index 37416487673..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallLayoutManager.java +++ /dev/null @@ -1,964 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -import static com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase.LAYOUT_TYPE_WATERFALL; - -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.util.SparseArray; -import android.util.SparseIntArray; -import android.view.View; -import android.view.ViewGroup; -import com.tencent.mtt.hippy.uimanager.PullFooterRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.HippyViewUtil; -import com.tencent.mtt.hippy.views.refresh.FooterUtil; -import com.tencent.mtt.hippy.views.refresh.HippyPullFooterView; -import com.tencent.mtt.hippy.views.waterfalllist.HippyWaterfallView.HippyWaterfallAdapter; -import com.tencent.mtt.supportui.views.recyclerview.BaseLayoutManager; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerAdapter; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerView; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewItem; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * A {@link HippyWaterfallLayoutManager} implementation which provides similar functionality to - * {@link android.widget.ListView}. - */ -public class HippyWaterfallLayoutManager extends BaseLayoutManager { - - private static final String TAG = "HippyWaterfallLayout"; - - static final int MIN_COLUMN = 2; - int mColumns = MIN_COLUMN; - int mItemGap = 0; - int mColumnSpacing = 0; - boolean mPaddingStartZero = true; - boolean mBannerViewMatch = false; - boolean mHasContainBannerView = false; - ArrayList mHeaderHeight = new ArrayList(); - - public HippyWaterfallLayoutManager(Context context) { - this(context, VERTICAL, false); - } - - /** - * @param context Current context, will be used to access resources. - * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}. - * @param reverseLayout When set to true, renders the layout from end to start. - */ - public HippyWaterfallLayoutManager(Context context, int orientation, boolean reverseLayout) { - super(context, orientation, false); - } - - public boolean getContainBannerView() { - return mHasContainBannerView; - } - - public void setContainBannerView(boolean containBannerView) { - mHasContainBannerView = containBannerView; - } - - public int getColumns() { - return mColumns; - } - - public void setColumns(int columns) { - this.mColumns = Math.max(2, columns); - } - - public int getItemGap() { - return mItemGap; - } - - public void setItemGap(int gap) { - mItemGap = Math.max(0, gap); - } - - public void setColumnSpacing(int spacing) { - mColumnSpacing = Math.max(0, spacing); - } - - public int getColumnSpacing() { - return mColumnSpacing; - } - - public void setPaddingStartZero(boolean paddingStartZero) { - mPaddingStartZero = paddingStartZero; - } - - public void setBannerViewMatch(boolean bannerViewMatch) { - mBannerViewMatch = bannerViewMatch; - } - - - public int getHeaderHeight(int index) { - if (index <= 0 || index > mHeaderHeight.size()) { - return 0; - } - return mHeaderHeight.get(index - 1); - } - - int[] calculateColumnHeightsBefore(int position, boolean caculateOffsetmap) { - // #lizard forgives - int[] columnHeights = new int[mColumns]; - SparseArray> items = new SparseArray<>(); - int n = 0; - - HippyWaterfallAdapter adapter = (HippyWaterfallAdapter) mRecyclerView.getAdapter(); - - if (mHasContainBannerView) { - position += 1; - } - - for (int i = 0; i < position; i++) { - int targetColumnIndex = 0; - for (int j = 0; j < columnHeights.length; j++) { - if (columnHeights[targetColumnIndex] > columnHeights[j]) { - targetColumnIndex = j; - } - } - - if (mHasContainBannerView) { - if (i == 0 || i == 1) { - n = 0; - } else if (i > 1) { - n = i - 1; - } - } else { - n = i; - } - - int myHeight = adapter.getItemHeight(n) + adapter - .getItemMaigin(RecyclerAdapter.LOCATION_TOP, n) - + adapter.getItemMaigin(RecyclerAdapter.LOCATION_BOTTOM, n); - - RenderNode node = adapter.getItemNode(i); - if (node instanceof PullFooterRenderNode) { - int height = getHightestColumnHeight(columnHeights) + myHeight; - Arrays.fill(columnHeights, height); - } else { - columnHeights[targetColumnIndex] += myHeight; - } - } - return columnHeights; - } - - // calculate the height of every column after the item with index position. - public int[] calculateColumnHeightsAfter(int position) { - // #lizard forgives - int[] columnHeights = new int[mColumns]; - SparseArray> items = new SparseArray<>(); - int n = 0; - HippyWaterfallAdapter adapter = (HippyWaterfallAdapter) mRecyclerView.getAdapter(); - - if (mHasContainBannerView) { - position += 1; - } - - for (int i = 0; i <= position; i++) { - int targetColumnIndex = 0; - for (int j = 0; j < columnHeights.length; j++) { - if (columnHeights[targetColumnIndex] > columnHeights[j]) { - targetColumnIndex = j; - } - } - - if (mHasContainBannerView) { - if (i == 0 || i == 1) { - n = 0; - } else if (i > 1) { - n = i - 1; - } - } else { - n = i; - } - - int myHeight = adapter.getItemHeight(n) + adapter - .getItemMaigin(RecyclerAdapter.LOCATION_TOP, n) - + adapter.getItemMaigin(RecyclerAdapter.LOCATION_BOTTOM, n); - - RenderNode node = adapter.getItemNode(i); - if (node instanceof PullFooterRenderNode) { - int height = getHightestColumnHeight(columnHeights) + myHeight; - Arrays.fill(columnHeights, height); - } else { - columnHeights[targetColumnIndex] += myHeight; - } - } - return columnHeights; - } - - public static int getShortestColumnIndex(int[] columnHeights) { - int shortestColumnIndex = 0; - for (int j = 0; j < columnHeights.length; ++j) { - if (columnHeights[shortestColumnIndex] > columnHeights[j]) { - shortestColumnIndex = j; - } - } - return shortestColumnIndex; - } - - public static int getShortestColumnHeight(int[] columnHeights) { - return columnHeights[getShortestColumnIndex(columnHeights)]; - } - - public static int getHightestColumnHeight(int[] columnHeights) { - int heightestColumnIndex = 0; - for (int j = 0; j < columnHeights.length; j++) { - if (columnHeights[heightestColumnIndex] < columnHeights[j]) { - heightestColumnIndex = j; - } - } - return columnHeights[heightestColumnIndex]; - } - - @Override - protected void updateRenderState(int layoutDirection, int requiredSpace, - boolean canUseExistingSpace, RecyclerViewBase.State state) { - super.updateRenderState(layoutDirection, requiredSpace, canUseExistingSpace, state); - resetTargetColumn(); - } - - @Override - protected void updateRenderStateToFillStart(int itemPosition, int offset) { - super.updateRenderStateToFillStart(itemPosition, offset); - if (mHasContainBannerView && itemPosition == 0) { - ((WaterFallRenderState) mRenderState).targetColumn = 0; - } else { - resetTargetColumn(); - } - } - - @Override - protected void updateRenderStateToFillEnd(int itemPosition, int offset) { - super.updateRenderStateToFillEnd(itemPosition, offset); - if (mHasContainBannerView && itemPosition == 0) { - ((WaterFallRenderState) mRenderState).targetColumn = 0; - } else { - resetTargetColumn(); - } - } - - private void resetTargetColumn() { - if (mHasContainBannerView && mRenderState.mCurrentPosition == 0) { - ((WaterFallRenderState) mRenderState).targetColumn = 0; - } else { - int[] columnHeights = calculateColumnHeightsBefore(mRenderState.mCurrentPosition, - false); - ((WaterFallRenderState) mRenderState).targetColumn = getShortestColumnIndex( - columnHeights); - } - } - - // #lizard forgives - void compensateLayoutStart(WaterFallRenderState renderState) {//转屏的时候需要往前回溯几个,以免顶部出现空白 - if (renderState.mCurrentPosition <= 0 - || renderState.mLayoutDirection != RenderState.LAYOUT_END - || renderState.mOffset >= 0) { - return; - } - - int[] columnHeights = calculateColumnHeightsBefore(renderState.mCurrentPosition, false); - int maxHeight = columnHeights[0]; - int minHeight = columnHeights[0]; - for (int i = 1; i < columnHeights.length; ++i) { - int one = columnHeights[i]; - if (one > maxHeight) { - maxHeight = one; - } else if (one < minHeight) { - minHeight = one; - } - } - - int screenTop = minHeight - renderState.mOffset; - if (maxHeight <= screenTop) { - return; - } - - final int rollbackLimit = mColumns; - int resultPosition = 0, resultHeight = 0, resultColumn = renderState.targetColumn; - for (int position = renderState.mCurrentPosition - 1; - position > 0 && renderState.mCurrentPosition - position < rollbackLimit; - --position) { - columnHeights = calculateColumnHeightsBefore(position, false); - maxHeight = columnHeights[0]; - minHeight = columnHeights[0]; - int minColumns = 0; - for (int i = 1; i < columnHeights.length; ++i) { - int one = columnHeights[i]; - if (one > maxHeight) { - maxHeight = one; - } else if (one < minHeight) { - minHeight = one; - minColumns = i; - } - } - - if (maxHeight <= screenTop) { - resultPosition = position; - resultHeight = minHeight; - resultColumn = minColumns; - break; - } - } - - if (renderState.mCurrentPosition - resultPosition >= rollbackLimit) { - Log.e(TAG, "compensateLayoutStart: discard inappropriate sugguestion " - + renderState.mCurrentPosition + " -> " + resultPosition); - return; - } - - int resultOffset = resultHeight - screenTop; - Log.d(TAG, "compensateLayoutStart: position=" + renderState.mCurrentPosition + "->" - + resultPosition + " mOffset=" + renderState.mOffset + "->" - + resultOffset + " column=" + renderState.targetColumn + "->" + resultColumn); - renderState.mCurrentPosition = resultPosition; - renderState.mOffset = resultOffset; - renderState.targetColumn = resultColumn; - } - - /** - * The magic functions :). Fills the given layout, defined by the renderState. This is fairly - * independent from the rest of the {@link HippyWaterfallLayoutManager} and with little change, - * can be made publicly available as a helper class. - * - * @param recycler Current recycler that is attached to RecyclerView - * @param renderState Configuration on how we should fill out the available space. - * @param state Context passed by the RecyclerView to control scroll steps. - * @param stopOnFocusable If true, filling stops in the first focusable new child - * @return Number of pixels that it added. Useful for scoll functions. - */ - // #lizard forgives - protected int fill(RecyclerViewBase.Recycler recycler, RenderState renderState, - RecyclerViewBase.State state, boolean stopOnFocusable) { - - compensateLayoutStart((WaterFallRenderState) renderState); - - final int itemWidth = (getWidth() - getPaddingLeft() - getPaddingRight()) / mColumns; - final int itemGapH = getColumnSpacing() * (mColumns - 1) / mColumns; - - // max offset we should set is mFastScroll + available - final int start = renderState.mAvailable; - if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) { - // TODO ugly bug fix. should not happen - if (renderState.mAvailable < 0) { - renderState.mScrollingOffset += renderState.mAvailable; - } - recycleByRenderState(recycler, renderState); - } - int remainingSpace = renderState.mAvailable + renderState.mExtra; - while (remainingSpace > 0) { - if (renderState.hasMore(state) == RenderState.FILL_TYPE_NOMORE) { - return remainingSpace; - } - - int index = renderState.mCurrentPosition; - int firstItemWidth = itemWidth; - if (mHasContainBannerView && index == 0) { - firstItemWidth = (getWidth() - getPaddingLeft() - getPaddingRight()); - } - // int currentRenderState = renderState.hasMore(state); - View view = getNextView(recycler, renderState, state); - if (view == null) { - if (false && renderState.mScrapList == null) { - throw new RuntimeException("received null view when unexpected"); - } - // if we are laying out views in scrap, this may return null - // which means there is - // no more items to layout. - break; - } - - if (isFooterView(view)) { - firstItemWidth = getWidth(); - } - - RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view - .getLayoutParams(); - if (params instanceof LayoutParams) { - ((LayoutParams) params).mLocateAtColumn = -1; - } - if (!params.isItemRemoved() && mRenderState.mScrapList == null) { - if (mShouldReverseLayout == (renderState.mLayoutDirection - == RenderState.LAYOUT_START)) { - addView(view); - } else { - addView(view, 0); - } - } - - int viewType = params.mViewHolder.mViewType; - int widthUsed = 0; - - if (viewType == RecyclerViewBase.ViewHolder.TYPE_NORMAL) { - if (params instanceof LayoutParams) { - int targetColumn = ((WaterFallRenderState) mRenderState).targetColumn; - ((LayoutParams) params).mLocateAtColumn = targetColumn; - if (!isFooterView(view)) { - setChildPadding(itemGapH, index, view, targetColumn); - } - } - if (getOrientation() == VERTICAL) { - params.width = firstItemWidth - params.leftMargin - params.rightMargin; - } else { - params.height = firstItemWidth - params.topMargin - params.bottomMargin; - } - - if (mRecyclerView.getAdapter() instanceof RecyclerAdapter - && ((RecyclerAdapter) mRecyclerView.getAdapter()) - .isAutoCalculateItemHeight() && view instanceof RecyclerViewItem) { - if (((RecyclerViewItem) view).getChildCount() > 0) { - View contentView = ((RecyclerViewItem) view).getChildAt(0); - ViewGroup.LayoutParams contentLayout = contentView.getLayoutParams(); - if (contentLayout != null) { - contentLayout.width = params.width; - } else { - contentLayout = new ViewGroup.LayoutParams(params); - } - if (!mHasContainBannerView || index != 0 || !mBannerViewMatch) { - if (!isFooterView(view)) { - if (contentLayout.width > 0) { - contentLayout.width -= itemGapH; - } - } - } - contentView.setLayoutParams(contentLayout); - - int widthSpec = View.MeasureSpec - .makeMeasureSpec(contentLayout.width, View.MeasureSpec.AT_MOST); - int heightSpec = View.MeasureSpec - .makeMeasureSpec(contentView.getMeasuredHeight(), - View.MeasureSpec.AT_MOST); - contentView.measure(widthSpec, heightSpec); - } - } - - if (isFooterView(view)) { - widthUsed = 0; - } else if (mHasContainBannerView && index == 0) { - widthUsed = mRecyclerView.getMeasuredWidth(); - } else { - widthUsed = - mRecyclerView.getMeasuredWidth() * (getColumns() - 1) / getColumns(); - } - } - - // TODO - // if (viewType == RecyclerView.ViewHolder.TYPE_FOOTER || viewType == RecyclerView.ViewHolder.TYPE_HEADERE) - // { - // if (view instanceof QBViewInterface) - // { - // ((QBViewInterface) view).switchSkin(); - // } - // } - - measureChildWithMargins(view, widthUsed, 0); - if (mRecyclerView.getAdapter() instanceof RecyclerAdapter - && ((RecyclerAdapter) mRecyclerView.getAdapter()).isAutoCalculateItemHeight()) { - if (view instanceof RecyclerViewItem) { - if (((RecyclerViewItem) view).getChildCount() > 0) { - recordItemSize(index, ((RecyclerViewItem) view).getChildAt(0)); - //((QBRecyclerAdapter) mRecyclerView.getAdapter()).forceUpdateOffsetMap(); - } - } else { - if (viewType == RecyclerViewBase.ViewHolder.TYPE_HEADERE) { - int height = view.getMeasuredHeight(); - int headerIndex = Math.abs(index) - 1; - while (headerIndex >= mHeaderHeight.size()) { - mHeaderHeight.add(0); - } - mHeaderHeight.set(headerIndex, height); - } - } - if (renderState.hasMore(state) == RenderState.FILL_TYPE_NOMORE) { - mRecyclerView.mState.mTotalHeight = mRecyclerView.getAdapter().getListTotalHeight(); - } - } - - int addViewLength = mOrientationHelper.getDecoratedMeasurement(view); - int left, top, right, bottom; - if (getOrientation() == VERTICAL) { - - if (isFooterView(view) || viewType == RecyclerViewBase.ViewHolder.TYPE_FOOTER) { - left = 0; - right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); - top = mOrientationHelper.getDecoratedEnd(getChildClosestToDefaultFooter()); - bottom = mOrientationHelper.getDecoratedEnd(getChildClosestToDefaultFooter()) - + addViewLength; - } else if (viewType == RecyclerViewBase.ViewHolder.TYPE_HEADERE) { - left = getPaddingLeft(); - right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { - bottom = renderState.mOffset; - top = renderState.mOffset - addViewLength; - } else { - top = renderState.mOffset; - bottom = renderState.mOffset + addViewLength; - } - } else { - // the layout derection of waterfall will not care about - // left-hander. - left = ((WaterFallRenderState) mRenderState).targetColumn * itemWidth - + getPaddingLeft(); - right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { - // renderState.mOffset = a; - bottom = renderState.mOffset; - top = renderState.mOffset - addViewLength; - } else { - top = renderState.mOffset; - bottom = renderState.mOffset + addViewLength; - } - } - } else { - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { - // renderState.mOffset = a; - bottom = getHeight() - getPaddingBottom() - - itemWidth * ((WaterFallRenderState) mRenderState).targetColumn; - top = bottom - mOrientationHelper.getDecoratedMeasurementInOther(view); - right = renderState.mOffset; - left = renderState.mOffset - addViewLength; - } else { - top = ((WaterFallRenderState) mRenderState).targetColumn * itemWidth - + getPaddingTop(); - bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); - left = renderState.mOffset; - right = renderState.mOffset + addViewLength; - } - } - // We calculate everything with View's bounding box (which includes - // decor and margins) - // To calculate correct layout position, we subtract margins. - layoutDecorated(view, left + params.leftMargin, top + params.topMargin, - right - params.rightMargin, bottom - params.bottomMargin); - - if (!params.isItemRemoved()) { - int cosume = 0; - if (viewType == RecyclerViewBase.ViewHolder.TYPE_FOOTER) { - int oldOffsetY = renderState.mOffset; - renderState.mOffset = mOrientationHelper - .getDecoratedEnd(getChildClosestToDefaultFooter()); - renderState.mOffset += mOrientationHelper.getDecoratedMeasurement(view); - Log.d(TAG, "fill: mOffset=" + renderState.mOffset + " viewType=" + viewType + " @1"); - cosume = renderState.mOffset - oldOffsetY; - } else if (viewType == RecyclerViewBase.ViewHolder.TYPE_HEADERE) { - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { - cosume = -mOrientationHelper.getDecoratedMeasurement(view); - } else { - cosume = mOrientationHelper.getDecoratedMeasurement(view); - } - renderState.mOffset += cosume; - Log.d(TAG, "fill: mOffset=" + renderState.mOffset + " viewType=" + viewType + " @2"); - } else { - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) { - int[] columnHeightBefore = calculateColumnHeightsAfter( - renderState.mCurrentPosition - renderState.mItemDirection); - int[] columnHeightAfter = calculateColumnHeightsBefore( - renderState.mCurrentPosition - renderState.mItemDirection, false); - int heightestHeightBefore = getHightestColumnHeight(columnHeightBefore); - int heightestHeightAfter = getHightestColumnHeight(columnHeightAfter); - cosume = heightestHeightAfter - heightestHeightBefore; - renderState.mOffset = mOrientationHelper - .getDecoratedStart(getChildClosestToStartInScreen()); - Log.d(TAG, "fill: mOffset=" + renderState.mOffset + " viewType=" + viewType + " @3"); - } else { - if (mHasContainBannerView && index == 0) { - cosume = addViewLength; - renderState.mOffset += cosume; - Log.d(TAG, "fill: mOffset=" + renderState.mOffset + " cosume=" + cosume + " viewType=" - + viewType + " @4"); - } else { - int[] columnHeightBefore = calculateColumnHeightsBefore( - renderState.mCurrentPosition - renderState.mItemDirection, - false); - int[] columnHeightAfter = calculateColumnHeightsAfter( - renderState.mCurrentPosition - renderState.mItemDirection); - int shortestHeightBefore = getShortestColumnHeight(columnHeightBefore); - int shortestHeightAfter = getShortestColumnHeight(columnHeightAfter); - cosume = shortestHeightAfter - shortestHeightBefore; - renderState.mOffset += cosume; - Log.d(TAG, "fill: mOffset=" + renderState.mOffset + " cosume=" + cosume + " viewType=" - + viewType + " @5"); - } - } - } - - if (mHasContainBannerView && index == 0) { - ((WaterFallRenderState) mRenderState).targetColumn = 0; - } else { - resetTargetColumn(); - } - - renderState.mAvailable -= Math.abs(cosume); - // we keep a separate remaining space because mAvailable is - // important for recycling - remainingSpace -= Math.abs(cosume); - - if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) { - renderState.mScrollingOffset += Math.abs(cosume); - if (renderState.mAvailable < 0) { - renderState.mScrollingOffset += renderState.mAvailable; - } - recycleByRenderState(recycler, renderState); - } - } - - if (stopOnFocusable && view.isFocusable()) { - break; - } - - if (state != null && state.getTargetScrollPosition() == getPosition(view)) { - break; - } - } - return start - renderState.mAvailable; - } - - void setChildPadding(int itemGapH, int index, View view, int targetColumn) { - if (mHasContainBannerView && index == 0) { - if (mBannerViewMatch) { - view.setPadding(0, 0, 0, mItemGap); - } else { - view.setPadding(itemGapH / 2, 0, itemGapH / 2, mItemGap); - } - } else { - if (mPaddingStartZero) { - if (targetColumn == 0) { - view.setPadding(0, 0, itemGapH, mItemGap); - } else if (targetColumn == mColumns - 1) { - view.setPadding(itemGapH, 0, 0, mItemGap); - } else { - view.setPadding(itemGapH / 2, 0, itemGapH / 2, mItemGap); - } - } else { - int edgePadding = itemGapH * mColumns / (mColumns + 1); - if (targetColumn == 0) { - view.setPadding(edgePadding, 0, itemGapH - edgePadding, mItemGap); - } else if (targetColumn == mColumns - 1) { - view.setPadding(itemGapH - edgePadding, 0, edgePadding, mItemGap); - } else { - view.setPadding(itemGapH / 2, 0, itemGapH / 2, mItemGap); - } - } - } - } - - @Override - public void measureChildWithMargins(View child, int widthUsed, int heightUsed) { - RecyclerViewBase.LayoutParams lp = null; - if (child == null) { - return; - } - if (child.getLayoutParams() != null) { - lp = (RecyclerViewBase.LayoutParams) child.getLayoutParams(); - } else { - lp = generateDefaultLayoutParams(); - } - final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); - widthUsed += insets.left + insets.right; - heightUsed += insets.top + insets.bottom; - - MeasureWH measureWH = new MeasureWH(); - measureWH.width = lp.width; - measureWH.height = lp.height; - boolean isFooterView = false; - if (mRecyclerView.getAdapter() instanceof RecyclerAdapter) { - boolean enableAutoItemHeight = ((RecyclerAdapter) mRecyclerView.getAdapter()) - .isAutoCalculateItemHeight(); - if (enableAutoItemHeight) { - if (child instanceof RecyclerViewItem) { - if (((RecyclerViewItem) child).getChildCount() > 0) { - View contentView = ((RecyclerViewItem) child).getChildAt(0); - if (isFooterView(contentView)) { - isFooterView = true; - setFooterMeasureWH(contentView, measureWH); - } else { - measureWH.width = contentView.getMeasuredWidth() - + child.getPaddingRight() + child - .getPaddingLeft();//mItemGap * (mColumns - 1) / mColumns; - measureWH.height = contentView.getMeasuredHeight() - + mItemGap;// + ((RecyclerAdapter) mRecyclerView.getAdapter()).getDividerHeight(0) - } - } - } else if (child instanceof HippyPullFooterView) { - isFooterView = true; - setFooterMeasureWH(child, measureWH); - } else if (child instanceof ViewGroup) { - ViewGroup viewGroup = (ViewGroup) child; - if (viewGroup.getChildCount() > 0) { - View contentView = viewGroup.getChildAt(0); - measureWH.width = contentView.getMeasuredWidth(); - measureWH.height = contentView.getMeasuredHeight(); - } - } - } - } - - int paddingHorizontally = isFooterView? 0 : getPaddingLeft() + getPaddingRight(); - final int widthSpec = getChildMeasureSpec(getWidth(), - paddingHorizontally + lp.leftMargin + lp.rightMargin + widthUsed, - measureWH.width, canScrollHorizontally()); - final int heightSpec = getChildMeasureSpec(getHeight(), - getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin + heightUsed, - measureWH.height, canScrollVertically()); - - child.measure(widthSpec, heightSpec); - } - - public static class MeasureWH { - - int width; - int height; - } - - void setFooterMeasureWH(View footerView, MeasureWH measureWH) { - RenderNode footerNode = HippyViewUtil.getRenderNode(footerView); - if (footerNode != null) { - measureWH.width = footerNode.getWidth(); - measureWH.height = footerNode.getHeight() + mItemGap; - } else { - measureWH.width = footerView.getWidth(); - measureWH.height = footerView.getHeight() + mItemGap; - } - } - - protected static class WaterFallRenderState extends RenderState { - - public int targetColumn = 0; - } - - @Override - protected void ensureRenderState() { - if (this.mRenderState == null) { - this.mRenderState = new WaterFallRenderState(); - } - - super.ensureRenderState(); - } - - @Override - public void calculateOffsetMap(SparseIntArray offsetMap, int startOffset) { - RecyclerAdapter adapter = (RecyclerAdapter) mRecyclerView.getAdapter(); - int itemCount = adapter.getItemCount(); - int[] columnHeights = new int[mColumns]; - for (int i = 0; i < itemCount; i++) { - int targetColumnIndex = getShortestColumnIndex(columnHeights); - offsetMap.append(i, columnHeights[targetColumnIndex]); - columnHeights[targetColumnIndex] += adapter.getItemHeight(i) + adapter - .getItemMaigin(RecyclerAdapter.LOCATION_TOP, i) - + adapter.getItemMaigin(RecyclerAdapter.LOCATION_BOTTOM, i); - } - } - - @Override - public int getLayoutType() { - return LAYOUT_TYPE_WATERFALL; - } - - public RecyclerViewBase.LayoutParams onCreateItemLayoutParams( - RecyclerView.ViewHolderWrapper holder, int position, int layoutType, - int cardType) { - int itemHeight = mRecyclerView.getAdapter().getItemHeight(position); - ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); - if (lp == null) { - return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, itemHeight); - } - if (lp instanceof LayoutParams) { - return (RecyclerViewBase.LayoutParams) lp; - } else { - return new LayoutParams(lp.width, itemHeight); - } - } - - public static class LayoutParams extends RecyclerViewBase.LayoutParams { - - public int mLocateAtColumn = -1; - - public LayoutParams(Context c, AttributeSet attrs) { - super(c, attrs); - } - - public LayoutParams(int width, int height) { - super(width, height); - } - - public LayoutParams(LayoutParams source) { - super(source); - mLocateAtColumn = source.mLocateAtColumn; - } - - public LayoutParams(ViewGroup.MarginLayoutParams source) { - super(source); - } - - public LayoutParams(ViewGroup.LayoutParams source) { - super(source); - } - } - - @Override - public int getHeightBefore(int pos) { - int[] columnHeights = calculateColumnHeightsBefore(pos, false); - return columnHeights[getShortestColumnIndex(columnHeights)]; - } - - public int getTotalHeight() { - int[] columnHeights = calculateColumnHeightsBefore(getItemCount(), false); - return getHightestColumnHeight(columnHeights); - } - - /** - * Convenience method to find the child closes to start. Caller should check it has enough - * children. - * - * @return The shortest column's top child. - */ - public View getChildClosestToStartInScreen() { - return mShouldReverseLayout ? getChildClosestToEndInternal() - : getChildClosestToStartInternal(); - } - - /** - * Convenience method to find the child closes to end. Caller should check it has enough - * children. - * - * @return The shortest column's bottom child. - */ - public View getChildClosestToEndInScreen() { - return mShouldReverseLayout ? getChildClosestToStartInternal() - : getChildClosestToEndInternal(); - } - - /** - * Convenience method to find the child closes to end. Caller should check it has enough - * children. - * - * @return The shortest column's bottom child. - */ - private View getChildClosestToDefaultFooter() { - View[] childsClosestToEnd = new View[mColumns]; - for (int i = 0; i < getChildCount() - 1; i++) { - View view = getChildAt(i); - LayoutParams params = (LayoutParams) view.getLayoutParams(); - for (int j = 0; j < mColumns; j++) { - if (params.mLocateAtColumn == j) { - childsClosestToEnd[j] = view; - break; - } - } - } - int targetIndex = 0; - for (int i = 0; i < mColumns; i++) { - if (childsClosestToEnd[targetIndex] == null) { - break; - } - if (childsClosestToEnd[i] == null) { - break; - } - if (childsClosestToEnd[targetIndex].getBottom() < childsClosestToEnd[i].getBottom()) { - targetIndex = i; - } - } - return childsClosestToEnd[targetIndex]; - } - - /** - * Convenience method to find the child closes to end. Caller should check it has enough - * children. - * - * @return The shortest column's bottom child. - */ - private View getChildClosestToEndInternal() { - if (mHasContainBannerView && getChildCount() == 1) { - return getChildAt(0); - } - - View[] childsClosestToEnd = new View[mColumns]; - for (int i = 0; i < getChildCount(); i++) { - View view = getChildAt(i); - if (view.getLayoutParams() instanceof LayoutParams) { - LayoutParams params = (LayoutParams) view.getLayoutParams(); - for (int j = 0; j < mColumns; j++) { - if (params.mLocateAtColumn == j) { - childsClosestToEnd[j] = view; - break; - } - } - } - } - int targetIndex = 0; - for (int i = 0; i < mColumns; i++) { - if (childsClosestToEnd[targetIndex] == null) { - break; - } - if (childsClosestToEnd[i] == null) { - targetIndex = i; - break; - } - - boolean isLastView = (getPosition(childsClosestToEnd[i]) == getItemCount() - 1); - if (isLastView) { - targetIndex = i; - break; - } - - boolean isFooter = isFooterView(childsClosestToEnd[targetIndex]); - if (isFooter) { - targetIndex = i; - break; - } - if (childsClosestToEnd[targetIndex].getBottom() > childsClosestToEnd[i].getBottom()) { - targetIndex = i; - } - } - return childsClosestToEnd[targetIndex]; - } - - private boolean isFooterView(View target) { - return FooterUtil.isFooterView(target); - } - - /** - * Convenience method to find the child closes to end. Caller should check it has enough - * children. - * - * @return The shortest column's bottom child. - */ - private View getChildClosestToStartInternal() { - int targetPosition = - getPosition(getChildClosestToStartByOrder()) + mRenderState.mItemDirection; - int[] columnHeights = calculateColumnHeightsBefore(targetPosition, false); - int targetColumn = getShortestColumnIndex(columnHeights); - View view = null; - for (int i = 0; i < getChildCount(); i++) { - view = getChildAt(i); - if (view.getLayoutParams() instanceof LayoutParams) { - LayoutParams params = (LayoutParams) view.getLayoutParams(); - if (params.mLocateAtColumn == targetColumn) { - break; - } - } - } - return view; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallView.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallView.java deleted file mode 100644 index 864344c2483..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallView.java +++ /dev/null @@ -1,1215 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -import android.content.Context; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import com.tencent.mtt.hippy.HippyEngineContext; -import com.tencent.mtt.hippy.HippyInstanceContext; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.DiffUtils; -import com.tencent.mtt.hippy.uimanager.HippyViewBase; -import com.tencent.mtt.hippy.uimanager.HippyViewEvent; -import com.tencent.mtt.hippy.uimanager.NativeGestureDispatcher; -import com.tencent.mtt.hippy.uimanager.PullFooterRenderNode; -import com.tencent.mtt.hippy.uimanager.PullHeaderRenderNode; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.hippy.views.list.HippyListView; -import com.tencent.mtt.hippy.views.refresh.FooterUtil; -import com.tencent.mtt.hippy.views.refresh.HippyPullFooterView; -import com.tencent.mtt.hippy.views.refresh.IFooterContainer; -import com.tencent.mtt.supportui.views.recyclerview.ContentHolder; -import com.tencent.mtt.supportui.views.recyclerview.IRecyclerViewFooter; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerAdapter; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerView; -import com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase; -import com.tencent.mtt.supportui.views.recyclerview.Scroller; -import java.util.ArrayList; - - -public class HippyWaterfallView extends HippyListView implements HippyViewBase, IFooterContainer { - - static final String TAG = "HippyWaterfallView"; - - HippyWaterfallAdapter mAdapter; - private HippyEngineContext mHippyContext; - private NativeGestureDispatcher mGestureDispatcher; - private Runnable mDispatchLayout = null; - - public static final int DEFAULT_REFRESH_TYPE = 1; - public static final int HIPPY_SKIN_CHANGE = 1001; - - boolean mEnableFooter; - boolean mEnableRefresh; - HippyArray mRefreshColors; - private OnInitialListReadyEvent mOnInitialListReadyEvent; - - private boolean mHasRemovePreDraw = false; - private ViewTreeObserver.OnPreDrawListener mPreDrawListener = null; - private ViewTreeObserver mViewTreeObserver = null; - private WaterfallEndChecker mEndChecker = new WaterfallEndChecker(); - - // for auto test >>> - private boolean mHasLoadMore = false; - private boolean mHasScrollToIndex = false; - private boolean mHasScrollToContentOffset = false; - private boolean mHasStartRefresh = false; - private boolean mHasCompeleteRefresh = false; - // for auto test <<< - - public HippyWaterfallView(Context context) { - super(context); - mHippyContext = ((HippyInstanceContext) context).getEngineContext(); - this.setLayoutManager(new HippyWaterfallLayoutManager(context)); - mAdapter = (HippyWaterfallAdapter) getAdapter(); - setRecycledViewPool(new RNWFRecyclerPool()); - - mEnableFooter = true; - mEnableRefresh = false; - mRefreshColors = null; - - addOnListScrollListener(mAdapter.getOnListScrollListener()); - setClipToPadding(false); - } - - @Override - protected HippyWaterfallAdapter createAdapter(RecyclerView hippyRecyclerView, - HippyEngineContext hippyEngineContext) { - return new HippyWaterfallAdapter(this); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean result = super.onTouchEvent(event); - if (mGestureDispatcher != null) { - result |= mGestureDispatcher.handleTouchEvent(event); - } - return result; - } - - @Override - public NativeGestureDispatcher getGestureDispatcher() { - return mGestureDispatcher; - } - - @Override - public void setGestureDispatcher(NativeGestureDispatcher dispatcher) { - this.mGestureDispatcher = dispatcher; - } - - @Override - protected HippyMap generateScrollEvent() { - HippyMap event = super.generateScrollEvent(); - - event.pushDouble("startEdgePos", PixelUtil.px2dp(getOffsetY())); - event.pushDouble("endEdgePos", PixelUtil.px2dp(getOffsetY() + getHeight())); - event.pushInt("firstVisibleRowIndex", getFirstVisibleItemPos()); - event.pushInt("lastVisibleRowIndex", getFirstVisibleItemPos() + getChildCountInItem()); - - HippyArray rowFrames = new HippyArray(); - for (int i = 0; i < getChildCountInItem(); ++i) { - View child = getChildAt(i); - if (child == null) { - continue; - } - HippyMap row = new HippyMap(); - row.pushDouble("x", PixelUtil.px2dp(child.getX())); - row.pushDouble("y", PixelUtil.px2dp(child.getY())); - row.pushDouble("width", PixelUtil.px2dp(child.getWidth())); - row.pushDouble("height", PixelUtil.px2dp(child.getHeight())); - rowFrames.pushMap(row); - } - event.pushArray("visibleRowFrames", rowFrames); - - return event; - } - - @Override - public void setListData() { - if (getAdapter() == null) { - setAdapter(mAdapter); - } - setFooterState(HippyListView.REFRESH_STATE_IDLE); // 每次刷新数据后重置footer状态 - - mAdapter.notifyDataSetChanged(); - - if (mDispatchLayout == null) { - mDispatchLayout = new Runnable() { - @Override - public void run() { - dispatchLayout(); - } - }; - } - removeCallbacks(mDispatchLayout); - post(mDispatchLayout); - } - - public void startLoadMore() { - mHasLoadMore = true; - mAdapter.setLoadingStatus(IRecyclerViewFooter.LOADING_STATUS_LOADING); - } - - @Override - public void handleInTraversal(int traversalPurpose, int position, View contentView) { - if (traversalPurpose == HIPPY_SKIN_CHANGE) { - traversalChildViewForSkinChange(contentView); - } - } - - private void traversalChildViewForSkinChange(View view) { - if (view instanceof ViewGroup) { - int childCount = ((ViewGroup) view).getChildCount(); - for (int i = 0; i < childCount; i++) { - traversalChildViewForSkinChange(((ViewGroup) view).getChildAt(i)); - } - } - } - - public void checkExposureForReport(int oldState, int newState) { - if (getAdapter() != null) { - mAdapter.checkExposureForReport(oldState, newState); - } - } - - public void setCustomRefreshColor(int ballColor, int bgColor, int tipsBgColor) { - } - - public void scrollToIndex(int xIndex, int yIndex, boolean animated) { - mHasScrollToIndex = true; - - if (animated) { - scrollToIndex(xIndex, yIndex, true, 0); - } else { - scrollToPosition(yIndex, 0); - post(this::dispatchLayout); - } - } - - public void scrollToContentOffset(double xOffset, double yOffset, boolean animated) { - mHasScrollToContentOffset = true; - - if (animated) { - smoothScrollBy(0, (int) yOffset); - } else { - scrollToPosition(0, (int) -PixelUtil.dp2px(yOffset)); - post(this::dispatchLayout); - } - } - - public void setScrollbarEnabled(boolean scrollbarEnabled) { - } - - public void setFastScrollerEnabled(boolean fastScrollerEnabled) { - } - - public void setLiftEnabled(boolean liftEnabled) { - } - - public void setPlaceHolderDrawableEnabled(boolean placeHolderDrawableEnabled) { - } - - public void setRefreshEnabled(boolean refreshEnabled) { - } - - public void setEnableScrollForReport(boolean enableScrollForReport) { - mAdapter.setEnableScrollForReport(enableScrollForReport); - } - - public void setEnableExposureReport(boolean enableExposureReport) { - mAdapter.setEnableExposureReport(enableExposureReport); - } - - public void setRefreshColors(HippyArray refreshColors) { - mRefreshColors = refreshColors; - } - - protected void setLoadingStatus(int loadingStatus, String text) { - mAdapter.setLoadingStatus(loadingStatus, text); - } - - @Override - public void checkNotifyFooterAppearWithFewChild(int endOffset) { - } - - @Override - public void onScrollStateChanged(int oldState, int newState) { - super.onScrollStateChanged(oldState, newState); - if (getAdapter() != null) { - mAdapter.checkScrollForReport(); - mAdapter.checkExposureForReport(oldState, newState); - } - } - - @Override - public void onScrolled(int x, int y) { - super.onScrolled(x, y); - mEndChecker.onScroll(this, y); - } - - public void startRefresh(int type) { - } - - public void setRefreshPromptInfo(String descriptionText, int descriptionTextColor, - int descriptionTextFontSize, String imgUrl, int imgWidth, int imgHeight) { - } - - public void startRefreshWithType(boolean inInit) { - } - - public void startRefreshWithOnlyAnimation(boolean inInit) { - } - - protected boolean enableOnSrollReport() { - return true; - } - - protected ExposureForReport getExposureForReport(int oldState, int newState) { - return mAdapter.getExposureForReportInner(oldState, newState); - } - - @Override - public void scrollToTopAtOnce() { - super.scrollToTopAtOnce(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (!mHasRemovePreDraw) { - mViewTreeObserver = getViewTreeObserver(); - if (mPreDrawListener == null) { - mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - if (mAdapter.getItemCount() > 0 - && HippyWaterfallView.this.getChildCount() > 0) { - mViewTreeObserver.removeOnPreDrawListener(this); - mHasRemovePreDraw = true; - post(new Runnable() { - @Override - public void run() { - getOnInitialListReadyEvent() - .send(HippyWaterfallView.this, null); - } - }); - - } - return true; - } - }; - } - mViewTreeObserver.removeOnPreDrawListener(mPreDrawListener); - mViewTreeObserver.addOnPreDrawListener(mPreDrawListener); - - } - } - - @Override - protected void onDetachedFromWindow() { - stopScroll(); - if (mPreDrawListener != null && mViewTreeObserver != null) { - mViewTreeObserver.removeOnPreDrawListener(mPreDrawListener); - } - super.onDetachedFromWindow(); - } - - @Override - protected void checkRefreshHeadOnFlingRun() { - } - - @Override - public boolean isRefreshing() { - return false; - } - - @Override - protected boolean changeUpOverScrollEnableOnComputeDxDy(int dx, int dy, - boolean careSpringBackMaxDistance, Scroller scroller, boolean isTouch, - boolean currentUpOverScrollEnabled) { - return currentUpOverScrollEnabled; - } - - @Override - protected boolean checkShouldStopScroll() { - return false; - } - - @Override - protected void invalidateRefreshHeader() { - } - - @Override - protected boolean shouldStopReleaseGlows(boolean canGoRefresh, boolean fromTouch) { - return false; - } - - @Override - protected boolean shouldStopOnInterceptTouchEvent(MotionEvent e, int totalHeight, - boolean upOverScrollEnabled) { - return false; - } - - @Override - protected boolean shouldStopOnTouchEvent(MotionEvent e, int totalHeight, - boolean upOverScrollEnabled) { - return false; - } - - protected void setPreloadItemNumber(int count) { - mAdapter.setPreloadItemNum(count); - } - - private int mFooterState = HippyListView.REFRESH_STATE_IDLE; - - @Override - public int getFooterState() { - return mFooterState; - } - - @Override - public void setFooterState(int state) { - mFooterState = state; - } - - @Override - public void onFooterRefreshFinish() { - setFooterState(HippyListView.REFRESH_STATE_LOADING); - } - - public class HippyWaterfallAdapter extends RecyclerAdapter implements - HippyWaterfallItemRenderNode.IRecycleItemTypeChange { - - private HippyWaterfallEvent mOnFooterAppearedEvent; - private HippyWaterfallEvent mOnRefreshEvent; - private HippyWaterfallEvent mOnScrollForReportEvent; - private int mPreloadItemNum; - private boolean mShouldUpdatePreloadDistance; - private int mPreloadDistanceWithItemNumber; - private boolean mOnPreloadCalled; - private boolean mEnableScrollForReport; - private boolean mEnableExposureReport; - private HippyMap mScrollReportResultMap; - private HippyMap mExposureReportResultMap; - private OnListScrollListener mOnListScrollListener; - - private boolean mHasOnScrollForReport = false; - private boolean mHasExposureReport = false; - private boolean mHasOnRefresh = false; - private boolean mHasOnFooterAppeared = false; - private boolean mHasPreload = false; - private boolean mHasSetLoadingStatus = false; - - public HippyWaterfallAdapter(RecyclerView recyclerView) { - super(recyclerView); - setLoadingStatus(IRecyclerViewFooter.LOADING_STATUS_LOADING); - } - - ArrayList mListViewHolder; - - public int getRecyclerItemCount() { - mListViewHolder = new ArrayList<>(); - - Recycler recycler = mParentRecyclerView.getRecycler(); - - mListViewHolder.addAll(recycler.mAttachedScrap); - - mListViewHolder.addAll(recycler.mCachedViews); - - for (int i = 0; i < recycler.getRecycledViewPool().mScrap.size(); i++) { - mListViewHolder.addAll(recycler.getRecycledViewPool().mScrap.valueAt(i)); - } - return mListViewHolder.size() + mParentRecyclerView.getChildCount(); - } - - View getRecyclerItemView(int index) { - if (index < mListViewHolder.size()) { - return mListViewHolder.get(index).mContent; - } else { - return mParentRecyclerView.getChildAt(index - mListViewHolder.size()); - } - - } - - @Override - public ContentHolder onCreateContentViewWithPos(ViewGroup parent, int position, - int viewType) { - NodeHolder contentHolder = new NodeHolder(); - RenderNode contentViewRenderNode = mHippyContext.getRenderManager() - .getRenderNode(getId()).getChildAt(position); - contentViewRenderNode.setLazy(false); - - contentHolder.mContentView = contentViewRenderNode.createViewRecursive(); - FooterUtil.checkFooterBinding(mParentRecyclerView, contentHolder.mContentView); - - contentHolder.mBindNode = contentViewRenderNode; - contentHolder.isCreated = true; - return contentHolder; - } - - public void onViewAbandonHelper(ViewHolderWrapper viewHolder) { - onViewAbandon(viewHolder); - } - - @Override - protected void onViewAbandon(ViewHolderWrapper viewHolder) { - // set is lazy true the holder is delete so delete view - NodeHolder nodeHolder = (NodeHolder) viewHolder.mContentHolder; - if (nodeHolder.mBindNode != null) { - nodeHolder.mBindNode.setLazy(true); - mHippyContext.getRenderManager().getControllerManager() - .deleteChild(mParentRecyclerView.getId(), nodeHolder.mBindNode.getId()); - } - - if (nodeHolder.mBindNode instanceof HippyWaterfallItemRenderNode) { - ((HippyWaterfallItemRenderNode) nodeHolder.mBindNode) - .setRecycleItemTypeChangeListener(null); - } - - super.onViewAbandon(viewHolder); - } - - @Override - public void onBindContentView(ContentHolder holder, int position, int layoutType) { - NodeHolder contentHolder = (NodeHolder) holder; - - if (contentHolder.isCreated) { - try { - contentHolder.mBindNode.updateViewRecursive(); - contentHolder.isCreated = false; - } catch (Throwable t) { - Log.e(TAG, "onBindContentView #" + position, t); - throw t; - } - } else { - //step 1: diff - RenderNode fromNode = contentHolder.mBindNode; - if (contentHolder.mBindNode != null) { - contentHolder.mBindNode.setLazy(true); - } - try { - RenderNode toNode = mHippyContext.getRenderManager().getRenderNode(getId()) - .getChildAt(position); - toNode.setLazy(false); - - ArrayList patchTypes = DiffUtils - .diff(contentHolder.mBindNode, toNode); - - try { - //step:2 delete unUseful views - DiffUtils.deleteViews(mHippyContext.getRenderManager().getControllerManager(), - patchTypes); - //step:3 replace id - DiffUtils.replaceIds(mHippyContext.getRenderManager().getControllerManager(), - patchTypes); - //step:4 create view is do not reUse - DiffUtils.createView(patchTypes); - //step:5 patch the dif result - DiffUtils.doPatch(mHippyContext.getRenderManager().getControllerManager(), - patchTypes); - } catch (Throwable t) { - Log.e(TAG, "onBindContentView #" + position, t); - throw t; - } - - contentHolder.mBindNode = toNode; - } catch (Throwable t) { - } - - } - - if (contentHolder.mContentView instanceof HippyPullFooterView) { - FooterUtil.sendFooterReleasedEvent((HippyPullFooterView) contentHolder.mContentView); - } - - if (contentHolder.mBindNode instanceof HippyWaterfallItemRenderNode) { - ((HippyWaterfallItemRenderNode) contentHolder.mBindNode) - .setRecycleItemTypeChangeListener(this); - } - } - - @Override - public int getItemCount() { - try { - return getRenderNode().getChildCount(); - } catch (NullPointerException e) { - e.printStackTrace(); - return 0; - } - } - - @Override - public boolean isAutoCalculateItemHeight() { - return true; - } - - @Override - public int getItemViewType(int index) { - RenderNode itemNode = getItemNode(index); - if (itemNode != null) { - HippyMap props = itemNode.getProps(); - if (props != null && props.containsKey("type")) { - return props.getInt("type"); - } - - if (itemNode instanceof PullFooterRenderNode) { - return RecyclerViewBase.ViewHolder.TYPE_CUSTOM_FOOTER; - } - if (itemNode instanceof PullHeaderRenderNode) { - return RecyclerViewBase.ViewHolder.TYPE_CUSTOM_HEADERE; - } - } - - return 0; - } - - RenderNode getRenderNode() { - return mHippyContext.getRenderManager().getRenderNode(getId()); - } - - View getHippyView(int id) { - return mHippyContext.getRenderManager().getControllerManager().findView(id); - } - - RenderNode getItemNode(int index) { - return getRenderNode().getChildAt(index); - } - - @Override - public int getItemHeight(int index) { - int itemHeight = 0; - RenderNode listNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()); - if (listNode != null && listNode.getChildCount() > index && index >= 0) { - RenderNode listItemNode = listNode.getChildAt(index); - if (listItemNode != null) { - itemHeight = listItemNode.getHeight(); - } - } - return itemHeight + ((HippyWaterfallLayoutManager) mParentRecyclerView - .getLayoutManager()).getItemGap(); - } - - @Override - public int getHeightBefore(int pos) { - return ((HippyWaterfallLayoutManager) getLayoutManager()).getHeightBefore(pos); - } - - @Override - public int getTotalHeight() { - return getLayoutManager().getTotalHeight(); - } - - @Override - public void notifyDataSetChanged() { - setPreloadItemNum(getPreloadThresholdInItemNumber()); - super.notifyDataSetChanged(); - } - - @Override - public void startRefreshData() { - mHasOnRefresh = true; - - //sendEvent("OnRefreshEvent"); - getOnRefreshEvent().send(mParentRecyclerView, null); - } - - public void startRefreshData(boolean fromPull) { - mHasOnRefresh = true; - HippyMap params = new HippyMap(); - params.pushString("refreshFrom", fromPull ? "pull" : "command"); - getOnRefreshEvent().send(mParentRecyclerView, params); - } - - @Override - public void notifyLastFooterAppeared() { - super.notifyLastFooterAppeared(); - if (mLoadingStatus != IRecyclerViewFooter.LOADING_STATUS_LOADING - && mLoadingStatus != IRecyclerViewFooter.LOADING_STATUS_CUSTOM - && mLoadingStatus != IRecyclerViewFooter.LOADING_STATUS_NOMORE_CLICKBACKWARDS) { - setLoadingStatus(IRecyclerViewFooter.LOADING_STATUS_LOADING); - } - - if (mLoadingStatus == IRecyclerViewFooter.LOADING_STATUS_LOADING) { - mHasOnFooterAppeared = true; - - getOnFooterAppearedEvent().send(mParentRecyclerView, null); - } - } - - protected void setLoadingStatus(int loadingStatus, String text) { - if (loadingStatus != IRecyclerViewFooter.LOADING_STATUS_LOADING) { - if (loadingStatus != IRecyclerViewFooter.LOADING_STATUS_CUSTOM) { - mHasSetLoadingStatus = true; - this.setLoadingStatus(loadingStatus); - } else { - mHasSetLoadingStatus = true; - this.setLoadingStatus(loadingStatus); - } - - if (this.mDefaultLoadingView != null) { - this.mDefaultLoadingView.measure( - MeasureSpec.makeMeasureSpec(this.mDefaultLoadingView.getWidth(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(this.mDefaultLoadingView.getHeight(), MeasureSpec.EXACTLY)); - this.mDefaultLoadingView.layout(this.mDefaultLoadingView.getLeft(), - this.mDefaultLoadingView.getTop(), this.mDefaultLoadingView.getRight(), - this.mDefaultLoadingView.getBottom()); - this.mDefaultLoadingView.invalidate(); - } - - mOnPreloadCalled = false; - } else { - mHasSetLoadingStatus = true; - this.setLoadingStatus(loadingStatus); - } - } - - protected void setPreloadItemNum(int preloadItemNum) { - mPreloadItemNum = preloadItemNum; - mShouldUpdatePreloadDistance = true; - } - - protected void setEnableScrollForReport(boolean enableScrollForReport) { - mEnableScrollForReport = enableScrollForReport; - } - - protected void setEnableExposureReport(boolean enableExposureReport) { - mEnableExposureReport = enableExposureReport; - } - - protected void checkScrollForReport() { - if (!mEnableScrollForReport) { - return; - } - - int startEdgePos = (int) PixelUtil.px2dp(mParentRecyclerView.mOffsetY); - int endEdgePos = (int) PixelUtil - .px2dp(mParentRecyclerView.getHeight() + mParentRecyclerView.mOffsetY); - int firstVisiblePos = ((HippyWaterfallLayoutManager) mParentRecyclerView - .getLayoutManager()).findFirstVisibleItemPosition(); - int lastVisiblePos = ((HippyWaterfallLayoutManager) mParentRecyclerView - .getLayoutManager()).findLastVisibleItemPosition(); - if (lastVisiblePos >= 1 && mParentRecyclerView.getLayoutManager() - .findViewByPosition(lastVisiblePos) instanceof HippyPullFooterView) { - lastVisiblePos = lastVisiblePos - 1; - } - - if (mParentRecyclerView.mViewFlinger.getScroller() == null) { - return; - } - - float currentVelocity = Math - .abs(mParentRecyclerView.mViewFlinger.getScroller().getCurrVelocity()); - int currentScrollState = mParentRecyclerView.getScrollState(); - - HippyArray visibleItemArray = new HippyArray(); - for (int i = firstVisiblePos; i <= lastVisiblePos; i++) { - View v = mParentRecyclerView.getLayoutManager() - .findViewByPosition(i); - if (v != null) { - HippyMap itemData = new HippyMap(); - itemData.pushInt("x", v.getLeft()); - itemData.pushInt("y", v.getTop() + mOffsetY); - itemData.pushInt("width", (int) PixelUtil.px2dp(getItemWidth(i))); - itemData.pushInt("height", (int) PixelUtil.px2dp(getItemHeight(i))); - - visibleItemArray.pushMap(itemData); - } - } - - handleCurrentScrollStateInner(startEdgePos, endEdgePos, firstVisiblePos, lastVisiblePos, - currentVelocity, currentScrollState, visibleItemArray); - } - - void handleCurrentScrollStateInner(int startEdgePos, int endEdgePos, - int firstVisiblePos, int lastVisiblePos, float currentVelocity, - int currentScrollState, - HippyArray visibleItemArray) { - if ((currentScrollState == RecyclerViewBase.SCROLL_STATE_IDLE - || currentScrollState == RecyclerViewBase.SCROLL_STATE_DRAGGING) && checkNeedToReport(0, - currentScrollState)) { - sendOnScrollForReport(startEdgePos, endEdgePos, firstVisiblePos, lastVisiblePos, - currentScrollState, visibleItemArray); - } else if (currentVelocity < mParentRecyclerView.getHeight() * 2 && checkNeedToReport( - currentVelocity, currentScrollState)) { - sendOnScrollForReport(startEdgePos, endEdgePos, firstVisiblePos, lastVisiblePos, - currentScrollState, visibleItemArray); - } - } - - private void sendOnScrollForReport(int startEdgePos, int endEdgePos, int firstVisiblePos, - int lastVisiblePos, - int currentScrollState, HippyArray visibleItemArray) { - mHasOnScrollForReport = true; - - if (mScrollReportResultMap == null) { - mScrollReportResultMap = new HippyMap(); - } - mScrollReportResultMap.clear(); - mScrollReportResultMap.pushInt("startEdgePos", startEdgePos); - mScrollReportResultMap.pushInt("endEdgePos", endEdgePos); - mScrollReportResultMap.pushInt("firstVisibleRowIndex", firstVisiblePos); - mScrollReportResultMap.pushInt("lastVisibleRowIndex", lastVisiblePos); - mScrollReportResultMap.pushInt("scrollState", currentScrollState); - mScrollReportResultMap.pushArray("visibleRowFrames", visibleItemArray); - getOnScrollForReportEvent().send(mParentRecyclerView, mScrollReportResultMap); - } - - protected void checkExposureForReport(int oldState, int newState) { - if (!mEnableExposureReport) { - return; - } - - ExposureForReport exposureForReport = getExposureForReport(oldState, newState); - if (exposureForReport == null) { - return; - } - if (checkNeedToReport(exposureForReport.mVelocity, newState)) { - if (mExposureReportResultMap == null) { - mExposureReportResultMap = new HippyMap(); - } - mExposureReportResultMap.clear(); - mExposureReportResultMap.pushInt("startEdgePos", exposureForReport.mStartEdgePos); - mExposureReportResultMap.pushInt("endEdgePos", exposureForReport.mEndEdgePos); - mExposureReportResultMap - .pushInt("firstVisibleRowIndex", exposureForReport.mFirstVisibleRowIndex); - mExposureReportResultMap - .pushInt("lastVisibleRowIndex", exposureForReport.mLastVisibleRowIndex); - mExposureReportResultMap.pushInt("scrollState", exposureForReport.mScrollState); - mExposureReportResultMap.pushArray("visibleRowFrames", exposureForReport.mVisibleRowFrames); - - exposureForReport.send(mParentRecyclerView, mExposureReportResultMap); - } - } - - protected ExposureForReport getExposureForReportInner(int oldState, int newState) { - if (!mEnableExposureReport) { - return null; - } - - if (mParentRecyclerView.mViewFlinger.getScroller() == null) { - return null; - } - mHasExposureReport = true; - - int startEdgePos = (int) PixelUtil.px2dp(mParentRecyclerView.mOffsetY); - int endEdgePos = (int) PixelUtil - .px2dp(mParentRecyclerView.getHeight() + mParentRecyclerView.mOffsetY); - int firstVisiblePos = ((HippyWaterfallLayoutManager) mParentRecyclerView - .getLayoutManager()).findFirstVisibleItemPosition(); - int lastVisiblePos = ((HippyWaterfallLayoutManager) mParentRecyclerView - .getLayoutManager()).findLastVisibleItemPosition(); - if (lastVisiblePos >= 1 && mParentRecyclerView.getLayoutManager() - .findViewByPosition(lastVisiblePos) instanceof HippyPullFooterView) { - lastVisiblePos = lastVisiblePos - 1; - } - HippyArray visibleItemArray = new HippyArray(); - - for (int i = firstVisiblePos; i <= lastVisiblePos; i++) { - View v = mParentRecyclerView.getLayoutManager() - .findViewByPosition(i); - if (v != null) { - HippyMap itemData = new HippyMap(); - itemData.pushInt("x", v.getLeft()); - itemData.pushInt("y", v.getTop() + mOffsetY); - itemData.pushInt("width", (int) PixelUtil.px2dp(getItemWidth(i))); - itemData.pushInt("height", (int) PixelUtil.px2dp(getItemHeight(i))); - - visibleItemArray.pushMap(itemData); - } - } - - float currentVelocity = Math - .abs(mParentRecyclerView.mViewFlinger.getScroller().getCurrVelocity()); - return new ExposureForReport(mParentRecyclerView.getId(), startEdgePos, endEdgePos, - firstVisiblePos, lastVisiblePos, (int) currentVelocity, newState, - visibleItemArray); - } - - - protected boolean checkNeedToReport(float velocity, int scrollState) { - return true; - } - - @Override - public void onPreload() { - mHasPreload = true; - - mOnPreloadCalled = true; - } - - public boolean hasCustomRecycler() { - return true; - } - - ViewHolder findBestHolderRecursive(int position, int targetType, - Recycler recycler) { - ViewHolder matchHolder = getScrapViewForPositionInner(position, - targetType, recycler); - if (matchHolder == null) { - matchHolder = recycler.getViewHolderForPosition(position); - } - - if (matchHolder != null && ((NodeHolder) matchHolder.mContentHolder).mBindNode - .isDelete()) { - matchHolder = findBestHolderRecursive(position, targetType, recycler); - } - - return matchHolder; - } - - @Override - public ViewHolder findBestHolderForPosition(int position, - Recycler recycler) { - int targetType = getItemViewType(position); - return findBestHolderRecursive(position, targetType, recycler); - } - - private ViewHolder getScrapViewForPositionInner(int position, int type, - Recycler recycler) { - final int scrapCount = recycler.mAttachedScrap.size(); - // Try first for an exact, non-invalid match from scrap. - for (int i = 0; i < scrapCount; i++) { - final ViewHolder holder = recycler.mAttachedScrap.get(i); - if (holder.getPosition() == position && !holder.isInvalid() && (!holder - .isRemoved())) { - if (holder.getItemViewType() == type - && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - RenderNode toNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()).getChildAt(position); - if (holderNode == toNode) { - recycler.mAttachedScrap.remove(i); - holder.setScrapContainer(null); - return holder; - } - } - } - } - - // Search in our first-level recycled view cache. - final int cacheSize = recycler.mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) { - final ViewHolder holder = recycler.mCachedViews.get(i); - if (holder.getPosition() == position && holder.getItemId() == type && !holder - .isInvalid() && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - RenderNode toNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()).getChildAt(position); - if (holderNode == toNode) { - recycler.mCachedViews.remove(i); - return holder; - } - } - } - // Give up. Head to the shared pool. - return this.getRecycledViewFromPoolInner(recycler.getRecycledViewPool(), type, position); - } - - private ViewHolder getRecycledViewFromPoolInner( - RecycledViewPool pool, int viewType, int position) { - if (pool != null) { - final ArrayList scrapHeap = pool.mScrap.get(viewType); - if (scrapHeap != null && !scrapHeap.isEmpty()) { - // traverse all scrap - for (ViewHolder holder : scrapHeap) { - if (holder.getItemViewType() == viewType - && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - RenderNode toNode = mHippyContext.getRenderManager() - .getRenderNode(mParentRecyclerView.getId()) - .getChildAt(position); - if (holderNode == toNode) { - scrapHeap.remove(holder); - return holder; - } - } - } - } - } - return null; - } - - private void checkHolderType(int oldType, int newType, - HippyWaterfallItemRenderNode listItemRenderNode) { - //do checkHolderType onScreen - if (doCheckHolderTypeOnScreen(oldType, newType, listItemRenderNode)) { - return; - } - - //do checkHolderType inCache - final int scrapCount = mRecycler.mAttachedScrap.size(); - // Try first for an exact, non-invalid match from scrap. - for (int i = 0; i < scrapCount; i++) { - final ViewHolder holder = mRecycler.mAttachedScrap.get(i); - - if (holder.getItemViewType() == oldType - && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - return; - } - } - } - - // Search in our first-level recycled view cache. - final int cacheSize = mRecycler.mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) { - final ViewHolder holder = mRecycler.mCachedViews.get(i); - if (holder.getItemViewType() == oldType - && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - return; - } - } - } - - // Give up. Head to the shared pool. - doHeadToTheSharedPool(oldType, newType, listItemRenderNode); - } - - private boolean doCheckHolderTypeOnScreen(int oldType, int newType, - HippyWaterfallItemRenderNode listItemRenderNode) { - int count = mParentRecyclerView.getChildCount(); - for (int i = 0; i < count; i++) { - final ViewHolder holder = mParentRecyclerView - .getChildViewHolder(mParentRecyclerView.getChildAt(i)); - if (holder.getItemViewType() == oldType - && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - return true; - } - } - } - return false; - } - - private void doHeadToTheSharedPool(int oldType, int newType, - HippyWaterfallItemRenderNode listItemRenderNode) { - if (mRecycler.getRecycledViewPool() != null) { - final ArrayList scrapHeap = mRecycler - .getRecycledViewPool().mScrap.get(oldType); - if (scrapHeap != null && !scrapHeap.isEmpty()) { - // traverse all scrap - for (ViewHolder holder : scrapHeap) { - if (holder.getItemViewType() == oldType - && holder.mContentHolder instanceof NodeHolder) { - RenderNode holderNode = ((NodeHolder) holder.mContentHolder).mBindNode; - if (holderNode == listItemRenderNode) { - holder.setItemViewType(newType); - scrapHeap.remove(holder); - mRecycler.getRecycledViewPool().getScrapHeapForType(newType) - .add(holder); - return; - } - } - } - } - } - } - - @Override - public int getPreloadThresholdInItemNumber() { - return mPreloadItemNum; - } - - @Override - public int calcPreloadThresholdWithItemNumber() { - if (mShouldUpdatePreloadDistance) { - int startIndex = getItemCount() - 1; - int endIndex = getItemCount() - mPreloadItemNum; - if (endIndex < 0) { - endIndex = 0; - } - mPreloadDistanceWithItemNumber = 0; - for (int i = startIndex; i >= endIndex; i--) { - mPreloadDistanceWithItemNumber += getItemHeight(i); - } - mShouldUpdatePreloadDistance = false; - } - return mPreloadDistanceWithItemNumber; - } - - @Override - public void onSuddenStop() { - checkScrollForReport(); - } - - private HippyWaterfallEvent getOnFooterAppearedEvent() { - if (mOnFooterAppearedEvent == null) { - mOnFooterAppearedEvent = new HippyWaterfallEvent("onFooterAppeared"); - } - return mOnFooterAppearedEvent; - } - - @Override - public void onRecycleItemTypeChanged(int oldType, int newType, - HippyWaterfallItemRenderNode listItemNode) { - checkHolderType(oldType, newType, listItemNode); - } - - private HippyWaterfallEvent getOnRefreshEvent() { - if (mOnRefreshEvent == null) { - mOnRefreshEvent = new HippyWaterfallEvent("onRefresh"); - } - return mOnRefreshEvent; - } - - private HippyWaterfallEvent getOnScrollForReportEvent() { - if (mOnScrollForReportEvent == null) { - mOnScrollForReportEvent = new HippyWaterfallEvent("onScrollForReport"); - } - return mOnScrollForReportEvent; - } - - public OnListScrollListener getOnListScrollListener() { - if (mOnListScrollListener == null) { - mOnListScrollListener = new OnListScrollListener() { - @Override - public void onStartDrag() { - - } - - @Override - public void onScroll(int i, int i1) { - if (mParentRecyclerView instanceof HippyWaterfallView - && ((HippyWaterfallView) mParentRecyclerView) - .enableOnSrollReport()) { - checkScrollForReport(); - } - } - - @Override - public void onScrollEnd() { - checkScrollForReport(); - } - - @Override - public void onDragEnd() { - - } - - @Override - public void onStartFling() { - - } - }; - } - return mOnListScrollListener; - } - } - - private static class NodeHolder extends ContentHolder { - - public RenderNode mBindNode; - public boolean isCreated = true; - - @Override - public String toString() { - return "NodeHolder@" + Integer.toHexString(hashCode()) + " created=" + isCreated - + " node=" + mBindNode.toString(); - } - } - - public static class RNWFRecyclerPool extends RecycledViewPool { - - @Override - public void putRecycledView(ViewHolder scrap, Adapter adapter) { - final int viewType = scrap.getItemViewType(); - final ArrayList scrapHeap = getScrapHeapForType(viewType); - if (mMaxScrap.get(viewType) <= scrapHeap.size()) { - ViewHolder head = (ViewHolder) scrapHeap.get(0); - scrapHeap.remove(0); - if (adapter instanceof Adapter && head instanceof ViewHolderWrapper) { - ((HippyWaterfallAdapter) adapter) - .onViewAbandonHelper((ViewHolderWrapper) head);//scrap); - } - //return; - } - scrap.mPosition = NO_POSITION; - //scrap.mDraggedPosition = NO_POSITION; - scrap.mOldPosition = NO_POSITION; - scrap.mItemId = NO_ID; - scrap.clearFlagsForSharedPool(); - scrapHeap.add(scrap); - } - } - - public static class ExposureForReport extends HippyViewEvent { - - public int mStartEdgePos = 0; - public int mEndEdgePos = 0; - public int mFirstVisibleRowIndex = 0; - public int mLastVisibleRowIndex = 0; - public int mVelocity = 0; - public int mScrollState = 0; - public HippyArray mVisibleRowFrames = null; - - public ExposureForReport(int tag, int startEdgePos, int endEdgePos, int firstVisiblePos, - int lastVisiblePos, int velocity, int scrollState, HippyArray visibleItemArray) { - super("onExposureReport"); - mStartEdgePos = startEdgePos; - mEndEdgePos = endEdgePos; - mFirstVisibleRowIndex = firstVisiblePos; - mLastVisibleRowIndex = lastVisiblePos; - mVelocity = velocity; - mScrollState = scrollState; - mVisibleRowFrames = visibleItemArray; - } - } - - private OnInitialListReadyEvent getOnInitialListReadyEvent() { - if (mOnInitialListReadyEvent == null) { - mOnInitialListReadyEvent = new OnInitialListReadyEvent("initialListReady"); - } - return mOnInitialListReadyEvent; - } - - private static class OnInitialListReadyEvent extends HippyViewEvent { - - public OnInitialListReadyEvent(String eventName) { - super(eventName); - } - } - - static class HippyWaterfallEvent extends HippyViewEvent { - - String eventName; - - public HippyWaterfallEvent(String name) { - super(name); - eventName = name; - } - - @Override - public void send(View view, Object param) { - super.send(view, param); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallViewController.java deleted file mode 100644 index 92f54406d1a..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallViewController.java +++ /dev/null @@ -1,256 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -import android.content.Context; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.HippyViewController; -import com.tencent.mtt.hippy.uimanager.RenderNode; -import com.tencent.mtt.hippy.utils.PixelUtil; -import com.tencent.mtt.supportui.views.recyclerview.IRecyclerViewFooter; - -@HippyController(name = WaterFallComponentName.CONTAINER) -public class HippyWaterfallViewController extends HippyViewController { - - static final String TAG = WaterFallComponentName.CONTAINER; - - @Override - protected void addView(ViewGroup parentView, View view, int index) { - } - - @Override - public int getChildCount(HippyWaterfallView viewGroup) { - return ((HippyWaterfallView.HippyWaterfallAdapter) viewGroup.getAdapter()) - .getRecyclerItemCount(); - } - - @Override - public View getChildAt(HippyWaterfallView viewGroup, int i) { - return ((HippyWaterfallView.HippyWaterfallAdapter) viewGroup.getAdapter()) - .getRecyclerItemView(i); - } - - @Override - protected View createViewImpl(Context context) { - return new HippyWaterfallView(context); - } - - @Override - public RenderNode createRenderNode(int id, HippyMap props, String className, - HippyRootView hippyRootView, ControllerManager controllerManager, - boolean lazy) { - return new HippyWaterfallViewNode(id, props, className, hippyRootView, controllerManager, - lazy); - } - - @Override - public void onBatchComplete(HippyWaterfallView view) { - Log.d(TAG, "onBatchComplete #" + view.getId()); - super.onBatchComplete(view); - view.setListData(); - } - - @HippyControllerProps(name = "containBannerView", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setContainBannerView(HippyWaterfallView listview, boolean containBannerView) { - ((HippyWaterfallLayoutManager) listview.getLayoutManager()) - .setContainBannerView(containBannerView); - } - - @HippyControllerProps(name = WaterFallComponentName.PROPERTY_CONTENT_INSET, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setContentInset(HippyWaterfallView listview, HippyMap data) { - int left = dpToPx(data.getInt("left")); - int top = dpToPx(data.getInt("top")); - int right = dpToPx(data.getInt("right")); - int bottom = dpToPx(data.getInt("bottom")); - - listview.setPadding(left, top, right, bottom); - } - - protected int dpToPx(int dp) { - return (int) PixelUtil.dp2px(dp); - } - - @HippyControllerProps(name = WaterFallComponentName.PROPERTY_ITEM_SPACING, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setItemSpacing(HippyWaterfallView listview, int spacing) { - ((HippyWaterfallLayoutManager) listview.getLayoutManager()) - .setItemGap(dpToPx(spacing)); - } - - @HippyControllerProps(name = WaterFallComponentName.PROPERTY_COLUMN_SPACING, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) - public void setColumnSpacing(HippyWaterfallView listview, int spacing) { - ((HippyWaterfallLayoutManager) listview.getLayoutManager()) - .setColumnSpacing(dpToPx(spacing)); - } - - @HippyControllerProps(name = "paddingStartZero", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = true) - public void setPaddingStartZero(HippyWaterfallView listview, boolean paddingStartZero) { - ((HippyWaterfallLayoutManager) listview.getLayoutManager()) - .setPaddingStartZero(paddingStartZero); - } - - @HippyControllerProps(name = "bannerViewMatch", defaultType = HippyControllerProps.BOOLEAN, defaultBoolean = false) - public void setBannerViewMatch(HippyWaterfallView listview, boolean bannerViewMatch) { - ((HippyWaterfallLayoutManager) listview.getLayoutManager()) - .setBannerViewMatch(bannerViewMatch); - } - - @HippyControllerProps(name = WaterFallComponentName.PROPERTY_COLUMNS, defaultType = HippyControllerProps.NUMBER, defaultNumber = 2) - public void setNumberOfColumns(HippyWaterfallView listview, int number) { - ((HippyWaterfallLayoutManager) listview.getLayoutManager()).setColumns(number); - } - - @HippyControllerProps(name = "enableLoadingFooter") - public void setEnableLoadingFooter(HippyWaterfallView listView, boolean enableFooter) { - if (enableFooter) { - listView.mEnableFooter = true; - listView.setLoadingStatus(IRecyclerViewFooter.LOADING_STATUS_FINISH, ""); - } else { - listView.setLoadingStatus(IRecyclerViewFooter.LOADING_STATUS_NONE, ""); - listView.mEnableFooter = false; - } - } - - @HippyControllerProps(name = "enableRefresh") - public void setEnableRefresh(HippyWaterfallView listView, boolean enableRefresh) { - if (enableRefresh && listView.mEnableRefresh) { - return; - } - listView.setRefreshEnabled(enableRefresh); - } - - @HippyControllerProps(name = "refreshColors") - public void setRefreshColors(HippyWaterfallView listView, HippyArray refreshColors) { - listView.setRefreshColors(refreshColors); - } - - @HippyControllerProps(name = "refreshColor") - public void setRefreshColor(HippyWaterfallView listView, int color) { - listView.setCustomRefreshColor(color, 0, 0); - } - - @HippyControllerProps(name = "preloadItemNumber") - public void setPreloadItemNumber(HippyWaterfallView listView, int preloadItemNumber) { - listView.setPreloadItemNumber(preloadItemNumber); - } - - @HippyControllerProps(name = "enableOnScrollForReport") - public void setEnableOnScrollForReport(HippyWaterfallView listView, boolean enable) { - listView.setEnableScrollForReport(enable); - } - - @HippyControllerProps(name = "enableExposureReport") - public void setOnExposureReport(HippyWaterfallView listView, boolean enable) { - listView.setEnableExposureReport(enable); - } - - // #lizard forgives - @Override - public void dispatchFunction(HippyWaterfallView listView, String functionName, - HippyArray dataArray) { - Log.e(TAG, "dispatchFunction " + functionName + dataArray.toString()); - super.dispatchFunction(listView, functionName, dataArray); - - int status; - String text; - int refreshResult; - switch (functionName) { - case "endReachedCompleted": { // 加载更多完成 - status = dataArray.getInt(0); - text = dataArray.getString(1); - refreshResult = 1; - switch (status) { - case 0: - refreshResult = 2; - break; - case 1: - refreshResult = 4; - break; - case 2: - refreshResult = 6; - break; - case 3: - refreshResult = 100; - break; - case 4: - refreshResult = 0; - } - - listView.setLoadingStatus(refreshResult, text); - break; - } - case "refreshCompleted": { - handleRefreshCompleted(listView, dataArray); - break; - } - case "startRefresh": { - Log.e("leo", "startRefresh"); -// listView.startRefresh(DEFAULT_REFRESH_TYPE); - break; - } - case "startRefreshWithType": { - int type = dataArray.getInt(0); - listView.startRefresh(type); - break; - } - case "startLoadMore": { - listView.startLoadMore(); - break; - } - case "scrollToIndex": { - int xIndex = dataArray.getInt(0); - int yIndex = dataArray.getInt(1); - boolean animated = dataArray.getBoolean(2); - listView.scrollToIndex(xIndex, yIndex, animated); - break; - } - case "scrollToContentOffset": { - double xOffset = dataArray.getDouble(0); - double yOffset = dataArray.getDouble(1); - boolean animated = dataArray.getBoolean(2); - listView.scrollToContentOffset(xOffset, yOffset, animated); - break; - } - case "callExposureReport": { - listView.onScrollStateChanged(listView.getScrollState(), listView.getScrollState()); - break; - } - case "setRefreshPromptInfo": { - String descriptionText = dataArray.getString(0); - int descriptionTextColor = dataArray.getInt(1); - int descriptionTextFontSize = dataArray.getInt(2); - String imgUrl = dataArray.getString(3); - int imgWidth = dataArray.getInt(4); - int imgHeight = dataArray.getInt(5); - listView.setRefreshPromptInfo(descriptionText, descriptionTextColor, - descriptionTextFontSize, imgUrl, imgWidth, imgHeight); - break; - } - default: - break; - } - } - - private void handleRefreshCompleted(HippyWaterfallView listView, HippyArray dataArray) { - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallViewNode.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallViewNode.java deleted file mode 100644 index 39bb00edcd3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/HippyWaterfallViewNode.java +++ /dev/null @@ -1,46 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -import com.tencent.mtt.hippy.HippyRootView; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.ControllerManager; -import com.tencent.mtt.hippy.uimanager.RenderNode; - -public class HippyWaterfallViewNode extends RenderNode { - - static final String TAG = "HippyWaterfallViewNode"; - - public HippyWaterfallViewNode(int mId, HippyMap mPropsToUpdate, String className, - HippyRootView mRootView, ControllerManager componentManager, - boolean isLazyLoad) { - super(mId, mPropsToUpdate, className, mRootView, componentManager, isLazyLoad); - } - - @Override - protected void addChildToPendingList(RenderNode renderNode) { - } - - @Override - public boolean removeChild(RenderNode uiNode) { - if (uiNode instanceof HippyWaterfallItemRenderNode) { - HippyWaterfallItemRenderNode listItemRenderNode = (HippyWaterfallItemRenderNode) uiNode; - listItemRenderNode.setRecycleItemTypeChangeListener(null); - } - return super.removeChild(uiNode); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/WaterFallComponentName.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/WaterFallComponentName.java deleted file mode 100644 index 1e8715b723f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/WaterFallComponentName.java +++ /dev/null @@ -1,28 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.waterfalllist; - -class WaterFallComponentName { - - public static final String CONTAINER = "WaterfallView"; - public static final String ITEM = "WaterfallItem"; - - public static final String PROPERTY_COLUMNS = "numberOfColumns"; - public static final String PROPERTY_ITEM_SPACING = "interItemSpacing"; - public static final String PROPERTY_COLUMN_SPACING = "columnSpacing"; - public static final String PROPERTY_CONTENT_INSET = "contentInset"; - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/WaterfallEndChecker.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/WaterfallEndChecker.java deleted file mode 100644 index 1f5ca00e561..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/waterfalllist/WaterfallEndChecker.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.tencent.mtt.hippy.views.waterfalllist; - -import android.view.View; -import com.tencent.mtt.hippy.views.waterfalllist.HippyWaterfallView.HippyWaterfallEvent; - -/** - * @author hengyangji - * on 2021/8/11 - */ -public class WaterfallEndChecker { - - private boolean isVerticalEnd = false; - public void onScroll(HippyWaterfallView waterfallView, int y) { - boolean currentVerticalEnd = checkVerticalEnd(waterfallView, y); - if (!isVerticalEnd && currentVerticalEnd) { - new HippyWaterfallEvent("onEndReached").send(waterfallView, null); - } - isVerticalEnd = currentVerticalEnd; - } - - private boolean checkVerticalEnd(HippyWaterfallView waterfallView, int y) { - HippyWaterfallLayoutManager layoutManager = (HippyWaterfallLayoutManager)waterfallView.getLayoutManager(); - int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); - boolean scrollToLastItem = lastVisibleItemPosition == layoutManager.getItemCount() - 1; - if (scrollToLastItem) { //滑到最后一位了 - View lastView = waterfallView.findViewByPosition(lastVisibleItemPosition); - return lastView.getBottom() <= waterfallView.getBottom(); - } - return false; - } -} - - diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/webview/HippyWebViewController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/webview/HippyWebViewController.java deleted file mode 100644 index be6a6cde784..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/webview/HippyWebViewController.java +++ /dev/null @@ -1,96 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.hippy.views.webview; - -import android.content.Context; -import android.text.TextUtils; -import android.view.View; - -import com.tencent.mtt.hippy.annotation.HippyController; -import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.common.HippyArray; -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.uimanager.HippyViewController; - -@SuppressWarnings({"deprecation", "unused"}) -@HippyController(name = HippyWebViewController.CLASS_NAME) -public class HippyWebViewController extends HippyViewController { - - public static final String CLASS_NAME = "WebView"; - - @HippyControllerProps(name = "url", defaultType = HippyControllerProps.STRING) - public void loadUrl(HippyWebView view, String url) { - if (!TextUtils.isEmpty(url)) { - view.mWebView.loadUrl(url); - } - } - - @Override - public void dispatchFunction(HippyWebView view, String functionName, HippyArray var) { - super.dispatchFunction(view, functionName, var); - if ("loadUrl".equals(functionName)) { - if (var != null) { - String url = var.getString(0); - loadUrl(view, url); - } - } - } - - @Override - protected View createViewImpl(Context context) { - return new HippyWebView(context); - } - - @HippyControllerProps(name = "source", defaultType = HippyControllerProps.MAP) - public void source(HippyWebView webView, HippyMap info) { - if (info != null) { - String userAgent = info.getString("userAgent"); - if (!TextUtils.isEmpty(userAgent)) { - webView.mWebView.getSettings().setUserAgentString(userAgent); - } - String uri = info.getString("uri"); - if (!TextUtils.isEmpty(uri)) { - String method = info.getString("method"); - if ("POST".equalsIgnoreCase(method)) { - String body = info.getString("body"); - webView.mWebView.postUrl(uri, body == null ? null : body.getBytes()); - } else { - webView.mWebView.loadUrl(uri); - } - } else { - String html = info.getString("html"); - if (!TextUtils.isEmpty(html)) { - String baseUrl = info.getString("baseUrl"); - if (!TextUtils.isEmpty(baseUrl)) { - webView.mWebView - .loadDataWithBaseURL(baseUrl, html, "text/html; charset=utf-8", "UTF-8", null); - } else { - webView.mWebView.loadData(html, "text/html; charset=utf-8", "UTF-8"); - } - } - } - } - } - - public void onViewDestroy(HippyWebView webView) { - webView.mWebView.destroy(); - } - - @Override - protected boolean handleGestureBySelf() { - return true; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/FooterExposureHelper.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/FooterExposureHelper.java deleted file mode 100644 index 93dee1d719c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/FooterExposureHelper.java +++ /dev/null @@ -1,123 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.footer; - -import android.graphics.Rect; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import android.view.View; -import android.view.View.OnAttachStateChangeListener; - -public class FooterExposureHelper extends RecyclerView.OnScrollListener implements - OnAttachStateChangeListener { - - private View exposureView; - private IFooterLoadMoreListener footerListener; - private boolean isViewVisible = false; - private float visibleRate = 0.3f; - private Runnable checkVisibleRunnable; - - public FooterExposureHelper() { - checkVisibleRunnable = new Runnable() { - @Override - public void run() { - if (isViewChangeToVisible(exposureView)) { - notifyFooterAppeared(); - } - } - }; - } - - /** - * 设置显示view的面积伐值,超过比例就回调显示 - * - * @param visibleRate (0,1] 1: 100%显示 - */ - public void setVisibleRate(float visibleRate) { - if (visibleRate > 0) { - this.visibleRate = Math.min(visibleRate, 1); - } - } - - /** - * @param exposureView 设置需要监控曝光的View - */ - public void setExposureView(View exposureView) { - if (this.exposureView != null) { - this.exposureView.removeCallbacks(checkVisibleRunnable); - this.exposureView.removeOnAttachStateChangeListener(this); - } - isViewVisible = false; - this.exposureView = exposureView; - if (this.exposureView != null) { - this.exposureView.addOnAttachStateChangeListener(this); - } - } - - public void setFooterListener(IFooterLoadMoreListener footerListener) { - this.footerListener = footerListener; - } - - /** - * 判断一个view在屏幕上是否可见 - */ - public boolean isViewChangeToVisible(View view) { - if (isViewVisible) { - return false; - } - if (!view.isShown()) { - isViewVisible = false; - return false; - } - Rect bounds = new Rect(); - boolean ret = view.getGlobalVisibleRect(bounds); - int totalArea = view.getWidth() * view.getHeight(); - - if (!ret || totalArea == 0) { - isViewVisible = false; - return false; - } - int viewedArea = bounds.width() * bounds.height(); - isViewVisible = viewedArea * 1f / totalArea > visibleRate; - return isViewVisible; - } - - void notifyFooterAppeared() { - if (footerListener != null) { - footerListener.onFooterLoadMore(); - } - } - - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - //onLayout排版的时候会调用过来,这里不能在排版的时候去请求数据,需要post一下 - if (exposureView != null) { - exposureView.removeCallbacks(checkVisibleRunnable); - exposureView.post(checkVisibleRunnable); - } - } - - @Override - public void onViewDetachedFromWindow(View v) { - isViewVisible = false; - } - - @Override - public void onViewAttachedToWindow(View v) { - - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/IFooterLoadMoreListener.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/IFooterLoadMoreListener.java deleted file mode 100644 index bf0cbcc9101..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/IFooterLoadMoreListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.footer; - -public interface IFooterLoadMoreListener { - - void onFooterLoadMore(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/IFooterLoadingView.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/IFooterLoadingView.java deleted file mode 100644 index ef96e99abef..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/footer/IFooterLoadingView.java +++ /dev/null @@ -1,33 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.footer; - -import android.view.View; - -public interface IFooterLoadingView { - - int LOAD_STATUS_NONE = 0; - int LOAD_STATUS_LOADING = 1; - int LOAD_STATUS_FAILED = 2; - int LOAD_STATUS_END = 3; - - View getView(); - - int getHeight(); - - void setLoadingStatus(int loadingStatus); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/HeaderRefreshHelper.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/HeaderRefreshHelper.java deleted file mode 100644 index e2fc4dc5bda..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/HeaderRefreshHelper.java +++ /dev/null @@ -1,284 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.header; - -import android.animation.Animator; -import android.animation.ValueAnimator; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.view.ViewConfiguration; -import android.view.ViewGroup.LayoutParams; -import com.tencent.mtt.nxeasy.recyclerview.helper.AnimatorListenerBase; - -public class HeaderRefreshHelper implements OnTouchListener { - - public static final int DURATION = 200; - protected View headerView; - protected IHeaderRefreshView headerRefreshView; - protected float lastRawY = -1; - protected float downRawY = -1; - protected boolean enable = true; - /// header 被下拉过程中显示出来 - private boolean isHeaderDragShowing; - private int refreshStatus = -1; - private IHeaderRefreshListener headerRefreshListener; - private ValueAnimator animator; - private ILayoutRequester layoutRequester; - private IHeaderStatusListener headerStatusListener; - - public void setEnable(boolean enable) { - this.enable = enable; - } - - public void setHeaderRefreshListener(IHeaderRefreshListener headerRefreshListener) { - this.headerRefreshListener = headerRefreshListener; - } - - public void setHeaderStatusListener(IHeaderStatusListener headerStatusListener) { - this.headerStatusListener = headerStatusListener; - } - - public void setLayoutRequester(ILayoutRequester layoutRequester) { - this.layoutRequester = layoutRequester; - } - - public void setHeaderRefreshView(IHeaderRefreshView headerLoadingView) { - this.headerRefreshView = headerLoadingView; - headerView = this.headerRefreshView.getView(); - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_FOLDED); - } - - public void onRefreshDone() { - if (refreshStatus == IHeaderRefreshView.HEADER_STATUS_REFRESHING) { - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_TO_FOLD); - smoothScrollTo(getVisibleHeight(), 0); - } - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - if (!enable) { - return false; - } - if (lastRawY == -1) { - lastRawY = event.getRawY(); - } - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - lastRawY = event.getRawY(); - downRawY = event.getRawY(); - break; - case MotionEvent.ACTION_MOVE: - //下拉的时候除以2,放慢拉动的速度,调节拉动的手感 - int deltaY = (int) (event.getRawY() - lastRawY) / 2; - lastRawY = event.getRawY(); - if (isStartMove(event) && canHandleTouchEvent()) { - endAnimation(); - setVisibleHeight(deltaY + getVisibleHeight()); - isHeaderDragShowing = isHeaderDragShowing || getVisibleHeight() > 0; - if (isHeaderDragShowing) { - onMove(); - } - } - break; - default: - isHeaderDragShowing = false; - lastRawY = -1; - downRawY = -1; - if (canHandleTouchEvent()) { - onRelease(); - } - break; - } - return isHeaderDragShowing && getVisibleHeight() > 0; - } - - private boolean isStartMove(MotionEvent event) { - return Math.abs(event.getRawY() - downRawY - getTouchSlop()) > 0; - } - - private int getTouchSlop() { - final ViewConfiguration vc = ViewConfiguration.get(headerView.getContext()); - return vc.getScaledTouchSlop(); - } - - /** - * 松口手后,需要回弹,可能进行两个状态的流转 - */ - private void onRelease() { - if (refreshStatus == IHeaderRefreshView.HEADER_STATUS_DRAGGING) { - if (isViewExposure(headerView)) { - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_DRAG_TO_REFRESH); - } else { - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_TO_FOLD); - } - } - if (isViewExposure(headerView)) { - smoothScrollTo(getVisibleHeight(), headerRefreshView.getContentHeight()); - } else { - smoothScrollTo(getVisibleHeight(), 0); - } - } - - private void setRefreshStatus(int newStatus) { - if (headerStatusListener != null) { - headerStatusListener.onHeaderStatusChanged(refreshStatus, newStatus); - } - this.refreshStatus = newStatus; - } - - private void onMove() { - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_DRAGGING); - headerRefreshView.onStartDrag(); - } - - /** - * 下拉之后,当正在刷新的时候,将位置从下拉到的位置恢复规定的位置的动画 - * - * @param destHeight 规定的高度 - */ - private void smoothScrollTo(int fromHeight, int destHeight) { - endAnimation(); - animator = ValueAnimator.ofInt(fromHeight, destHeight); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - setVisibleHeight((int) animation.getAnimatedValue()); - } - }); - animator.addListener(new AnimatorListenerBase() { - @Override - public void onAnimationEnd(Animator animation) { - if (isGoingToRefresh()) { - gotoRefresh(); - } - if (refreshStatus == IHeaderRefreshView.HEADER_STATUS_TO_FOLD) { - setFolded(); - } - } - }); - animator.setDuration(DURATION).start(); - } - - void gotoRefresh() { - headerRefreshListener.onHeaderRefreshing(refreshStatus); - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_REFRESHING); - headerRefreshView.onRefreshing(); - } - - private void setFolded() { - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_FOLDED); - headerRefreshView.onFolded(); - } - - - /** - * 返回当前的可视高度 - */ - public int getVisibleHeight() { - if (!enable) { - return 0; - } - LayoutParams layoutParams = headerView.getLayoutParams(); - if (layoutParams == null) { - return 0; - } - return layoutParams.height; - } - - private void setVisibleHeight(int height) { - LayoutParams layoutParams = headerView.getLayoutParams(); - layoutParams.height = Math.max(height, 0); - headerView.setLayoutParams(layoutParams); - if (layoutRequester != null) { - layoutRequester.requestLayout(); - } - headerRefreshView.onHeaderHeightChanged(Math.max(getVisibleHeight(), 0)); - } - - private boolean canHandleTouchEvent() { - return headerView.isShown(); - } - - /** - * 判断View是否已经完全显示出来 - */ - private boolean isViewExposure(View view) { - return view.getHeight() >= headerRefreshView.getContentHeight(); - } - - /** - * 触发刷新 - */ - public void triggerRefresh() { - if (refreshStatus == IHeaderRefreshView.HEADER_STATUS_FOLDED) { - setRefreshStatus(IHeaderRefreshView.HEADER_STATUS_CLICK_TO_REFRESH); - smoothScrollTo(0, headerRefreshView.getContentHeight()); - } - } - - public void triggerRefresh(boolean hasAnimation) { - if (hasAnimation) { - triggerRefresh(); - } else { - setVisibleHeight(headerRefreshView.getContentHeight()); - gotoRefresh(); - } - } - - /** - * 是否处于手动的拖动过程中 - * - * @return - */ - public boolean isDragging() { - return refreshStatus == IHeaderRefreshView.HEADER_STATUS_DRAGGING; - } - - public boolean isGoingToRefresh() { - return refreshStatus == IHeaderRefreshView.HEADER_STATUS_DRAG_TO_REFRESH || - refreshStatus == IHeaderRefreshView.HEADER_STATUS_CLICK_TO_REFRESH; - } - - /** - * 改变header的高度 - * - * @param dy dy>0 header的高度变小,反之变大 - */ - public void rollBackHeaderHeight(int dy) { - setVisibleHeight(getVisibleHeight() - dy); - } - - /** - * 收起header,将状态置为folded状态 - */ - public void reset() { - endAnimation(); - setVisibleHeight(0); - setFolded(); - } - - private void endAnimation() { - if (animator != null) { - animator.removeAllListeners(); - animator.removeAllUpdateListeners(); - animator.end(); - animator = null; - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderRefreshListener.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderRefreshListener.java deleted file mode 100644 index 2daefe5e067..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderRefreshListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.header; - -public interface IHeaderRefreshListener { - - /** - * @param refreshWay 刷新触发的方式,目前只要两种方式 {@link IHeaderRefreshView#HEADER_STATUS_CLICK_TO_REFRESH} - * {@link IHeaderRefreshView#HEADER_STATUS_DRAG_TO_REFRESH} - */ - void onHeaderRefreshing(int refreshWay); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderRefreshView.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderRefreshView.java deleted file mode 100644 index b763d5a1245..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderRefreshView.java +++ /dev/null @@ -1,48 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.header; - -import android.view.View; - -public interface IHeaderRefreshView { - - /** - * 状态机: 1:HEADER_STATUS_FOLDED -> HEADER_STATUS_DRAGGING 2:HEADER_STATUS_DRAGGING-> - * HEADER_STATUS_TO_REFRESH ,或者HEADER_STATUS_DRAGGING-> HEADER_STATUS_TO_FOLD - * 3:HEADER_STATUS_DRAG_TO_REFRESH -> HEADER_STATUS_REFRESHING 4:HEADER_STATUS_CLICK_TO_REFRESH -> - * HEADER_STATUS_REFRESHING 5:HEADER_STATUS_REFRESHING -> HEADER_STATUS_TO_FOLD - * 6:HEADER_STATUS_TO_FOLD -> HEADER_STATUS_FOLDED - */ - int HEADER_STATUS_FOLDED = 0;//收起状态 - int HEADER_STATUS_DRAGGING = 1;//拖动状态 - int HEADER_STATUS_DRAG_TO_REFRESH = 2;//下拉拖动触发刷新 - int HEADER_STATUS_CLICK_TO_REFRESH = 3;//外部点击触发刷新 - int HEADER_STATUS_REFRESHING = 4;//正在刷新 - int HEADER_STATUS_TO_FOLD = 5;//去向收起 - - View getView(); - - void onStartDrag(); - - void onHeaderHeightChanged(int sumOffset); - - void onRefreshing(); - - int getContentHeight(); - - void onFolded(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderStatusListener.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderStatusListener.java deleted file mode 100644 index b7ec17007d8..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/IHeaderStatusListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.header; - -public interface IHeaderStatusListener { - - void onHeaderStatusChanged(int oldStatus, int newStatus); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/ILayoutRequester.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/ILayoutRequester.java deleted file mode 100644 index 54fc3e46ec2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/header/ILayoutRequester.java +++ /dev/null @@ -1,22 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.header; - -public interface ILayoutRequester { - - void requestLayout(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/IHeaderAttachListener.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/IHeaderAttachListener.java deleted file mode 100644 index 62183c40b0a..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/IHeaderAttachListener.java +++ /dev/null @@ -1,31 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.skikcy; - -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import android.view.View; - -public interface IHeaderAttachListener { - - /** - * header被摘下来,需要对header进行还原或者回收对处理 - * - * @param aboundHeader HeaderView对应的Holder - * @param currentHeaderView headerView的实体内容 - */ - void onHeaderDetached(ViewHolder aboundHeader, View currentHeaderView); - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/IHeaderHost.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/IHeaderHost.java deleted file mode 100644 index 6a89970ff3f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/IHeaderHost.java +++ /dev/null @@ -1,29 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.skikcy; - -import android.view.View; -import android.view.ViewTreeObserver.OnGlobalLayoutListener; -import android.widget.FrameLayout.LayoutParams; - -public interface IHeaderHost { - - void attachHeader(View headerView, LayoutParams layoutParams); - - void addOnLayoutListener(OnGlobalLayoutListener listener); - - void removeOnLayoutListener(OnGlobalLayoutListener listener); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/StickyHeaderHelper.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/StickyHeaderHelper.java deleted file mode 100644 index b02b693c595..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/StickyHeaderHelper.java +++ /dev/null @@ -1,242 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.skikcy; - -import static androidx.recyclerview.widget.RecyclerView.HORIZONTAL; -import static androidx.recyclerview.widget.RecyclerView.VERTICAL; - -import androidx.recyclerview.widget.EasyRecyclerView; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.OnScrollListener; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout.LayoutParams; - -public class StickyHeaderHelper extends OnScrollListener implements - ViewTreeObserver.OnGlobalLayoutListener { - - private static final int INVALID_POSITION = -1; - private final IHeaderAttachListener headerAttachListener; - private EasyRecyclerView recyclerView; - private IStickyItemsProvider stickyItemsProvider; - private StickyViewFactory stickyViewFactory; - private ViewHolder headerOrgViewHolder; - private boolean orgViewHolderCanRecyclable = false; - private View currentHeaderView; - private int orientation; - private int currentStickPos = -1; - private IHeaderHost headerHost; - - public StickyHeaderHelper(final EasyRecyclerView recyclerView, - IStickyItemsProvider stickyItemsProvider, - IHeaderAttachListener headerAttachListener, IHeaderHost headerHost) { - this.recyclerView = recyclerView; - this.headerAttachListener = headerAttachListener; - this.stickyItemsProvider = stickyItemsProvider; - stickyViewFactory = new StickyViewFactory(recyclerView); - this.headerHost = headerHost; - orientation = recyclerView.getLayoutManager().canScrollVertically() ? VERTICAL : HORIZONTAL; - } - - /** - * 1、寻找stickyHeader 2、挂载stickyHeader 3、设置stickyHeader的偏移 - */ - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - int newStickyPosition = getStickyItemPosition(); - if (currentStickPos != newStickyPosition) { - detachSticky(); - attachSticky(newStickyPosition); - } - offsetSticky(); - } - - /** - * 如果当前stickHolder和新的stickyHolder 不一样,那么把当前的stickyHolder删除掉,并还原HeaderView的Translation - */ - private void detachSticky() { - if (headerOrgViewHolder != null) { - removeViewFromParent(this.currentHeaderView); - currentHeaderView.setTranslationY(0); - currentHeaderView.setTranslationX(0); - returnHeaderBackToList(); - headerHost.removeOnLayoutListener(this); - } - currentStickPos = -1; - headerOrgViewHolder = null; - } - - /** - * 还原Header到List中去 1、ViewHolder正好是之前的ViewHolder,直接将headerView返回给headerOrgContainer - * 2、position相同,但是ViewHolder已经是不同了,出现在header的Item滑动到屏幕外,又滑回来,重新创建了一个ViewHolder - * 3、对于被顶出去的headView,是无法还原到list中的,需要把headView进行回收处理,如果不回收,Hippy场景无法重新创建View - */ - private void returnHeaderBackToList() { - headerOrgViewHolder.setIsRecyclable(orgViewHolderCanRecyclable); - if (headerAttachListener != null) { - headerAttachListener.onHeaderDetached(headerOrgViewHolder, currentHeaderView); - } else { - ViewHolder viewHolderToReturn = recyclerView - .findViewHolderForAdapterPosition(headerOrgViewHolder.getAdapterPosition()); - if (viewHolderToReturn != null && viewHolderToReturn.itemView instanceof ViewGroup) { - ViewGroup itemView = (ViewGroup) viewHolderToReturn.itemView; - //已经有孩子了,就不要加了,这个可能是新创建的ViewHolder已经有了内容 - if (itemView.getChildCount() <= 0) { - itemView.addView(this.currentHeaderView); - } - } - } - } - - /** - * 将stickyItemPosition对应的View挂载到RecyclerView的父亲上面 - */ - private void attachSticky(int newStickyPosition) { - if (newStickyPosition != INVALID_POSITION) { - headerOrgViewHolder = stickyViewFactory.getHeaderForPosition(newStickyPosition); - currentStickPos = newStickyPosition; - Log.d("returnHeader", "attachSticky:" + headerOrgViewHolder); - currentHeaderView = ((ViewGroup) headerOrgViewHolder.itemView).getChildAt(0); - removeViewFromParent(currentHeaderView); - //内容被取走了,不能被回收,避免view滑出屏幕,回收再利用,此时已经不能再被别人用了 - orgViewHolderCanRecyclable = headerOrgViewHolder.isRecyclable(); - headerOrgViewHolder.setIsRecyclable(false); - currentHeaderView.setVisibility(View.INVISIBLE); - LayoutParams layoutParams = new LayoutParams( - LayoutParams.MATCH_PARENT, 0); - ViewGroup.LayoutParams lp = headerOrgViewHolder.itemView.getLayoutParams(); - layoutParams.height = lp != null ? lp.height : LayoutParams.WRAP_CONTENT; - headerHost.addOnLayoutListener(this); - headerHost.attachHeader(currentHeaderView, layoutParams); - } - } - - /** - * 设置吸顶的View的偏移 在下一个吸顶view和当前吸顶的view交汇的时候,需要把当前吸顶view往上面移动,慢慢会把当前的吸顶view顶出屏幕 - */ - private void offsetSticky() { - if (headerOrgViewHolder != null) { - float offset = getOffset(findNextSticky(currentStickPos)); - if (orientation == VERTICAL) { - currentHeaderView.setTranslationY(offset); - } else { - currentHeaderView.setTranslationX(offset); - } - } - } - - /** - * 找到屏幕中,下一个即将吸顶的view,主要用于计算当前吸顶的HeaderView的Offset, 下一个即将吸顶的View会慢慢把当前正在吸顶的HeaderView慢慢顶出屏幕外 - */ - private View findNextSticky(int currentStickyPos) { - for (int i = 0; i < recyclerView.getChildCount(); i++) { - View nextStickyView = recyclerView.getChildAt(i); - int nextStickyPos = recyclerView.getChildLayoutPosition(nextStickyView); - if (nextStickyPos > currentStickyPos && stickyItemsProvider - .isStickyPosition(nextStickyPos)) { - return nextStickyView; - } - } - return null; - } - - /** - * 当nextStickyView和当前stickyView重叠的时候,是应该把当前的view移出屏幕外 支持水平排版和垂直排版 - */ - private float getOffset(View nextStickyView) { - float offset = 0; - View stickView = this.currentHeaderView; - if (stickView != null && nextStickyView != null) { - if (orientation == VERTICAL) { - if (nextStickyView.getY() < stickView.getHeight()) { - offset = nextStickyView.getY() - stickView.getHeight(); - } - } else { - if (stickView.isShown()) { - offset = -stickView.getWidth(); - } else if (nextStickyView.getX() < stickView.getWidth()) { - offset = stickView.getX() - stickView.getWidth(); - } - } - } - return offset; - } - - /** - * 高度确定后,设置HeaderView为可见状态,并且重新刷新offset的正确位置,解决下拉header上屏的闪烁问题 - */ - @Override - public void onGlobalLayout() { - if (currentHeaderView != null) { - currentHeaderView.setVisibility(View.VISIBLE); - offsetSticky(); - } - } - - /** - * 找到距离顶部最近的一个stickyItem的位置 - * - * @return INVALID_POSITION,没有找到stickyItem - */ - public int getStickyItemPosition() { - if (recyclerView.getChildCount() <= 0) { - return INVALID_POSITION; - } - int positionToSticky = INVALID_POSITION; - int startPosition = recyclerView.getFirstChildPosition(); - View firstView = recyclerView.getChildAt(0); - if (firstView.getY() >= 0) { - startPosition--;//当前view已经完全露出,需要往从前面一个开始寻找 - } - for (int i = startPosition; i >= 0; i--) { - if (stickyItemsProvider.isStickyPosition(i)) { - positionToSticky = i; - break; - } - } - if (positionToSticky != INVALID_POSITION) { - if (positionToSticky != recyclerView.getFirstChildPosition()) { - //positionToSticky已经被滑出屏幕,此时positionToSticky可以直接返回 - return positionToSticky; - } else { - //stickyItem和第一个孩子位置一样,如果完全和吸顶位置重合,不需要进行吸顶 - positionToSticky = - !headerAwayFromEdge(firstView) ? INVALID_POSITION : positionToSticky; - } - } - return positionToSticky; - } - - /** - * headerToCopy == null表示,headerToCopy 已经完全移除屏幕外 headerToCopy != null ,getY()<0 部分移动屏幕外 - * - * @param headerToCopy 即将被选中吸顶的view - */ - private boolean headerAwayFromEdge(View headerToCopy) { - return headerToCopy != null && (orientation == VERTICAL ? headerToCopy.getY() < 0 - : headerToCopy.getX() < 0); - } - - private void removeViewFromParent(View view) { - if (view.getParent() instanceof ViewGroup) { - ((ViewGroup) view.getParent()).removeView(view); - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/StickyViewFactory.java b/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/StickyViewFactory.java deleted file mode 100644 index c81a1477e36..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/nxeasy/recyclerview/helper/skikcy/StickyViewFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* Tencent is pleased to support the open source community by making easy-recyclerview-helper available. - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.nxeasy.recyclerview.helper.skikcy; - -import androidx.recyclerview.widget.EasyRecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; - -public final class StickyViewFactory implements IHeaderViewFactory { - - private final EasyRecyclerView recyclerView; - - public StickyViewFactory(EasyRecyclerView recyclerView) { - this.recyclerView = recyclerView; - } - - /** - * 根据position的位置,获取到一个实体到ViewHolder 1、先在已经上屏的view中,找到一个ViewHolder 2、第一步没有找到,就重新通过recyclerView去获取一个,这种获取的viewHolder可能是cache里面的,也可能 - * 是新创建的,不用再次进行bindViewHolder的操作 - * - * @param position 指定要获取到ViewHolder到位置 - * @return 返回对应到ViewHolder,不会返回Null - */ - public ViewHolder getHeaderForPosition(int position) { - if (position < 0) { - return null; - } - ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position); - if (viewHolder == null) { - viewHolder = recyclerView.getViewHolderForPosition(position); - } - return viewHolder; - } -} \ No newline at end of file diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IDrawableTarget.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IDrawableTarget.java deleted file mode 100644 index ad7fecfb426..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IDrawableTarget.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2018 Tencent, Inc. - * - * 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 com.tencent.mtt.supportui.adapters.image; - -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; - -public interface IDrawableTarget -{ - Drawable getDrawable(); - - Bitmap getBitmap(); - - String getSource(); - - Object getExtraData(); - - String getImageType(); - - void onDrawableAttached(); - - void onDrawableDetached(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IImageLoaderAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IImageLoaderAdapter.java deleted file mode 100644 index 3bb2c830d9b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IImageLoaderAdapter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (C) 2018 Tencent, Inc. - * - * 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 com.tencent.mtt.supportui.adapters.image; - -/** - * Created by leonardgong on 2017/12/4 0004. - */ - -public interface IImageLoaderAdapter -{ - /** - * fetch image with url and asynchronous callback - * - * @param url - * @param requestListener - */ - void fetchImage(String url, T requestListener, Object param); - - /** - * get image with url and return immediately - * - * @param url - */ - IDrawableTarget getImage(String url, Object param); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IImageRequestListener.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IImageRequestListener.java deleted file mode 100644 index 4fd989f197f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/adapters/image/IImageRequestListener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2018 Tencent, Inc. - * - * 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 com.tencent.mtt.supportui.adapters.image; - -/** - * Created by leonardgong on 2017/12/4 0004. - */ - -public interface IImageRequestListener -{ - /** - * notify image request start - * - * @param drawableTarget - */ - void onRequestStart(T drawableTarget); - - /** - * notify image request success, pass a IDrawableTarget instance - * - * @param drawableTarget - */ - void onRequestSuccess(T drawableTarget); - - /** - * notify image request fail - */ - void onRequestFail(Throwable cause, String source); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IBorder.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IBorder.java deleted file mode 100644 index b3decd6ada2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IBorder.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.tencent.mtt.supportui.views; - -public interface IBorder -{ - void setBorderRadius(float radius, int position); - - void setBorderWidth(float width, int position); - - void setBorderColor(int color, int position); - - void setBorderStyle(int style); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IGradient.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IGradient.java deleted file mode 100644 index e3ba6db4ed0..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IGradient.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.tencent.mtt.supportui.views; - -import java.util.ArrayList; - -public interface IGradient { - void setGradientAngle(String angle); - - void setGradientColors(ArrayList colors); - - void setGradientPositions(ArrayList positions); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IShadow.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IShadow.java deleted file mode 100644 index 46121f60e6b..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/IShadow.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.tencent.mtt.supportui.views; - -public interface IShadow -{ - void setShadowOffsetY(float y); - - void setShadowOffsetX(float x); - - void setShadowOpacity(float opacity); - - void setShadowRadius(float radius); - - void setShadowSpread(float spread); - - void setShadowColor(int color); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/AsyncImageView.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/AsyncImageView.java deleted file mode 100644 index 7a45b80a1e3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/AsyncImageView.java +++ /dev/null @@ -1,708 +0,0 @@ -/* Copyright (C) 2018 Tencent, Inc. - * - * 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 com.tencent.mtt.supportui.views.asyncimage; - -import com.tencent.mtt.supportui.adapters.image.IDrawableTarget; -import com.tencent.mtt.supportui.adapters.image.IImageLoaderAdapter; -import com.tencent.mtt.supportui.adapters.image.IImageRequestListener; -import com.tencent.mtt.supportui.views.IBorder; -import com.tencent.mtt.supportui.views.IGradient; -import com.tencent.mtt.supportui.views.IShadow; - -import android.animation.Animator; -import android.animation.IntEvaluator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.text.TextUtils; -import android.view.View; -import android.view.ViewGroup; -import java.util.ArrayList; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -public class AsyncImageView extends ViewGroup implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener, IBorder, IShadow, - IGradient -{ - public static final int FADE_DURATION = 150; - public final static int IMAGE_UNLOAD = 0; - public final static int IMAGE_LOADING = 1; - public final static int IMAGE_LOADED = 2; - - protected final static int SOURCE_TYPE_SRC = 1; - protected final static int SOURCE_TYPE_DEFAULT_SRC = 2; - protected IDrawableTarget mSourceDrawable; - private IDrawableTarget mDefaultSourceDrawable; - - protected String mUrl; - protected String mDefaultSourceUrl; - protected String mImageType; - - // the 'mURL' is fetched succeed - protected int mUrlFetchState = IMAGE_UNLOAD; - - protected int mTintColor; - protected ScaleType mScaleType; - protected Drawable mContentDrawable; - - private boolean mIsAttached; - protected IImageLoaderAdapter mImageAdapter; - private boolean mFadeEnable; - private long mFadeDuration; - private ValueAnimator mAlphaAnimator; - - protected BackgroundDrawable mBGDrawable; - - private int mImagePositionX; - private int mImagePositionY; - - public enum ScaleType - { - FIT_XY, - CENTER, - CENTER_INSIDE, - CENTER_CROP, - ORIGIN, - REPEAT // Robinsli add for hippy - } - - public AsyncImageView(Context context) - { - super(context); - mUrl = null; - mDefaultSourceUrl = null; - mImageType = null; - setFadeEnabled(false); - setFadeDuration(FADE_DURATION); - } - - public void setImageAdapter(IImageLoaderAdapter imageAdapter) - { - mImageAdapter = imageAdapter; - } - - public void setImageType(String type) { - mImageType = type; - } - - public void setUrl(String url) - { - if (!TextUtils.equals(url, mUrl)) - { - mUrl = url; - mUrlFetchState = IMAGE_UNLOAD; - if (isAttached()) - { - onDrawableDetached(); - fetchImageByUrl(mUrl, SOURCE_TYPE_SRC); - } - } - } - - public String getUrl() - { - return mUrl; - } - - public void setFadeEnabled(boolean enable) - { - mFadeEnable = enable; - } - - public boolean isFadeEnabled() - { - return mFadeEnable; - } - - public void setFadeDuration(long duration) - { - mFadeDuration = duration; - } - - protected void resetFadeAnimation() - { - if (mFadeEnable) - { - if (mAlphaAnimator != null && mAlphaAnimator.isRunning()) - { - mAlphaAnimator.cancel(); - } - mAlphaAnimator = null; - } - } - - protected void startFadeAnimation() - { - if (mFadeEnable) - { - if (this.mFadeDuration > 0 && this.mAlphaAnimator == null) - { - this.mAlphaAnimator = ValueAnimator.ofInt(new int[] { 0, 255 }); - this.mAlphaAnimator.setEvaluator(new IntEvaluator()); - this.mAlphaAnimator.addUpdateListener(this); - this.mAlphaAnimator.addListener(this); - this.mAlphaAnimator.setDuration((long) this.mFadeDuration); - } - if (this.mAlphaAnimator != null) - { - if (this.mAlphaAnimator.isRunning()) - { - this.mAlphaAnimator.cancel(); - } - - this.mAlphaAnimator.setCurrentPlayTime(0L); - this.mAlphaAnimator.start(); - } - } - } - - protected void performFetchImage() - { - fetchImageByUrl(mUrl, SOURCE_TYPE_SRC); - } - - public void setDefaultSource(String defaultSource) - { - if (!TextUtils.equals(mDefaultSourceUrl, defaultSource)) - { - mDefaultSourceUrl = defaultSource; - fetchImageByUrl(mDefaultSourceUrl, SOURCE_TYPE_DEFAULT_SRC); - } - } - - public void setTintColor(int tintColor) - { - mTintColor = tintColor; - applyTintColor(mTintColor); - } - - protected void applyTintColor(int tintColor) - { - if (mContentDrawable instanceof ContentDrawable) - { - ((ContentDrawable) mContentDrawable).setTintColor(tintColor); - invalidate(); - } - } - - protected int getTintColor() - { - return mTintColor; - } - - public void setScaleType(ScaleType scaleType) - { - mScaleType = scaleType; - } - - public void setImagePositionX(int positionX) - { - mImagePositionX = positionX; - } - - public void setImagePositionY(int positionY) - { - mImagePositionY = positionY; - } - - protected void onFetchImage(String url) - { - - } - - protected boolean shouldFetchImage() - { - return true; - } - - protected boolean isAttached() - { - return mIsAttached; - } - - private void fetchImageByUrl(String url, final int sourceType) - { - if (url == null) - { - return; - } - - - if (mImageAdapter != null) - { - // fetch or get image, depending on url type - - // http or https => async fetch - // eg. - if (shouldUseFetchImageMode(url)) - { - url = url.trim().replaceAll(" ", "%20"); - if (sourceType == SOURCE_TYPE_SRC) { - if (!shouldFetchImage()) { - return; - } - mUrlFetchState = IMAGE_LOADING; - } - - onFetchImage(url); - handleGetImageStart(); - doFetchImage(getFetchParam(), sourceType); - } - else - { - // [file/resource/base64] => direct get - // eg. - // eg. - // eg. - - handleGetImageStart(); - handleImageRequest(mImageAdapter.getImage(url, null), sourceType, null); - } - } - } - - protected boolean shouldUseFetchImageMode(String url) - { - return true; - } - - protected Object getFetchParam() - { - return mSourceDrawable != null ? mSourceDrawable.getExtraData() : null; - } - - protected void doFetchImage(Object param, final int sourceType) - { - if (mImageAdapter != null) - { - // 这里不判断下是取背景图片还是取当前图片怎么行? - String url = sourceType == SOURCE_TYPE_SRC ? mUrl : mDefaultSourceUrl; - mImageAdapter.fetchImage(url, new IImageRequestListener() - { - @Override - public void onRequestStart(IDrawableTarget IDrawableTarget) - { - mSourceDrawable = IDrawableTarget; - } - - @Override - public void onRequestSuccess(IDrawableTarget IDrawableTarget) - { - handleImageRequest(IDrawableTarget, sourceType, null); - } - - @Override - public void onRequestFail(Throwable throwable, String source) - { - handleImageRequest(null, sourceType, throwable); - } - }, param); - } - } - - protected void handleImageRequest(IDrawableTarget resultDrawable, int sourceType, Object requestInfo) { - if (resultDrawable == null) { - if (sourceType == SOURCE_TYPE_SRC) { - mSourceDrawable = null; - if (mDefaultSourceDrawable != null) { - if (mContentDrawable == null) { - mContentDrawable = generateContentDrawable(); - } - setContent(SOURCE_TYPE_DEFAULT_SRC); - } else { - mContentDrawable = null; - } - handleGetImageFail(requestInfo instanceof Throwable ? (Throwable) requestInfo : null); - } else if (sourceType == SOURCE_TYPE_DEFAULT_SRC) { - mDefaultSourceDrawable = null; - } - } else { - mContentDrawable = generateContentDrawable(); - if (sourceType == SOURCE_TYPE_SRC) { - mSourceDrawable = resultDrawable; - handleGetImageSuccess(); - } else if (sourceType == SOURCE_TYPE_DEFAULT_SRC) { - mDefaultSourceDrawable = resultDrawable; - } - setContent(sourceType); - } - } - - protected ContentDrawable generateContentDrawable() - { - return new ContentDrawable(); - } - - protected BackgroundDrawable generateBackgroundDrawable() - { - return new BackgroundDrawable(); - } - - @Override - protected void onDetachedFromWindow() - { - mIsAttached = false; - if (mFadeEnable) - { - if (mAlphaAnimator != null) - { - mAlphaAnimator.cancel(); - } - } - super.onDetachedFromWindow(); - onDrawableDetached(); - if (mDefaultSourceDrawable != null) - { - mDefaultSourceDrawable.onDrawableDetached(); - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) - { - - } - - @Override - protected void onAttachedToWindow() - { - mIsAttached = true; - super.onAttachedToWindow(); - if (mDefaultSourceDrawable != null && shouldFetchImage()) - { - mDefaultSourceDrawable.onDrawableAttached(); - setContent(SOURCE_TYPE_DEFAULT_SRC); - } - - fetchImageByUrl(mUrl, SOURCE_TYPE_SRC); - onDrawableAttached(); - } - - protected void onDrawableAttached() - { - if (mSourceDrawable != null) - { - mSourceDrawable.onDrawableAttached(); - } - } - - protected void onDrawableDetached() - { - if (mSourceDrawable != null) - { - mSourceDrawable.onDrawableDetached(); - } - } - - protected void resetContent() - { - mContentDrawable = null; - mBGDrawable = null; - super.setBackgroundDrawable(null); - } - - protected void onSetContent(String url) - { - - } - - protected void afterSetContent(String url) - { - - } - - protected void performSetContent() - { - setContent(SOURCE_TYPE_SRC); - } - - protected boolean shouldSetContent() - { - return true; - } - - protected Bitmap getBitmap() - { - if (mSourceDrawable != null) - { - return mSourceDrawable.getBitmap(); - } - return null; - } - - protected void setContent(int sourceType) - { - if (mContentDrawable != null) - { - if (!shouldSetContent()) - { - return; - } - - onSetContent(mUrl); - updateContentDrawableProperty(sourceType); - - if (mBGDrawable != null) - { - if (mContentDrawable instanceof ContentDrawable) - { - ((ContentDrawable) mContentDrawable).setBorder(mBGDrawable.getBorderRadiusArray(), mBGDrawable.getBorderWidthArray()); - ((ContentDrawable) mContentDrawable).setShadowOffsetX(mBGDrawable.getShadowOffsetX()); - ((ContentDrawable) mContentDrawable).setShadowOffsetY(mBGDrawable.getShadowOffsetY()); - ((ContentDrawable) mContentDrawable).setShadowRadius(mBGDrawable.getShadowRadius()); - } - setBackgroundDrawable(new LayerDrawable(new Drawable[] { mBGDrawable, mContentDrawable })); - } - else - { - setBackgroundDrawable(mContentDrawable); - } - afterSetContent(mUrl); - } - } - - protected void updateContentDrawableProperty(int sourceType) { - if (!(mContentDrawable instanceof ContentDrawable)) { - return; - } - - Bitmap bitmap = null; - switch (sourceType) { - case SOURCE_TYPE_SRC: - if (mSourceDrawable != null){ - bitmap = mSourceDrawable.getBitmap(); - } - break; - case SOURCE_TYPE_DEFAULT_SRC: - if (mDefaultSourceDrawable != null && (mUrlFetchState != IMAGE_LOADED || mSourceDrawable == null)) { - bitmap = mDefaultSourceDrawable.getBitmap(); - } - break; - } - - if (bitmap != null) { - ((ContentDrawable) mContentDrawable).setSourceType(sourceType); - ((ContentDrawable) mContentDrawable).setBitmap(bitmap); - ((ContentDrawable) mContentDrawable).setTintColor(getTintColor()); - ((ContentDrawable) mContentDrawable).setScaleType(mScaleType); - ((ContentDrawable) mContentDrawable).setImagePositionX(mImagePositionX); - ((ContentDrawable) mContentDrawable).setImagePositionY(mImagePositionY); - } - } - - protected void handleGetImageStart() - { - } - - protected void handleGetImageSuccess() - { - } - - protected void handleGetImageFail(Throwable throwable) - { - } - - @Override - public void onAnimationStart(Animator animation) - { - - } - - @Override - public void onAnimationEnd(Animator animation) - { - if (mFadeEnable) - { - restoreBackgroundColorAfterSetContent(); - } - } - - @Override - public void onAnimationCancel(Animator animation) - { - if (mFadeEnable) - { - if (mContentDrawable != null) - { - mContentDrawable.setAlpha(255); - } - restoreBackgroundColorAfterSetContent(); - } - } - - @Override - public void onAnimationRepeat(Animator animation) - { - - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) - { - if (mFadeEnable) - { - if (!isAttached() && mAlphaAnimator != null) - { - mAlphaAnimator.cancel(); - } - if (mContentDrawable != null) - { - mContentDrawable.setAlpha(((Integer) animation.getAnimatedValue()).intValue()); - } - } - } - - protected void restoreBackgroundColorAfterSetContent() - { - setBackgroundColor(Color.TRANSPARENT); - } - - protected void setCustomBackgroundDrawable(BackgroundDrawable commonBackgroundDrawable) - { - mBGDrawable = commonBackgroundDrawable; - super.setBackgroundDrawable(mBGDrawable); - } - - @Override - public void setBorderRadius(float radius, int position) - { - getBackGround().setBorderRadius(radius, position); - if (mContentDrawable instanceof ContentDrawable) - { - ((ContentDrawable) mContentDrawable).setBorder(mBGDrawable.getBorderRadiusArray(), mBGDrawable.getBorderWidthArray()); - invalidate(); - } - } - - @Override - public void setBorderWidth(float width, int position) - { - getBackGround().setBorderWidth(width, position); - if (mContentDrawable instanceof ContentDrawable) - { - ((ContentDrawable) mContentDrawable).setBorder(mBGDrawable.getBorderRadiusArray(), mBGDrawable.getBorderWidthArray()); - invalidate(); - } - } - - @Override - public void setBorderColor(int color, int position) - { - getBackGround().setBorderColor(color, position); - invalidate(); - } - - @Override - public void setBorderStyle(int borderStyle) - { - getBackGround().setBorderStyle(borderStyle); - invalidate(); - } - - @Override - public void setBackgroundColor(int color) - { - getBackGround().setBackgroundColor(color); - invalidate(); - } - - @Override - public void setShadowOffsetX(float x) - { - getBackGround().setShadowOffsetX(x); - invalidate(); - } - - @Override - public void setShadowOffsetY(float y) - { - getBackGround().setShadowOffsetY(y); - invalidate(); - } - - @Override - public void setShadowOpacity(float opacity) - { - getBackGround().setShadowOpacity(opacity); - invalidate(); - } - - @Override - public void setShadowRadius(float radius) - { - getBackGround().setShadowRadius(Math.abs(radius)); - if (radius != 0) - { - setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - invalidate(); - } - - @Override - public void setShadowSpread(float spread) { - - } - - @Override - public void setShadowColor(int color) - { - getBackGround().setShadowColor(color); - invalidate(); - } - - @Override - public void setGradientAngle(String angle) { - getBackGround().setGradientAngle(angle); - invalidate(); - } - - @Override - public void setGradientColors(ArrayList colors) { - getBackGround().setGradientColors(colors); - invalidate(); - } - - @Override - public void setGradientPositions(ArrayList positions) { - getBackGround().setGradientPositions(positions); - invalidate(); - } - - private BackgroundDrawable getBackGround() - { - if (mBGDrawable == null) - { - mBGDrawable = generateBackgroundDrawable(); - Drawable currBGDrawable = getBackground(); - super.setBackgroundDrawable(null); - if (currBGDrawable == null) - { - super.setBackgroundDrawable(mBGDrawable); - } - else - { - LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] { mBGDrawable, currBGDrawable }); - super.setBackgroundDrawable(layerDrawable); - } - } - return mBGDrawable; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/BackgroundDrawable.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/BackgroundDrawable.java deleted file mode 100644 index ea2cae20bec..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/BackgroundDrawable.java +++ /dev/null @@ -1,962 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.supportui.views.asyncimage; - -import android.graphics.LinearGradient; -import android.graphics.PointF; -import android.graphics.Shader; -import android.text.TextUtils; -import com.tencent.mtt.hippy.utils.LogUtils; -import com.tencent.mtt.supportui.utils.CommonTool; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.DashPathEffect; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.os.Build; -import java.util.ArrayList; - -/** - * Created by leonardgong on 2017/11/30 0030. - */ - -public class BackgroundDrawable extends BaseDrawable -{ - - private float[] mBorderWidthArray; - private float[] mBorderRadiusArray; - private int[] mBorderColorArray; - private int mBorderStyle = 0; - private DashPathEffect mDashPathEffect = null; - private DashPathEffect mDotPathEffect = new DashPathEffect(new float[] { 2, 2}, 0); - private Path mPathWithBorder; - private final Paint mPaint; - private int mBackgroundColor; - private RectF mTempRectForBorderRadius; - private Path mPathForBorderRadius; - private boolean mNeedUpdateBorderPath = false; - - private Paint mShadowPaint; - private Paint gradientPaint; - private String gradientAngleDesc; - private int gradientAngle = Integer.MAX_VALUE; - private int[] gradientColors; - private float[] gradientPositions; - - protected float mShadowOpacity = 0.8f; - protected int mShadowColor = Color.GRAY; - protected RectF mShadowRect; - - /** - * solve drawPath problem on 4.x android - **/ - private Bitmap mCanvasBitmap = null; - private Canvas mBitmapCanvas = null; - private Paint mBitmapPaint = null; - - public BackgroundDrawable() - { - mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - } - - @Override - public void setBounds(int left, int top, int right, int bottom) - { - super.setBounds(left, top, right, bottom); - mShadowRect = new RectF(left + mShadowRadius - mShadowOffsetX, top + mShadowRadius - mShadowOffsetY, right - mShadowRadius - mShadowOffsetX, - bottom - mShadowRadius - mShadowOffsetY); - updateContentRegion(); - } - - @Override - public void draw(Canvas canvas) - { - if (canvas.getWidth() == 0 || canvas.getHeight() == 0) - return; - boolean hasBorderRadius = CommonTool.hasPositiveItem(mBorderRadiusArray); - float dotBorderWidth = 2; -// if(mBorderRadiusArray !=null && mBorderRadiusArray.length > 1) -// dotBorderWidth = mBorderRadiusArray[0]; - if(mBorderStyle == 1 && dotBorderWidth >0) - { - if(mDashPathEffect == null) - { - mDashPathEffect = new DashPathEffect(new float[] { 4*dotBorderWidth, 2*dotBorderWidth}, 0); - } - mPaint.setPathEffect(mDashPathEffect); - } - else if(mBorderStyle == 2 && dotBorderWidth > 0) - { - if(mDotPathEffect == null) - { - mDotPathEffect = new DashPathEffect(new float[] { 2*dotBorderWidth, 2*dotBorderWidth}, 0); - } - mPaint.setPathEffect(mDotPathEffect); - } - else - { - mPaint.setPathEffect(null); - } - - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && // 只在有需要绘制border的时候,才使用bitmap - CommonTool.hasPositiveItem(mBorderWidthArray)) - { - int canvasWidth = canvas.getWidth(); - int canvasHeight = canvas.getHeight(); - if (mCanvasBitmap == null) - /** generate bitmap for temp canvas **/ - { - try - { - mCanvasBitmap = generateBitmap(canvas.getWidth(), canvas.getHeight()); - /** draw on temp canvas **/ - mBitmapCanvas = new Canvas(mCanvasBitmap); - mBitmapPaint = new Paint(); - } - catch (OutOfMemoryError e) - { - return; - } - catch (NullPointerException e) - { - return; - } - } - // 当canvas或者view大小发生改变时,重新设置bitmap和临时canvas - if (canvasWidth != mCanvasBitmap.getWidth() || canvasHeight != mCanvasBitmap.getHeight()) - { - try - { - mCanvasBitmap = generateBitmap(canvas.getWidth(), canvas.getHeight()); - /** draw on temp canvas **/ - mBitmapCanvas = new Canvas(mCanvasBitmap); - } - catch (OutOfMemoryError error) - { - return; - } - catch (NullPointerException e) - { - return; - } - } - - /** clear canvas first **/ - mBitmapCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - - drawBGShadow(mBitmapCanvas); - - if (!hasBorderRadius) - { - drawBG(mBitmapCanvas); - } - else - { - drawBGWithRadius(mBitmapCanvas); - } - /** save canvasBitmap to real canvas **/ - canvas.drawBitmap(mCanvasBitmap, 0, 0, mBitmapPaint); - } - else - { - drawBGShadow(canvas); - - if (!hasBorderRadius) - { - drawBG(canvas); - } - else - { - drawBGWithRadius(canvas); - } - } - } - - public void setGradientAngle(String angle) { - gradientAngleDesc = angle; - } - - public void setGradientColors(ArrayList colors) { - int size = colors.size(); - if (size > 0) { - gradientColors = new int[size]; - for (int i = 0; i < size; i++) { - gradientColors[i] = colors.get(i); - } - } else { - gradientColors = null; - } - } - - public void setGradientPositions(ArrayList positions) { - int size = positions.size(); - if (size > 0) { - int lastPos = 0; - float lastValue = 0.0f; - gradientPositions = new float[size]; - for (int i = 0; i < size; i++) { - float value = positions.get(i); - if (i == 0) { - gradientPositions[i] = value; - lastValue = value; - continue; - } - - if (value <= 0.0f && lastPos < i) { - continue; - } - - if (value > 0.0f && lastPos < (i - 1)) { - float average = (value - lastValue)/(i - lastPos); - for (int j = (lastPos + 1); j < i; j++) { - gradientPositions[j] = lastValue + average*(j - lastPos); - } - } - - lastPos = i; - lastValue = value; - gradientPositions[i] = value; - } - } else { - gradientPositions = null; - } - } - - private int getOppositeAngle() { - double angrad = Math.atan(mRect.width()/mRect.height()); - double angdeg = Math.toDegrees(angrad); - return (int)Math.round(angdeg); - } - - private boolean checkSpecialAngle(PointF start, PointF end) { - switch (gradientAngle) { - case 0: - end.x = mRect.centerX(); - end.y = mRect.top; - start.x = mRect.centerX(); - start.y = mRect.bottom; - break; - case 90: - end.x = mRect.right; - end.y = mRect.centerY(); - start.x = mRect.left; - start.y = mRect.centerY(); - break; - case 180: - end.x = mRect.centerX(); - end.y = mRect.bottom; - start.x = mRect.centerX(); - start.y = mRect.top; - break; - case 270: - end.x = mRect.left; - end.y = mRect.centerY(); - start.x = mRect.right; - start.y = mRect.centerY(); - break; - default: - return false; - } - - return true; - } - - private void correctPointWithOriginDegree(PointF start, PointF end) { - if (gradientAngle > 90 && gradientAngle < 180) { - start.y = mRect.bottom - start.y; - end.y = mRect.bottom - end.y; - } else if (gradientAngle > 180 && gradientAngle < 270) { - PointF tempPoint = new PointF(start.x, start.y); - start.x = end.x; - start.y = end.y; - end.x = tempPoint.x; - end.y = tempPoint.y; - } else if (gradientAngle > 270 && gradientAngle < 360) { - end.x = mRect.left + (mRect.right - end.x); - start.x = mRect.right - start.x; - } - } - - private void calculateStartEndPoint(PointF start, PointF end, int oppositeDegree) { - if (checkSpecialAngle(start, end)) { - return; - } - - int tempDegree = gradientAngle%90; - if ((gradientAngle > 90 && gradientAngle < 180) || (gradientAngle > 270 && gradientAngle < 360)) { - tempDegree = 90 - tempDegree; - } - - if (tempDegree == oppositeDegree) { - end.x = mRect.right; - end.y = mRect.top; - start.x = mRect.left; - start.y = mRect.bottom; - } else if (tempDegree < oppositeDegree) { - float xl = (float)(Math.tan(Math.toRadians(tempDegree)) * mRect.height()/2); - end.x = mRect.centerX() + xl; - end.y = mRect.top; - start.x = mRect.centerX() - xl; - start.y = mRect.bottom; - } else { - float yl = (float)(Math.tan(Math.toRadians(90 - tempDegree)) * mRect.width()/2); - end.x = mRect.right; - end.y = mRect.centerY() - yl; - start.x = mRect.left; - start.y = mRect.centerY() + yl; - } - - correctPointWithOriginDegree(start, end); - } - - private void calculategradientAngle(int oppositeDegree) { - if (gradientAngleDesc.equals("totopright")) { - gradientAngle = (90 - oppositeDegree); - } else if (gradientAngleDesc.equals("tobottomright")) { - gradientAngle = (90 + oppositeDegree); - } else if (gradientAngleDesc.equals("tobottomleft")) { - gradientAngle = 270 - oppositeDegree; - } else if (gradientAngleDesc.equals("totopleft")) { - gradientAngle = 270 + oppositeDegree; - } else { - try { - float fa = Float.parseFloat(gradientAngleDesc); - gradientAngle = Math.round(fa)%360; - } catch (NumberFormatException ignored) { - ignored.printStackTrace(); - } - } - } - - private boolean initGradientPaint() { - if (TextUtils.isEmpty(gradientAngleDesc)) { - return false; - } - - int oppositeDegree = getOppositeAngle(); - calculategradientAngle(oppositeDegree); - - if (gradientAngle == Integer.MAX_VALUE || gradientColors == null || gradientColors.length < 2) { - return false; - } - - if (gradientPositions != null && gradientColors.length != gradientPositions.length) { - gradientPositions = null; - } - - if (gradientPaint == null) { - gradientPaint = new Paint(); - } - - gradientPaint.setStyle(Paint.Style.FILL); - - PointF start = new PointF(); - PointF end = new PointF(); - - calculateStartEndPoint(start, end, oppositeDegree); - - try { - LinearGradient linearGradient = new LinearGradient(start.x, start.y, end.x, end.y, - gradientColors, gradientPositions, Shader.TileMode.CLAMP); - gradientPaint.setShader(linearGradient); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - return false; - } - - return true; - } - - private void drawBGShadow (Canvas canvas) - { - if (mShadowRadius == 0 || mShadowOpacity <= 0) - { - return; - } - - int opacity = (mShadowOpacity >= 1) ? 255 : Math.round(255 * mShadowOpacity); - - float borderRadius = 0.0f; - if (mBorderRadiusArray != null && mBorderRadiusArray.length > 0) { - for (int i = 0; i < mBorderRadiusArray.length; i++) { - if (mBorderRadiusArray[i] > borderRadius) { - borderRadius = mBorderRadiusArray[i]; - } - } - } - - if (mShadowPaint == null) { - mShadowPaint = new Paint(); - } - - mShadowPaint.setColor(Color.TRANSPARENT); - mShadowPaint.setAntiAlias(true); - mShadowPaint.setAlpha(opacity); - mShadowPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mShadowColor); - mShadowPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); - canvas.drawRoundRect(mShadowRect, borderRadius, borderRadius, mShadowPaint); - } - - private void drawBGWithRadius(Canvas canvas) - { - // updateStyle border with radius path - updatePath(); - - // draw bg color - boolean useGradientPaint = initGradientPaint(); - if (useGradientPaint) { - canvas.drawPath(mPathForBorderRadius, gradientPaint); - } else if (mBackgroundColor != 0) { - mPaint.setColor(mBackgroundColor); - mPaint.setStyle(Paint.Style.FILL); - canvas.drawPath(mPathForBorderRadius, mPaint); - } - - // draw border - //话圆角矩形必须四条边的宽度是一样的. - if (CommonTool.hasPositiveItem(mBorderWidthArray) && mBorderWidthArray[0] > 0 && mBorderColorArray != null ) - { - //qb上一般都是走这个分支 - if( mBorderColorArray[0] != 0 || //如果指定了四边的颜色 - (mBorderColorArray[1]==mBorderColorArray[2] //或者单独指定的四条边的颜色一样 - &&mBorderColorArray[2]==mBorderColorArray[3] - &&mBorderColorArray[3]==mBorderColorArray[4] - )) - { - int borderColor = mBorderColorArray[0] ; - if(mBorderColorArray[0] ==0) - borderColor = mBorderColorArray[1]; - if(borderColor == 0) //没有颜色退出 - return; - mPaint.setColor(borderColor); - mPaint.setStyle(Paint.Style.STROKE); - mPaint.setStrokeWidth(mBorderWidthArray[0]); - canvas.drawPath(mPathForBorderRadius, mPaint); - } - else - { - drawBGWithRadiusWithSingleColor(canvas);//四个颜色不一样,那么每边单独画 - } - - } - } - private void drawBGWithRadiusWithSingleColor(Canvas canvas) - { - // draw border - if (CommonTool.hasPositiveItem(mBorderWidthArray)) - { - RectF bounds = mRect; - - int border = Math.round( mBorderWidthArray[0]); //一定大于-0 - - int colorLeft = mBorderColorArray == null ? 0 : mBorderColorArray[1]; - if (colorLeft == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorLeft = mBorderColorArray[0]; - } - int colorTop = mBorderColorArray == null ? 0 : mBorderColorArray[2]; - if (colorTop == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorTop = mBorderColorArray[0]; - } - int colorRight = mBorderColorArray == null ? 0 : mBorderColorArray[3]; - if (colorRight == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorRight = mBorderColorArray[0]; - } - int colorBottom = mBorderColorArray == null ? 0 : mBorderColorArray[4]; - if (colorBottom == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorBottom = mBorderColorArray[0]; - } - - - float topLeftRadius = mBorderRadiusArray[1]; - if (topLeftRadius == 0 && mBorderRadiusArray[0] > 0) - { - topLeftRadius = mBorderRadiusArray[0]; - } - float topRightRadius = mBorderRadiusArray[2]; - if (topRightRadius == 0 && mBorderRadiusArray[0] > 0) - { - topRightRadius = mBorderRadiusArray[0]; - } - float bottomRightRadius = mBorderRadiusArray[3]; - if (bottomRightRadius == 0 && mBorderRadiusArray[0] > 0) - { - bottomRightRadius = mBorderRadiusArray[0]; - } - float bottomLeftRadius = mBorderRadiusArray[4]; - if (bottomLeftRadius == 0 && mBorderRadiusArray[0] > 0) - { - bottomLeftRadius = mBorderRadiusArray[0]; - } - - float top = bounds.top; - float left = bounds.left; - float bottom = bounds.bottom; - float right = bounds.right; - float width = bounds.width(); - float height = bounds.height(); - - mPaint.setAntiAlias(false); - mPaint.setStrokeWidth(border); - - mPaint.setStyle(Paint.Style.STROKE); - if (mPathWithBorder == null) - { - mPathWithBorder = new Path(); - } - int scaleLength = border/2; - - if (colorLeft != Color.TRANSPARENT) { - mPaint.setColor(colorLeft); - mPathWithBorder.reset(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - //直线 - mPathWithBorder.moveTo(left+scaleLength, top + topLeftRadius); - mPathWithBorder.lineTo(left+scaleLength, bottom - bottomLeftRadius); - //左上角圆圈 - mPathWithBorder.addArc( - (float) left+scaleLength, - (float) top+scaleLength, - (float) left + 2 * topLeftRadius-scaleLength, - (float) top + 2 * topLeftRadius-scaleLength, - (float) -180, - (float) 45); - - //右下圆圈 - mPathWithBorder.addArc( - (float) left+scaleLength, - (float) bottom - 2 * bottomLeftRadius+scaleLength, - (float) left + 2 * bottomLeftRadius-scaleLength, - (float) bottom-scaleLength, - (float) 135, - (float) 45); - } - else - { - //直线 - mPathWithBorder.moveTo(left+scaleLength, top ); - mPathWithBorder.lineTo(left+scaleLength, bottom); - } - canvas.drawPath(mPathWithBorder, mPaint); - } - - if ( colorTop != Color.TRANSPARENT) - { - mPaint.setColor(colorTop); - mPathWithBorder.reset(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - //直线 - mPathWithBorder.moveTo(left+topLeftRadius, top+ scaleLength); - mPathWithBorder.lineTo(right-topRightRadius, top +scaleLength ); - //左上角圆圈 - mPathWithBorder.addArc( - (float) left+scaleLength, - (float) top+scaleLength, - (float) left + 2 * topLeftRadius-scaleLength, - (float) top + 2 * topLeftRadius-scaleLength, - (float) -135, - (float) 45); - - //右上圆 - mPathWithBorder.addArc( - (float) right-2*topRightRadius+scaleLength, - (float) top +scaleLength, - (float) right - scaleLength, - (float) top+2*topRightRadius-scaleLength, - (float) -90, - (float) 45); - } - else - { - //直线 - mPathWithBorder.moveTo(left, top+ scaleLength); - mPathWithBorder.lineTo(right, top +scaleLength ); - } - canvas.drawPath(mPathWithBorder, mPaint); - } - - if (colorRight != Color.TRANSPARENT) - { - mPaint.setColor(colorRight); - mPathWithBorder.reset(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - //直线 - mPathWithBorder.moveTo(right-scaleLength, top +topRightRadius); - mPathWithBorder.lineTo(right-scaleLength, bottom-bottomRightRadius ); - //右下 - mPathWithBorder.addArc( - (float) right - 2*bottomRightRadius +scaleLength, - (float) bottom-2*bottomRightRadius +scaleLength, - (float) right-scaleLength, - (float) bottom -scaleLength, - (float) -0, - (float) 45); - - //右上圆 - mPathWithBorder.addArc( - (float) right-2*topRightRadius+scaleLength, - (float) top+scaleLength, - (float) right-scaleLength, - (float) top+2*topRightRadius-scaleLength, - (float) -45, - (float) 45); - } - else - { - mPathWithBorder.moveTo(right-scaleLength, top ); - mPathWithBorder.lineTo(right-scaleLength, bottom ); - } - canvas.drawPath(mPathWithBorder, mPaint); - } - - if ( colorBottom != Color.TRANSPARENT) { - mPaint.setColor(colorBottom); - mPathWithBorder.reset(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - //直线 - mPathWithBorder.moveTo(left + bottomLeftRadius, bottom - scaleLength); - mPathWithBorder.lineTo(right - bottomRightRadius, bottom - scaleLength); - //右下 - mPathWithBorder.addArc( - (float) right - 2 * bottomRightRadius + scaleLength, - (float) bottom - 2 * bottomRightRadius + scaleLength, - (float) right - scaleLength, - (float) bottom - scaleLength, - (float) 45, - (float) 45); - //左下 - mPathWithBorder.addArc( - (float) left + scaleLength, - (float) bottom - 2 * bottomLeftRadius + scaleLength, - (float) left + 2 * bottomLeftRadius - scaleLength, - (float) bottom - scaleLength, - (float) 90, - (float) 45); - - } else - { - //直线 - mPathWithBorder.moveTo(left, bottom-scaleLength); - mPathWithBorder.lineTo(right, bottom -scaleLength); - } - canvas.drawPath(mPathWithBorder, mPaint); - } - - mPaint.setAntiAlias(true); - } - } - private void drawBG(Canvas canvas) - { - boolean useGradientPaint = initGradientPaint(); - if (useGradientPaint) { - canvas.drawRect(mRect, gradientPaint); - } else if (mBackgroundColor != 0) { - mPaint.setColor(mBackgroundColor); - mPaint.setStyle(Paint.Style.FILL); - canvas.drawRect(mRect, mPaint); - } - - // draw border - if (CommonTool.hasPositiveItem(mBorderWidthArray)) - { - RectF bounds = mRect; - - int borderLeft = Math.round(mBorderWidthArray[1]); - if (borderLeft == 0 && mBorderWidthArray[0] > 0) - { - borderLeft = Math.round(mBorderWidthArray[0]); - } - int borderTop = Math.round(mBorderWidthArray[2]); - if (borderTop == 0 && mBorderWidthArray[0] > 0) - { - borderTop = Math.round(mBorderWidthArray[0]); - } - int borderRight = Math.round(mBorderWidthArray[3]); - if (borderRight == 0 && mBorderWidthArray[0] > 0) - { - borderRight = Math.round(mBorderWidthArray[0]); - } - int borderBottom = Math.round(mBorderWidthArray[4]); - if (borderBottom == 0 && mBorderWidthArray[0] > 0) - { - borderBottom = Math.round(mBorderWidthArray[0]); - } - int colorLeft = mBorderColorArray == null ? 0 : mBorderColorArray[1]; - if (colorLeft == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorLeft = mBorderColorArray[0]; - } - int colorTop = mBorderColorArray == null ? 0 : mBorderColorArray[2]; - if (colorTop == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorTop = mBorderColorArray[0]; - } - int colorRight = mBorderColorArray == null ? 0 : mBorderColorArray[3]; - if (colorRight == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorRight = mBorderColorArray[0]; - } - int colorBottom = mBorderColorArray == null ? 0 : mBorderColorArray[4]; - if (colorBottom == 0 && mBorderColorArray != null && mBorderColorArray[0] != 0) - { - colorBottom = mBorderColorArray[0]; - } - - float top = bounds.top; - float left = bounds.left; - float width = bounds.width(); - float height = bounds.height(); - - mPaint.setAntiAlias(false); - - if (mPathWithBorder == null) - { - mPathWithBorder = new Path(); - } - - if (borderLeft > 0 && colorLeft != Color.TRANSPARENT) - { - mPaint.setColor(colorLeft); - mPathWithBorder.reset(); - mPathWithBorder.moveTo(left, top); - mPathWithBorder.lineTo(left + borderLeft, top + borderTop); - mPathWithBorder.lineTo(left + borderLeft, top + height - borderBottom); - mPathWithBorder.lineTo(left, top + height); - mPathWithBorder.lineTo(left, top); - canvas.drawPath(mPathWithBorder, mPaint); - } - - if (borderTop > 0 && colorTop != Color.TRANSPARENT) - { - mPaint.setColor(colorTop); - mPathWithBorder.reset(); - mPathWithBorder.moveTo(left, top); - mPathWithBorder.lineTo(left + borderLeft, top + borderTop); - mPathWithBorder.lineTo(left + width - borderRight, top + borderTop); - mPathWithBorder.lineTo(left + width, top); - mPathWithBorder.lineTo(left, top); - canvas.drawPath(mPathWithBorder, mPaint); - } - - if (borderRight > 0 && colorRight != Color.TRANSPARENT) - { - mPaint.setColor(colorRight); - mPathWithBorder.reset(); - mPathWithBorder.moveTo(left + width, top); - mPathWithBorder.lineTo(left + width, top + height); - mPathWithBorder.lineTo(left + width - borderRight, top + height - borderBottom); - mPathWithBorder.lineTo(left + width - borderRight, top + borderTop); - mPathWithBorder.lineTo(left + width, top); - canvas.drawPath(mPathWithBorder, mPaint); - } - - if (borderBottom > 0 && colorBottom != Color.TRANSPARENT) - { - mPaint.setColor(colorBottom); - mPathWithBorder.reset(); - mPathWithBorder.moveTo(left, top + height); - mPathWithBorder.lineTo(left + width, top + height); - mPathWithBorder.lineTo(left + width - borderRight, top + height - borderBottom); - mPathWithBorder.lineTo(left + borderLeft, top + height - borderBottom); - mPathWithBorder.lineTo(left, top + height); - canvas.drawPath(mPathWithBorder, mPaint); - } - - mPaint.setAntiAlias(true); - } - } - - public Bitmap generateBitmap(int width, int height) { - return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - } - - private void updatePath() - { - if (!mNeedUpdateBorderPath) - { - return; - } - mNeedUpdateBorderPath = false; - if (mPathForBorderRadius == null) - { - mPathForBorderRadius = new Path(); - mTempRectForBorderRadius = new RectF(); - } - - mPathForBorderRadius.reset(); - - mTempRectForBorderRadius.set(mRect); - float fullBorderWidth = mBorderWidthArray == null ? 0 : mBorderWidthArray[0]; - if (fullBorderWidth > 1) - { - mTempRectForBorderRadius.inset(fullBorderWidth * 0.5f, fullBorderWidth * 0.5f); - } - - float topLeftRadius = mBorderRadiusArray[1]; - if (topLeftRadius == 0 && mBorderRadiusArray[0] > 0) - { - topLeftRadius = mBorderRadiusArray[0]; - } - float topRightRadius = mBorderRadiusArray[2]; - if (topRightRadius == 0 && mBorderRadiusArray[0] > 0) - { - topRightRadius = mBorderRadiusArray[0]; - } - float bottomRightRadius = mBorderRadiusArray[3]; - if (bottomRightRadius == 0 && mBorderRadiusArray[0] > 0) - { - bottomRightRadius = mBorderRadiusArray[0]; - } - float bottomLeftRadius = mBorderRadiusArray[4]; - if (bottomLeftRadius == 0 && mBorderRadiusArray[0] > 0) - { - bottomLeftRadius = mBorderRadiusArray[0]; - } - - mPathForBorderRadius.addRoundRect(mTempRectForBorderRadius, new float[] { topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, - bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius }, Path.Direction.CW); - } - - @Override - public void setAlpha(int alpha) - { - - } - - @Override - protected void onBoundsChange(Rect bounds) - { - super.onBoundsChange(bounds); - mNeedUpdateBorderPath = true; - } - - @Override - public void setColorFilter(ColorFilter colorFilter) - { - - } - - @Override - public int getOpacity() - { - return PixelFormat.UNKNOWN; - } - - public void setBorderRadius(float radius, int position) - { - if (mBorderRadiusArray == null) - { - mBorderRadiusArray = new float[5]; - } - mBorderRadiusArray[position] = radius; - - mNeedUpdateBorderPath = true; - invalidateSelf(); - } - - public void setBorderWidth(float width, int position) - { - if (mBorderWidthArray == null) - { - mBorderWidthArray = new float[5]; - } - mBorderWidthArray[position] = width; - - mNeedUpdateBorderPath = true; - invalidateSelf(); - } - - public void setBorderColor(int color, int position) - { - if (mBorderColorArray == null) - { - mBorderColorArray = new int[5]; - } - mBorderColorArray[position] = color; - - invalidateSelf(); - } - // 0 solid,1 dashed,2 dotted - public void setBorderStyle(int borderStyle) - { - if(borderStyle < 0 || borderStyle > 2) - mBorderStyle = 0; - else - mBorderStyle = borderStyle; - - invalidateSelf(); - } - - - public void setBackgroundColor(int color) - { - mBackgroundColor = color; - invalidateSelf(); - } - - public float[] getBorderWidthArray() - { - return mBorderWidthArray; - } - - public float[] getBorderRadiusArray() - { - return mBorderRadiusArray; - } - public float getShadowOffsetX() - { - return mShadowOffsetX; - } - - public float getShadowOffsetY() - { - return mShadowOffsetY; - } - - public float getShadowRadius() - { - return mShadowRadius; - } - - public void setShadowOpacity(float opacity) - { - mShadowOpacity = opacity; - invalidateSelf(); - } - - public void setShadowColor(int color) - { - mShadowColor = color; - invalidateSelf(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/BaseDrawable.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/BaseDrawable.java deleted file mode 100644 index 75f1acff4a3..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/BaseDrawable.java +++ /dev/null @@ -1,92 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.mtt.supportui.views.asyncimage; - -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; - -public abstract class BaseDrawable extends Drawable -{ - protected float mShadowOffsetX; - protected float mShadowOffsetY; - protected float mShadowRadius; - protected RectF mRect = new RectF(); - - public void updateContentRegion() - { - Rect rectT = getBounds(); - - float topT = rectT.top + mShadowRadius; - float leftT = rectT.left + mShadowRadius; - float rightT = rectT.right - mShadowRadius; - float bottomT = rectT.bottom - mShadowRadius; - - if (mShadowOffsetX > 0) { - if (mShadowRadius >= mShadowOffsetX) { - leftT -= mShadowOffsetX; - rightT -= mShadowOffsetX; - } else { - leftT -= mShadowRadius; - } - } else { - float offsetXAbs = Math.abs(mShadowOffsetX); - if (mShadowRadius >= offsetXAbs) { - leftT += offsetXAbs; - rightT += offsetXAbs; - } else { - rightT += mShadowRadius; - } - } - - if (mShadowOffsetY > 0) { - if (mShadowRadius >= mShadowOffsetY) { - topT -= mShadowOffsetY; - bottomT -= mShadowOffsetY; - } else { - topT -= mShadowRadius; - } - } else { - float offsetYAbs = Math.abs(mShadowOffsetY); - if (mShadowRadius >= offsetYAbs) { - topT += mShadowOffsetY; - bottomT += mShadowOffsetY; - } else { - bottomT += mShadowRadius; - } - } - - mRect.set(new RectF(leftT, topT, rightT, bottomT)); - } - - public void setShadowOffsetX(float x) - { - mShadowOffsetX = x; - invalidateSelf(); - } - - public void setShadowOffsetY(float y) - { - mShadowOffsetY = y; - invalidateSelf(); - } - - public void setShadowRadius(float radius) - { - mShadowRadius = radius; - invalidateSelf(); - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/ContentDrawable.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/ContentDrawable.java deleted file mode 100644 index 5e09666668c..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/ContentDrawable.java +++ /dev/null @@ -1,437 +0,0 @@ -/* Copyright (C) 2018 Tencent, Inc. - * - * 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 com.tencent.mtt.supportui.views.asyncimage; - -import static com.tencent.mtt.supportui.views.asyncimage.AsyncImageView.SOURCE_TYPE_SRC; - -import com.tencent.mtt.supportui.utils.CommonTool; - -import android.graphics.Bitmap; -import android.graphics.BitmapShader; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Shader; -import android.graphics.drawable.Drawable; -import android.os.Build; -import com.tencent.mtt.supportui.views.asyncimage.AsyncImageView.ScaleType; - -/** - * Created by leonardgong on 2017/12/5 0005. - */ - -public class ContentDrawable extends BaseDrawable -{ - - protected Bitmap mContentBitmap; - - protected Paint mPaint; - - protected int mTintColor; - protected int mAlpha; - protected AsyncImageView.ScaleType mScaleType; - - private float[] mBorderWidthArray; - private float[] mBorderRadiusArray; - - private boolean mNeedUpdateBorderPath; - private Path mBorderPath; - private RectF mTempRectForBorderRadius; - - private int mImagePositionX; - private int mImagePositionY; - public Path mSelfClipPath = null;//自定义裁剪路径,这里按理应该设置位private,通过接口修改.鉴于981的改动风险,直接位public - private int sourceType = SOURCE_TYPE_SRC; - - public ContentDrawable() - { - mScaleType = AsyncImageView.ScaleType.FIT_XY; - mAlpha = 255; - mNeedUpdateBorderPath = true; - } - - @Override - public void setBounds(int left, int top, int right, int bottom) { - super.setBounds(left, top, right, bottom); - updateContentRegion(); - } - - public void setSourceType(int type) { - sourceType = type; - } - - public int getSourceType() { - return sourceType; - } - - public void setBitmap(Bitmap contentBitmap) - { - mContentBitmap = contentBitmap; - } - - public void setTintColor(int tintColor) - { - mTintColor = tintColor; - } - - public void setScaleType(AsyncImageView.ScaleType scaleType) - { - if (scaleType != null) - { - mScaleType = scaleType; - } - } - - public void setBorder(float[] radiusArray, float[] widthArray) - { - mBorderWidthArray = widthArray; - mBorderRadiusArray = radiusArray; - mNeedUpdateBorderPath = true; - } - - public void setImagePositionX(int positionX) - { - mImagePositionX = positionX; - } - - public void setImagePositionY(int positionY) - { - mImagePositionY = positionY; - } - - private void updatePath() - { - if (mNeedUpdateBorderPath && mContentBitmap != null) - { - if (mBorderPath == null) - { - mBorderPath = new Path(); - } - mNeedUpdateBorderPath = false; - if (mTempRectForBorderRadius == null) - { - mTempRectForBorderRadius = new RectF(); - } - mTempRectForBorderRadius.set(mRect); - // calc scale here - int bitmapWidth = mContentBitmap.getWidth(); - int bitmapHeight = mContentBitmap.getHeight(); - float boundWidth = mRect.width(); - float boundHeight = mRect.height(); - float xScale = boundWidth / bitmapWidth; - float yScale = boundHeight / bitmapHeight; - - ScaleType scaleType = mScaleType; - if (scaleType == ScaleType.CENTER && (bitmapWidth > boundWidth || bitmapHeight > boundHeight)) { - scaleType = ScaleType.CENTER_INSIDE; - } - - // border rect - switch (scaleType) - { - case REPEAT: - // DO Nothing - break; - case FIT_XY: - // 拉伸图片且不维持宽高比,直到宽高都刚好填满容器(默认) - break; - case ORIGIN: - // 不拉伸,居左上 - mTempRectForBorderRadius.top = 0; - mTempRectForBorderRadius.bottom = bitmapHeight; - mTempRectForBorderRadius.left = 0; - mTempRectForBorderRadius.right = bitmapWidth; - break; - case CENTER: - // 居中不拉伸 - mTempRectForBorderRadius.top = (boundHeight - bitmapHeight) / 2; - mTempRectForBorderRadius.bottom = (boundHeight + bitmapHeight) / 2; - mTempRectForBorderRadius.left = (boundWidth - bitmapWidth) / 2; - mTempRectForBorderRadius.right = (boundWidth + bitmapWidth) / 2; - break; - case CENTER_INSIDE: - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸 - // 这样图片完全被包裹在容器中,容器中可能留有空白 -// if (xScale >= 1 || yScale >= 1) - { - if (xScale > yScale) - { // y到顶 - mTempRectForBorderRadius.top = 0; - mTempRectForBorderRadius.bottom = boundHeight; - mTempRectForBorderRadius.left = (int) ((boundWidth - bitmapWidth * yScale) / 2); - mTempRectForBorderRadius.right = (int) ((boundWidth + bitmapWidth * yScale) / 2); - } - else - { // x到顶 - mTempRectForBorderRadius.top = (int) ((boundHeight - bitmapHeight * xScale) / 2); - mTempRectForBorderRadius.bottom = (int) ((boundHeight + bitmapHeight * xScale) / 2); - mTempRectForBorderRadius.left = 0; - mTempRectForBorderRadius.right = boundWidth; - } - } - break; - case CENTER_CROP: - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸 - // 这样图片完全覆盖甚至超出容器,容器中不留任何空白 - break; - } - - mTempRectForBorderRadius.top += mImagePositionY; - mTempRectForBorderRadius.bottom += mImagePositionY; - mTempRectForBorderRadius.left += mImagePositionX; - mTempRectForBorderRadius.right += mImagePositionX; - - float fullBorderWidth = mBorderWidthArray == null ? 0 : mBorderWidthArray[0]; - if (fullBorderWidth > 1) - { - mTempRectForBorderRadius.inset(fullBorderWidth * 0.5f, fullBorderWidth * 0.5f); - } - - if (CommonTool.hasPositiveItem(mBorderRadiusArray)) - { - - float topLeftRadius = mBorderRadiusArray[1]; - if (topLeftRadius == 0 && mBorderRadiusArray[0] > 0) - { - topLeftRadius = mBorderRadiusArray[0]; - } - float topRightRadius = mBorderRadiusArray[2]; - if (topRightRadius == 0 && mBorderRadiusArray[0] > 0) - { - topRightRadius = mBorderRadiusArray[0]; - } - float bottomRightRadius = mBorderRadiusArray[3]; - if (bottomRightRadius == 0 && mBorderRadiusArray[0] > 0) - { - bottomRightRadius = mBorderRadiusArray[0]; - } - float bottomLeftRadius = mBorderRadiusArray[4]; - if (bottomLeftRadius == 0 && mBorderRadiusArray[0] > 0) - { - bottomLeftRadius = mBorderRadiusArray[0]; - } - - mBorderPath.addRoundRect(mTempRectForBorderRadius, new float[] { topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, - bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius }, Path.Direction.CW); - } - else - { - // no border radius - mBorderPath.addRect(mTempRectForBorderRadius, Path.Direction.CW); - } - } - } - - @Override - protected void onBoundsChange(Rect bounds) - { - super.onBoundsChange(bounds); - mNeedUpdateBorderPath = true; - } - - @Override - public void draw(Canvas canvas) - { - if (mContentBitmap == null || mContentBitmap.isRecycled()) - { - return; - } - if (mPaint == null) - { - mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - } - - updateContentRegion(); - updatePath(); - - if (mContentBitmap != null) - { - Matrix matrix = new Matrix(); - matrix.reset(); - RectF scaleDst = new RectF(mRect); - - float fullBorderWidth = this.mBorderWidthArray == null ? 0.0F : this.mBorderWidthArray[0]; - if (fullBorderWidth > 1.0F) - { - scaleDst.inset(fullBorderWidth * 0.5F, fullBorderWidth * 0.5F); - } - // calc scale here - int bitmapWidth = mContentBitmap.getWidth(); - int bitmapHeight = mContentBitmap.getHeight(); - float boundWidth = mRect.width(); - float boundHeight = mRect.height(); - float xScale = boundWidth / bitmapWidth; - float yScale = boundHeight / bitmapHeight; - - ScaleType scaleType = mScaleType; - if (scaleType == ScaleType.CENTER && (bitmapWidth > boundWidth || bitmapHeight > boundHeight)) { - scaleType = ScaleType.CENTER_INSIDE; - } - - // bitmap scale rect - switch (scaleType) - { - case REPEAT: - //DO Nothing 使用Sharder的Repeat来实现 - break; - case FIT_XY: - // 拉伸图片且不维持宽高比,直到宽高都刚好填满容器(默认) - break; - case ORIGIN: - // 不拉伸,居左上 - scaleDst.top = 0; - scaleDst.bottom = bitmapHeight; - scaleDst.left = 0; - scaleDst.right = bitmapWidth; - break; - case CENTER: - // 居中不拉伸 - scaleDst.top = (boundHeight - bitmapHeight) / 2; - scaleDst.bottom = (boundHeight + bitmapHeight) / 2; - scaleDst.left = (boundWidth - bitmapWidth) / 2; - scaleDst.right = (boundWidth + bitmapWidth) / 2; - break; - case CENTER_INSIDE: - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸 - // 这样图片完全被包裹在容器中,容器中可能留有空白 -// if (xScale >= 1 || yScale >= 1) - { - if (xScale > yScale) - { // y到顶 - scaleDst.top = 0; - scaleDst.bottom = boundHeight; - scaleDst.left = (int) ((boundWidth - bitmapWidth * yScale) / 2); - scaleDst.right = (int) ((boundWidth + bitmapWidth * yScale) / 2); - } - else - { // x到顶 - scaleDst.top = (int) ((boundHeight - bitmapHeight * xScale) / 2); - scaleDst.bottom = (int) ((boundHeight + bitmapHeight * xScale) / 2); - scaleDst.left = 0; - scaleDst.right = boundWidth; - } - } - break; - case CENTER_CROP: - float cropScale = xScale > yScale ? xScale : yScale; - scaleDst.top = (int) ((boundHeight - bitmapHeight * cropScale) / 2); - scaleDst.bottom = (int) ((boundHeight + bitmapHeight * cropScale) / 2); - scaleDst.left = (int) ((boundWidth - bitmapWidth * cropScale) / 2); - scaleDst.right = (int) ((boundWidth + bitmapWidth * cropScale) / 2); - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸 - // 这样图片完全覆盖甚至超出容器,容器中不留任何空白 - break; - } - - scaleDst.top += mImagePositionY; - scaleDst.bottom += mImagePositionY; - scaleDst.left += mImagePositionX; - scaleDst.right += mImagePositionX; - - matrix.setRectToRect(new RectF(0, 0, mContentBitmap.getWidth(), mContentBitmap.getHeight()), scaleDst, Matrix.ScaleToFit.FILL); - - mPaint.reset(); - mPaint.setAlpha(mAlpha); - if (mTintColor != Color.TRANSPARENT) - { - mPaint.setColorFilter(new PorterDuffColorFilter(mTintColor, PorterDuff.Mode.SRC_ATOP)); - } - - drawBitmap(canvas, matrix); - } - } - - protected void drawBitmap(Canvas canvas, Matrix matrix) - { - //用户自定义了裁剪路径 - if (mSelfClipPath != null ) - { - try - { - canvas.clipPath(mSelfClipPath); - } - catch (Throwable t) - { - //mSelfClipPath前端设置进来的,为了避免异常,保护一下 - } - - } - if(mScaleType == AsyncImageView.ScaleType.REPEAT) - { - BitmapShader bitmapShader = new BitmapShader(mContentBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); - mPaint.setShader(bitmapShader); - // 进行绘制 - if (mBorderPath != null) - { - mPaint.setAntiAlias(true); - canvas.drawPath(mBorderPath, mPaint); - } - return; - } - if (CommonTool.hasPositiveItem(mBorderRadiusArray) || CommonTool.hasPositiveItem(mBorderWidthArray) - || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) - { - // 有圆角 - BitmapShader bitmapShader = new BitmapShader(mContentBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - // 根据控件大小对纹理图进行拉伸缩放处理 - bitmapShader.setLocalMatrix(matrix); - mPaint.setShader(bitmapShader); - - // 进行绘制 - if (mBorderPath != null) - { - mPaint.setAntiAlias(true); - canvas.drawPath(mBorderPath, mPaint); - } - } - else - { - mPaint.setFilterBitmap(true); - canvas.drawBitmap(mContentBitmap, matrix, mPaint); - } - } - - @Override - public void setAlpha(int alpha) - { - mAlpha = alpha; - invalidateSelf(); - } - - public int getAlphaValue() - { - return mAlpha; - } - - @Override - public void setColorFilter(ColorFilter colorFilter) - { - - } - - @Override - public int getOpacity() - { - return PixelFormat.UNKNOWN; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/BaseLayoutManager.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/BaseLayoutManager.java deleted file mode 100644 index 4c158e9e7e6..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/BaseLayoutManager.java +++ /dev/null @@ -1,2841 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import java.util.ArrayList; -import java.util.List; - -import android.content.Context; -import android.graphics.PointF; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; -import android.view.FocusFinder; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -public abstract class BaseLayoutManager extends RecyclerViewBase.LayoutManager -{ - - private static final String TAG = "LinearLayoutManager"; - - protected static final boolean DEBUG = false; - - public static final int HORIZONTAL = LinearLayout.HORIZONTAL; - - public static final int VERTICAL = LinearLayout.VERTICAL; - - private static final float SUSPEND_ITEM_ALPHA = .8f; - protected int mSuspentedAreaSize = 0; - - /** - * While trying to find next view to focus, LinearLayoutManager will not try - * to scroll more than this factor times the total space of the list. If - * layout is vertical, total space is the height minus padding, if layout is - * horizontal, total space is the width minus padding. - */ - private static final float MAX_SCROLL_FACTOR = 0.33f; - // private Stack mSuspentions; - - /** - * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL} - */ - private int mOrientation; - - /** - * Helper class that keeps temporary rendering state. It does not keep state - * after rendering is complete but we still keep a reference to re-use the - * same object. - */ - public RenderState mRenderState; - - /** - * Many calculations are made depending on orientation. To keep it clean, - * this interface helps {@link BaseLayoutManager} make those decisions. - * Based on {@link #mOrientation}, an implementation is lazily created in - * {@link #ensureRenderState} method. - */ - public OrientationHelper mOrientationHelper; - - /** - * We need to track this so that we can ignore current position when it - * changes. - */ - private boolean mLastStackFromEnd; - - /** - * Defines if layout should be calculated from end to start. - * - * @see #mShouldReverseLayout - */ - private boolean mReverseLayout = false; - - /** - * This keeps the final value for how LayoutManager should start laying out - * views. It is calculated by checking {@link #getReverseLayout()} and - * View's layout direction. - * {@link #onLayoutChildren(RecyclerViewBase.Recycler, RecyclerViewBase.State)} - * is run. - */ - protected boolean mShouldReverseLayout = false; - - /** - * Works the same way as - * {@link android.widget.AbsListView#setStackFromBottom(boolean)} and it - * supports both orientations. see - * {@link android.widget.AbsListView#setStackFromBottom(boolean)} - */ - private boolean mStackFromEnd = false; - - private SavedState mPendingSavedState = null; - - private View mCurrentSuspentionView = null; - private int mCurrentSuspentionPos = RecyclerViewBase.NO_POSITION; - - - private int mPendingGravity = Gravity.NO_GRAVITY; - - private int mPendingScrollPositionItemHeight; - - protected boolean mEndReached = false; - - /** - * Creates a vertical LinearLayoutManager - * - * @param context - * Current context, will be used to access resources. - */ - public BaseLayoutManager(Context context) - { - this(context, VERTICAL, false); - } - - /** - * @param context - * Current context, will be used to access resources. - * @param orientation - * Layout orientation. Should be {@link #HORIZONTAL} or - * {@link #VERTICAL}. - * @param reverseLayout - * When set to true, renders the layout from end to start. - */ - public BaseLayoutManager(Context context, int orientation, boolean reverseLayout) - { - setOrientation(orientation); - setReverseLayout(reverseLayout); - } - - /** - * {@inheritDoc} - */ - @Override - public RecyclerViewBase.LayoutParams generateDefaultLayoutParams() - { - return new RecyclerViewBase.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - } - - @Override - public Parcelable onSaveInstanceState() - { - if (mPendingSavedState != null) - { - return new SavedState(mPendingSavedState); - } - SavedState state = new SavedState(); - if (getChildCount() > 0) - { - boolean didLayoutFromEnd = mLastStackFromEnd ^ mShouldReverseLayout; - state.mAnchorLayoutFromEnd = didLayoutFromEnd; - if (didLayoutFromEnd) - { - // final View refChild = getChildClosestToEndInVisual(); - state.mAnchorOffset = mOrientationHelper.getEndAfterPadding() - mOrientationHelper.getDecoratedEnd(getChildClosestToEndInScreen()); - state.mAnchorPosition = getPosition(getChildClosestToEndByOrder()); - } - else - { - // final View refChild = getChildClosestToStartInVisual(); - state.mAnchorPosition = getPosition(getChildClosestToStartByOrder()); - state.mAnchorOffset = mOrientationHelper.getDecoratedStart(getChildClosestToStartInScreen()) - - mOrientationHelper.getStartAfterPadding(); - } - } - else - { - state.mAnchorPosition = 0; - state.mAnchorOffset = 0; - } - state.mStackFromEnd = mStackFromEnd; - state.mReverseLayout = mReverseLayout; - state.mOrientation = mOrientation; - return state; - } - - @Override - public void onRestoreInstanceState(Parcelable state) - { - if (state instanceof SavedState) - { - mPendingSavedState = (SavedState) state; - requestLayout(); - if (DEBUG) - { -// Log.d(TAG, "loaded saved state"); - } - } - else if (DEBUG) - { -// Log.d(TAG, "invalid saved state class"); - } - } - - /** - * @return true if {@link #getOrientation()} is {@link #HORIZONTAL} - */ - @Override - public boolean canScrollHorizontally() - { - return mOrientation == HORIZONTAL; - } - - /** - * @return true if {@link #getOrientation()} is {@link #VERTICAL} - */ - @Override - public boolean canScrollVertically() - { - return mOrientation == VERTICAL; - } - - /** - * Compatibility support for - * {@link android.widget.AbsListView#setStackFromBottom(boolean)} - */ - public void setStackFromEnd(boolean stackFromEnd) - { - if (mPendingSavedState != null && mPendingSavedState.mStackFromEnd != stackFromEnd) - { - // override pending state - mPendingSavedState.mStackFromEnd = stackFromEnd; - } - if (mStackFromEnd == stackFromEnd) - { - return; - } - mStackFromEnd = stackFromEnd; - requestLayout(); - } - - public boolean getStackFromEnd() - { - return mStackFromEnd; - } - - /** - * Returns the current orientaion of the layout. - * - * @return Current orientation. - * @see #mOrientation - * @see #setOrientation(int) - */ - public int getOrientation() - { - return mOrientation; - } - - /** - * Sets the orientation of the layout. - * {@link LinearLayoutManager} - * will do its best to keep scroll position. - * - * @param orientation - * {@link #HORIZONTAL} or {@link #VERTICAL} - */ - public void setOrientation(int orientation) - { - if (orientation != HORIZONTAL && orientation != VERTICAL) - { - throw new IllegalArgumentException("invalid orientation."); - } - if (mPendingSavedState != null && mPendingSavedState.mOrientation != orientation) - { - // override pending state - mPendingSavedState.mOrientation = orientation; - } - if (orientation == mOrientation) - { - return; - } - mOrientation = orientation; - mOrientationHelper = null; - requestLayout(); - } - - /** - * Calculates the view layout order. (e.g. from end to start or start to - * end) RTL layout support is applied automatically. So if layout is RTL and - * {@link #getReverseLayout()} is {@code true}, elements will be laid out - * starting from left. - */ - private void resolveShouldLayoutReverse() - { - // A == B is the same result, but we rather keep it readable - if (mOrientation == VERTICAL || !isLayoutRTL()) - { - mShouldReverseLayout = mReverseLayout; - } - else - { - mShouldReverseLayout = !mReverseLayout; - } - } - - /** - * Returns if views are laid out from the opposite direction of the layout. - * - * @return If layout is reversed or not. - * @see {@link #setReverseLayout(boolean)} - */ - public boolean getReverseLayout() - { - return mReverseLayout; - } - - /** - * Used to reverse item traversal and layout order. This behaves similar to - * the layout change for RTL views. When set to true, first item is rendered - * at the end of the UI, second item is render before it etc. - *

- * For horizontal layouts, it depends on the layout direction. When set to - * true, If {@link RecyclerViewBase} - * is LTR, than it will render from RTL, if - * {@link RecyclerViewBase} is RTL, it - * will render from LTR. - *

- * If you are looking for the exact same behavior of - * {@link android.widget.AbsListView#setStackFromBottom(boolean)}, use - * {@link #setStackFromEnd(boolean)} - */ - public void setReverseLayout(boolean reverseLayout) - { - if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) - { - // override pending state - mPendingSavedState.mReverseLayout = reverseLayout; - } - if (reverseLayout == mReverseLayout) - { - return; - } - mReverseLayout = reverseLayout; - requestLayout(); - } - - @Override - public View findViewByPosition(int position) - { - final int childCount = getChildCount(); - if (childCount == 0) - { - return null; - } - final int firstChild = getPosition(getChildAt(0)); - final int viewPosition = position - firstChild; - if (viewPosition >= 0 && viewPosition < childCount) - { - return getChildAt(viewPosition); - } - return null; - } - - /** - *

- * Returns the amount of extra space that should be rendered by - * LinearLayoutManager. By default, - * {@link LinearLayoutManager} - * lays out 1 extra page of items while smooth scrolling and 0 otherwise. - * You can override this method to implement your custom layout pre-cache - * logic. - *

- *

- * Laying out invisible elements will eventually come with performance cost. - * On the other hand, in places like smooth scrolling to an unknown - * location, this extra content helps LayoutManager to calculate a much - * smoother scrolling; which improves user experience. - *

- *

- * You can also use this if you are trying to pre-render your upcoming - * views. - *

- * - * @return The extra space that should be laid out (in pixels). - */ - protected int getExtraLayoutSpace(RecyclerViewBase.State state) - { - return (mRecyclerView.shouldPrebindItem() || state.hasTargetScrollPosition()) ? mOrientationHelper.getTotalSpace() : 0; - } - - @Override - public void smoothScrollToPosition(RecyclerViewBase recyclerView, RecyclerViewBase.State state, int position) - { - LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) - { - @Override - public PointF computeScrollVectorForPosition(int targetPosition) - { - return BaseLayoutManager.this.computeScrollVectorForPosition(targetPosition); - } - }; - linearSmoothScroller.setTargetPosition(position); - startSmoothScroll(linearSmoothScroller); - } - - public PointF computeScrollVectorForPosition(int targetPosition) - { - if (getChildCount() == 0) - { - return null; - } - final int firstChildPos = getPosition(getChildAt(0)); - final int direction = targetPosition < firstChildPos != mShouldReverseLayout ? -1 : 1; - if (mOrientation == HORIZONTAL) - { - return new PointF(direction, 0); - } - else - { - return new PointF(0, direction); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void onLayoutChildren(RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state) - { - // layout algorithm: - // 1) by checking children and other variables, find an anchor - // coordinate and an anchor - // item position. - // 2) fill towards start, stacking from bottom - // 3) fill towards end, stacking from top - // 4) scroll to fulfill requirements like stack from bottom. - // create render state - if (DEBUG) - { -// Log.d(TAG, "is pre layout:" + state.isPreLayout()); -// Log.d("RecyclerView", "start layout!!"); - } -// Log.d("leo", "onlayoutchildren"); - if (mPendingSavedState != null) - { - setOrientation(mPendingSavedState.mOrientation); - setReverseLayout(mPendingSavedState.mReverseLayout); - setStackFromEnd(mPendingSavedState.mStackFromEnd); - mPendingScrollPosition = mPendingSavedState.mAnchorPosition; - } - - ensureRenderState(); - // Log.d("LinearLayoutManager#RenderState", - // "onlayoutchildren started!"); - // mRenderState.log(); - // resolve layout direction - resolveShouldLayoutReverse(); - - // validate scroll position if exists - if (mPendingScrollPosition != RecyclerViewBase.NO_POSITION) - { - // validate it -// Log.d("RecyclerView", "baselayoutmanager mPendingScrollPosition=" + mPendingScrollPosition); - if (mPendingScrollPosition < -state.mHeaderCount || (mPendingScrollPosition >= state.getItemCount())) - { - if (mPendingScrollPosition != 0 || state.getItemCount() != 0) - { - mPendingScrollPosition = RecyclerViewBase.NO_POSITION; - mPendingScrollPositionOffset = INVALID_OFFSET; - if (DEBUG) - { -// Log.e(TAG, "ignoring invalid scroll position " + mPendingScrollPosition); - } - } - - } - } - // this value might be updated if there is a target scroll position - // without an offset - boolean layoutFromEnd = mShouldReverseLayout ^ mStackFromEnd; - - final boolean stackFromEndChanged = mLastStackFromEnd != mStackFromEnd; - - int anchorCoordinate, anchorItemPosition; - if (mPendingScrollPosition != RecyclerViewBase.NO_POSITION) - { - // if child is visible, try to make it a reference child and ensure - // it is fully visible. - // if child is not visible, align it depending on its virtual - // position. - anchorItemPosition = mPendingScrollPosition; - if (mPendingGravity != Gravity.NO_GRAVITY) - { - final int verticalGravity = mPendingGravity & Gravity.VERTICAL_GRAVITY_MASK; - switch (verticalGravity) - { - case Gravity.TOP: - mPendingScrollPositionOffset = mOrientationHelper.getStartAfterPadding(); - break; - case Gravity.CENTER_VERTICAL: - mPendingScrollPositionOffset = (mRecyclerView.getMeasuredHeight() - mPendingScrollPositionItemHeight) / 2 - - mPendingScrollPositionItemHeight; - break; - case Gravity.BOTTOM: - mPendingScrollPositionOffset = mRecyclerView.getMeasuredHeight() - mPendingScrollPositionItemHeight; - break; - default: - } - } - if (mPendingSavedState != null) - { - // Anchor offset depends on how that child was laid out. Here, - // we update it - // according to our current view bounds - layoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd; - if (layoutFromEnd) - { - anchorCoordinate = mOrientationHelper.getEndAfterPadding() - mPendingSavedState.mAnchorOffset; - } - else - { - anchorCoordinate = mOrientationHelper.getStartAfterPadding() + mPendingSavedState.mAnchorOffset; - } - } - else if (mPendingScrollPositionOffset == INVALID_OFFSET) - { - View child = findViewByPosition(mPendingScrollPosition); - if (child != null) - { - final int startGap = mOrientationHelper.getDecoratedStart(child) - mOrientationHelper.getStartAfterPadding(); - final int endGap = mOrientationHelper.getEndAfterPadding() - mOrientationHelper.getDecoratedEnd(child); - final int childSize = mOrientationHelper.getDecoratedMeasurement(child); - if (childSize > mOrientationHelper.getTotalSpace()) - { - // item does not fit. fix depending on layout direction - anchorCoordinate = layoutFromEnd ? mOrientationHelper.getEndAfterPadding() : mOrientationHelper.getStartAfterPadding(); - } - else if (startGap < 0) - { - anchorCoordinate = mOrientationHelper.getStartAfterPadding(); - layoutFromEnd = false; - } - else if (endGap < 0) - { - anchorCoordinate = mOrientationHelper.getEndAfterPadding(); - layoutFromEnd = true; - } - else - { - anchorCoordinate = layoutFromEnd ? mOrientationHelper.getDecoratedEnd(child) : mOrientationHelper.getDecoratedStart(child); - } - } - else - { // item is not visible. - if (getChildCount() > 0) - { - // get position of any child, does not matter - int pos = getPosition(getChildAt(0)); - if (mPendingScrollPosition < pos == mShouldReverseLayout) - { - anchorCoordinate = mOrientationHelper.getEndAfterPadding(); - layoutFromEnd = true; - } - else - { - anchorCoordinate = mOrientationHelper.getStartAfterPadding(); - layoutFromEnd = false; - } - } - else - { - anchorCoordinate = layoutFromEnd ? mOrientationHelper.getEndAfterPadding() : mOrientationHelper.getStartAfterPadding(); - } - } - } - else - { - // override layout from end values for consistency - if (mShouldReverseLayout) - { - anchorCoordinate = mOrientationHelper.getEndAfterPadding() - mPendingScrollPositionOffset; - layoutFromEnd = true; - } - else - { - anchorCoordinate = mOrientationHelper.getStartAfterPadding() + mPendingScrollPositionOffset; - layoutFromEnd = false; - } - } - } - else if (getChildCount() > 0 && !stackFromEndChanged) - { - if (layoutFromEnd) - { - // View referenceChild = getChildClosestToEndInLogic(); - anchorCoordinate = mOrientationHelper.getDecoratedEnd(getChildClosestToEndInScreen()); - anchorItemPosition = getPosition(getChildClosestToEndByOrder()); - } - else - { - // View referenceChild = getChildClosestToStartInLogic(); - // View firstValidView=getFirstValidChild(); - // if (firstValidView ==null) - // { - // anchorCoordinate = mOrientationHelper.getStartAfterPadding(); - // anchorItemPosition = - // -mRecyclerView.mAdapter.getHeaderViewCount(); - // } - // else - // { - View firstValidView = getChildClosestToStartByOrder(); - // View firstValidView = getChildClosestToStartInScreen(); - anchorCoordinate = mOrientationHelper.getDecoratedStart(firstValidView); - anchorItemPosition = getPosition(firstValidView); - // } - // FIXME:ugly bug - // fix,gridlayout在横竖屏切换之后,选取的anchor不能被column整出,排版异常。 - // if (mRecyclerView.mLayoutType == - // RecyclerView.LAYOUT_TYPE_GRID) - // { - // int remain = anchorItemPosition % ((GridLayoutManager) - // this).mColumns; - // if (remain != 0) - // { - // anchorItemPosition = anchorItemPosition + - // ((GridLayoutManager) this).mColumns - remain; - // } - // } - - } - } - else - { - anchorCoordinate = layoutFromEnd ? mOrientationHelper.getEndAfterPadding() : mOrientationHelper.getStartAfterPadding(); - anchorItemPosition = mStackFromEnd ? state.getItemCount() - 1 + mRecyclerView.mAdapter.getFooterViewCount() - : -mRecyclerView.mAdapter.getHeaderViewCount(); - } - anchorItemPosition = mRecyclerView.validateAnchorItemPosition(anchorItemPosition); - anchorItemPosition = validateAnchorPosition(mRenderState.mItemDirection, anchorItemPosition, - state.getItemCount()); - detachAndScrapAttachedViews(recycler); - if (state.mDataChanged) - { - state.mDataChanged = false; - // set current suspension View recyclable here - if (mCurrentSuspentionView != null && !mRecyclerView.isRepeatableSuspensionMode()) - { - RecyclerViewBase.ViewHolder suspensionViewHolder = mRecyclerView.getChildViewHolder(mCurrentSuspentionView); - if (suspensionViewHolder != null) - { - suspensionViewHolder.setIsRecyclable(true); - } - } - removeAndRecycleScrapInt(recycler, true, true); - } - final int extraForStart; - final int extraForEnd; - final int extra = getExtraLayoutSpace(state); - boolean before = state.getTargetScrollPosition() < anchorItemPosition; - if (before == mShouldReverseLayout) - { - extraForEnd = extra; - extraForStart = 0; - } - else - { - extraForStart = extra; - extraForEnd = 0; - } - // first fill towards start - updateRenderStateToFillStart(anchorItemPosition, anchorCoordinate); - mRenderState.mExtra = extraForStart; - if (!layoutFromEnd) - { - mRenderState.mCurrentPosition += mRenderState.mItemDirection; - } - fill(recycler, mRenderState, state, false); - int currPos = mRenderState.mCurrentPosition - mRenderState.mItemDirection; - // Log.d("Scrollbar", "currPos=" + currPos); - int startOffset = mRenderState.mOffset; - if (mOrientation == VERTICAL) - { - // Log.e("leo", "after fill mOffsetY " + mRecyclerView.mOffsetY); - mRecyclerView.mOffsetY = getHeightBefore(currPos) - startOffset; - // Log.e("leo", "after fill == mOffsetY " + mRecyclerView.mOffsetY); - // Log.d("leo", "in onLayout offset=" + mRecyclerView.mOffsetY); - } - else if (mOrientation == HORIZONTAL) - { - - mRecyclerView.mOffsetX = getHeightBefore(currPos) - startOffset; - // Log.d("leo", "in onLayout offset=" + mRecyclerView.mOffsetY); - } - // fill towards end - updateRenderStateToFillEnd(anchorItemPosition, anchorCoordinate); - mRenderState.mExtra = extraForEnd; - if (layoutFromEnd) - { - mRenderState.mCurrentPosition += mRenderState.mItemDirection; - } - fill(recycler, mRenderState, state, false); - int endOffset = mRenderState.mOffset; - mRecyclerView.onItemsFill(endOffset); - mRecyclerView.checkNotifyFooterAppearWithFewChild(endOffset); - // checkChildNotMuch(endOffset); - // changes may cause gaps on the UI, try to fix them. - if (getChildCount() > 0 && !mPreventFixGap && mRecyclerView.mState.mCustomHeaderHeight == 0) - { - // because layout from end may be changed by scroll to position - // we re-calculate it. - // find which side we should check for gaps. - // if (mShouldReverseLayout ^ mStackFromEnd) - // { - // int fixOffset = fixLayoutEndGap(endOffset, recycler, state, - // true); - // startOffset += fixOffset; - // endOffset += fixOffset; - // fixOffset = fixLayoutStartGap(startOffset, recycler, state, - // false); - // startOffset += fixOffset; - // endOffset += fixOffset; - // } - // else - // { - if (getHeight() <= mRecyclerView.mAdapter.getListTotalHeight()) - { - int fixOffset = fixLayoutStartGap(startOffset, recycler, state, true); - startOffset += fixOffset; - // TODO:这里注释掉了,可以解决问题,但不知道会不会引起其他问题。 - // if (getHeight() <= mRecyclerView.mAdapter.getTotalHeight()) - // { - endOffset += fixOffset; - // } - fixOffset = fixLayoutEndGap(endOffset, recycler, state, false); - startOffset += fixOffset; - endOffset += fixOffset; - } - else - { - //niuniuyang:如果内容小于屏幕高度了,如果mOffset不是原点,必须把list的offset重新回到原点 - int gap = mRecyclerView.mOffsetY - mOrientationHelper.getStartAfterPadding(); - if (gap != 0) - { - if (!doNotCheckAgain) - { - doNotCheckAgain = true; - int firstPosition = -mRecyclerView.mAdapter.getHeaderViewCount(); - scrollToPositionWidthOffsetInLayout(firstPosition, mOrientationHelper.getStartAfterPadding()); - } - else - { - doNotCheckAgain = false; - } - } - else if (doNotCheckAgain) - { - doNotCheckAgain = false; - } - - } - // } - } - - // If there are scrap children that we did not layout, we need to find - // where they did go - // and layout them accordingly so that animations can work as expected. - // This case may happen if new views are added or an existing view - // expands and pushes - // another view out of bounds. - if (getChildCount() > 0 && !state.isPreLayout() && supportsPredictiveItemAnimations()) - { - // to make the logic simpler, we calculate the size of children and - // call fill. - int scrapExtraStart = 0, scrapExtraEnd = 0; - final List scrapList = recycler.getScrapList(); - final int scrapSize = scrapList.size(); - final int firstChildPos = getPosition(getChildAt(0)); - for (int i = 0; i < scrapSize; i++) - { - RecyclerViewBase.ViewHolder scrap = scrapList.get(i); - final int position = scrap.getPosition(); - final int direction = position < firstChildPos != mShouldReverseLayout ? RenderState.LAYOUT_START : RenderState.LAYOUT_END; - if (direction == RenderState.LAYOUT_START) - { - scrapExtraStart += mOrientationHelper.getDecoratedMeasurement(scrap.itemView); - } - else - { - scrapExtraEnd += mOrientationHelper.getDecoratedMeasurement(scrap.itemView); - } - } - - if (DEBUG) - { -// Log.d(TAG, "for unused scrap, decided to add " + scrapExtraStart + " towards start and " + scrapExtraEnd + " towards end"); - } - mRenderState.mScrapList = scrapList; - if (scrapExtraStart > 0) - { - // View anchor = getChildClosestToStartInScreen(); - updateRenderStateToFillStart(getPosition(getChildClosestToStartByOrder()), startOffset); - mRenderState.mExtra = scrapExtraStart; - mRenderState.mAvailable = 0; - mRenderState.mCurrentPosition += mShouldReverseLayout ? 1 : -1; - fill(recycler, mRenderState, state, false); - } - - if (scrapExtraEnd > 0) - { - // View anchor = getChildClosestToEndByOrder(); - updateRenderStateToFillEnd(getPosition(getChildClosestToEndByOrder()), endOffset); - mRenderState.mExtra = scrapExtraEnd; - mRenderState.mAvailable = 0; - mRenderState.mCurrentPosition += mShouldReverseLayout ? -1 : 1; - fill(recycler, mRenderState, state, false); - } - mRenderState.mScrapList = null; - } - removeSuspentions(); - ensureSuspentionState(); - mPendingScrollPosition = RecyclerViewBase.NO_POSITION; - mPendingScrollPositionOffset = INVALID_OFFSET; - mLastStackFromEnd = mStackFromEnd; - mPendingGravity = Gravity.NO_GRAVITY; - mPendingSavedState = null; // we don't need this anymore - if (DEBUG) - { - // validateChildOrder(); - } - } - - public void removeSuspentions() - { - if (mCurrentSuspentionView != null && mCurrentSuspentionView.getParent() == mRecyclerView) - { - mCurrentSuspentionView.clearAnimation(); - mRecyclerView.removeAnimatingView(mCurrentSuspentionView, true); - mCurrentSuspentionView = null; - } - } - - public View getCurrentSuspentionView() - { - return mCurrentSuspentionView; - } - - public int getCurrentSuspentionPosition() - { - return mCurrentSuspentionPos; - } - - private boolean doNotCheckAgain = false; - - protected int getHeightBefore(int pos) - { - if (mRecyclerView != null) - { - return mRecyclerView.getHeightBefore(pos); - } - return 0; - } - - /** - * @return The final offset amount for children - */ - private int fixLayoutEndGap(int endOffset, RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state, boolean canOffsetChildren) - { - // 下拉刷新的时候,刷新的位置距离顶部是有距离的,但是这个距离是主动调用了smoothScrollBy来消除的,所以这里不需要fixGap了,anyuanzhao - if (mRecyclerView.isRefreshing() || mRecyclerView.mState.mCustomHeaderHeight > 0) - { - return 0; - } - int gap = mOrientationHelper.getEndAfterPadding() - endOffset; - int fixOffset = 0; - if (gap > 0) - { - state.overscroll = false; - fixOffset = -scrollBy(-gap, recycler, state); - } - else - { - return 0; // nothing to fix - } - // move offset according to scroll amount - endOffset += fixOffset; - if (canOffsetChildren) - { - // re-calculate gap, see if we could fix it - gap = mOrientationHelper.getEndAfterPadding() - endOffset; - if (gap > 0) - { - mOrientationHelper.offsetChildren(gap); - return gap + fixOffset; - } - } - return fixOffset; - } - - // private int fixLayoutEndGap(int endOffset, RecyclerView.Recycler - // recycler, RecyclerView.State state, boolean canOffsetChildren) - // { - // int gap = mOrientationHelper.getEndAfterPadding() - endOffset; - // int fixOffset = 0; - // if (gap > 0) - // { - // // fixOffset = -scrollBy(-gap, recycler, state); - // View view = getChildClosestToEndInVisual(); - // if (view != null && view instanceof DefaultFooterView) - // { - // Adapter adapter = mRecyclerView.getAdapter(); - // if (adapter != null && adapter instanceof QBRecyclerAdapter) - // { - // ((QBRecyclerAdapter) adapter).notifyLastFooterAppeared(); - // } - // } - // } - // else - // { - // return 0; // nothing to fix - // } - // // // move offset according to scroll amount - // // endOffset += fixOffset; - // // if (canOffsetChildren) - // // { - // // // re-calculate gap, see if we could fix it - // // gap = mOrientationHelper.getEndAfterPadding() - endOffset; - // // if (gap > 0) - // // { - // // mOrientationHelper.offsetChildren(gap); - // // return gap + fixOffset; - // // } - // // } - // return fixOffset; - // } - - /** - * @return The final offset amount for children - */ - private int fixLayoutStartGap(int startOffset, RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state, boolean canOffsetChildren) - { - // 下拉刷新的时候,刷新的位置距离顶部是有距离的,但是这个距离是主动调用了smoothScrollBy来消除的,所以这里不需要fixGap了,anyuanzhao - if (mRecyclerView.isRefreshing()) - { - return 0; - } - int gap = startOffset - mOrientationHelper.getStartAfterPadding(); - /*- ((mRecyclerView.mEnableRefresh && mRecyclerView.mMode != RecyclerView.MODE_EDIT) ? mRecyclerView.mQBRefreshHeader.mContentheight*/ - // : 0); - int fixOffset = 0; - if (gap > 0) - { - // check if we should fix this gap. - state.overscroll = false; - fixOffset = -scrollBy(gap, recycler, state); - } - else - { - return 0; // nothing to fix - } - startOffset += fixOffset; - if (canOffsetChildren) - { - // re-calculate gap, see if we could fix it - gap = startOffset - mOrientationHelper.getStartAfterPadding(); - // - ((mRecyclerView.mEnableRefresh && mRecyclerView.mMode != - // RecyclerView.MODE_EDIT) ? - // mRecyclerView.mQBRefreshHeader.mContentheight - // : 0); - if (gap > 0) - { - mOrientationHelper.offsetChildren(-gap); - return fixOffset - gap; - } - } - return fixOffset; - } - - protected void updateRenderStateToFillEnd(int itemPosition, int offset) - { - mRenderState.mAvailable = mOrientationHelper.getEndAfterPadding() - offset; - mRenderState.mItemDirection = mShouldReverseLayout ? RenderState.ITEM_DIRECTION_HEAD : RenderState.ITEM_DIRECTION_TAIL; - mRenderState.mCurrentPosition = itemPosition; - mRenderState.mLayoutDirection = RenderState.LAYOUT_END; - mRenderState.mOffset = offset; - mRenderState.mScrollingOffset = RenderState.SCOLLING_OFFSET_NaN; - if (DEBUG) - mRenderState.log("updateRenderStateToFillEnd(" + itemPosition + "," + offset + ") "); - } - - protected void updateRenderStateToFillStart(int itemPosition, int offset) - { - mRenderState.mAvailable = offset - mOrientationHelper.getStartAfterPadding(); - mRenderState.mCurrentPosition = itemPosition; - mRenderState.mItemDirection = mShouldReverseLayout ? RenderState.ITEM_DIRECTION_TAIL : RenderState.ITEM_DIRECTION_HEAD; - mRenderState.mLayoutDirection = RenderState.LAYOUT_START; - mRenderState.mOffset = offset; - mRenderState.mScrollingOffset = RenderState.SCOLLING_OFFSET_NaN; - if (DEBUG) - mRenderState.log("updateRenderStateToFillStart(" + itemPosition + "," + offset + ") "); - } - - protected boolean isLayoutRTL() - { - return false; - } - - - protected void ensureRenderState() - { - if (mRenderState == null) - { - mRenderState = new RenderState(); - } - if (mOrientationHelper == null) - { - mOrientationHelper = mOrientation == HORIZONTAL ? createHorizontalOrientationHelper() : createVerticalOrientationHelper(); - } - } - - /** - *

- * Scroll the RecyclerView to make the position visible. - *

- *

- *

- * RecyclerView will scroll the minimum amount that is necessary to make the - * target position visible. If you are looking for a similar behavior to - * {@link android.widget.ListView#setSelection(int)} or - * {@link android.widget.ListView#setSelectionFromTop(int, int)}, use - * {@link #scrollToPositionWithOffset(int, int)}. - *

- *

- *

- * Note that scroll position change will not be reflected until the next - * layout call. - *

- * - * @param position - * Scroll to this adapter position - * @see #scrollToPositionWithOffset(int, int) - */ - @Override - public void scrollToPosition(int position) - { - mPendingScrollPosition = position; - mPendingScrollPositionOffset = INVALID_OFFSET; - requestLayout(); - } - - public int getPendingOffset() - { - return mPendingScrollPositionOffset; - } - - @Override - public void scrollToPositionWidthGravity(int position, int gravity, int itemHeight) - { - // TODO Auto-generated method stub - mPendingScrollPosition = position; - mPendingGravity = gravity; - mPendingScrollPositionOffset = INVALID_OFFSET; - mPendingScrollPositionItemHeight = itemHeight; - requestLayout(); - } - - /** - *

- * Scroll to the specified adapter position with the given offset from - * layout start. - *

- *

- *

- * Note that scroll position change will not be reflected until the next - * layout call. - *

- *

- *

- * If you are just trying to make a position visible, use - * {@link #scrollToPosition(int)}. - *

- * - * @param position - * Index (starting at 0) of the reference item. - * @param offset - * The distance (in pixels) between the start edge of the item - * view and start edge of the RecyclerView. - * @see #setReverseLayout(boolean) - * @see #scrollToPosition(int) - */ - public void scrollToPositionWithOffset(int position, int offset) - { - mPendingScrollPosition = position; - mPendingScrollPositionOffset = offset; - requestLayout(); - } - - public void scrollToPositionWidthOffsetInLayout(int position, int offset) - { - mPendingGravity = Gravity.NO_GRAVITY; - mPendingScrollPosition = position; - mPendingScrollPositionOffset = offset; - mRecyclerView.dispatchLayout(); - } - - /** - * {@inheritDoc} - */ - @Override - public int scrollHorizontallyBy(int dx, RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state) - { - if (mOrientation == VERTICAL) - { - return 0; - } - state.overscroll = true; - return scrollBy(dx, recycler, state); - } - - /** - * {@inheritDoc} - */ - @Override - public int scrollVerticallyBy(int dy, RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state) - { - if (mOrientation == HORIZONTAL) - { - return 0; - } - if (Math.abs(dy) > getHeight() * 1.5f) - { - int newDy = dy; - if (mRecyclerView.mOffsetY + dy < -mRecyclerView.getSpringBackMaxDistance()) - { - newDy = -mRecyclerView.getSpringBackMaxDistance() - mRecyclerView.mOffsetY; - } - else if (mRecyclerView.mOffsetY + dy > mRecyclerView.mAdapter.getListTotalHeight() + mRecyclerView.getSpringBackMaxDistance()) - { - newDy = mRecyclerView.mAdapter.getListTotalHeight() + mRecyclerView.getSpringBackMaxDistance() - mRecyclerView.mOffsetY; - } - int newOffsetY = mRecyclerView.mOffsetY + newDy; - int[] target = mRecyclerView.mAdapter.getBeginPositionWithOffset(newOffsetY); - mRecyclerView.mLayout.mPendingScrollPosition = target[0]; - mRecyclerView.mLayout.mPendingScrollPositionOffset = target[1]; - mRecyclerView.dispatchLayout(); - return Math.abs(newDy); - } - else - { - state.overscroll = true; - return scrollBy(dy, recycler, state); - } - } - - @Override - public int computeHorizontalScrollOffset(RecyclerViewBase.State state) - { - if (getChildCount() == 0) - { - return 0; - } - final int topPosition = getPosition(getChildClosestToStartByOrder()); - return mShouldReverseLayout ? state.getItemCount() - 1 - topPosition : topPosition; - } - - @Override - public int computeVerticalScrollOffset(RecyclerViewBase.State state) - { - if (getChildCount() == 0) - { - return 0; - } - final int topPosition = getPosition(getChildClosestToStartByOrder()); - return mShouldReverseLayout ? state.getItemCount() - 1 - topPosition : topPosition; - } - - @Override - public int computeHorizontalScrollExtent(RecyclerViewBase.State state) - { - return getChildCount(); - } - - @Override - public int computeVerticalScrollExtent(RecyclerViewBase.State state) - { - return getChildCount(); - } - - @Override - public int computeHorizontalScrollRange(RecyclerViewBase.State state) - { - return state.getItemCount(); - } - - @Override - public int computeVerticalScrollRange(RecyclerViewBase.State state) - { - return state.getItemCount(); - } - - protected void updateRenderState(int layoutDirection, int requiredSpace, boolean canUseExistingSpace, RecyclerViewBase.State state) - { - mRenderState.mExtra = getExtraLayoutSpace(state); - mRenderState.mLayoutDirection = layoutDirection; - int fastScrollSpace; - if (layoutDirection == RenderState.LAYOUT_END) - { - // get the first child in the direction we are going - // final View child = getChildClosestToEndInVisual(); - if (DEBUG) - { - // Log.d(TAG, "child close to end=" + getPosition(child)); - } - - // the direction in which we are traversing children - mRenderState.mItemDirection = mShouldReverseLayout ? RenderState.ITEM_DIRECTION_HEAD : RenderState.ITEM_DIRECTION_TAIL; - mRenderState.mCurrentPosition = getPosition(getChildClosestToEndByOrder()) + mRenderState.mItemDirection; - // Log.d(TAG, "currPos=" + mRenderState.mCurrentPosition + - // ",itemCount=" + state.mItemCount); - mRenderState.mOffset = mOrientationHelper.getDecoratedEnd(getChildClosestToEndInScreen()); - // calculate how much we can scroll without adding new children - // (independent of layout) - fastScrollSpace = mOrientationHelper.getDecoratedEnd(getChildClosestToEndInScreen()) - mOrientationHelper.getEndAfterPadding(); - - } - else - { - // final View child = getChildClosestToStartInVisual(); - mRenderState.mItemDirection = mShouldReverseLayout ? RenderState.ITEM_DIRECTION_TAIL : RenderState.ITEM_DIRECTION_HEAD; - mRenderState.mCurrentPosition = getPosition(getChildClosestToStartByOrder()) + mRenderState.mItemDirection; - // getDecoratedStart是child的top - mRenderState.mOffset = mOrientationHelper.getDecoratedStart(getChildClosestToStartInScreen()); - // getStartAfterPadding是recyclerview的top - fastScrollSpace = -mOrientationHelper.getDecoratedStart(getChildClosestToStartInScreen()) + mOrientationHelper.getStartAfterPadding(); - } -// if (DEBUG) -// Log.d(TAG, "updateRenderState layoutDirection=" + layoutDirection + " mRenderState.mOffset=" + mRenderState.mOffset); - mRenderState.mAvailable = requiredSpace; - if (canUseExistingSpace) - { - mRenderState.mAvailable -= fastScrollSpace; - } - mRenderState.overscroll = state.overscroll; - mRenderState.mScrollingOffset = fastScrollSpace; - } - - long time = 0; - - private int scrollBy(int dy, RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state) - { - - time = System.currentTimeMillis(); - if (getChildCount() == 0 || dy == 0) - { - return 0; - } - ensureRenderState(); - final int layoutDirection = dy > 0 ? RenderState.LAYOUT_END : RenderState.LAYOUT_START; - final int absDy = Math.abs(dy); - // if (DEBUG) - // { - // if (mCurrentSuspension != -1) - // Log.d(TAG, "before scroll!," + "mCurrentPos=" + mCurrentSuspension + - // ",offset=" + mSuspensionOffset + "v.getTop=" - // + mRecyclerView.getAnimatingView(mCurrentSuspension, - // RecyclerView.INVALID_TYPE).getTop()); - // } - // ensureSuspensionState(layoutDirection); - updateRenderState(layoutDirection, absDy, true, state); - final int freeScroll = mRenderState.mScrollingOffset; - //Log.e("RecyclerView", "start scroll---------------------dy=" + dy); - final int consumed = freeScroll + fill(recycler, mRenderState, state, false); - if (consumed < 0) - { - if (DEBUG) - { -// Log.d(TAG, "Don't have any more elements to scroll"); - } - return 0; - - } - final int scrolled = absDy > consumed ? layoutDirection * consumed : dy; - mOrientationHelper.offsetChildren(-scrolled); - if (DEBUG) - { -// Log.d("leo", "scroll req: " + dy + " scrolled: " + scrolled); - } - ensureSuspentionState(); - if (DEBUG) - { - // if (mCurrentSuspension != -1) - // Log.d(TAG, "after scroll!," + "mCurrentPos=" + mCurrentSuspension - // + ",offset=" + mSuspensionOffset + "v.getTop=" - // + mRecyclerView.getAnimatingView(mCurrentSuspension, - // RecyclerView.INVALID_TYPE).getTop()); - } - final int preloadThresholdInPixel = mRecyclerView.mAdapter.getPreloadThresholdInPixels(); - final int preloadThresholdInItemNumber = mRecyclerView.mAdapter.getPreloadThresholdInItemNumber(); - if (preloadThresholdInPixel > 0 && mRecyclerView.getHeight() < state.mTotalHeight) // 根据离end的距离,触发预加载 - { - if (mRecyclerView.mOffsetY + preloadThresholdInPixel + mRecyclerView.getHeight() < state.mTotalHeight - && mRecyclerView.mOffsetY + preloadThresholdInPixel + scrolled + mRecyclerView.getHeight() >= state.mTotalHeight) - { - mRecyclerView.mAdapter.onPreload(); - } - } - else if (preloadThresholdInItemNumber > 0 && mRecyclerView.getHeight() < state.mTotalHeight) // 根据离end的item个数,触发预加载 - { - int currentPosHeight = mRecyclerView.mAdapter.getHeightBefore(mRenderState.mCurrentPosition - mRenderState.mItemDirection); - if (mRenderState.mCurrentPosition == getItemCount() - preloadThresholdInItemNumber - && mRecyclerView.mOffsetY + mRecyclerView.getHeight() < currentPosHeight - && mRecyclerView.mOffsetY + scrolled + mRecyclerView.getHeight() >= currentPosHeight) - { - mRecyclerView.mAdapter.onPreload(); - } - } - if (mOrientation == HORIZONTAL) - { - mRecyclerView.mOffsetX += scrolled; - } - else - { - // Log.e("leo", "scrollBy mOffsetY " + mRecyclerView.mOffsetY); - mRecyclerView.mOffsetY += scrolled; - // Log.e("leo", "scrollBy ===mOffsetY " + mRecyclerView.mOffsetY); - } - // Log.d("leo", "scrollBy offset=" + mRecyclerView.mOffsetY); - mPreventFixGap = mRecyclerView.isInOverScrollArea(); - // Log.d(TAG, "scrollY=" + mRecyclerView.mOffsetY + "height=" + - // getHeight()); - return scrolled; - } - - - private void ensureSuspentionState() - { - if (!mRecyclerView.hasSuspentedItem()) - { - return; - } - - final int count = getChildCount(); - if (count == 0) - { - return; - } -// Log.d("leo", "ensureSuspensionState,count=" + count); - // Log.d("leo", "--------------------------------"); - View startView = getChildClosestToStartByOrder(); - int startPos = getPosition(startView); - if (startView.getTop() > 0) - { - showCurrentSuspention(RecyclerViewBase.NO_POSITION); - return; - } - // int top = getDecoratedStart(startView); - int lastSuspentedPos = mRecyclerView.findPrevSuspentedPos(startPos); - if (lastSuspentedPos != -1) - { - showCurrentSuspention(lastSuspentedPos); - } - // Log.d("TMYSUS", "start=" + startPos + ",last=" + lastSuspendedPos); - if (mCurrentSuspentionView != null && mCurrentSuspentionView.getParent() == mRecyclerView) - { - int currentHeight = mCurrentSuspentionView.getMeasuredHeight(); - int nextSuspendedPos = mRecyclerView.findNextSuspentedPos(startPos); - View nextSuspentedView = null; - if (nextSuspendedPos != -1) - { - nextSuspentedView = findViewByPosition(nextSuspendedPos); - } - int nextTop = nextSuspentedView == null ? Integer.MAX_VALUE : nextSuspentedView.getTop(); - if (nextTop < currentHeight) - { - mCurrentSuspentionView.offsetTopAndBottom(nextTop - currentHeight); - } - // Log.d("TMYSUS", "next=" + nextSuspendedPos + ",nextTop=" + - // nextTop + ",currHeight=" + currentHeight); - } - - - } - - - // private void ensureSuspentionState(int layoutDirection) - // { - // if (!mRecyclerView.hasSuspentedItem()) - // { - // return; - // } - // final int count = getChildCount(); - // if (count == 0) - // { - // return; - // } - // int startPos = getPosition(getChildClosestToStartByOrder()); - // if (layoutDirection == RenderState.LAYOUT_NO_DIRECTION) - // { - // mCurrentSuspentionView = -1; - // if (mSuspentions != null) - // { - // mSuspentions.clear(); - // mSuspentions = null; - // } - // mSuspentedAreaSize = 0; - // adjustfillPos(startPos); - // mSuspentionOffset = 0; - // if (mCurrentSuspentionView != -1 && mSuspentedAreaSize != 0) - // { - // for (int i = 0; i < count; i++) - // { - // View suspentionCandidate = getChildAt(i); - // if (suspentionCandidate instanceof QBRecyclerViewItem) - // { - // QBRecyclerViewItem suspention = (QBRecyclerViewItem) suspentionCandidate; - // if (suspention.mHolder != null && mRecyclerView.getAdapter() != null) - // { - // boolean isSuspention = suspention.mHolder.isSuspentedItem(); - // if (isSuspention) - // { - // mSuspentionOffset = Math.max(Math.min(suspention.getTop(), - // mSuspentedAreaSize), 0); - // break; - // } - // } - // } - // } - // } - // applyChildOffset(); - // return; - // } - // - // int i = 0; - // for (i = 0; i < count; i++) - // { - // View suspentionCandidate = getChildAt(i); - // if (suspentionCandidate instanceof QBRecyclerViewItem) - // { - // QBRecyclerViewItem suspention = (QBRecyclerViewItem) suspentionCandidate; - // if (suspention.mHolder != null && mRecyclerView.getAdapter() != null) - // { - // boolean isSuspention = suspention.mHolder.isSuspentedItem(); - // int baseLine = mOrientationHelper.getDecoratedStart(suspentionCandidate); - // if (isSuspention) - // { - // // 上滑 - // if (layoutDirection == RenderState.LAYOUT_END) - // { - // // 推上去 - // if (0 < baseLine && baseLine < mSuspentedAreaSize && - // mCurrentSuspentionView != suspention.mHolder.mPosition) - // { - // int suspentionOffset = baseLine - mSuspentedAreaSize; - // adjustfillPos(suspention.mHolder.mPosition - 1); - // setSuspentionOffset(suspentionOffset); - // break; - // } - // // 换悬浮条目 - // if (mCurrentSuspentionView < suspention.mHolder.mPosition && baseLine <= - // 0) - // { - // setSuspentionOffset(0); - // adjustfillPos(suspention.mHolder.mPosition); - // break; - // } - // } - // // 下滑 - // else if (layoutDirection == RenderState.LAYOUT_START) - // { - // View sus = findViewByPosition(suspention.mHolder.mPosition); - // if (sus != null) - // { - // int start = mOrientationHelper.getDecoratedStart(sus); - // if (start >= 0) - // { - // if (start >= mOldSuspentedAreaSize) - // { - // start = mOldSuspentedAreaSize; - // } - // setSuspentionOffset(start - mOldSuspentedAreaSize); - // adjustRemovePos(suspention.mHolder.mPosition - 1); - // break; - // } - // } - // } - // } - // } - // } - // } - // if (i == count) - // { - // if (layoutDirection == RenderState.LAYOUT_END) - // { - // adjustfillPos(startPos - 1); - // } - // else - // { - // setSuspentionOffset(0); - // adjustRemovePos(startPos); - // } - // } - // applyChildOffset(); - // } - // - // private void adjustRemovePos(int pos) - // { - // mCurrentSuspentionView = showOldSuspentedChild(pos); - // mOldSuspentedAreaSize = mSuspentedAreaSize; - // mSuspentedAreaSize = getCurrentSuspentionChildHeight(); - // } - // - // private void adjustfillPos(int pos) - // { - // if (pos < mCurrentSuspentionView) - // { - // return; - // } - // fillBetween(mCurrentSuspentionView, pos); - // mCurrentSuspentionView = showCurrentSuspention(); - // mOldSuspentedAreaSize = mSuspentedAreaSize; - // mSuspentedAreaSize = getCurrentSuspentionChildHeight(); - // } - - // private void applyChildOffset() - // { - // if (DEBUG) - // { - // Log.d("TMYSUS", "after ensuresuspen! " + "mCurrentSus=" + - // mCurrentSuspentionView); - // } - // // TODO Auto-generated method stub - // if (mCurrentSuspentionView != -1) - // { - // View v = mRecyclerView.getAnimatingView(mCurrentSuspentionView, - // RecyclerView.INVALID_TYPE); - // if (v != null && v.getParent() == mRecyclerView) - // { - // v.offsetTopAndBottom(mSuspentionOffset - v.getTop()); - // // Log.d(TAG, "after ensuresuspen! " + "v.getTop=" + - // // v.getTop()); - // } - // } - // } - // - // private void fillBetween(int start, int end) - // { - // Adapter adapter = mRecyclerView.getAdapter(); - // if (adapter != null) - // { - // for (int i = start + 1; i <= end; i++) - // { - // if (isSuspentedItem(i)) - // { - // addSuspentions(i); - // } - // } - // } - // } - - // public static class SuspentionInfo - // { - // public int mSuspentionPos; - // public ViewHolder vh; - // - // public SuspentionInfo(int s, ViewHolder holder) - // { - // vh = holder; - // mSuspentionPos = s; - // } - // - // @Override - // public String toString() - // { - // // TODO Auto-generated method stub - // return "mPos=" + mSuspentionPos; - // } - // } - // - // public int getCurrentSuspentionChildHeight() - // { - // if (mSuspentions != null && mSuspentions.size() != 0 && - // mSuspentions.lastElement() != null) - // { - // SuspentionInfo sii = mSuspentions.lastElement(); - // if (sii.vh != null) - // { - // return sii.vh.itemView.getHeight(); - // } - // } - // return 0; - // } - - // public int showOldSuspentedChild(int endPos) - // { - // removeSuspentions(endPos); - // return showCurrentSuspention(); - // } - - // public void setSuspentionOffset(int offset) - // { - // mSuspentionOffset = offset; - // } - // - // public void addSuspentions(int i) - // { - // if (mSuspentions == null) - // { - // mSuspentions = new Stack(); - // mSuspentions.push(new SuspentionInfo(-1, null)); - // } - // mSuspentions.push(new SuspentionInfo(i, null)); - // if (DEBUG) - // { - // Log.d("TMYSUS", "after add " + Arrays.toString(mSuspentions.toArray())); - // } - // } - // - // public void removeSuspentions(int endPos) - // { - // while (mSuspentions != null && !mSuspentions.empty()) - // { - // SuspentionInfo si = mSuspentions.lastElement(); - // if (si.mSuspentionPos > endPos) - // { - // SuspentionInfo poped = mSuspentions.pop(); - // if (poped.vh != null) - // { - // poped.vh.setIsRecyclable(true); - // mRecyclerView.removeAnimatingView(poped.vh.itemView); - // } - // if (DEBUG) - // { - // Log.d("TMYSUS", "after pop " + Arrays.toString(mSuspentions.toArray())); - // } - // } - // else - // { - // break; - // } - // } - // } - - protected void handleRecordItemHeightChange(int index, int oldItemHeight, int newItemHeight) - { - - } - - protected void recordItemSize(int index, View itemView) - { - if (mRecyclerView != null && mRecyclerView.getAdapter() != null) - { - if (mRecyclerView.getAdapter() instanceof RecyclerAdapter) - { - RecyclerAdapter adapter = (RecyclerAdapter) mRecyclerView.getAdapter(); - if (adapter.isAutoCalculateItemHeight()) - { - // // Height - // int itemHeight = itemView.getMeasuredHeight(); - // if (adapter.mItemHeightList == null) - // { - // adapter.mItemHeightList = new ArrayList<>(adapter.getItemCount()); - // } - // if (adapter.mItemHeightList.size() > index) - // { - // // Log.e("leo", "set itemHeight " + adapter.mItemHeightList.get(index) + ", " + itemHeight + ", " + index); - // int oldItemHeight = adapter.mItemHeightList.get(index); - // mRecyclerView.mState.mTotalHeight -= oldItemHeight; - // adapter.mItemHeightList.set(index, itemHeight); - // mRecyclerView.mState.mTotalHeight += itemHeight; - // Log.e("leolistnew", "replace index " + index + " old " + oldItemHeight + " new " + itemHeight); - // handleRecordItemHeightChange(index, oldItemHeight, itemHeight); - // // Log.e("leo", "mTotalHeight " + mRecyclerView.mState.mTotalHeight); - // } - // else if (adapter.mItemHeightList.size() == index) - // { - // // Log.e("leo", "add itemHeight " + itemHeight + ", " + index); - // adapter.mItemHeightList.add(itemHeight); - // mRecyclerView.mState.mTotalHeight += itemHeight; - // Log.e("leolistnew", "new index " + index + " new " + itemHeight); - // // Log.e("leo", "mTotalHeight " + mRecyclerView.mState.mTotalHeight); - // } - // else - // { - // Log.e("leolistnew", "recordItemSize with wrong index " + index + ", itemHeight " + itemHeight + ", listSize " - // + adapter.mItemHeightList.size()); - // LogUtils.e(TAG, "recordItemSize with wrong index " + index + ", itemHeight " + itemHeight + ", listSize " - // + adapter.mItemHeightList.size()); - // } - - // Width - int itemWidth = itemView.getMeasuredWidth(); - if (adapter.mItemWidthList == null) - { - adapter.mItemWidthList = new ArrayList<>(adapter.getItemCount()); - } - if (adapter.mItemWidthList.size() > index) - { - // Log.e("leo", "set itemWidth " + adapter.mItemWidthList.get(index) + ", " + itemWidth + ", " + index); - adapter.mItemWidthList.set(index, itemWidth); - } - else if (adapter.mItemWidthList.size() == index) - { - // Log.e("leo", "add itemWidth " + itemWidth + ", " + index); - adapter.mItemWidthList.add(itemWidth); - } - else - Log.e(TAG, "recordItemSize with wrong index " + index + ", itemWidth " + itemWidth + ", listSize " - + adapter.mItemWidthList.size()); - - } - } - } - } - - public void showCurrentSuspention(int position) - { - // TODO Auto-generated method stub - Log.d("TMYHIS", "showCurrentSuspention="); - mRecyclerView.mAnimatingViewPrevPos = mRecyclerView.mAnimatingViewPos; - mRecyclerView.mAnimatingViewPos = position; - mCurrentSuspentionPos = position; - removeSuspentions(); - if (position == RecyclerViewBase.NO_POSITION || mRecyclerView.mRecycler == null) - { - mCurrentSuspentionView = null; - return; - } - View v; - if (mRecyclerView.isRepeatableSuspensionMode()) - { - v = mRecyclerView.mRecycler.getViewForPosition(position); - } - else - { - v = mRecyclerView.mRecycler.getSuspendViewForPosition(position); - } - if (v == null) - { - return; - } - measureChildWithMargins(v, 0, 0); - layoutDecorated(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); - // addView(v); - mRecyclerView.addAnimatingView(v, true); - mCurrentSuspentionView = v; - // ViewCompat.setAlpha(v, SUSPEND_ITEM_ALPHA); - RecyclerViewBase.ViewHolder vh = mRecyclerView.getChildViewHolder(v); - if (vh.isRecyclable()) - { - vh.setIsRecyclable(false); - } - } - - /** - * Recycles children between given indices. - * - * @param startIndex - * inclusive - * @param endIndex - * exclusive - */ - private void recycleChildren(RecyclerViewBase.Recycler recycler, int startIndex, int endIndex) - { - if (startIndex == endIndex) - { - return; - } - if (DEBUG) - { - Log.d("RecyclerView", "Recycling " + Math.abs(startIndex - endIndex) + " items" + ",from " + startIndex + " to " + (endIndex - 1)); - } - if (endIndex > startIndex) - { - for (int i = endIndex - 1; i >= startIndex; i--) - { - removeAndRecycleViewAt(i, recycler); - } - } - else - { - for (int i = startIndex; i > endIndex; i--) - { - removeAndRecycleViewAt(i, recycler); - } - } - } - - /** - * Recycles views that went out of bounds after scrolling towards the end of - * the layout. - * - * @param recycler - * Recycler instance of - * {@link RecyclerViewBase} - * @param dt - * This can be used to add additional padding to the visible - * area. This is used to detect children that will go out of - * bounds after scrolling, without actually moving them. - */ - private void recycleViewsFromStart(RecyclerViewBase.Recycler recycler, int dt) - { - if (dt < 0) - { - if (DEBUG) - { - Log.d(TAG, "Called recycle from start with a negative value. This might happen" + " during layout changes but may be sign of a bug"); - } - // return; - dt = 0; - } - final int limit = mOrientationHelper.getStartAfterPadding() + dt; - final int childCount = getChildCount(); - if (mShouldReverseLayout) - { - for (int i = childCount - 1; i >= 0; i--) - { - View child = getChildAt(i); - if (mOrientationHelper.getDecoratedEnd(child) > limit) - {// stop - // here - recycleChildren(recycler, childCount - 1, i); - return; - } - } - } - else - { - for (int i = 0; i < childCount; i++) - { - View child = getChildAt(i); - if (mOrientationHelper.getDecoratedEnd(child) > limit) - {// stop - // here - recycleChildren(recycler, 0, i); - return; - } - } - } - } - - /** - * Recycles views that went out of bounds after scrolling towards the start - * of the layout. - * - * @param recycler - * Recycler instance of - * {@link RecyclerViewBase} - * @param dt - * This can be used to add additional padding to the visible - * area. This is used to detect children that will go out of - * bounds after scrolling, without actually moving them. - */ - private void recycleViewsFromEnd(RecyclerViewBase.Recycler recycler, int dt) - { - final int childCount = getChildCount(); - if (dt < 0) - { - if (DEBUG) - { - Log.d(TAG, "Called recycle from end with a negative value. This might happen" + " during layout changes but may be sign of a bug"); - } - // return; - dt = 0; - } - final int limit = mOrientationHelper.getEndAfterPadding() - dt; - if (mShouldReverseLayout) - { - for (int i = 0; i < childCount; i++) - { - View child = getChildAt(i); - if (mOrientationHelper.getDecoratedStart(child) < limit) - {// stop - // here - recycleChildren(recycler, 0, i); - return; - } - } - } - else - { - for (int i = childCount - 1; i >= 0; i--) - { - View child = getChildAt(i); - if (mOrientationHelper.getDecoratedStart(child) < limit) - {// stop - // here - recycleChildren(recycler, childCount - 1, i); - return; - } - } - } - - } - - /** - * Helper method to call appropriate recycle method depending on current - * render layout direction - * - * @param recycler - * Current recycler that is attached to RecyclerView - * @param renderState - * Current render state. Right now, this object does not change - * but we may consider moving it out of this view so passing - * around as a parameter for now, rather than accessing - * {@link #mRenderState} - * @see #recycleViewsFromStart(RecyclerViewBase.Recycler, - * int) - * @see #recycleViewsFromEnd(RecyclerViewBase.Recycler, - * int) - * @see LinearLayoutManager.RenderState#mLayoutDirection - */ - protected void recycleByRenderState(RecyclerViewBase.Recycler recycler, RenderState renderState) - { - //Log.e("RecyclerView", "recycleByRenderState"); - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) - { - recycleViewsFromEnd(recycler, renderState.mScrollingOffset); - } - else - { - recycleViewsFromStart(recycler, renderState.mScrollingOffset); - } - } - - /** - * The magic functions :). Fills the given layout, defined by the - * renderState. This is fairly independent from the rest of the - * {@link LinearLayoutManager} and - * with little change, can be made publicly available as a helper class. - * - * @param recycler - * Current recycler that is attached to RecyclerView - * @param renderState - * Configuration on how we should fill out the available space. - * @param state - * Context passed by the RecyclerView to control scroll steps. - * @param stopOnFocusable - * If true, filling stops in the first focusable new child - * @return Number of pixels that it added. Useful for scoll functions. - */ - protected abstract int fill(RecyclerViewBase.Recycler recycler, RenderState renderState, RecyclerViewBase.State state, boolean stopOnFocusable); - - /** - * Converts a focusDirection to orientation. - * - * @param focusDirection - * One of {@link View#FOCUS_UP}, - * {@link View#FOCUS_DOWN}, - * {@link View#FOCUS_LEFT}, - * {@link View#FOCUS_RIGHT}, - * {@link View#FOCUS_BACKWARD}, - * {@link View#FOCUS_FORWARD} or 0 for not - * applicable - * @return {@link RenderState#LAYOUT_START} or - * {@link RenderState#LAYOUT_END} if focus direction is applicable - * to current state, {@link RenderState#INVALID_LAYOUT} otherwise. - */ - private int convertFocusDirectionToLayoutDirection(int focusDirection) - { - switch (focusDirection) - { - case View.FOCUS_BACKWARD: - return RenderState.LAYOUT_START; - case View.FOCUS_FORWARD: - return RenderState.LAYOUT_END; - case View.FOCUS_UP: - return mOrientation == VERTICAL ? RenderState.LAYOUT_START : RenderState.INVALID_LAYOUT; - case View.FOCUS_DOWN: - return mOrientation == VERTICAL ? RenderState.LAYOUT_END : RenderState.INVALID_LAYOUT; - case View.FOCUS_LEFT: - return mOrientation == HORIZONTAL ? RenderState.LAYOUT_START : RenderState.INVALID_LAYOUT; - case View.FOCUS_RIGHT: - return mOrientation == HORIZONTAL ? RenderState.LAYOUT_END : RenderState.INVALID_LAYOUT; - default: - if (DEBUG) - { - Log.d(TAG, "Unknown focus request:" + focusDirection); - } - return RenderState.INVALID_LAYOUT; - } - - } - - /** - * Convenience method to find the child closes to start. Caller should check - * it has enough children. - * - * @return The child closes to start of the layout from user's perspective. - */ - public View getChildClosestToStartInScreen() - { - return getChildAt(mShouldReverseLayout ? getChildCount() - 1 : 0); - } - - public View getChildClosestToStartByOrder() - { - return getChildAt(mShouldReverseLayout ? getChildCount() - 1 : 0); - } - - /** - * Convenience method to find the child closes to end. Caller should check - * it has enough children. - * - * @return The child closes to end of the layout from user's perspective. - */ - public View getChildClosestToEndInScreen() - { - return getChildAt(mShouldReverseLayout ? 0 : getChildCount() - 1); - } - - public View getChildClosestToEndByOrder() - { - return getChildAt(mShouldReverseLayout ? 0 : getChildCount() - 1); - } - - /** - * Returns the adapter position of the first visible view. - *

- * Note that, this value is not affected by layout orientation or item order - * traversal. ({@link #setReverseLayout(boolean)}). Views are sorted by - * their positions in the adapter, not in the layout. - *

- * If RecyclerView has item decorators, they will be considered in - * calculations as well. - *

- * LinearLayoutManager may pre-cache some views that are not necessarily - * visible. Those views are ignored in this method. - * - * @return The adapter position of the first visible item or - * {@link RecyclerViewBase#NO_POSITION} - * if there aren't any visible items. - * @see #findFirstCompletelyVisibleItemPosition() - * @see #findLastVisibleItemPosition() - */ - public int findFirstVisibleItemPosition() - { - return findOneVisibleChild(0, getChildCount(), false); - } - - /** - * Returns the adapter position of the first fully visible view. - *

- * Note that bounds check is only performed in the current orientation. That - * means, if LinearLayoutManager is horizontal, it will only check the - * view's left and right edges. - * - * @return The adapter position of the first fully visible item or - * {@link RecyclerViewBase#NO_POSITION} - * if there aren't any visible items. - * @see #findFirstVisibleItemPosition() - * @see #findLastCompletelyVisibleItemPosition() - */ - public int findFirstCompletelyVisibleItemPosition() - { - return findOneVisibleChild(0, getChildCount(), true); - } - - /** - * Returns the adapter position of the last visible view. - *

- * Note that, this value is not affected by layout orientation or item order - * traversal. ({@link #setReverseLayout(boolean)}). Views are sorted by - * their positions in the adapter, not in the layout. - *

- * If RecyclerView has item decorators, they will be considered in - * calculations as well. - *

- * LinearLayoutManager may pre-cache some views that are not necessarily - * visible. Those views are ignored in this method. - * - * @return The adapter position of the last visible view or - * {@link RecyclerViewBase#NO_POSITION} - * if there aren't any visible items. - * @see #findLastCompletelyVisibleItemPosition() - * @see #findFirstVisibleItemPosition() - */ - public int findLastVisibleItemPosition() - { - return findOneVisibleChild(getChildCount() - 1, -1, false); - } - - /** - * Returns the adapter position of the last fully visible view. - *

- * Note that bounds check is only performed in the current orientation. That - * means, if LinearLayoutManager is horizontal, it will only check the - * view's left and right edges. - * - * @return The adapter position of the last fully visible view or - * {@link RecyclerViewBase#NO_POSITION} - * if there aren't any visible items. - * @see #findLastVisibleItemPosition() - * @see #findFirstCompletelyVisibleItemPosition() - */ - public int findLastCompletelyVisibleItemPosition() - { - return findOneVisibleChild(getChildCount() - 1, -1, true); - } - - protected int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) - { - if (mOrientationHelper == null) // 异常情况返回-1 - return -1; - final int start = mOrientationHelper.getStartAfterPadding(); - final int end = mOrientationHelper.getEndAfterPadding(); - final int next = toIndex > fromIndex ? 1 : -1; - for (int i = fromIndex; i != toIndex; i += next) - { - final View child = getChildAt(i); - final int childStart = mOrientationHelper.getDecoratedStart(child); - final int childEnd = mOrientationHelper.getDecoratedEnd(child); - if (childStart < end && childEnd > start) - { - if (completelyVisible) - { - if (childStart >= start && childEnd <= end) - { - return getPosition(child); - } - } - else - { - return getPosition(child); - } - } - } - return RecyclerViewBase.NO_POSITION; - } - - @Override - public View onFocusSearchFailed(View focused, int focusDirection, RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state) - { - resolveShouldLayoutReverse(); - if (getChildCount() == 0) - { - return null; - } - - final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection); - if (layoutDir == RenderState.INVALID_LAYOUT) - { - return null; - } - final View referenceChild; - if (layoutDir == RenderState.LAYOUT_START) - { - referenceChild = getChildClosestToStartInScreen(); - } - else - { - referenceChild = getChildClosestToEndInScreen(); - } - ensureRenderState(); - final int maxScroll = (int) (MAX_SCROLL_FACTOR * (mOrientationHelper.getEndAfterPadding() - mOrientationHelper.getStartAfterPadding())); - updateRenderState(layoutDir, maxScroll, false, state); - mRenderState.mScrollingOffset = RenderState.SCOLLING_OFFSET_NaN; - mRecyclerView.filterCheckNotifyFooterAppeared = true; - fill(recycler, mRenderState, state, true); - View nextFocus = null; - // if (layoutDir == RenderState.LAYOUT_START) - // { - final FocusFinder ff = FocusFinder.getInstance(); - try - { - nextFocus = ff.findNextFocus(mRecyclerView, focused, focusDirection); - } - catch (Exception e) - { - - } - // } - // else - // { - // nextFocus = getChildClosestToEndInScreen(); - // } - if (nextFocus == null || nextFocus == referenceChild || !nextFocus.isFocusable()) - { - return null; - } - return nextFocus; - // return super.onFocusSearchFailed(focused, focusDirection, recycler, - // state); - } - - /** - * Used for debugging. Logs the internal representation of children to - * default logger. - */ - private void logChildren() - { - Log.d(TAG, "internal representation of views on the screen"); - for (int i = 0; i < getChildCount(); i++) - { - View child = getChildAt(i); - Log.d(TAG, "item " + getPosition(child) + ", coord:" + mOrientationHelper.getDecoratedStart(child)); - } - Log.d(TAG, "=============="); - } - - public int getDecoratedStart(View child) - { - return mOrientationHelper.getDecoratedStart(child); - } - - public int getDecoratedEnd(View child) - { - return mOrientationHelper.getDecoratedEnd(child); - } - - /** - * Used for debugging. Validates that child views are laid out in correct - * order. This is important because rest of the algorithm relies on this - * constraint. - *

- * In default layout, child 0 should be closest to screen position 0 and - * last child should be closest to position WIDTH or HEIGHT. In reverse - * layout, last child should be closes to screen position 0 and first child - * should be closest to position WIDTH or HEIGHT - */ - protected void validateChildOrder() - { - Log.d(TAG, "validating child count " + getChildCount()); - if (getChildCount() < 1) - { - return; - } - int lastPos = getPosition(getChildAt(0)); - int lastScreenLoc = mOrientationHelper.getDecoratedStart(getChildAt(0)); - if (mShouldReverseLayout) - { - for (int i = 1; i < getChildCount(); i++) - { - View child = getChildAt(i); - int pos = getPosition(child); - int screenLoc = mOrientationHelper.getDecoratedStart(child); - if (pos < lastPos) - { - logChildren(); - throw new RuntimeException("detected invalid position. loc invalid? " + (screenLoc < lastScreenLoc)); - } - if (screenLoc > lastScreenLoc) - { - logChildren(); - throw new RuntimeException("detected invalid location"); - } - } - } - else - { - for (int i = 1; i < getChildCount(); i++) - { - View child = getChildAt(i); - int pos = getPosition(child); - int screenLoc = mOrientationHelper.getDecoratedStart(child); - if (pos < lastPos) - { - logChildren(); - throw new RuntimeException("detected invalid position. loc invalid? " + (screenLoc < lastScreenLoc)); - } - if (screenLoc < lastScreenLoc) - { - logChildren(); - throw new RuntimeException("detected invalid location"); - } - } - } - } - - public int validateAnchorPosition(int dataDirection, int currentPos,int totalCount) - { - return currentPos; - } - - @Override - public boolean supportsPredictiveItemAnimations() - { - return false; - } - - /** - * Helper class that keeps temporary state while {LayoutManager} is filling - * out the empty space. - */ - protected static class RenderState - { - public final static int FILL_TYPE_NOMORE = 1; - public final static int FILL_TYPE_HEADER = 2; - public final static int FILL_TYPE_NORMAL = 3; - public final static int FILL_TYPE_FOOTER = 4; - - final static String TAG = "TMYGRID"; - - public final static int LAYOUT_START = -1; - - public final static int LAYOUT_END = 1; - - public static final int LAYOUT_NO_DIRECTION = Integer.MAX_VALUE; - - public final static int INVALID_LAYOUT = Integer.MIN_VALUE; - - public final static int ITEM_DIRECTION_HEAD = -1; - - public final static int ITEM_DIRECTION_TAIL = 1; - - public final static int SCOLLING_OFFSET_NaN = Integer.MIN_VALUE; - public boolean overscroll = false; - /** - * Pixel offset where rendering should start - */ - public int mOffset; - - /** - * Number of pixels that we should fill, in the layout direction. - */ - public int mAvailable; - - /** - * Current position on the adapter to get the next item. - */ - public int mCurrentPosition; - - /** - * Defines the direction in which the data adapter is traversed. Should - * be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL} - */ - public int mItemDirection; - - /** - * Defines the direction in which the layout is filled. Should be - * {@link #LAYOUT_START} or {@link #LAYOUT_END} - */ - public int mLayoutDirection; - - /** - * Used when RenderState is constructed in a scrolling state. It should - * be set the amount of scrolling we can make without creating a new - * view. Settings this is required for efficient view recycling. - */ - public int mScrollingOffset; - - /** - * Used if you want to pre-layout items that are not yet visible. The - * difference with {@link #mAvailable} is that, when recycling, distance - * rendered for {@link #mExtra} is not considered to avoid recycling - * visible children. - */ - public int mExtra = 0; - - /** - * When LLM needs to layout particular views, it sets this list in which - * case, RenderState will only return views from this list and return - * null if it cannot find an item. - */ - public List mScrapList = null; - - /** - * @return true if there are more items in the data adapter - */ - public int hasMore(RecyclerViewBase.State state) - { - if (mCurrentPosition < 0) - { - if (Math.abs(mCurrentPosition) <= state.mHeaderCount) - { - return FILL_TYPE_HEADER; - } - else - { - return FILL_TYPE_NOMORE; - } - } - else if (mCurrentPosition >= state.getItemCount()) - { - // Log.d(TAG, "currPos=" + mCurrentPosition + ",itemcount=" + - // state.getItemCount()); - if (Math.abs(mCurrentPosition) - state.getItemCount() < state.mFooterCount) - { - return FILL_TYPE_FOOTER; - } - else - { - return FILL_TYPE_NOMORE; - } - } - else - { - return FILL_TYPE_NORMAL; - } - } - - /** - * Gets the view for the next element that we should render. Also - * updates current item index to the next item, based on - * {@link #mItemDirection} - * - * @return The next element that we should render. - */ - public View next(RecyclerViewBase.Recycler recycler) - { - if (mScrapList != null) - { - return nextFromLimitedList(); - } - final View view = recycler.getViewForPosition(mCurrentPosition); - mCurrentPosition += mItemDirection; - return view; - } - - /** - * Gets the view for the next Header that we should render. Also updates - * current item index to the next item, based on {@link #mItemDirection} - * - * @return The next Header that we should render. - */ - public View nextHeader(RecyclerViewBase.Recycler recycler) - { - final View view = recycler.getHeaderForPosition(Math.abs(mCurrentPosition)); - mCurrentPosition += mItemDirection; - return view; - } - - /** - * Gets the view for the next Footer that we should render. Also updates - * current item index to the next item, based on {@link #mItemDirection} - * - * @return The next Footer that we should render. - */ - public View nextFooter(RecyclerViewBase.Recycler recycler, RecyclerViewBase.State state) - { - final View view = recycler.getFooterForPosition(Math.abs(mCurrentPosition) - state.getItemCount() + 1); - mCurrentPosition += mItemDirection; - return view; - } - - /** - * Returns next item from limited list. - *

- * Upon finding a valid VH, sets current item position to - * VH.itemPosition + mItemDirection - * - * @return View if an item in the current position or direction exists - * if not null. - */ - private View nextFromLimitedList() - { - int size = mScrapList.size(); - RecyclerViewBase.ViewHolder closest = null; - int closestDistance = Integer.MAX_VALUE; - for (int i = 0; i < size; i++) - { - RecyclerViewBase.ViewHolder viewHolder = mScrapList.get(i); - final int distance = (viewHolder.getPosition() - mCurrentPosition) * mItemDirection; - if (distance < 0) - { - continue; // item is not in current direction - } - if (distance < closestDistance) - { - closest = viewHolder; - closestDistance = distance; - if (distance == 0) - { - break; - } - } - } - if (DEBUG) - { - Log.d(TAG, "layout from scrap. found view:?" + (closest != null)); - } - if (closest != null) - { - mCurrentPosition = closest.getPosition() + mItemDirection; - return closest.itemView; - } - return null; - } - - public void log() - { - log(""); - } - - public void log(String prefix) - { - Log.d(TAG, prefix + "avail:" + mAvailable + ", ind:" + mCurrentPosition + ", dir:" + mItemDirection + ", offset:" + mOffset - + ", layoutDir:" + mLayoutDirection + ", scrollOffset:" + mScrollingOffset); - } - } - - OrientationHelper createVerticalOrientationHelper() - { - return new OrientationHelper() - { - @Override - public int getEndAfterPadding() - { - return getHeight() - getPaddingBottom() + mRecyclerView.mState.mCustomHeaderHeight; - } - - @Override - public void offsetChildren(int amount) - { - offsetChildrenVertical(amount); - } - - @Override - public int getStartAfterPadding() - { - return getPaddingTop() - mRecyclerView.mState.mCustomHeaderHeight; - } - - @Override - public int getDecoratedMeasurement(View view) - { - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedMeasuredHeight(view) + params.topMargin + params.bottomMargin; - } - - @Override - public int getDecoratedMeasurementInOther(View view) - { - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedMeasuredWidth(view) + params.leftMargin + params.rightMargin; - } - - @Override - public int getDecoratedEnd(View view) - { - if (view == null) - { - return 0; - } - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedBottom(view) + params.bottomMargin; - } - - @Override - public int getDecoratedStart(View view) - { - if (view == null) - { - return 0; - } - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedTop(view) - params.topMargin; - } - - @Override - public int getTotalSpace() - { - return getHeight() - getPaddingTop() - getPaddingBottom(); - } - }; - } - - OrientationHelper createHorizontalOrientationHelper() - { - return new OrientationHelper() - { - @Override - public int getEndAfterPadding() - { - return getWidth() - getPaddingRight() + mRecyclerView.mState.mCustomHeaderWidth; - } - - @Override - public void offsetChildren(int amount) - { - offsetChildrenHorizontal(amount); - } - - @Override - public int getStartAfterPadding() - { - return getPaddingLeft() - mRecyclerView.mState.mCustomHeaderWidth; - } - - @Override - public int getDecoratedMeasurement(View view) - { - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedMeasuredWidth(view) + params.leftMargin + params.rightMargin; - } - - @Override - public int getDecoratedMeasurementInOther(View view) - { - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedMeasuredHeight(view) + params.topMargin + params.bottomMargin; - } - - @Override - public int getDecoratedEnd(View view) - { - if (view == null) - { - return 0; - } - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedRight(view) + params.rightMargin; - } - - @Override - public int getDecoratedStart(View view) - { - if (view == null) - { - return 0; - } - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - return getDecoratedLeft(view) - params.leftMargin; - } - - @Override - public int getTotalSpace() - { - return getWidth() - getPaddingLeft() - getPaddingRight(); - } - }; - } - - /** - * Helper interface to offload orientation based decisions - */ - public interface OrientationHelper - { - - /** - * @param view - * The view element to check - * @return The first pixel of the element - * @see #getDecoratedEnd(View) - */ - - int getDecoratedStart(View view); - - /** - * @param view - * The view element to check - * @return The last pixel of the element - * @see #getDecoratedStart(View) - */ - int getDecoratedEnd(View view); - - /** - * @param view - * The view element to check - * @return Total space occupied by this view - */ - int getDecoratedMeasurement(View view); - - /** - * @param view - * The view element to check - * @return Total space occupied by this view in the perpendicular - * orientation to current one - */ - int getDecoratedMeasurementInOther(View view); - - /** - * @return The very first pixel we can draw. - */ - int getStartAfterPadding(); - - /** - * @return The last pixel we can draw - */ - int getEndAfterPadding(); - - /** - * Offsets all children's positions by the given amount - * - * @param amount - * Value to add to each child's layout parameters - */ - void offsetChildren(int amount); - - /** - * Returns the total space to layout. - * - * @return Total space to layout children - */ - int getTotalSpace(); - } - - static class SavedState implements Parcelable - { - - int mOrientation; - - int mAnchorPosition; - - int mAnchorOffset; - - boolean mReverseLayout; - - boolean mStackFromEnd; - - boolean mAnchorLayoutFromEnd; - - public SavedState() - { - - } - - SavedState(Parcel in) - { - mOrientation = in.readInt(); - mAnchorPosition = in.readInt(); - mAnchorOffset = in.readInt(); - mReverseLayout = in.readInt() == 1; - mStackFromEnd = in.readInt() == 1; - mAnchorLayoutFromEnd = in.readInt() == 1; - } - - public SavedState(SavedState other) - { - mOrientation = other.mOrientation; - mAnchorPosition = other.mAnchorPosition; - mAnchorOffset = other.mAnchorOffset; - mReverseLayout = other.mReverseLayout; - mStackFromEnd = other.mStackFromEnd; - mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd; - } - - @Override - public int describeContents() - { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) - { - dest.writeInt(mOrientation); - dest.writeInt(mAnchorPosition); - dest.writeInt(mAnchorOffset); - dest.writeInt(mReverseLayout ? 1 : 0); - dest.writeInt(mStackFromEnd ? 1 : 0); - dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0); - } - - public static final Creator CREATOR = new Creator() - { - @Override - public SavedState createFromParcel(Parcel in) - { - return new SavedState(in); - } - - @Override - public SavedState[] newArray(int size) - { - return new SavedState[size]; - } - }; - } - - protected View getNextView(RecyclerViewBase.Recycler recycler, RenderState renderState, RecyclerViewBase.State state) - { - View view = null; - if (renderState.hasMore(state) == RenderState.FILL_TYPE_HEADER) - { - view = renderState.nextHeader(recycler); - if (view != null) - { - ViewGroup.LayoutParams lp = view.getLayoutParams(); - RecyclerViewBase.LayoutParams params = null; - if (lp instanceof ViewGroup.MarginLayoutParams) - { - params = new RecyclerViewBase.LayoutParams((ViewGroup.MarginLayoutParams) lp); - } - else - { - params = new RecyclerViewBase.LayoutParams(lp); - } - - params.mViewHolder = mRecyclerView.createViewHolder(view, mRecyclerView); - params.mViewHolder.mViewType = RecyclerViewBase.ViewHolder.TYPE_HEADERE; - params.mViewHolder.mPosition = renderState.mCurrentPosition - renderState.mItemDirection; - view.setLayoutParams(params); - state.mHeaderCountInScreen++; - } - } - else if (renderState.hasMore(state) == RenderState.FILL_TYPE_FOOTER) - { - - view = renderState.nextFooter(recycler, state); - if (view != null) - { - RecyclerViewBase.LayoutParams params = new RecyclerViewBase.LayoutParams(view.getLayoutParams()); - params.mViewHolder = mRecyclerView.createViewHolder(view, mRecyclerView); - params.mViewHolder.mViewType = RecyclerViewBase.ViewHolder.TYPE_FOOTER; - params.mViewHolder.mPosition = renderState.mCurrentPosition - renderState.mItemDirection; - if (mRecyclerView.getAdapter().getFooterViewInBottomMode()) - { - int incrementFooterViewHeight = mRecyclerView.getHeight() - mRecyclerView.getAdapter().getListTotalHeight(); - int originFooterViewHeight = mRecyclerView.getAdapter().getFooterViewHeight(mRecyclerView.getAdapter().getFooterViewCount()); - if (incrementFooterViewHeight > 0) - { - params.height = incrementFooterViewHeight + originFooterViewHeight; - view.setPadding(view.getPaddingLeft(), incrementFooterViewHeight, view.getPaddingRight(), view.getPaddingBottom()); - } - else - { - params.height = originFooterViewHeight; - view.setPadding(view.getPaddingLeft(), 0, view.getPaddingRight(), view.getPaddingBottom()); - } - } - view.setLayoutParams(params); - state.mFooterCountInScreen++; - // Log.d(TAG, "holder pos=" + params.mViewHolder.mPosition + - // ",state itemcount=" + state.getItemCount() + - // ",state.mFooterCount=" - // + state.mFooterCount); - if (params.mViewHolder.mPosition - state.getItemCount() + 1 == state.mFooterCount - && (mRenderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN || mRecyclerView.filterCheckNotifyFooterAppeared)) - { - // Log.d(TAG, "needNotify getFooter"); - if (mRecyclerView.filterCheckNotifyFooterAppeared) - { - mRecyclerView.filterCheckNotifyFooterAppeared = false; - } - mRecyclerView.needNotifyFooter = true; - } - } - } - else - { - view = renderState.next(recycler); - } - return view; - } - - public int getPendingPosition() - { - return mPendingScrollPosition; - } - - public View getFirstItemAfterOffset(int offset) - { - return super.getFirstItemAfterOffset(offset + mOrientationHelper.getStartAfterPadding()); - } - - public View getFirstItemBeforeOffset(int offset) - { - return super.getFirstItemBeforeOffset(offset + mOrientationHelper.getStartAfterPadding()); - } -} - diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/ContentHolder.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/ContentHolder.java deleted file mode 100644 index 459b34fd4de..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/ContentHolder.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import android.view.View; - -/** - * Created by leonardgong on 2018/4/9 0008. - */ - -public class ContentHolder -{ - public Object mParentViewHolder; - public View mContentView; - public int mContentLeftPadding = 0; - public int mItemPaddingLeft = 0; - public int mItemPaddingRight = 0; - public boolean mFocusable = true; - public boolean mForceBind = false; - - public void inTraversals(int traversalPurpose, int position, RecyclerViewBase recyclerView) - { - - } - - public void setEnable(boolean enabled) - { - if (mContentView != null && mContentView.getParent() != null) - { - ((View) mContentView.getParent()).setEnabled(enabled); - } - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IBlockTouchListener.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IBlockTouchListener.java deleted file mode 100644 index 381acd018f2..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IBlockTouchListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -/** - * Created by niuniuyang on 2020-03-06. - * Description - */ -public interface IBlockTouchListener { - void onRecyclerViewTouchEnabled(boolean enableTouch); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IRecyclerViewFooter.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IRecyclerViewFooter.java deleted file mode 100644 index f4381c95bd1..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IRecyclerViewFooter.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -/** - * Created by leonardgong on 2017/7/30 0030. - */ - -public interface IRecyclerViewFooter -{ - int LOADING_STATUS_NONE = 0; - int LOADING_STATUS_LOADING = 1; - int LOADING_STATUS_FINISH = 2; - int LOADING_STATUS_ERROR = 3; - int LOADING_STATUS_ERROR_RETRY = 4; - int LOADING_STATUS_ERROR_PULL_UP = 5; - int LOADING_STATUS_NOMORE_CLICKBACKWARDS = 6; - int LOADING_STATUS_BLANK = 7; - int LOADING_STATUS_FINISH_WITH_NUM = 8; - int LOADING_STATUS_ERROR_NETWORK_DISCONNECTED = 9; - int LOADING_STATUS_ERROR_NETWORK_ERROR = 10; - int LOADING_STATUS_CUSTOM = 100; - - void setLoadingStatus(int loadingStatus); - - int getLoadingStatus(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IViewRecycleStateListener.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IViewRecycleStateListener.java deleted file mode 100644 index b4416b24611..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/IViewRecycleStateListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -/** - * Created by leonardgong on 2018/1/8 0008. - */ - -public interface IViewRecycleStateListener -{ - int NOTIFY_ON_USE = 1; - int NOTIFY_ON_RECYCLE = 2; - - void onUse(); - - void onRecycle(); -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/LinearLayoutManager.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/LinearLayoutManager.java deleted file mode 100644 index 5b0e3e0ee6f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/LinearLayoutManager.java +++ /dev/null @@ -1,287 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import android.content.Context; -import android.util.Log; -import android.util.SparseIntArray; -import android.view.View; - -import static com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase.Adapter.LOCATION_BOTTOM; -import static com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase.Adapter.LOCATION_LEFT; -import static com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase.Adapter.LOCATION_RIGHT; -import static com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase.Adapter.LOCATION_TOP; -import static com.tencent.mtt.supportui.views.recyclerview.RecyclerViewBase.LAYOUT_TYPE_LIST; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -/** - * A - * {@link LinearLayoutManager} - * implementation which provides - * similar functionality to {@link android.widget.ListView}. - */ -public class LinearLayoutManager extends BaseLayoutManager -{ - private static final String TAG = "LinearLayoutManager"; - - public LinearLayoutManager(Context context) - { - this(context, VERTICAL, false); - } - - /** - * @param context Current context, will be used to access resources. - * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or - * {@link #VERTICAL}. - * @param reverseLayout When set to true, renders the layout from end to - * start. - */ - public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) - { - super(context, orientation, false); - } - - @Override - public int getLayoutType() - { - return LAYOUT_TYPE_LIST; - } - - /** - * The magic functions :). Fills the given layout, defined by the - * renderState. This is fairly - * independent from the rest of the - * {@link LinearLayoutManager} and - * with little change, can be made publicly available as a helper class. - * - * @param recycler Current recycler that is attached to RecyclerView - * @param renderState Configuration on how we should fill out the available - * space. - * @param state Context passed by the RecyclerView to control scroll steps. - * @param stopOnFocusable If true, filling stops in the first focusable new - * child - * @return Number of pixels that it added. Useful for scoll functions. - */ - - protected int fill(RecyclerViewBase.Recycler recycler, RenderState renderState, RecyclerViewBase.State state, boolean stopOnFocusable) - { - // max offset we should set is mFastScroll + available - final int start = renderState.mAvailable; - if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) - { - // TODO ugly bug fix. should not happen - if (renderState.mAvailable < 0) - { - renderState.mScrollingOffset += renderState.mAvailable; - } - recycleByRenderState(recycler, renderState); - } - int remainingSpace = renderState.mAvailable + renderState.mExtra; - while (remainingSpace > 0) - { - if (renderState.hasMore(state) == RenderState.FILL_TYPE_NOMORE) - { - int res = start - renderState.mAvailable + remainingSpace; - if (DEBUG) - { -// Log.d("leo", "nomore!!" + ",remainspace=" + remainingSpace + ",res=" + res); - } - if (!renderState.overscroll) - { - break; - } - if (renderState.mItemDirection > 0 && !mEndReached) - { - mEndReached = true; - if (mRecyclerView.getAdapter() != null) - { - mRecyclerView.getAdapter().notifyEndReached(); - } - } - return res; - } - mEndReached = false; - int index = renderState.mCurrentPosition; - // int currentRenderState = renderState.hasMore(state); - View view = getNextView(recycler, renderState, state); - if (view == null) - { - if (false && renderState.mScrapList == null) - { - throw new RuntimeException("received null view when unexpected"); - } - // if we are laying out views in scrap, this may return null - // which means there is - // no more items to layout. - break; - } - RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - if (!params.isItemRemoved() && mRenderState.mScrapList == null) - { - if (mShouldReverseLayout == (renderState.mLayoutDirection == RenderState.LAYOUT_START)) - { - addView(view); - } - else - { - addView(view, 0); - } - } - - // int viewType = params.mViewHolder.mViewType; - // if (viewType == RecyclerView.ViewHolder.TYPE_FOOTER || viewType == RecyclerView.ViewHolder.TYPE_HEADERE) - // { - // if (view instanceof QBViewInterface) - // { - // ((QBViewInterface) view).switchSkin(); - // } - // } - - measureChildWithMargins(view, 0, 0); - if (mRecyclerView.getAdapter() instanceof RecyclerAdapter && ((RecyclerAdapter) mRecyclerView.getAdapter()).isAutoCalculateItemHeight()) - { - if (view instanceof RecyclerViewItem) - { - if (((RecyclerViewItem) view).getChildCount() > 0) - { - recordItemSize(index, ((RecyclerViewItem) view).getChildAt(0)); - ((RecyclerAdapter) mRecyclerView.getAdapter()).forceUpdateOffsetMap(); - } - } - if (renderState.hasMore(state) == RenderState.FILL_TYPE_NOMORE) - { - // Log.e("leo", "FILL_TYPE_NOMORE " + state.mTotalHeight); - mRecyclerView.getAdapter().getTotalHeight(); -// ((RecyclerAdapter) mRecyclerView.getAdapter()).mAutoCalcItemHeightFinish = true; - } - else - { - // Log.e("leo", "other FILL_TYPE " + state.mTotalHeight + " still autoCalcItemHeight"); -// ((RecyclerAdapter) mRecyclerView.getAdapter()).mAutoCalcItemHeightFinish = false; - // 在NotifyDataSetChange的时候置为false - } - } - - int consumed = mOrientationHelper.getDecoratedMeasurement(view); - int left, top, right, bottom; - if (getOrientation() == VERTICAL) - { - if (isLayoutRTL()) - { - right = getWidth() - getPaddingRight(); - left = right - mOrientationHelper.getDecoratedMeasurementInOther(view); - } - else - { - left = getPaddingLeft(); - right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); - } - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) - { - bottom = renderState.mOffset; - top = renderState.mOffset - consumed; - } - else - { - top = renderState.mOffset; - bottom = renderState.mOffset + consumed; - } - } - else - { - top = getPaddingTop(); - bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); - - if (renderState.mLayoutDirection == RenderState.LAYOUT_START) - { - right = renderState.mOffset; - left = renderState.mOffset - consumed; - } - else - { - left = renderState.mOffset; - right = renderState.mOffset + consumed; - } - } - // We calculate everything with View's bounding box (which includes - // decor and margins) - // To calculate correct layout position, we subtract margins. - layoutDecorated(view, left + params.leftMargin, top + params.topMargin, right - params.rightMargin, bottom - params.bottomMargin); - if (DEBUG) - { -// Log.d("RecyclerView", "laid out child at position " + getPosition(view) + ", with l:" + (left + params.leftMargin) + ", t:" -// + (view.getTop()) + ", r:" + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin)); - } - renderState.mOffset += consumed * renderState.mLayoutDirection; - - if (!params.isItemRemoved()) - { - renderState.mAvailable -= consumed; - // we keep a separate remaining space because mAvailable is - // important for recycling - remainingSpace -= consumed; - } - //Log.e("RecyclerView", "before recycle!"); - if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) - { - renderState.mScrollingOffset += consumed; - if (renderState.mAvailable < 0) - { - renderState.mScrollingOffset += renderState.mAvailable; - } - recycleByRenderState(recycler, renderState); - } - if (stopOnFocusable && view.isFocusable()) - { - break; - } - - if (state != null && state.getTargetScrollPosition() == getPosition(view)) - { - break; - } - } - if (DEBUG) - { - // validateChildOrder(); - } - return start - renderState.mAvailable; - } - - @Override - protected void handleRecordItemHeightChange(int index, int oldItemHeight, int newItemHeight) - { - if (mRecyclerView != null && mRecyclerView.getFirstVisibleItemPos() >= index && mRecyclerView.mOffsetY > 0) - { - mRecyclerView.mOffsetY -= oldItemHeight; - mRecyclerView.mOffsetY += newItemHeight; - } - } - - @Override - public void calculateOffsetMap(SparseIntArray offsetMap, int startOffset) - { - if (mRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_LIST) - { - int currOffset = startOffset; - int itemCount = getItemCount(); - for (int i = 0; i < itemCount; i++) - { - offsetMap.append(i, currOffset); - if (mRecyclerView.mLayout.canScrollHorizontally()) - { - currOffset += ((RecyclerAdapter)mRecyclerView.getAdapter()).getItemWidth(i); - currOffset += mRecyclerView.getAdapter().getItemMaigin(LOCATION_LEFT, i); - currOffset += mRecyclerView.getAdapter().getItemMaigin(LOCATION_RIGHT, i); - } - else - { - currOffset += ((RecyclerAdapter)mRecyclerView.getAdapter()).getItemHeight(i); - currOffset += mRecyclerView.getAdapter().getItemMaigin(LOCATION_TOP, i); - currOffset += mRecyclerView.getAdapter().getItemMaigin(LOCATION_BOTTOM, i); - } - } - } - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/LinearSmoothScroller.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/LinearSmoothScroller.java deleted file mode 100644 index 866a944b817..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/LinearSmoothScroller.java +++ /dev/null @@ -1,370 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import android.content.Context; -import android.graphics.PointF; -import android.util.DisplayMetrics; -import android.view.View; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.LinearInterpolator; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -/** - * {@link RecyclerViewBase.SmoothScroller} implementation which uses - * {@link LinearInterpolator} until the target position becomes a child of - * the RecyclerView and then uses - * {@link DecelerateInterpolator} to slowly approach to - * target position. - */ -abstract public class LinearSmoothScroller extends RecyclerViewBase.SmoothScroller -{ - - private static final String TAG = "LinearSmoothScroller"; - - private static final boolean DEBUG = false; - - private static final float MILLISECONDS_PER_INCH = 25f; - - private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000; - - /** - * Align child view's left or top with parent view's left or top - * - * @see #calculateDtToFit(int, int, int, int, int) - * @see #calculateDxToMakeVisible(View, int) - * @see #calculateDyToMakeVisible(View, int) - */ - public static final int SNAP_TO_START = -1; - - /** - * Align child view's right or bottom with parent view's right or bottom - * - * @see #calculateDtToFit(int, int, int, int, int) - * @see #calculateDxToMakeVisible(View, int) - * @see #calculateDyToMakeVisible(View, int) - */ - public static final int SNAP_TO_END = 1; - - /** - *

- * Decides if the child should be snapped from start or end, depending on where - * it - * currently is in relation to its parent. - *

- *

- * For instance, if the view is virtually on the left of RecyclerView, using - * {@code SNAP_TO_ANY} is the same as using {@code SNAP_TO_START} - *

- * - * @see #calculateDtToFit(int, int, int, int, int) - * @see #calculateDxToMakeVisible(View, int) - * @see #calculateDyToMakeVisible(View, int) - */ - public static final int SNAP_TO_ANY = 0; - - // Trigger a scroll to a further distance than TARGET_SEEK_SCROLL_DISTANCE_PX so that if target - // view is not laid out until interim target position is reached, we can detect the case before - // scrolling slows down and reschedule another interim target scroll - private static final float TARGET_SEEK_EXTRA_SCROLL_RATIO = 1.2f; - - protected final LinearInterpolator mLinearInterpolator = new LinearInterpolator(); - - protected final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator(); - - protected PointF mTargetVector; - - private final float MILLISECONDS_PER_PX; - - // Temporary variables to keep track of the interim scroll target. These values do not - // point to a real item position, rather point to an estimated location pixels. - protected int mInterimTargetDx = 0, mInterimTargetDy = 0; - - public LinearSmoothScroller(Context context) - { - MILLISECONDS_PER_PX = calculateSpeedPerPixel(context.getResources().getDisplayMetrics()); - } - - /** - * {@inheritDoc} - */ - @Override - protected void onStart() - { - - } - - /** - * {@inheritDoc} - */ - @Override - protected void onTargetFound(View targetView, RecyclerViewBase.State state, Action action) - { - final int dx = calculateDxToMakeVisible(targetView, getHorizontalSnapPreference()); - final int dy = calculateDyToMakeVisible(targetView, getVerticalSnapPreference()); - final int distance = (int) Math.sqrt(dx * dx + dy * dy); - final int time = calculateTimeForDeceleration(distance); - if (time > 0) - { - action.update(-dx, -dy, time, mDecelerateInterpolator); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void onSeekTargetStep(int dx, int dy, RecyclerViewBase.State state, Action action) - { - if (getChildCount() == 0) - { - stop(); - return; - } - if (DEBUG && mTargetVector != null && ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) - { - throw new IllegalStateException("Scroll happened in the opposite direction" + " of the target. Some calculations are wrong"); - } - mInterimTargetDx = clampApplyScroll(mInterimTargetDx, dx); - mInterimTargetDy = clampApplyScroll(mInterimTargetDy, dy); - - if (mInterimTargetDx == 0 && mInterimTargetDy == 0) - { - updateActionForInterimTarget(action); - } // everything is valid, keep going - - } - - /** - * {@inheritDoc} - */ - @Override - protected void onStop() - { - mInterimTargetDx = mInterimTargetDy = 0; - mTargetVector = null; - } - - /** - * Calculates the scroll speed. - * - * @param displayMetrics DisplayMetrics to be used for real dimension - * calculations - * @return The time (in ms) it should take for each pixel. For instance, if - * returned value is - * 2 ms, it means scrolling 1000 pixels with LinearInterpolation should - * take 2 seconds. - */ - protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) - { - return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; - } - - /** - *

- * Calculates the time for deceleration so that transition from - * LinearInterpolator to - * DecelerateInterpolator looks smooth. - *

- * - * @param dx Distance to scroll - * @return Time for DecelerateInterpolator to smoothly traverse the distance - * when transitioning - * from LinearInterpolation - */ - protected int calculateTimeForDeceleration(int dx) - { - // we want to cover same area with the linear interpolator for the first 10% of the - // interpolation. After that, deceleration will take control. - // area under curve (1-(1-x)^2) can be calculated as (1 - x/3) * x * x - // which gives 0.100028 when x = .3356 - // this is why we divide linear scrolling time with .3356 - return (int) Math.ceil(calculateTimeForScrolling(dx) / .3356); - } - - /** - * Calculates the time it should take to scroll the given distance (in pixels) - * - * @param dx Distance in pixels that we want to scroll - * @return Time in milliseconds - * @see #calculateSpeedPerPixel(DisplayMetrics) - */ - protected int calculateTimeForScrolling(int dx) - { - // In a case where dx is very small, rounding may return 0 although dx > 0. - // To avoid that issue, ceil the result so that if dx > 0, we'll always return positive - // time. - return (int) Math.ceil(Math.abs(dx) * MILLISECONDS_PER_PX); - } - - /** - * When scrolling towards a child view, this method defines whether we should - * align the left - * or the right edge of the child with the parent RecyclerView. - * - * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current - * target vector - * @see #SNAP_TO_START - * @see #SNAP_TO_END - * @see #SNAP_TO_ANY - */ - protected int getHorizontalSnapPreference() - { - return mTargetVector == null || mTargetVector.x == 0 ? SNAP_TO_ANY : mTargetVector.x > 0 ? SNAP_TO_END : SNAP_TO_START; - } - - /** - * When scrolling towards a child view, this method defines whether we should - * align the top - * or the bottom edge of the child with the parent RecyclerView. - * - * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current - * target vector - * @see #SNAP_TO_START - * @see #SNAP_TO_END - * @see #SNAP_TO_ANY - */ - protected int getVerticalSnapPreference() - { - return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY : mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START; - } - - /** - * When the target scroll position is not a child of the RecyclerView, this - * method calculates - * a direction vector towards that child and triggers a smooth scroll. - * - * @see #computeScrollVectorForPosition(int) - */ - protected void updateActionForInterimTarget(Action action) - { - // find an interim target position - PointF scrollVector = computeScrollVectorForPosition(getTargetPosition()); - if (scrollVector == null || (scrollVector.x == 0 && scrollVector.y == 0)) - { - // Log.e(TAG, "To support smooth scrolling, you should override \n" - // + "LayoutManager#computeScrollVectorForPosition.\n" - // + "Falling back to instant scroll"); - final int target = getTargetPosition(); - stop(); - instantScrollToPosition(target); - return; - } - normalize(scrollVector); - mTargetVector = scrollVector; - - mInterimTargetDx = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.x); - mInterimTargetDy = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.y); - final int time = calculateTimeForScrolling(TARGET_SEEK_SCROLL_DISTANCE_PX); - // To avoid UI hiccups, trigger a smooth scroll to a distance little further than the - // interim target. Since we track the distance travelled in onSeekTargetStep callback, it - // won't actually scroll more than what we need. - action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO), (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO), - (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator); - } - - private int clampApplyScroll(int tmpDt, int dt) - { - final int before = tmpDt; - tmpDt -= dt; - if (before * tmpDt <= 0) - { // changed sign, reached 0 or was 0, reset - return 0; - } - return tmpDt; - } - - /** - * Helper method for {@link #calculateDxToMakeVisible(View, int)} - * and - * {@link #calculateDyToMakeVisible(View, int)} - */ - public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) - { - switch (snapPreference) - { - case SNAP_TO_START: - return boxStart - viewStart; - case SNAP_TO_END: - return boxEnd - viewEnd; - case SNAP_TO_ANY: - final int dtStart = boxStart - viewStart; - if (dtStart > 0) - { - return dtStart; - } - final int dtEnd = boxEnd - viewEnd; - if (dtEnd < 0) - { - return dtEnd; - } - break; - default: - throw new IllegalArgumentException( - "snap preference should be one of the" + " constants defined in SmoothScroller, starting with SNAP_"); - } - return 0; - } - - /** - * Calculates the vertical scroll amount necessary to make the given view fully - * visible - * inside the RecyclerView. - * - * @param view The view which we want to make fully visible - * @param snapPreference The edge which the view should snap to when entering - * the visible - * area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or - * {@link #SNAP_TO_END}. - * @return The vertical scroll amount necessary to make the view visible with - * the given - * snap preference. - */ - public int calculateDyToMakeVisible(View view, int snapPreference) - { - final RecyclerViewBase.LayoutManager layoutManager = getLayoutManager(); - if (!layoutManager.canScrollVertically()) - { - return 0; - } - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - final int top = layoutManager.getDecoratedTop(view) - params.topMargin; - final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin; - final int start = layoutManager.getPaddingTop(); - final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom(); - return calculateDtToFit(top, bottom, start, end, snapPreference); - } - - /** - * Calculates the horizontal scroll amount necessary to make the given view - * fully visible - * inside the RecyclerView. - * - * @param view The view which we want to make fully visible - * @param snapPreference The edge which the view should snap to when entering - * the visible - * area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or - * {@link #SNAP_TO_END} - * @return The vertical scroll amount necessary to make the view visible with - * the given - * snap preference. - */ - public int calculateDxToMakeVisible(View view, int snapPreference) - { - final RecyclerViewBase.LayoutManager layoutManager = getLayoutManager(); - if (!layoutManager.canScrollHorizontally()) - { - return 0; - } - final RecyclerViewBase.LayoutParams params = (RecyclerViewBase.LayoutParams) view.getLayoutParams(); - final int left = layoutManager.getDecoratedLeft(view) - params.leftMargin; - final int right = layoutManager.getDecoratedRight(view) + params.rightMargin; - final int start = layoutManager.getPaddingLeft(); - final int end = layoutManager.getWidth() - layoutManager.getPaddingRight(); - return calculateDtToFit(left, right, start, end, snapPreference); - } - - abstract public PointF computeScrollVectorForPosition(int targetPosition); -} - diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerAdapter.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerAdapter.java deleted file mode 100644 index 31037e6a29f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerAdapter.java +++ /dev/null @@ -1,1380 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import static com.tencent.mtt.supportui.views.recyclerview.RecyclerViewItem.ITEM_VIEW_DEFAULT_HEIGHT; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import android.util.Log; -import android.util.SparseIntArray; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -public abstract class RecyclerAdapter extends RecyclerViewBase.Adapter implements View.OnClickListener -{ - /* private */static final String TAG = "RecyclerAdapter"; - public View mDefaultLoadingView; - public int mLoadingStatus = IRecyclerViewFooter.LOADING_STATUS_NONE; - /* private */ DataHolder mRoot; - // edit mode related - // click related - protected RecyclerViewItemListener mRecyclerViewItemListener; - - // data related - /* private */ ArrayList mDataList = new ArrayList(); - protected int mContentHeight = -1; - SparseIntArray mOffsetMap = null; - - public RecyclerView mParentRecyclerView; - - // public ArrayList mItemHeightList = null; - public ArrayList mItemWidthList = null; - - public boolean isAutoCalculateItemHeight() - { - return false; - } - - public static class DataHolder /* implements Comparable */ - { - public int mItemViewType = 0; - public int mItemHeight = ITEM_VIEW_DEFAULT_HEIGHT; - public Object mData = null; - /* - * the value of mItemViewStyle is one of the following : - * QBViewResourceManager.CARD_ITEM_TYPE_TOP - * QBViewResourceManager.CARD_ITEM_TYPE_MIDDLE - * QBViewResourceManager.CARD_ITEM_TYPE_BOTTOM - * QBViewResourceManager.CARD_ITEM_TYPE_FULL - * QBViewResourceManager.DEFAULT_ITEM - * 0 - */ - public int mItemViewStyle = 0; - public int mTopMargin = 0; - public int mBottomMargin = 0; - public int mLeftMargin = 0; - public int mRightMargin = 0; - public boolean mHasDivider = true; - - // public int mStartOffset = 0; - - // public int getItemHeight() - // { - // return mItemHeight + mTopMargin + mBottomMargin; - // } - // - // public int getEndOffset() - // { - // return mStartOffset + getItemHeight(); - // } - - // @Override - // public int compareTo(DataHolder another) - // { - // // TODO Auto-generated method stub - // if (another == null) - // { - // return -1; - // } - // int height = getItemHeight(); - // if (mStartOffset > another.mStartOffset) - // { - // return 1; - // } - // else if (mStartOffset + height < another.mStartOffset) - // { - // return -1; - // } - // else - // { - // return 0; - // } - } - - public final void addData(DataHolder newData) - { - - if (newData != null) - { - mDataList.add(newData); - mContentHeight = -1; - } - } - - public int indexOf(DataHolder data) - { - int index = -1; - index = mDataList.indexOf(data); - return index; - } - - public final void appendData(ArrayList newDatas) - { - if (newDatas != null && !newDatas.isEmpty()) - { - mDataList.addAll(newDatas); - mContentHeight = -1; - } - } - - public final void insertData(DataHolder newData, int index) - { - if (index >= 0 && newData != null && mDataList.size() >= index) - { - mDataList.add(index, newData); - mContentHeight = -1; - } - } - - /* private */int itemRangeCompare(int item, int offset, int target) - { - int height = getItemRange(item); - if (offset > target) - { - return 1; - } - else if (offset + height < target) - { - return -1; - } - else - { - return 0; - } - } - - /* private */int binarySearch(SparseIntArray array, int key) - { -// Log.d("leo", "key=" + key); - if (array == null || array.size() == 0) - { - return -1; - } - int low = array.keyAt(0); - int high = array.keyAt(array.size() - 1);// position - while (low <= high) - { - int middle = low + ((high - low) >> 1); - int middleValue = array.valueAt(middle); - int res = itemRangeCompare(middle, middleValue, key); - if (res == 0) - { - return middle; - } - else if (res > 0) - { - high = middle - 1; - } - else - { - low = middle + 1; - } - } - return -1; - } - - protected int getItemRange(int pos) - { - int dividerH = 0; - return getItemHeight(pos) + getItemMaigin(LOCATION_TOP, pos) + getItemMaigin(LOCATION_BOTTOM, pos) + dividerH; - } - - public int[] getBeginPositionWithOffset(int targetOffset) - { - - int[] result = new int[2]; - int count = getItemCount() + getFooterViewCount(); - int i = 0; - int headerHeight = 0; - int headerCount = getHeaderViewCount(); - int totalHeight = mParentRecyclerView.getCachedTotalHeight(); - for (i = 1; i <= headerCount; i++) - { - headerHeight += getHeaderViewHeight(i); - } -// Log.d("leo", "targetOffset=" + targetOffset + ",headerH=" + headerHeight + ",totalHeight=" + totalHeight); - - if (targetOffset >= totalHeight) - { - result[0] = count; - result[1] = totalHeight - getItemHeight(count) - targetOffset; - } - else if (targetOffset < 0) - { - result[0] = -headerCount; - result[1] = -headerHeight - targetOffset; - } - else if (targetOffset < headerHeight) - { - // Log.e("leo", "header"); - int sum = 0; - boolean found = false; - for (int j = -headerCount; j < 0; j++) - { - sum += getHeaderViewHeight(-j); - if (sum > targetOffset) - { - result[0] = j; - found = true; - result[1] = sum - getHeaderViewHeight(-j) - targetOffset; - break; - } - } - if (!found) - { -// Log.e("leo", "should not happened!"); - } - } - else - { - // if (mDataList != null && !mDataList.isEmpty()) - // { - // footer - calculateOffsetMapIfNeed(); - final int lastPos = /* mDataList.size() - 1 */mOffsetMap.size() - 1; - // DataHolder lastHolder = mDataList.get(lastPos); - final int lastOffset = /* lastHolder.getEndOffset() */mOffsetMap.get(lastPos) + getItemRange(lastPos); - // Log.d("leo", "lastOffset=" + lastOffset); - if (targetOffset > lastOffset) - { - int sum = lastOffset; - int footerCount = getFooterViewCount(); - boolean found = false; - if (footerCount > 0) - { - int k; - for (k = 1; k <= footerCount; k++) - { - sum += getFooterViewHeight(k); - if (sum > targetOffset) - { - result[0] = lastPos + k; - found = true; - result[1] = sum - getFooterViewHeight(k) - targetOffset; - break; - } - } - if (!found) - { - result[0] = lastPos + k; - result[1] = sum - getFooterViewHeight(k) - targetOffset; -// Log.e("leo", "should not happened!"); - } - } - // Log.d("leo", "footer,result=" + result[0] + "," + - // result[1]); - return result; - } - // Log.d("TMYBINARY", "normal"); - // targetOffset -= headerHeight; - // DataHolder key = new DataHolder(); - // key.mStartOffset = targetOffset; - int hit = binarySearch(mOffsetMap, targetOffset); - if (targetOffset == 0) - { - hit = 0; - } - if (hit != -1) - { - // DataHolder hitHolder = mDataList.get(hit); - int hitValue = mOffsetMap.get(hit); - // if (hitHolder != null) - // { - if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_GRID) - { - // 向前查找第一个等高条目 - while (--hit >= 0) - { - // DataHolder prev = mDataList.get(hit); - int prev = mOffsetMap.get(hit); - if (prev != hitValue) - { - break; - } - } - result[0] = hit + 1; - } - else if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_LIST) - { - result[0] = hit; - } - else if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_WATERFALL) - { - result[0] = hit; - } - result[1] = hitValue - targetOffset; - // } - } - // } - } - // Log.d("leo", "result=" + result[0] + "," + result[1]); - return result; - } - - public int getHeightBefore(int pos) - { - - int sum = 0; - // TODO 瀑布流调用 @ 171215-2002 瀑布流直接重载getHeightBefore - // if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_WATERFALL) - // { - // int columnHeights[] = mParentRecyclerView.calculateColumnHeightsBefore(pos, false); - // sum = columnHeights[mParentRecyclerView.getShortestColumnIndex(columnHeights)]; - // return sum; - // } - - int count = getHeaderViewCount(); - if (pos < -count) - { - throw new IllegalStateException("pos less than header count,should not happened"); - } - if (pos >= 0) - { - calculateOffsetMapIfNeed(); - sum = mOffsetMap.get(pos); - } - else - { - for (int i = -count; i < pos; i++) - { - sum += getHeaderViewHeight(-i); - } - } -// Log.d("leo", "getHeightBefore:pos=" + pos + ",result=" + sum); - return sum; - } - - public final void insertData(ArrayList newDatas, int index, int counts) - { - if (index >= 0 && counts > 0 && newDatas != null && !newDatas.isEmpty() && mDataList.size() >= index) - { - ArrayList oldList = mDataList; - mDataList = new ArrayList(); - mDataList.addAll(oldList.subList(0, index)); - mDataList.addAll(newDatas); - mDataList.addAll(oldList.subList(index, oldList.size())); - - mContentHeight = -1; - } - } - - - public void removeData(int index, int counts) - { - if (mDataList.size() >= (index + counts) && index >= 0 && counts > 0) - { - mDataList.subList(index, index + counts).clear(); - mContentHeight = -1; - } - } - - public void clearData() - { - mDataList.clear(); - mContentHeight = -1; - } - - public void removeDatas(int type) - { - ArrayList removedList = new ArrayList(); - for (DataHolder data : mDataList) - { - if (data.mItemViewType == type) - { - removedList.add(data); - } - } - mDataList.removeAll(removedList); - mContentHeight = -1; - } - - public ArrayList getDataHolderList() - { - return new ArrayList(mDataList); - } - - public final DataHolder getDataHolder(int index) - { - try - { - if (mDataList.size() > index && index >= 0) - { - return mDataList.get(index); - } - } - catch (Exception e) - { - } - return null; - } - - public int getItemHeight(int index) - { - try - { - if (mDataList.size() > index && index >= 0) - { - return mDataList.get(index).mItemHeight; - } - // if (isAutoCalculateItemHeight() && mItemHeightList != null && mItemHeightList.size() > index && index >= 0) - // { - // int itemGap = 0; - // if (mParentRecyclerView != null) - // { - // RecyclerViewBase.LayoutManager layoutManager = mParentRecyclerView.getLayoutManager(); - // if (layoutManager != null) - // { - // // TODO 瀑布流调用 @171215-2014 - // // if (layoutManager instanceof WaterFallLayoutManager) - // // { - // // itemGap = ((WaterFallLayoutManager) layoutManager).getItemGap(); - // // } - // } - // } - // - // return mItemHeightList.get(index) + itemGap; - // } - return 0; - } - catch (Exception e) - { - return 0; - } - } - - public int getItemWidth(int index) - { - try - { - if (isAutoCalculateItemHeight() && mItemWidthList != null && mItemWidthList.size() > index && index >= 0) - { - return mItemWidthList.get(index); - } - return 0; - } - catch (Exception e) - { - return 0; - } - } - - public int getItemOffset(int position) - { - if (mOffsetMap != null) - { - return mOffsetMap.get(position); - } - return -1; - } - - public void setItemOffset(int index, int value) - { - if (mOffsetMap != null) - { - mOffsetMap.put(index, value); - } - } - - @Override - public void reset() - { - // TODO Auto-generated method stub - mContentHeight = -1; - dataChanged(); - } - - @Override - public int getTotalHeight() - { - if (isAutoCalculateItemHeight()) - { - mContentHeight = -1; - } - if (mContentHeight == -1) - { - // Log.e("leo", "getTotalHeight mContentHeight " + mContentHeight); - int itemCount = getItemCount(); - mContentHeight = 0; - // TODO grid流调用 - // if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_GRID) - // { - // if (mParentRecyclerView.mLayout instanceof GridLayoutManager) - // { - // GridLayoutManager layoutManager = (GridLayoutManager) (mParentRecyclerView.mLayout); - // for (int i = 0; i < itemCount; i++) - // { - // if (i % layoutManager.mColumns == 0) - // { - // int itemTotalHeihgt = getItemHeight(i) + getItemMaigin(LOCATION_TOP, i) + getItemMaigin(LOCATION_BOTTOM, i); - // mContentHeight += itemTotlaHeihgt; - // } - // } - // } - // else - // { - // mContentHeight = 0; - // } - // } - if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_LIST) - { - for (int i = 0; i < itemCount; i++) - { - // Log.e("leo", "getTotalHeight " + getItemHeight(i) + ", " + i); - mContentHeight += getItemHeight(i); - mContentHeight += getItemMaigin(LOCATION_TOP, i); - mContentHeight += getItemMaigin(LOCATION_BOTTOM, i); - - } - } - // TODO 瀑布流调用 @171215-2016 - else if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_WATERFALL) - { - // int columnHeights[] = mParentRecyclerView.calculateColumnHeightsBefore(getItemCount(), false); - // int heightestColumnIndex = 0; - // for (int j = 0; j < columnHeights.length; j++) - // { - // if (columnHeights[heightestColumnIndex] < columnHeights[j]) - // { - // heightestColumnIndex = j; - // } - // } - // mContentHeight = columnHeights[heightestColumnIndex]; - // ... 瀑布流直接重载getTotalHeight - } - } -// Log.e("leo", hashCode() + "getTotalHeight,height=" + mContentHeight + ",from="); - // Log.e("leo", "getTotalHeight mContentHeight after " + mContentHeight); - // Log.d("leo", DebugUtils.printStackTrack(500)); - return mContentHeight; - } - - @Override - public int getItemMaigin(int location, int position) - { - int margin = 0; - // int cardType = getCardItemViewType(position); - if (position < mDataList.size() && position >= 0) - { - try - { - DataHolder data = mDataList.get(position); - switch (location) - { - case LOCATION_LEFT: - margin = data.mLeftMargin; - break; - case LOCATION_TOP: - // if (cardType == - // QBViewResourceManager.CARD_ITEM_TYPE_TOP - // || cardType == - // QBViewResourceManager.CARD_ITEM_TYPE_FULL) - // { - // data.mTopMargin = 50; - // } - margin = data.mTopMargin; - break; - case LOCATION_RIGHT: - margin = data.mRightMargin; - break; - case LOCATION_BOTTOM: - // if (cardType == - // QBViewResourceManager.CARD_ITEM_TYPE_BOTTOM || - // cardType - // == QBViewResourceManager.CARD_ITEM_TYPE_FULL) - // { - // margin = 50; - // } - margin = data.mBottomMargin; - break; - } - } - catch (Exception e) - { - - } - } - return margin; - } - - @Override - public int getItemCount() - { - return mDataList.size(); - } - - public final boolean hasData() - { - return !mDataList.isEmpty(); - } - - @Override - public int getItemViewType(int index) - { - try - { - if (mDataList.size() > index && index >= 0) - { - return mDataList.get(index).mItemViewType; - } - return super.getItemViewType(index); - } - catch (Exception e) - { - return 0; - } - } - - @Override - public int getCardItemViewType(int index) - { - try - { - if (mDataList.size() > index && index >= 0) - { - return mDataList.get(index).mItemViewStyle; - } - return super.getCardItemViewType(index); - } - catch (Exception e) - { - return 0; - } - } - - public RecyclerAdapter(RecyclerView recyclerView) - { - mParentRecyclerView = recyclerView; - } - - public void setParentRecyclerView(RecyclerView recyclerView) - { - mParentRecyclerView = recyclerView; - } - - public void setItemClickListener(RecyclerViewItemListener qBItemClickListener) - { - mRecyclerViewItemListener = qBItemClickListener; - } - - public RecyclerViewItemListener getItemClickListener() - { - return mRecyclerViewItemListener; - } - - public void onEnterModeStart(int mode) - { - - } - - protected RecyclerViewItem getViewItem(RecyclerViewBase parent) - { - return mParentRecyclerView.createViewItem(); - // the layout type of recycler view is list - // else the layout type of recycler view is grid or waterfall - // if (mParentRecyclerView.mLayoutType == RecyclerView.LAYOUT_TYPE_LIST) - // { - // v = new QBListViewItem(parent.getContext(), (QBRecyclerView) parent, parent.mQBViewResourceManager.mSupportSkin); - // } - // else if (mParentRecyclerView.mLayoutType == RecyclerView.LAYOUT_TYPE_GRID - // || mParentRecyclerView.mLayoutType == RecyclerView.LAYOUT_TYPE_WATERFALL) - // { - // v = new QBGridViewItem(parent.getContext(), (QBRecyclerView) parent); - // } - -// return v; - } - - protected RecyclerViewItem getViewItemWithPos(RecyclerViewBase parent, int position) - { - return getViewItem(parent); - } - - @Override - public RecyclerView.ViewHolderWrapper onCreateViewHolderWithPos(RecyclerViewBase parent, int position, int viewType) - { - RecyclerViewItem v = getViewItemWithPos(parent, position); - - ContentHolder contentHolder = onCreateContentViewWithPos(v, position, viewType); - if (contentHolder == null) - return null; - if (v != null) - { - v.addContentView(contentHolder.mContentView, false); - v.setPadding(contentHolder.mItemPaddingLeft, 0, contentHolder.mItemPaddingRight, 0); - } - RecyclerView.ViewHolderWrapper h = new RecyclerView.ViewHolderWrapper(v, parent); - h.setContentHolder(contentHolder); - return h; - } - - @Override - public RecyclerView.ViewHolderWrapper onCreateSuspendViewHolderWithPos(RecyclerViewBase parent, int position, int viewType) - { - return null; - } - - @Override - public RecyclerView.ViewHolderWrapper onCreateViewHolder(RecyclerViewBase parent, int viewType) - { - RecyclerViewItem v = null; - // the layout type of recycler view is list - // else the layout type of recycler view is grid or waterfall - // if (mParentRecyclerView.mLayoutType == RecyclerView.LAYOUT_TYPE_LIST) - // { - // v = new QBListViewItem(parent.getContext(), (QBRecyclerView) parent, parent.mQBViewResourceManager.mSupportSkin); - // } - // else if (mParentRecyclerView.mLayoutType == RecyclerView.LAYOUT_TYPE_GRID - // || mParentRecyclerView.mLayoutType == RecyclerView.LAYOUT_TYPE_WATERFALL) - // { - // v = new QBGridViewItem(parent.getContext(), (QBRecyclerView) parent); - // } - v = getViewItem(parent); - - ContentHolder contentHolder = onCreateContentView(v, viewType); - if (contentHolder == null) - { - return null; - } - if (v != null) - { - v.addContentView(contentHolder.mContentView, false); - v.setPadding(contentHolder.mItemPaddingLeft, 0, contentHolder.mItemPaddingRight, 0); - } - RecyclerView.ViewHolderWrapper h = new RecyclerView.ViewHolderWrapper(v, parent); - h.setContentHolder(contentHolder); - contentHolder.mParentViewHolder = h; - return h; - } - - - public ContentHolder onCreateContentView(ViewGroup parent, int viewType) - { - return null; - } - - public ContentHolder onCreateContentViewWithPos(ViewGroup parent, int position, int viewType) - { - return null; - } - - public View onCreateCustomerView(ViewGroup parent, int viewType) - { - return null; - } - - @Override - public void onBindViewHolder(final RecyclerView.ViewHolderWrapper holder, int position, int layoutType, int cardType) - { - if (holder == null || holder.itemView == null || holder.mContentHolder == null) - { - return; - } - holder.itemView.setPressed(false); - holder.itemView.setSelected(false); - - onBindContentView(holder.mContentHolder, position, layoutType); - positionContentView(holder.mContentHolder, position, layoutType, false); - onBindCustomerView(holder, position, layoutType); - // Log.d("TMYDIVIDER", "onBindDivider,position=" + position + - // ",dividerH=" + dividerH + ",itemH=" + - // getDataHolder(position).mItemHeight); - RecyclerViewBase.LayoutParams params; - // TODO 瀑布流调用 @171218-0919 - if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_WATERFALL) - { - // ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); - // params = new QBWaterFallView.LayoutParams(lp != null ? lp.width : ViewGroup.LayoutParams.MATCH_PARENT, - // getItemHeight(position) + dividerH); - params = mParentRecyclerView.mLayout.onCreateItemLayoutParams(holder, position, layoutType, cardType); - } - else - { - if (mParentRecyclerView.mLayout.canScrollHorizontally()) - { - params = new RecyclerViewBase.LayoutParams(getItemWidth(position), ViewGroup.LayoutParams.MATCH_PARENT); - } - else - { - params = new RecyclerViewBase.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getItemHeight(position)); - } - } - params.mViewHolder = holder; - params.topMargin = getItemMaigin(LOCATION_TOP, position); - params.bottomMargin = getItemMaigin(LOCATION_BOTTOM, position); - params.leftMargin = getItemMaigin(LOCATION_LEFT, position); - params.rightMargin = getItemMaigin(LOCATION_RIGHT, position); - holder.itemView.setLayoutParams(params); - - - ((RecyclerViewItem) holder.itemView).mHolder = holder; - holder.mForceBind = holder.mContentHolder.mForceBind; - holder.itemView.setFocusable(holder.mContentHolder.mFocusable); - holder.itemView.setOnClickListener(new View.OnClickListener() - { - @Override - public void onClick(View v) - { - if (v instanceof RecyclerViewItem) - { - if (mRecyclerViewItemListener != null) - { - mRecyclerViewItemListener.onItemClick(holder.itemView, holder.mPosition, holder.mContentHolder); - } - } - } - }); - } - - public void deSelecteItem(int position) - { - View view = mParentRecyclerView.findViewByPosition(position); - if (view != null) - { - view.setSelected(false); - } - } - - public void deleteItem(int position) - { - onItemDeleted(position); - if (mParentRecyclerView != null && doDeleteItem()) - { - mParentRecyclerView.postAdapterUpdate(mParentRecyclerView.obtainUpdateOp(RecyclerViewBase.UpdateOp.REMOVE, position, 1)); - } - } - - protected void onShowContextMenu(float x, float y, int position) - { - - } - - public void positionContentView(ContentHolder holder, int position, int layoutType, boolean hasCustomView) - { - if (layoutType == RecyclerViewBase.LAYOUT_TYPE_GRID || layoutType == RecyclerViewBase.LAYOUT_TYPE_WATERFALL) - { - - } - else if (layoutType == RecyclerViewBase.LAYOUT_TYPE_LIST) - { - if (holder == null || holder.mContentView == null) - { - return; - } - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) holder.mContentView.getLayoutParams(); - params.gravity = Gravity.RIGHT; - { - params.leftMargin = 0; - params.rightMargin = 0; - } - } - } - - public void onBindContentView(ContentHolder holder, int position, int layoutType) - { - - } - - public boolean notifyOrderChanged(int fromPosition, int toPosition) - { - return true; - } - - @Override - protected void onViewRecycled(RecyclerView.ViewHolderWrapper holder) - { - onViewRecycled(holder.mContentHolder, holder.mPosition); - } - - public void onViewRecycled(ContentHolder holder, int position) - { - - } - - @Override - protected void onViewAbandon(RecyclerView.ViewHolderWrapper viewHolder) - { - - } - - public void onBindCustomerView(RecyclerView.ViewHolderWrapper holder, int position, int layoutType) - { - } - - - // public void removeIndex(int position) - // { - // } - - - public interface RecyclerViewItemListener - { - void onItemClickInEditMode(View view, int position, ContentHolder contentHolder); - - void onItemClick(View view, int position, ContentHolder contentHolder); - - void onCheckedChanged(View view, int position, boolean isChecked); - - boolean onItemLongClick(View view, int position); - } - - @Override - public int getCustomHeaderViewWidth() - { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getCustomFooterViewWidth() - { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getCustomHeaderViewHeight() - { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getCustomFooterViewHeight() - { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getHeaderViewHeight(int position) - { - // TODO Auto-generated method stub - return 0; - } - - @Override - public int getHeaderViewCount() - { - // TODO Auto-generated method stub - return 0; - } - - @Override - public View getHeaderView(int position) - { - // TODO Auto-generated method stub - return null; - } - - @Override - public int getFooterViewHeight(int position) - { - if (mLoadingStatus != IRecyclerViewFooter.LOADING_STATUS_NONE) - { - if (position == getFooterViewCount()) - { - return getDefaultFooterHeight(); - } - else - { - return getCustomFooterViewHeight(position); - } - } - else - { - return getCustomFooterViewHeight(position); - } - } - - @Override - public int getFooterViewCount() - { - if (mLoadingStatus != IRecyclerViewFooter.LOADING_STATUS_NONE) - { - return getCustomFooterViewCount() + 1; - } - else - { - return getCustomFooterViewCount(); - } - } - - @Override - public View getFooterView(int position) - { -// Log.d("QBRefreshHeader", "getFooterView"); - if (mLoadingStatus != IRecyclerViewFooter.LOADING_STATUS_NONE) - { - if (position == getFooterViewCount()) - { - if (mDefaultLoadingView == null) - { -// Log.d("QBRefreshHeader", "getFooterView-->createFooterView"); - mDefaultLoadingView = mParentRecyclerView.createFooterView(mParentRecyclerView.getContext()); - //if (mDefaultLoadingView != null && mDefaultLoadingView instanceof IRecyclerViewFooter) - //{ - // ((IRecyclerViewFooter) mDefaultLoadingView).setPullToRefreshListener(this); - //} - } - if (mDefaultLoadingView != null) - { - mDefaultLoadingView.setOnClickListener(this); - } - if (mDefaultLoadingView != null && mDefaultLoadingView instanceof IRecyclerViewFooter) - { - ((IRecyclerViewFooter) mDefaultLoadingView).setLoadingStatus(mLoadingStatus); - } - return mDefaultLoadingView; - } - else - { - return getCustomFooterView(position); - } - } - else - { - return getCustomFooterView(position); - } - } - - public int getDefaultFooterHeight() - { - return 108; - } - - // 用户上拉触发了加载,footer开始转圈,业务开始拉去数据 - @Override - public void notifyLastFooterAppeared() - { - super.notifyLastFooterAppeared(); - } - - public void setLoadingStatus(int status) - { - setLoadingStatus(status, -1); - } - - public void setLoadingStatus(int status, int number) - { -// Log.d("QBRefreshHeader", "recycleradapter:setLoadingStatus"); - mLoadingStatus = status; - if (mDefaultLoadingView != null && mDefaultLoadingView instanceof IRecyclerViewFooter) - { - ((IRecyclerViewFooter) mDefaultLoadingView).setLoadingStatus(status); - } - } - - public int getCustomFooterViewHeight(int position) - { - return 0; - } - - public int getCustomFooterViewCount() - { - return 0; - } - - @Override - public int getListTotalHeight() - { - return super.getListTotalHeight() + mParentRecyclerView.getPaddingTop() + mParentRecyclerView.getPaddingBottom(); -// return height; - } - - public void forceUpdateOffsetMap() - { - mDataChanged = true; - calculateOffsetMapIfNeed(); - } - - /* private */void calculateOffsetMapIfNeed() - { - if (mOffsetMap == null) - { - mOffsetMap = new SparseIntArray(); - } - if (mDataChanged) - { - mOffsetMap.clear(); - int itemCount = getItemCount(); - - int headerHeight = 0; - int headerCount = getHeaderViewCount(); - for (int i = 1; i <= headerCount; i++) - { - headerHeight += getHeaderViewHeight(i); - } - int currOffset = headerHeight; - // if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_GRID) - // { - // GridLayoutManager layoutManager = (GridLayoutManager) (mParentRecyclerView.mLayout); - // for (int i = 0; i < itemCount; i++) - // { - // if (i % layoutManager.mColumns == 0) - // { - // int itemTotlaHeihgt = getItemHeight(i) + getItemMaigin(LOCATION_TOP, i) + getItemMaigin(LOCATION_BOTTOM, i) - // + getDividerHeight(i); - // if (i != 0) - // { - // currOffset += itemTotlaHeihgt; - // } - // } - // mOffsetMap.append(i, currOffset); - // } - // } - // if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_LIST) - // { - // for (int i = 0; i < itemCount; i++) - // { - // mOffsetMap.append(i, currOffset); - // currOffset += getItemHeight(i); - // currOffset += getItemMaigin(LOCATION_TOP, i); - // currOffset += getItemMaigin(LOCATION_BOTTOM, i); - // } - // } - // else if (mParentRecyclerView.mLayoutType == RecyclerViewBase.LAYOUT_TYPE_WATERFALL) - // { - // // int columnHeights[] = mParentRecyclerView.calculateColumnHeightsBefore(mDataList.size(), true); - // // int heightestColumnIndex = 0; - // // for (int j = 0; j < columnHeights.length; j++) - // // { - // // if (columnHeights[heightestColumnIndex] < columnHeights[j]) - // // { - // // heightestColumnIndex = j; - // // } - // // } - // // currOffset = columnHeights[heightestColumnIndex]; - // mParentRecyclerView.getLayoutManager().calculateOffsetMap(mOffsetMap, currOffset); - // } - // 调用对应的layoutManager进行计算 - mParentRecyclerView.mLayout.calculateOffsetMap(mOffsetMap, currOffset); - - mDataChanged = false; - } - } - - public View getCustomFooterView(int position) - { - return null; - } - - @Override - public void onClick(View v) - { - // TODO Auto-generated method stub - if (mLoadingStatus == IRecyclerViewFooter.LOADING_STATUS_ERROR_RETRY - || mLoadingStatus == IRecyclerViewFooter.LOADING_STATUS_ERROR_NETWORK_DISCONNECTED - || mLoadingStatus == IRecyclerViewFooter.LOADING_STATUS_ERROR_NETWORK_ERROR) - { - onClickRetry(); - } - else if (mLoadingStatus == IRecyclerViewFooter.LOADING_STATUS_NOMORE_CLICKBACKWARDS) - { - onClickBackward(); - } - } - - protected void onClickRetry() - { - } - - protected void onClickBackward() - { - mParentRecyclerView.smoothScrollBy(0, -mParentRecyclerView.mOffsetY); - } - - /* private */ List mSuspentedPos; - - /* private */void initSuspentedPosIfNeed() - { - if (mSuspentedPos == null) - { - mSuspentedPos = new ArrayList(); - fillSuspentedPos(); - } - if (mSuspentionDataChanged) - { - mSuspentedPos.clear(); - fillSuspentedPos(); - mSuspentionDataChanged = false; - } - } - - @Override - protected void onViewAttached() - { - // if (mTextLayoutCache != null) - // { - // mTextLayoutCache.start(); - // } - super.onViewAttached(); - } - - @Override - protected void onViewDetached() - { - // if (mTextLayoutCache != null) - // { - // mTextLayoutCache.stop(); - // } - super.onViewDetached(); - } - - @Override - public void dataChanged() - { - super.dataChanged(); - // if (mTextLayoutCache != null) - // { - // mTextLayoutCache.waitForTasksComplete(); - // } - } - - /* private */void fillSuspentedPos() - { - int count = getItemCount(); - for (int i = 0; i < count; i++) - { - if (isSuspentedItem(i)) - { - addSuspentedPos(i); - } - } - Collections.sort(mSuspentedPos); - } - - @Override - public int findPrevSuspentedPos(int pos) - { - initSuspentedPosIfNeed(); - - if (mSuspentedPos == null || mSuspentedPos.isEmpty()) - { - return -1; - } - // Log.d("leo", "findPrev:sus=" + - // Arrays.toString(mSuspentedPos.toArray())); - int size = mSuspentedPos.size(); - for (int i = 0; i < size; i++) - { - int value = mSuspentedPos.get(i); - if (mSuspentedPos.get(i) >= pos) - { - if (value == pos) - { - return value; - } - if (i == 0) - { - return -1; - } - return mSuspentedPos.get(i - 1); - } - } - return mSuspentedPos.get(size - 1); - } - - - public int findNextSuspentedPos(int pos) - { - if (mSuspentedPos == null || mSuspentedPos.isEmpty()) - { - return -1; - } - int last = findPrevSuspentedPos(pos); - int lastIndex = mSuspentedPos.indexOf(last); - if (last == -1 || lastIndex + 1 >= mSuspentedPos.size()) - { - return -1; - } - return mSuspentedPos.get(lastIndex + 1); - } - - public void addSuspentedPos(int pos) - { - if (!mParentRecyclerView.hasSuspentedItem()) - { - return; - } - if (mSuspentedPos == null) - { - mSuspentedPos = new ArrayList(); - } - if (!mSuspentedPos.contains(pos)) - { - mSuspentedPos.add(pos); - } - } - - - @Override - public void notifyItemChanged(int position) - { - mContentHeight = -1; - super.notifyItemChanged(position); - } - - public void notifyItemRangeChanged(int positionStart, int itemCount) - { - mContentHeight = -1; - super.notifyItemRangeChanged(positionStart, itemCount); - } - - @Override - public void notifyDataSetChanged() - { - mContentHeight = -1; - // if (isAutoCalculateItemHeight() && mItemHeightList != null) - // { - // mAutoCalcItemHeightFinish = false; - // } - super.notifyDataSetChanged(); - } - - @Override - public void notifyItemInserted(int position) - { - mContentHeight = -1; - super.notifyItemInserted(position); - } - - @Override - public void notifyItemRangeInserted(int positionStart, int itemCount) - { - mContentHeight = -1; - super.notifyItemRangeInserted(positionStart, itemCount); - } - - public void notifyItemRangeRemoved(int positionStart, int itemCount) - { - mContentHeight = -1; - super.notifyItemRangeRemoved(positionStart, itemCount); - } - - @Override - public void notifyItemRemoved(int position) - { - mContentHeight = -1; - super.notifyItemRemoved(position); - } - - @Override - public boolean getFooterViewInBottomMode() - { - return false; - } - - public void notifyItemsRemoved(ArrayList positions) - { - mContentHeight = -1; - super.notifyItemsRemoved(positions); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerView.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerView.java deleted file mode 100644 index b1b8b41d66f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerView.java +++ /dev/null @@ -1,354 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import java.util.ArrayList; -import java.util.List; - -import com.tencent.mtt.supportui.views.ScrollChecker; - -import android.content.Context; -import android.content.res.Configuration; -import android.view.View; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -public class RecyclerView extends RecyclerViewBase implements RecyclerViewBase.OnScrollListener, ScrollChecker.IScrollCheck -{ - public RecyclerAdapter mRecyclerViewAdapter; - - public interface OnListScrollListener - { - void onStartDrag(); - - void onScroll(int dx, int dy); - - void onScrollEnd(); - - void onDragEnd(); - - void onStartFling(); - - } - - public CopyOnWriteArrayList mListScrollListeners = null; - - public void addOnListScrollListener(OnListScrollListener listener) - { - if (mListScrollListeners == null) - { - mListScrollListeners = new CopyOnWriteArrayList(); - - } - if (!mListScrollListeners.contains(listener)) - { - mListScrollListeners.add(listener); - } - } - - public void removeOnListScrollListener(OnListScrollListener listener) - { - if (mListScrollListeners != null && mListScrollListeners.contains(listener)) - { - mListScrollListeners.remove(listener); - } - } - - public RecyclerView(Context context) - { - super(context); - setOverScrollEnabled(true); - setVerticalScrollBarEnabled(true); - setHorizontalScrollBarEnabled(false); - setOnScrollListener(this); - setAnimationCacheEnabled(false); - } - - public void reset() - { - scrollToPosition(0); - mOffsetY = 0; - mInitialTouchY = 0; - mLastTouchY = 0; - mScrollState = SCROLL_STATE_IDLE; - mScrollPointerId = -1; - mVelocityTracker = null; - - } - - @SuppressWarnings("rawtypes") - @Override - public void setAdapter(Adapter adapter) - { - super.setAdapter(adapter); - mRecyclerViewAdapter = (RecyclerAdapter) adapter; - } - - public int getHeightBefore(int pos) - { - if (mRecyclerViewAdapter != null) - { - return mRecyclerViewAdapter.getHeightBefore(pos); - } - return 0; - } - - @Override - protected boolean canTranversal(int purpose, ViewHolder holder) - { - return super.canTranversal(purpose, holder); - } - - public static class ViewHolderWrapper extends ViewHolder - { - public ViewHolderWrapper(View itemView, RecyclerViewBase rv) - { - super(itemView, rv); - if (itemView instanceof RecyclerViewItem) - { - RecyclerViewItem item = (RecyclerViewItem) itemView; - mContent = item.mContentView; - } - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append("holder:" + Integer.toHexString(hashCode()) + ",pos=" + getPosition() + ","); - if (mContentHolder != null) - { - sb.append(mContentHolder.toString()); - } - return sb.toString(); - } - - public void setContentHolder(ContentHolder contentHolder) - { - mContentHolder = contentHolder; - } - - @Override - public void inTraversals(int traversalPurpose) - { - - if (traversalPurpose == TRAVERSAL_PURPOSE_MODECHANGE || traversalPurpose == TRAVERSAL_PURPOSE_ITEMCHANGE) - { - mBindNextTime = true; - // addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID); - // mFlags &= ~ViewHolder.FLAG_BOUND; - } - else if (mContentHolder != null) - { - mContentHolder.inTraversals(traversalPurpose, mPosition, mParent); - } - } - } - - @Override - public void onScrollStateChanged(int oldState, int newState) - { - switch (newState) - { - case SCROLL_STATE_IDLE: - if (oldState == SCROLL_STATE_SETTLING) - { - // stop fling - onScrollFlingEnded(); - if (mListScrollListeners != null) - { - for (OnListScrollListener listener : mListScrollListeners) - { - listener.onScrollEnd(); - } - } - } - else if (oldState == SCROLL_STATE_DRAGGING) - { - // stop drag - onScrollDragEnded(); - if (mListScrollListeners != null) - { - for (OnListScrollListener listener : mListScrollListeners) - { - listener.onDragEnd(); - } - } - } - break; - case SCROLL_STATE_SETTLING: - if (oldState == SCROLL_STATE_DRAGGING) - { - // stop drag and start fling - onScrollDragEnded(); - onScrollFlingStarted(); - if (mListScrollListeners != null) - { - for (OnListScrollListener listener : mListScrollListeners) - { - listener.onStartFling(); - } - } - } - break; - case SCROLL_STATE_DRAGGING: - if (oldState == SCROLL_STATE_IDLE) - { - // start drag here - onScrollDragStarted(); - if (mListScrollListeners != null) - { - for (OnListScrollListener listener : mListScrollListeners) - { - listener.onStartDrag(); - } - } - } - else if (oldState == SCROLL_STATE_SETTLING) - { - // stop fling and start drag - onScrollFlingEnded(); - onScrollDragStarted(); - } - break; - } - } - - protected void onScrollDragStarted() - { - - } - - protected void onScrollDragEnded() - { - - } - - protected void onScrollFlingStarted() - { - - } - - protected void onScrollFlingEnded() - { - - } - - @Override - public void onScrolled(int dx, int dy) - { - if (mListScrollListeners == null || mListScrollListeners.size() == 0) - { - return; - } - for (OnListScrollListener listener : mListScrollListeners) - { - listener.onScroll(dx, dy); - } - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) - { - super.onConfigurationChanged(newConfig); - onOrientationChanged(); - } - - public void onOrientationChanged() - { - // Log.d("RecyclerView", "onOrientationChanged:view"); - } - - @Override - public int findPrevSuspentedPos(int pos) - { - // TODO Auto-generated method stub - return mAdapter.findPrevSuspentedPos(pos); - } - - public int findNextSuspentedPos(int pos) - { - return mAdapter.findNextSuspentedPos(pos); - } - - - // protected int getSpringBackMaxDistance() - // { - // return 120; - // } - // - // protected int getAutoScrollVelocity() - // { - // return 9; - // } - - @Override - public ViewHolder createViewHolder(View itemView, RecyclerViewBase rv) - { - return new ViewHolderWrapper(itemView, rv); - } - - @Override - public void onItemsFill(int offset) - { - super.onItemsFill(offset); - Adapter adapter = getAdapter(); - if (adapter != null) - { - adapter.onItemsFill(offset); - } - } - - @Override - public void checkNotifyFooterAppearWithFewChild(int endOffset) - { - Adapter adapter = getAdapter(); - if (adapter != null && (mOffsetY + getHeight() >= adapter.getListTotalHeight() - adapter.getDefaultFooterHeight())) - { - View view = getLayoutManager().getChildClosestToEndInScreen(); - if (view != null && view instanceof IRecyclerViewFooter) - { - adapter.notifyLastFooterAppeared(); - } - } - } - - @Override - public boolean verticalCanScroll(int direction) - { - if (mLayout != null) - { - return mVerticalCanScroll && mLayout.canScrollVertically(); - } - return false; - } - - @Override - public boolean horizontalCanScroll(int direction) - { - if (mLayout != null) - { - return mHorizontalCanScroll && mLayout.canScrollHorizontally(); - } - return false; - } - - - public RecyclerViewItem createViewItem() - { - return new RecyclerViewItem(getContext(), this); - } - - @Override - protected boolean needAdvancedStopDetachChildView() - { - return false; - } - - - public View createFooterView(Context context) - { - return null; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerViewBase.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerViewBase.java deleted file mode 100644 index 17aa10198c9..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerViewBase.java +++ /dev/null @@ -1,8544 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import com.tencent.mtt.supportui.views.recyclerview.BaseLayoutManager.SavedState; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import com.tencent.mtt.supportui.utils.ViewCompatTool; -import com.tencent.mtt.supportui.utils.struct.ArrayMap; -import com.tencent.mtt.supportui.utils.struct.Pools; - -import android.content.Context; -import android.database.Observable; -import android.graphics.Canvas; -import android.graphics.PointF; -import android.graphics.Rect; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; -import android.util.SparseArray; -import android.util.SparseIntArray; -import android.view.FocusFinder; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.animation.Interpolator; - -public abstract class RecyclerViewBase extends ViewGroup -{ - public static final int TRAVERSAL_PURPOSE_MODECHANGE = 1991102; - public static final int TRAVERSAL_PURPOSE_ITEMCHANGE = 1991103; - static final String TAG = "RecyclerViewBase"; - - public static final boolean DEBUG = /* - * BuildConfig - * . - * DEBUG - */false; - static final boolean ENABLE_PREDICTIVE_ANIMATIONS = false; - - public static final int LAYOUT_TYPE_LIST = 1; - public static final int LAYOUT_TYPE_GRID = 2; - public static final int LAYOUT_TYPE_WATERFALL = 3; - - /* private */static final boolean DISPATCH_TEMP_DETACH = false; - public static final int HORIZONTAL = 0; - public static final int VERTICAL = 1; - public static final int NO_POSITION = Integer.MIN_VALUE; - public static final long NO_ID = -1; - public static final int INVALID_TYPE = -1; - - /* private */static final int MAX_SCROLL_DURATION = 2000; - - /* private */final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver(); - - protected Recycler mRecycler = new Recycler(); - - /* private */SavedState mPendingSavedState; - public boolean needNotifyFooter = false; - /** - * Note: this Runnable is only ever posted if: 1) We've been through first - * layout 2) We know we have a fixed size (mHasFixedSize) 3) We're attached - */ - /* private */final Runnable mUpdateChildViewsRunnable = new Runnable() - { - public void run() - { - if (mPendingUpdates.isEmpty()) - { - setRecyclerViewTouchEnabled(true); - return; - } - eatRequestLayout(); - updateChildViews(); - traversal(TRAVERSAL_PURPOSE_ITEMCHANGE); - resumeRequestLayout(true); - if (!mPostedAnimatorRunner) - { - setRecyclerViewTouchEnabled(true); - } - // if (DeviceUtils.getSdkVersion() < 11) - // { - // invalidate(); - // } - } - }; - - /* private */final Rect mTempRect = new Rect(); - - /* private */final ArrayList mPendingUpdates = new ArrayList(); - /* private */final ArrayList mPendingLayoutUpdates = new ArrayList(); - /* private */Pools.Pool mUpdateOpPool = new Pools.SimplePool( - UpdateOp.POOL_SIZE); - - public Adapter mAdapter; - public LayoutManager mLayout; - /* private */final ArrayList mItemDecorations = new ArrayList(); - /* private */final ArrayList mOnItemTouchListeners = new ArrayList(); - /* private */OnItemTouchListener mActiveOnItemTouchListener; - /* private */boolean mIsAttached; - /* private */boolean mHasFixedSize; - /* private */boolean mEatRequestLayout; - /* private */boolean mLayoutRequestEaten; - /* private */boolean mAdapterUpdateDuringMeasure; - /* private */final boolean mPostUpdatesOnAnimation; - public int mLayoutType; - public int mOffsetY = 0; - public int mOffsetX = 0; - - protected boolean mBlockScroll = false; - /* private */static final int INVALID_POINTER = -1; - public static final int DIRECTION_UP = -1; - public static final int DIRECTION_DOWN = 1; - /** - * The RecyclerView is not currently scrolling. - * - * @see #getScrollState() - */ - public static final int SCROLL_STATE_IDLE = 0; - /** - * The RecyclerView is currently being dragged by outside input such as user - * touch input. - * - * @see #getScrollState() - */ - public static final int SCROLL_STATE_DRAGGING = 1; - - /** - * The RecyclerView is currently animating to a final position while not - * under outside control. - * - * @see #getScrollState() - */ - public static final int SCROLL_STATE_SETTLING = 2; - - // Touch/scrolling handling - public boolean optimizeHeaderRefresh = false; - protected int mScrollState = SCROLL_STATE_IDLE; - protected int mScrollPointerId = INVALID_POINTER; - protected VelocityTracker mVelocityTracker; - protected int mInitialTouchX; - protected int mInitialTouchY; - protected int mLastTouchX; - protected int mLastTouchY; - protected final int mTouchSlop; - /* private */final int mMinFlingVelocity; - /* private */final int mMaxFlingVelocity; - public final ViewFlinger mViewFlinger = new ViewFlinger(); - private boolean mShouldPrebindItem = false; - // protected final SpringBackHandler mSpringBackHandler = new - // SpringBackHandler(); - - public final State mState = new State(); - - /* private */OnScrollListener mScrollListener; - - // For use in item animations - protected boolean mItemsAddedOrRemoved = false; - protected boolean mItemsChanged = false; - int mAnimatingViewIndex = -1; - int mNumAnimatingViews = 0; - int mAnimatingViewPos = -1; - int mAnimatingViewPrevPos = -1; - boolean mInPreLayout = false; - protected boolean mPostedAnimatorRunner = false; - protected Runnable mItemAnimatorRunner = new Runnable() - { - @Override - public void run() - { - forceBlockTouch = true; - mPostedAnimatorRunner = false; - } - }; - - - /* private */static final Interpolator sQuinticInterpolator = new Interpolator() - { - public float getInterpolation(float t) - { - t -= 1.0f; - return t * t * t * t * t + 1.0f; - } - }; - - protected static final int AUTO_SCROLL_DELAY_DURATION = 800; - - protected int mEnterPos; - - protected int mExitPos; - - protected boolean mEnterCalled; - - protected boolean mExitCalled; - - protected boolean mExchangeFromBigger; - - protected AutoScrollRunnable mAutoScrollRunnable; - - protected boolean mScrollRunnablePosted; - - // /* private */SwipeHelper mSwipeHelper; - - - public boolean checkNotifyFooterOnRelease; - public boolean filterCheckNotifyFooterAppeared = false; - - public int mNeedStopAtTitleIndex = -1; - /* private */boolean mStopAtTitle = false; - - protected boolean mIsChangingMode = false; - /* private */boolean mIsTouching; - - private boolean mEnableRecyclerViewTouchListener = false; // 业务是否需要监听recyclerView的touch事件,默认不监听 - - public boolean mAnimatingBlockTouch; - private IBlockTouchListener blockTouchListener; - - protected boolean forceBlockTouch; - private boolean mDisallowParentInterceptTouchEventWhenDrag = true; - /* private */boolean mHasSuspentedItem; - /* private */boolean mUseRepeatableSuspensionMode = true; - - private boolean mTouchDownWhenSettlingFlag = false; - private static final int TOUCH_DOWN_WHEN_SETTING_CHECK_INTERVAL = 50; - private Runnable mTouchDownWhenSettlingCheckRunnable = null; - private int mTouchEventState = MotionEvent.ACTION_UP; - - public RecyclerViewBase(Context context) - { - super(context); - final int version = Build.VERSION.SDK_INT; - mPostUpdatesOnAnimation = version >= 16; - final ViewConfiguration vc = ViewConfiguration.get(context); - mTouchSlop = vc.getScaledTouchSlop(); - mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); - setWillNotDraw(false); - setHasFixedSize(true); - - mAutoScrollRunnable = new AutoScrollRunnable(); - - mTouchDownWhenSettlingCheckRunnable = new Runnable() - { - @Override - public void run() - { - if (mTouchDownWhenSettlingFlag) - { - mTouchDownWhenSettlingFlag = false; - if (mTouchEventState == MotionEvent.ACTION_DOWN) - { - // only touch down currently, so stopScroll here - stopScroll(); - } - else if (mTouchEventState == MotionEvent.ACTION_MOVE) - { - if (mVelocityTracker != null) - { - mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity); - float yVelocity = mVelocityTracker.getYVelocity(); - if (Math.abs(yVelocity) < mMaxFlingVelocity * 2 / 3) - { - // drag at slow velocity currently, so stopScroll here - stopScroll(); - } - } - } - } - } - }; - } - - /** - * RecyclerView can perform several optimizations if it can know in advance - * that changes in adapter content cannot change the size of the - * RecyclerView itself. If your use of RecyclerView falls into this - * category, set this to true. - * - * @param hasFixedSize true if adapter changes cannot affect the size of the - * RecyclerView. - */ - public void setHasFixedSize(boolean hasFixedSize) - { - mHasFixedSize = hasFixedSize; - } - - public ArrayList getCachedViews() - { - return mRecycler.mCachedViews; - } - - /** - * @return true if the app has specified that changes in adapter content - * cannot change the size of the RecyclerView itself. - */ - public boolean hasFixedSize() - { - return mHasFixedSize; - } - - /** - * Set a new adapter to provide child views on demand. - * - * @param adapter The new adapter to set, or null to set no adapter. - */ - public void setAdapter(Adapter adapter) - { - if (mAdapter != null) - { - mAdapter.unregisterAdapterDataObserver(mObserver); - } - // Since animations are ended, mLayout.children should be equal to - // recyclerView.children. - // This may not be true if item animator's end does not work as - // expected. (e.g. not release - // children instantly). It is safer to use mLayout's child count. - if (mLayout != null) - { - mLayout.removeAndRecycleAllViews(mRecycler); - mLayout.removeAndRecycleScrapInt(mRecycler, true, true); - } - - final Adapter oldAdapter = mAdapter; - mAdapter = adapter; - if (adapter != null) - { - adapter.registerAdapterDataObserver(mObserver); - } - if (mLayout != null) - { - mLayout.onAdapterChanged(oldAdapter, mAdapter); - } - mRecycler.onAdapterChanged(oldAdapter, mAdapter); - mState.mStructureChanged = true; - markKnownViewsInvalid(); - requestLayout(); - } - - /** - * Retrieves the previously set adapter or null if no adapter is set. - * - * @return The previously set adapter - * @see #setAdapter(Adapter) - */ - public Adapter getAdapter() - { - return mAdapter; - } - - public Recycler getRecycler() - { - return mRecycler; - } - - public void setEnableHorizontalDrag(boolean enable) - { - } - - /** - * Set the {@link LayoutManager} that this RecyclerView will use. - *

- *

- * In contrast to other adapter-backed views such as - * {@link android.widget.ListView} or {@link android.widget.GridView}, - * RecyclerView allows client code to provide custom layout arrangements for - * child views. These arrangements are controlled by the - * {@link LayoutManager}. A LayoutManager must be provided for RecyclerView - * to function. - *

- *

- *

- * Several default strategies are provided for common uses such as lists and - * grids. - *

- * - * @param layout LayoutManager to use - */ - public void setLayoutManager(LayoutManager layout) - { - mLayoutType = layout.getLayoutType(); - - if (layout == mLayout) - { - return; - } - if (mAdapter != null) - { - mAdapter.reset(); - } - mRecycler.clear(); - removeAllViews(); - if (mLayout != null) - { - if (mIsAttached) - { - mLayout.onDetachedFromWindow(this); - } - mLayout.mRecyclerView = null; - } - mLayout = layout; - if (layout != null) - { - if (layout.mRecyclerView != null) - { - throw new IllegalArgumentException("LayoutManager " + layout + " is already attached to a RecyclerView: " + layout.mRecyclerView); - } - layout.mRecyclerView = this; - if (mIsAttached) - { - mLayout.onAttachedToWindow(this); - } - } - requestLayout(); - } - - @Override - protected Parcelable onSaveInstanceState() - { - SavedState state = new SavedState(super.onSaveInstanceState()); - if (mPendingSavedState != null) - { - state.copyFrom(mPendingSavedState); - } - else if (mLayout != null) - { - state.mLayoutState = mLayout.onSaveInstanceState(); - } - else - { - state.mLayoutState = null; - } - - return state; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (state != null && state instanceof BaseLayoutManager.SavedState) { - mPendingSavedState = (SavedState)state; - super.onRestoreInstanceState(mPendingSavedState.getSuperState()); - if (mLayout != null && mPendingSavedState.mLayoutState != null) { - mLayout.onRestoreInstanceState(mPendingSavedState.mLayoutState); - } - } - } - - /** - * Adds a view to the animatingViews list. mAnimatingViews holds the child - * views that are currently being kept around purely for the purpose of - * being animated out of view. They are drawn as a regular part of the child - * list of the RecyclerView, but they are invisible to the LayoutManager as - * they are managed separately from the regular child views. - * - * @param view The view to be removed - */ - public void addAnimatingView(View view, boolean inlayout) - { - boolean alreadyAdded = false; - if (mNumAnimatingViews > 0) - { - for (int i = mAnimatingViewIndex; i < getChildCount(); ++i) - { - if (getChildAt(i) == view) - { - alreadyAdded = true; - break; - } - } - } - if (!alreadyAdded) - { - // if (mNumAnimatingViews == 0) - // { - // } - ++mNumAnimatingViews; - if (inlayout) - { - addViewInLayout(view, -1, view.getLayoutParams(), true); - } - else - { - addView(view); - } - mAnimatingViewIndex = getChildCount() - mNumAnimatingViews; - } - if (DEBUG) - { - // Log.d("leo", "after add animatingViews count=" + mNumAnimatingViews); - } - mRecycler.unscrapView(getChildViewHolder(view)); - } - - public void addAnimatingView(View view) - { - addAnimatingView(view, false); - } - - /* private */void removeAnimatingViews() - { - int count = getChildCount(); - View[] views = new View[count]; - for (int i = 0; i < count; i++) - { - views[i] = getChildAt(i); - } - for (int j = 0; j < count; j++) - { - removeAnimatingView(views[j]); - } - } - - /* private */void layoutAnimationViews() - { - int count = getChildCount(); - if (mAnimatingViewIndex != -1) - { - mAnimatingViewIndex = Math.max(0, Math.min(count, mAnimatingViewIndex)); - View v = getChildAt(mAnimatingViewIndex); - if (v != null && mLayout != null) - { - mLayout.measureChildWithMargins(v, 0, 0); - mLayout.layoutDecorated(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); - } - } - } - - /** - * Removes a view from the animatingViews list. - * - * @param view The view to be removed - * @see #addAnimatingView(View) - */ - public void removeAnimatingView(View view, boolean inlayout) - { - if (mNumAnimatingViews > 0) - { - for (int i = mAnimatingViewIndex; i < getChildCount(); ++i) - { - if (getChildAt(i) == view) - { - if (inlayout) - { - removeViewInLayout(view); - } - else - { - if (getAdapter() != null && getAdapter().hasCustomRecycler() && mAnimatingViewPos >= 0 - && mAnimatingViewPos == mAnimatingViewPrevPos) - { - - } - else - { - removeViewAt(i); - } - } - --mNumAnimatingViews; - if (mNumAnimatingViews == 0) - { - mAnimatingViewIndex = -1; - } - if (DEBUG) - { - // Log.d("leo", "after remove animatingViews count=" + mNumAnimatingViews); - } - if (getAdapter() != null && getAdapter().hasCustomRecycler() && mAnimatingViewPos >= 0 - && mAnimatingViewPos == mAnimatingViewPrevPos && !inlayout) - { - - } - else - { - mRecycler.recycleView(view); - } - return; - } - } - } - } - - public void removeAnimatingView(View view) - { - removeAnimatingView(view, false); - } - - public View getAnimatingView(int position, int type) - { - if (mNumAnimatingViews > 0) - { - for (int i = mAnimatingViewIndex; i < getChildCount(); ++i) - { - final View view = getChildAt(i); - ViewHolder holder = getChildViewHolder(view); - if (holder != null && holder.getPosition() == position && (type == INVALID_TYPE || holder.getItemViewType() == type)) - { - return view; - } - } - } - return null; - } - - /** - * Return the {@link LayoutManager} currently responsible for layout policy - * for this RecyclerView. - * - * @return The currently bound LayoutManager - */ - public LayoutManager getLayoutManager() - { - return mLayout; - } - - /** - * Retrieve this RecyclerView's {@link RecycledViewPool}. This method will - * never return null; if no pool is set for this view a new one will be - * created. See {@link #setRecycledViewPool(RecycledViewPool) - * setRecycledViewPool} for more information. - * - * @return The pool used to store recycled item views for reuse. - * @see #setRecycledViewPool(RecycledViewPool) - */ - public RecycledViewPool getRecycledViewPool() - { - return mRecycler.getRecycledViewPool(); - } - - /** - * Recycled view pools allow multiple RecyclerViews to share a common pool - * of scrap views. This can be useful if you have multiple RecyclerViews - * with adapters that use the same view types, for example if you have - * several data sets with the same kinds of item views displayed by - * ViewPager. - * - * @param pool Pool to set. If this parameter is null a new pool will be - * created and used. - */ - public void setRecycledViewPool(RecycledViewPool pool) - { - mRecycler.setRecycledViewPool(pool); - } - - /** - * Set the number of offscreen views to retain before adding them to the - * potentially shared {@link #getRecycledViewPool() recycled view pool}. - *

- *

- * The offscreen view cache stays aware of changes in the attached adapter, - * allowing a LayoutManager to reuse those views unmodified without needing - * to return to the adapter to rebind them. - *

- * - * @param size Number of views to cache offscreen before returning them to - * the general recycled view pool - */ - public void setItemViewCacheSize(int size) - { - mRecycler.setViewCacheSize(size); - } - - /** - * Return the current scrolling state of the RecyclerView. - * - * @return {@link #SCROLL_STATE_IDLE}, {@link #SCROLL_STATE_DRAGGING} or - * {@link #SCROLL_STATE_SETTLING} - */ - public int getScrollState() - { - return mScrollState; - } - - /* private */void setScrollState(int state) - { - if (state == mScrollState) - { - return; - } - int oldState = mScrollState; - mScrollState = state; - if (state != SCROLL_STATE_SETTLING) - { - if (!isTouchStopWhenFastFling() && oldState == SCROLL_STATE_SETTLING && state == SCROLL_STATE_DRAGGING) - { - mTouchDownWhenSettlingFlag = true; - } - else - { - stopScroll(); - } - } - if (mScrollListener != null) - { - mScrollListener.onScrollStateChanged(oldState, state); - } - } - - /** - * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can - * affect both measurement and drawing of individual item views. - *

- *

- * Item decorations are ordered. Decorations placed earlier in the list will - * be run/queried/drawn first for their effects on item views. Padding added - * to views will be nested; a padding added by an earlier decoration will - * mean further item decorations in the list will be asked to draw/pad - * within the previous decoration's given area. - *

- * - * @param decor Decoration to add - * @param index Position in the decoration chain to insert this decoration - * at. - * If this value is negative the decoration will be added at the - * end. - */ - public void addItemDecoration(ItemDecoration decor, int index) - { - if (mItemDecorations.isEmpty()) - { - setWillNotDraw(false); - } - if (index < 0) - { - mItemDecorations.add(decor); - } - else - { - mItemDecorations.add(index, decor); - } - markItemDecorInsetsDirty(); - requestLayout(); - } - - /** - * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can - * affect both measurement and drawing of individual item views. - *

- *

- * Item decorations are ordered. Decorations placed earlier in the list will - * be run/queried/drawn first for their effects on item views. Padding added - * to views will be nested; a padding added by an earlier decoration will - * mean further item decorations in the list will be asked to draw/pad - * within the previous decoration's given area. - *

- * - * @param decor Decoration to add - */ - public void addItemDecoration(ItemDecoration decor) - { - addItemDecoration(decor, -1); - } - - /** - * Remove an {@link ItemDecoration} from this RecyclerView. - *

- *

- * The given decoration will no longer impact the measurement and drawing of - * item views. - *

- * - * @param decor Decoration to remove - * @see #addItemDecoration(ItemDecoration) - */ - public void removeItemDecoration(ItemDecoration decor) - { - mItemDecorations.remove(decor); - if (mItemDecorations.isEmpty()) - { - setWillNotDraw(false); - } - markItemDecorInsetsDirty(); - requestLayout(); - } - - /** - * Set a listener that will be notified of any changes in scroll state or - * position. - * - * @param listener Listener to set or null to clear - */ - public void setOnScrollListener(OnScrollListener listener) - { - mScrollListener = listener; - } - - /** - * Convenience method to scroll to a certain position without smoothly or - * animation - *

- * RecyclerView does not implement scrolling logic, rather forwards the call - * to {@link #scrollToPosition(int)} - * - * @param position Scroll to this adapter position - * @see #scrollToPosition(int) - */ - public void scrollToPosition(int position) - { - stopScroll(); - mLayout.scrollToPosition(position); - if (mScrollListener != null) - { - mScrollListener.onScrolled((int) getX(), position); - } - } - - /** - * Convenience method to scroll to a certain position without smoothly or - * animation - */ - public void scrollToPosition(int position, int offset) - { - stopScroll(); - mLayout.scrollToPositionWithOffset(position, offset); - if (mScrollListener != null) - { - mScrollListener.onScrolled((int) getX(), position); - } - } - - public void scrollToPositionWithGravity(int position, int gravity, int itemHeight) - { - stopScroll(); - mLayout.scrollToPositionWidthGravity(position, gravity, itemHeight); - } - - public void smoothScrollToPosition(int position) - { - mLayout.smoothScrollToPosition(this, mState, position); - } - - @Override - public void scrollTo(int x, int y) - { - throw new UnsupportedOperationException("RecyclerView does not support scrolling to an absolute position."); - } - - @Override - public void scrollBy(int x, int y) - { - if (mLayout == null) - { - throw new IllegalStateException("Cannot scroll without a LayoutManager set. " + "Call setLayoutManager with a non-null argument."); - } - final boolean canScrollHorizontal = mLayout.canScrollHorizontally(); - final boolean canScrollVertical = mLayout.canScrollVertically(); - if (canScrollHorizontal || canScrollVertical) - { - scrollByInternal(canScrollHorizontal ? x : 0, canScrollVertical ? y : 0); - } - } - - /** - * Helper method reflect data changes to the state. - *

- * Adapter changes during a scroll may trigger a crash because scroll - * assumes no data change but data actually changed. - *

- * This method consumes all deferred changes to avoid that case. - *

- * This also ends all pending animations. It will be changed once we can - * support animations during scroll. - */ - protected void consumePendingUpdateOperations() - { - if (mPendingUpdates.size() > 0) - { - mUpdateChildViewsRunnable.run(); - } - } - - int[] tmpResult = new int[2]; - - protected int getSpringBackMaxDistance() - { - return 120; // UIResourceDimen.dimen.uifw_recycler_springback_max_distance - } - - protected int getAutoScrollVelocity() - { - return 9; // UIResourceDimen.dimen.uifw_recycler_auto_scroll_velocity - } - - protected boolean changeUpOverScrollEnableOnComputeDxDy(int dx, int dy, boolean careSpringBackMaxDistance, Scroller scroller, boolean isTouch, - boolean currentUpOverScrollEnabled) - { - return currentUpOverScrollEnabled; - } - - /* private */int[] computeDxDy(int dx, int dy, boolean careSpringBackMaxDistance, Scroller scroller, boolean isTouch) - { - int[] result = tmpResult; - result[0] = dx; - result[1] = dy; - // Log.d("leo", "computeDxDy:total=" + mState.mTotalHeight); - final int springbackDis = getSpringBackMaxDistance(); - boolean upOverScrollEnabled = mUpOverScrollEnabled; - boolean downOverScrollEnabled = mDownOverScrollEnabled; - upOverScrollEnabled = changeUpOverScrollEnableOnComputeDxDy(dx, dy, careSpringBackMaxDistance, scroller, isTouch, mUpOverScrollEnabled); - if (dx != 0) // 水平方向滑动 - { - if (mOffsetX + dx < 0) - { - if (!upOverScrollEnabled) - { - dx = -mOffsetX; - if (scroller != null) - { - scroller.forceFinished(true); - } - } - else - { - if (mOffsetX < 0) - { - dx = dx > 0 ? dx : (dx / 3 == 0 || !isTouch ? dx : dx / 3); - } - if (mOffsetX + dx <= -springbackDis && careSpringBackMaxDistance) - { - dx = -mOffsetX - springbackDis; - if (scroller != null) - { - scroller.forceFinished(true); - } - } - } - } - else if (mOffsetX + dx > mState.mTotalHeight - getWidth()) - { - if (!downOverScrollEnabled) - { - if (mState.mTotalHeight <= getWidth()) - { - dx = 0; - } - else - { - dx = mState.mTotalHeight - getWidth() - mOffsetX; - } - if (scroller != null) - { - scroller.forceFinished(true); - } - } - else - { - if (mOffsetX > mState.mTotalHeight - getWidth()) - { - dx = dx < 0 ? dx : (dx / 3 == 0 || !isTouch ? dx : dx / 3); - } - int d = 0; - if (mState.mTotalHeight <= getWidth()) - { - d = 0; - } - else - { - d = mState.mTotalHeight - getWidth(); - } - if (mOffsetX + dx >= d + springbackDis && careSpringBackMaxDistance) - { - - dx = -mOffsetX + d + springbackDis; - if (scroller != null) - { - scroller.forceFinished(true); - } - } - } - - } - } - if (dy != 0) // 竖直方向滑动 - { - if (mOffsetY + dy <= 0) - { - if (!upOverScrollEnabled) - { - int unConsumedY = dy + mOffsetY; - dy = -mOffsetY; - if (scroller != null && scroller.isFling()) - { - onFlingToTopEdge(scroller.getCurrVelocity(), unConsumedY); - } - else if (mIsTouching) - { - onScrollToTopEdge(); - } - if (scroller != null) - { - scroller.forceFinished(true); - } - } - else - { - if (mOffsetY < 0) - { - dy = dy > 0 ? dy : (dy / 3 == 0 || !isTouch ? dy : dy / 3); - } - - if (mOffsetY + dy <= -springbackDis && careSpringBackMaxDistance) - { - dy = -mOffsetY - springbackDis; - if (scroller != null) - { - scroller.forceFinished(true); - } - } - } - } - else if (mOffsetY + dy > mState.mTotalHeight - getHeight()) - { - if (!downOverScrollEnabled) // 不能向下overScroll - { - // if (getAdapter() instanceof RecyclerAdapter && ((RecyclerAdapter) getAdapter()).isAutoCalculateItemHeight() - // && !((RecyclerAdapter) getAdapter()).mAutoCalcItemHeightFinish) - // { - // // 在总长度还没计算出来时,不修改dy - // // Log.e("leo", "no mTotalHeight pass " + mState.mTotalHeight); - // } - // else - { - if (mState.mTotalHeight <= getHeight()) - { - // Log.e("leo", "mState.mTotalHeight <= getHeight() => 0, " + mState.mTotalHeight + ", " + getHeight()); - dy = 0; - } - else - { - // Log.e("leo", "dy = mState.mTotalHeight - getHeight() - mOffsetY " + - // mState.mTotalHeight + ", " + getHeight() + ", " + mOffsetY); - dy = mState.mTotalHeight - getHeight() - mOffsetY; - } - if (scroller != null) - { - // Log.e("leo", "scroller.forceFinished(true);"); - scroller.forceFinished(true); - } - } - } - else - {// 可以向下overScroll - if (DEBUG) - { - // Log.d("leo", "computedxdy overscroll!!" + "mOffsetY=" + mOffsetY + ",listTotal=" + mState.mTotalHeight); - } - // if (getAdapter() instanceof RecyclerAdapter && ((RecyclerAdapter) getAdapter()).isAutoCalculateItemHeight() - // && !((RecyclerAdapter) getAdapter()).mAutoCalcItemHeightFinish) - // { - // // 在总长度还没计算出来时,不修改dy - // // Log.e("leo", "no mTotalHeight pass " + mState.mTotalHeight); - // } - // else - { - if (mOffsetY > mState.mTotalHeight - getHeight()) - { - dy = dy < 0 ? dy : (dy / 3 == 0 || !isTouch ? dy : dy / 3); - } - int distance = 0; - if (mState.mTotalHeight <= getHeight()) - { - distance = 0; - } - else - { - distance = mState.mTotalHeight - getHeight(); - } - if (mOffsetY + dy >= distance + springbackDis && careSpringBackMaxDistance) - { - // Log.d("leo", "overscroll!!!!!!!!!!" + "mOffsetY=" + - // mOffsetY + ",listTotal=" + - // mAdapter.getListTotalHeight()); - if (DEBUG) - { - // Log.d("leo", "scroll to barrier!!mOffsetY=" + mOffsetY); - } - dy = -mOffsetY + distance + springbackDis; - if (scroller != null) - { - scroller.forceFinished(true); - } - // } - } - } - } - } - else if (mStopAtTitle && mNeedStopAtTitleIndex != -1) - { - int distance = getStopPosition(); - if (mOffsetY + dy < distance) - { - dy = distance - mOffsetY; - if (scroller != null) - { - scroller.forceFinished(true); - } - } - } - - } - result[0] = dx; - result[1] = dy; - return result; - } - - protected void onScrollToTopEdge() - { - - } - - /* private */int getStopPosition() - { - int distance = 0; - int headerCount = mAdapter.getHeaderViewCount(); - for (int i = headerCount; i > mNeedStopAtTitleIndex; i--) - { - distance += mAdapter.getHeaderViewHeight(i); - } - return distance; - } - - /* private */void resetStopAtTitle() - { - if (mNeedStopAtTitleIndex != -1) - { - if (mStopAtTitle) - { - if (mOffsetY == getStopPosition()) - { - mStopAtTitle = false; - } - } - else - { - if (mOffsetY >= getStopPosition()) - { - mStopAtTitle = (getHeight() + getStopPosition()) < mState.mTotalHeight; - } - } - } - } - - protected void onFlingToTopEdge(float velocity, int unConsumedY) - { - - } - - protected boolean checkShouldStopScroll() - { - return false; - } - - protected boolean checkShouldConsumePendingUpdates() - { - return true; - } - - protected boolean checkShouldInvalidateInScroll() - { - return true; - } - - /** - * Does not perform bounds checking. Used by internal methods that have - * already validated input. - */ - void scrollByInternal(int x, int y) - { - int overscrollX = 0, overscrollY = 0; - if (checkShouldConsumePendingUpdates()) - { - consumePendingUpdateOperations(); - } - if (checkShouldStopScroll()) - { - return; - } - if (mAdapter != null) - { - eatRequestLayout(); - if (x != 0) - { - x = computeDxDy(x, 0, false, null, true)[0]; - final int hresult = mLayout.scrollHorizontallyBy(x, mRecycler, mState); - overscrollX = x - hresult; - } - if (y != 0) - { - y = computeDxDy(0, y, false, null, true)[1]; - final int vresult = mLayout.scrollVerticallyBy(y, mRecycler, mState); - overscrollY = y - vresult; - } - - resumeRequestLayout(false); - } - - if (!mItemDecorations.isEmpty()) - { - invalidate(); - } - invalidateRefreshHeader(); - pullGlows(overscrollX, overscrollY); - if (mScrollListener != null && (x != 0 || y != 0)) - { - mScrollListener.onScrolled(x, y); - } - if (checkShouldInvalidateInScroll()) - { - invalidate(); - } - pullGlows(overscrollX, overscrollY); - if (mScrollListener != null && (x != 0 || y != 0)) - { - mScrollListener.onScrolled(x, y); - } - if (!awakenScrollBars()) - { - // invalidate(); - } - } - - protected void invalidateRefreshHeader() - { - - } - - @Override - protected int computeHorizontalScrollOffset() - { - return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollOffset(mState) : 0; - } - - @Override - protected int computeHorizontalScrollExtent() - { - return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollExtent(mState) : 0; - } - - @Override - protected int computeHorizontalScrollRange() - { - return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollRange(mState) : 0; - } - - @Override - protected int computeVerticalScrollOffset() - { - return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollOffset(mState) : 0; - } - - @Override - protected int computeVerticalScrollExtent() - { - return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollExtent(mState) : 0; - } - - @Override - protected int computeVerticalScrollRange() - { - return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollRange(mState) : 0; - } - - protected void eatRequestLayout() - { - if (!mEatRequestLayout) - { - mEatRequestLayout = true; - mLayoutRequestEaten = false; - } - } - - protected void resumeRequestLayout(boolean performLayoutChildren) - { - if (mEatRequestLayout) - { - if (performLayoutChildren && mLayoutRequestEaten && mLayout != null && mAdapter != null) - { - dispatchLayout(); - } - mEatRequestLayout = false; - mLayoutRequestEaten = false; - } - } - - /** - * Animate a scroll by the given amount of pixels along either axis. - * - * @param dx Pixels to scroll horizontally - * @param dy Pixels to scroll vertically - */ - public void smoothScrollBy(int dx, int dy) - { - smoothScrollBy(dx, dy, true); - } - - public void smoothScrollBy(int dx, int dy, boolean careSpringBackMaxDistance) - { - smoothScrollBy(dx, dy, careSpringBackMaxDistance, false); - } - - public void smoothScrollBy(int dx, int dy, boolean careSpringBackMaxDistance, boolean forceScroll) - { - if (dx != 0 || dy != 0) - { - if (!mState.mStructureChanged || forceScroll) - { - mViewFlinger.smoothScrollBy(dx, dy, careSpringBackMaxDistance); - } - } - } - - public int getOffsetY() - { - return mOffsetY; - } - - /** - * Begin a standard fling with an initial velocity along each axis in pixels - * per second. If the velocity given is below the system-defined minimum - * this method will return false and no fling will occur. - * - * @param velocityX Initial horizontal velocity in pixels per second - * @param velocityY Initial vertical velocity in pixels per second - * @return true if the fling was started, false if the velocity was too low - * to fling - */ - public boolean fling(int velocityX, int velocityY) - { - if (Math.abs(velocityX) < mMinFlingVelocity) - { - velocityX = 0; - } - if (Math.abs(velocityY) < mMinFlingVelocity) - { - velocityY = 0; - } - velocityX = Math.max(-mMaxFlingVelocity, Math.min(velocityX, mMaxFlingVelocity)); - velocityY = Math.max(-mMaxFlingVelocity, Math.min(velocityY, mMaxFlingVelocity)); - if (velocityX != 0 || velocityY != 0) - { - mViewFlinger.fling(velocityX, velocityY); - return true; - } - return false; - } - - /** - * Stop any current scroll in progress, such as one started by - * {@link #smoothScrollBy(int, int)}, {@link #fling(int, int)} or a - * touch-initiated fling. - */ - public void stopScroll() - { - mViewFlinger.stop(); - mLayout.stopSmoothScroller(); - } - - /** - * Apply a pull to relevant overscroll glow effects - */ - /* private */void pullGlows(int overscrollX, int overscrollY) - { - if (overscrollY > 0) - { - // stopScroll(); - } - } - - protected boolean shouldStopReleaseGlows(boolean canGoRefresh, boolean fromTouch) - { - return false; - } - - protected void onTouchMove(int x, int y) { - - } - - protected void releaseGlowsForHorizontal() - { - if (mOffsetX < mState.mCustomHeaderWidth || getWidth() > mState.mTotalHeight) - { - scrollToTop(null); - } - else if (mOffsetX > mState.mTotalHeight - getWidth()) - { - smoothScrollBy(mState.mTotalHeight - getWidth() - mOffsetX, 0); - } - } - - protected void releaseGlowsForVertical() - { - final int totalHeight = mState.mTotalHeight; - if (mOffsetY < mState.mCustomHeaderHeight || getHeight() > totalHeight) - { - scrollToTop(null); - } - else if (mOffsetY > totalHeight - getHeight()) - { - smoothScrollBy(0, totalHeight - getHeight() - mOffsetY); - } - else if (mOffsetY >= totalHeight - getHeight() && needNotifyFooter) - { - if (this.shouldPrebindItem() && mOffsetY + getHeight() != totalHeight) - { - return; - } - // Log.d("leo", "onrelease glows neednotify"); - needNotifyFooter = false; - checkNotifyFooterOnRelease = false; - mRecycler.notifyLastFooterAppeared(); - } - } - - protected void releaseGlows(boolean canGoRefresh, boolean fromTouch) - { - if (mState.mCustomHeaderHeight != 0 || mState.mCustomFooterHeight != 0 || mOffsetY < 0 || getHeight() > mState.mTotalHeight) - { - if (shouldStopReleaseGlows(canGoRefresh, fromTouch)) - { - return; - } - } - - if (mLayout.canScrollHorizontally()) - { - releaseGlowsForHorizontal(); - } - else - { - releaseGlowsForVertical(); - } - } - - // /*private*/ void scrollToInSpringBack(int x, int y) - // { - // scrollTo(x, y); - // } - - public int getTotalHeight() - { - return mState.mTotalHeight; - } - - void absorbGlows(int velocityX, int velocityY) - { - } - - // Focus handling - - @Override - public View focusSearch(View focused, int direction) - { - View result = mLayout.onInterceptFocusSearch(focused, direction); - if (result != null) - { - return result; - } - final FocusFinder ff = FocusFinder.getInstance(); - result = ff.findNextFocus(this, focused, direction); - if (result == null && mAdapter != null) - { - eatRequestLayout(); - result = mLayout.onFocusSearchFailed(focused, direction, mRecycler, mState); - resumeRequestLayout(false); - } - return result != null ? result : super.focusSearch(focused, direction); - } - - @Override - public void requestChildFocus(View child, View focused) - { - if (focused != null && mLayout != null && !mLayout.onRequestChildFocus(this, child, focused)) - { - mTempRect.set(0, 0, focused.getWidth(), focused.getHeight()); - offsetDescendantRectToMyCoords(focused, mTempRect); - offsetRectIntoDescendantCoords(child, mTempRect); - // @DenverHan, 这里 不能使用动画来滚屏 - // requestChildRectangleOnScreen(child, mTempRect, - // !mFirstLayoutComplete); - requestChildRectangleOnScreen(child, mTempRect, true); - } - super.requestChildFocus(child, focused); - // showFocusChild(focused); - } - - @Override - public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) - { - return mLayout.requestChildRectangleOnScreen(this, child, rect, immediate); - } - - @Override - public void addFocusables(ArrayList views, int direction, int focusableMode) - { - if (!mLayout.onAddFocusables(this, views, direction, focusableMode)) - { - super.addFocusables(views, direction, focusableMode); - } - } - - @Override - protected void onAttachedToWindow() - { - super.onAttachedToWindow(); - mIsAttached = true; - if (mLayout != null) - { - mLayout.onAttachedToWindow(this); - } - mPostedAnimatorRunner = false; - if (mAdapter != null) - { - mAdapter.onViewAttached(); - } - } - - @Override - protected void onDetachedFromWindow() - { - super.onDetachedFromWindow(); - - // TODO Mark what our target position was if relevant, then we can jump - // there - // on reattach. - mIsAttached = false; - if (mLayout != null) - { - mLayout.onDetachedFromWindow(this); - } - removeCallbacks(mItemAnimatorRunner); - if (mAdapter != null) - { - mAdapter.onViewDetached(); - } - } - - public void addOnItemTouchListener(OnItemTouchListener listener) - { - mOnItemTouchListeners.add(listener); - } - - public void addOnItemTouchListenerToFront(OnItemTouchListener listener) - { - mOnItemTouchListeners.add(0, listener); - } - - /** - * Remove an {@link OnItemTouchListener}. It will no longer be able to - * intercept touch events. - * - * @param listener Listener to remove - */ - public void removeOnItemTouchListener(OnItemTouchListener listener) - { - mOnItemTouchListeners.remove(listener); - if (mActiveOnItemTouchListener == listener) - { - mActiveOnItemTouchListener = null; - } - } - - /* private */boolean dispatchOnItemTouchIntercept(MotionEvent e) - { - final int action = e.getAction(); - if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_DOWN) - { - mActiveOnItemTouchListener = null; - } - - final int listenerCount = mOnItemTouchListeners.size(); - for (int i = 0; i < listenerCount; i++) - { - final OnItemTouchListener listener = mOnItemTouchListeners.get(i); - if (listener.onInterceptTouchEvent(this, e) && action != MotionEvent.ACTION_CANCEL) - { - mActiveOnItemTouchListener = listener; - return true; - } - } - return false; - } - - /* private */boolean dispatchOnItemTouch(MotionEvent e) - { - final int action = e.getAction(); - if (mActiveOnItemTouchListener != null) - { - if (action == MotionEvent.ACTION_DOWN) - { - // Stale state from a previous gesture, we're starting a new - // one. Clear it. - mActiveOnItemTouchListener = null; - } - else - { - mActiveOnItemTouchListener.onTouchEvent(this, e); - if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) - { - // Clean up for the next gesture. - mActiveOnItemTouchListener = null; - } - return true; - } - } - - // Listeners will have already received the ACTION_DOWN via - // dispatchOnItemTouchIntercept - // as called from onInterceptTouchEvent; skip it. - if (action != MotionEvent.ACTION_DOWN) - { - final int listenerCount = mOnItemTouchListeners.size(); - for (int i = 0; i < listenerCount; i++) - { - final OnItemTouchListener listener = mOnItemTouchListeners.get(i); - if (listener.onInterceptTouchEvent(this, e)) - { - mActiveOnItemTouchListener = listener; - return true; - } - } - } - return false; - } - - public void setDisallowParentInterceptTouchEventWhenDrag(boolean disallow) - { - this.mDisallowParentInterceptTouchEventWhenDrag = disallow; - } - - public void setBlockScroll(boolean blockScroll) - { - mBlockScroll = blockScroll; - } - - public boolean isBlockScroll() - { - return mBlockScroll; - } - - protected boolean shouldStopOnInterceptTouchEvent(MotionEvent e, int totalHeight, boolean upOverScrollEnabled) - { - return false; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent e) - { - if (mAnimatingBlockTouch) - { - return true; - } - final int totalHeight = mState.mTotalHeight; - boolean interceptDown = false; - if (shouldStopOnInterceptTouchEvent(e, totalHeight, mUpOverScrollEnabled)) - { - return true; - } - if (mScrollState != SCROLL_STATE_DRAGGING) - { - boolean res = dispatchOnItemTouchIntercept(e); - if (res && e.getAction() != MotionEvent.ACTION_DOWN) - { - cancelTouch(); - return true; - } - else if (res) - { - interceptDown = true; - } - } - - final boolean canScrollHorizontally = mLayout.canScrollHorizontally(); - final boolean canScrollVertically = mLayout.canScrollVertically(); - - if (mVelocityTracker == null) - { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(e); - - final int action = e.getActionMasked(); - final int actionIndex = e.getActionIndex(); - - switch (action) - { - case MotionEvent.ACTION_DOWN: - mScrollPointerId = e.getPointerId(0); - mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f); - mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f); - if (interceptDown) - { - return true; - } - if (mScrollState == SCROLL_STATE_SETTLING) - { - if (mDisallowParentInterceptTouchEventWhenDrag) - { - // getParent().requestDisallowInterceptTouchEvent(true); - } - setScrollState(SCROLL_STATE_DRAGGING); - resetStopAtTitle(); - } - - break; - - case MotionEvent.ACTION_POINTER_DOWN: - mScrollPointerId = e.getPointerId(actionIndex); - mInitialTouchX = mLastTouchX = (int) (e.getX(actionIndex) + 0.5f); - mInitialTouchY = mLastTouchY = (int) (e.getY(actionIndex) + 0.5f); - break; - - case MotionEvent.ACTION_MOVE: - { - final int index = e.findPointerIndex(mScrollPointerId); - if (index < 0) - { - // Log.e(TAG, - // "Error processing scroll; pointer index for id " + - // mScrollPointerId + - // " not found. Did any MotionEvents get skipped?"); - return false; - } - - if (!mBlockScroll) - { - final float x = e.getX(index); - final float y = e.getY(index); - if (mScrollState != SCROLL_STATE_DRAGGING) - { - final float dx = x - mInitialTouchX; - final float dy = y - mInitialTouchY; - boolean startScroll = false; - if (canScrollHorizontally && Math.abs(dx) > mTouchSlop && Math.abs(dx) > Math.abs(dy)) - { - // 这里加入dy>dx的判断,防止在recyclerview吃掉左右滑动事件,从而能够将左右滑动事件传递给子view - mLastTouchX = mInitialTouchX + mTouchSlop * (dx < 0 ? -1 : 1); - startScroll = true; - } - if (canScrollVertically && Math.abs(dy) > mTouchSlop && Math.abs(dy) > Math.abs(dx)) - { - // 这里加入dy>dx的判断,防止在recyclerview吃掉上下滑动事件,从而能够将上下滑动事件传递给子view - mLastTouchY = mInitialTouchY + mTouchSlop * (dy < 0 ? -1 : 1); - startScroll = true; - } - if (startScroll && onStartScroll((int) Math.abs(dy))) - { - if (mDisallowParentInterceptTouchEventWhenDrag) - { - getParent().requestDisallowInterceptTouchEvent(true); - } - setScrollState(SCROLL_STATE_DRAGGING); - } - } - } - } - break; - - case MotionEvent.ACTION_POINTER_UP: - { - onPointerUp(e); - } - break; - - case MotionEvent.ACTION_UP: - { - mVelocityTracker.clear(); - - // cancelLift(); - } - break; - - case MotionEvent.ACTION_CANCEL: - { - // cancelTouch(); - } - } - return mScrollState == SCROLL_STATE_DRAGGING; - } - - protected boolean shouldStopOnTouchEvent(MotionEvent e, int totalHeight, boolean upOverScrollEnabled) - { - return false; - } - - - @Override - public boolean onTouchEvent(MotionEvent e) - { - final boolean canScrollHorizontally = !mBlockScroll && mLayout.canScrollHorizontally(); - final boolean canScrollVertically = !mBlockScroll && mLayout.canScrollVertically(); - if (mAnimatingBlockTouch) - { - return true; - } - final int totalHeight = mState.mTotalHeight; - if (shouldStopOnTouchEvent(e, totalHeight, mUpOverScrollEnabled)) - { - return true; - } - if (mScrollState != SCROLL_STATE_DRAGGING) - { - if (dispatchOnItemTouch(e)) - { - cancelTouch(); - return true; - } - } - - if (mVelocityTracker == null) - { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(e); - - final int action = e.getActionMasked(); - final int actionIndex = e.getActionIndex(); - - switch (action) - { - case MotionEvent.ACTION_DOWN: - { - mTouchEventState = MotionEvent.ACTION_DOWN; - mScrollPointerId = e.getPointerId(0); - mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f); - mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f); - if (!isTouchStopWhenFastFling()) - { - removeCallbacks(mTouchDownWhenSettlingCheckRunnable); - postDelayed(mTouchDownWhenSettlingCheckRunnable, TOUCH_DOWN_WHEN_SETTING_CHECK_INTERVAL); - } - if (getAdapter() != null) - { - getAdapter().onSuddenStop(); - } - } - break; - - case MotionEvent.ACTION_POINTER_DOWN: - { - mScrollPointerId = e.getPointerId(actionIndex); - mInitialTouchX = mLastTouchX = (int) (e.getX(actionIndex) + 0.5f); - mInitialTouchY = mLastTouchY = (int) (e.getY(actionIndex) + 0.5f); - } - break; - - case MotionEvent.ACTION_MOVE: - { - final int index = e.findPointerIndex(mScrollPointerId); - if (index < 0) - { - return false; - } - mTouchEventState = MotionEvent.ACTION_MOVE; - mIsTouching = true; - final int x = (int) (e.getX(index) + 0.5f); - final int y = (int) (e.getY(index) + 0.5f); - if (mScrollState != SCROLL_STATE_DRAGGING) - { - final int dx = x - mInitialTouchX; - final int dy = y - mInitialTouchY; - boolean startScroll = false; - if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) - { - mLastTouchX = mInitialTouchX + mTouchSlop * (dx < 0 ? -1 : 1); - startScroll = true; - } - if (canScrollVertically && Math.abs(dy) > mTouchSlop) - { - mLastTouchY = mInitialTouchY + mTouchSlop * (dy < 0 ? -1 : 1); - startScroll = true; - } - if (startScroll) - { - if (mDisallowParentInterceptTouchEventWhenDrag) - { - if (getParent() != null) - { - getParent().requestDisallowInterceptTouchEvent(true); - } - } - setScrollState(SCROLL_STATE_DRAGGING); - } - } - if (mScrollState == SCROLL_STATE_DRAGGING) - { - final int dx = x - mLastTouchX; - final int dy = y - mLastTouchY; - scrollByInternal(canScrollHorizontally ? -dx : 0, canScrollVertically ? -dy : 0); - if (needNotifyFooter && !checkNotifyFooterOnRelease) - { - if (!this.shouldPrebindItem() || mOffsetY + getHeight() >= getTotalHeight()) - { - needNotifyFooter = false; - if (mRecycler != null) - { - mRecycler.notifyLastFooterAppeared(); - } - } - } - onTouchMove(x, y); - } - mLastTouchX = x; - mLastTouchY = y; - } - break; - - case MotionEvent.ACTION_POINTER_UP: - { - onPointerUp(e); - } - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - { - mTouchEventState = MotionEvent.ACTION_UP; - mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity); - final float xvel = canScrollHorizontally ? -mVelocityTracker.getXVelocity(mScrollPointerId) : 0; - final float yvel = canScrollVertically ? -mVelocityTracker.getYVelocity(mScrollPointerId) : 0; - if (!((xvel != 0 || yvel != 0) && fling((int) xvel, (int) yvel))) - { - resetStopAtTitle(); - setScrollState(SCROLL_STATE_IDLE); - handleOnTouchUpEventWhenStartFling(xvel, yvel); - } - if (mEnableRecyclerViewTouchListener && Math.abs(e.getX() - mInitialTouchX) < mTouchSlop - && Math.abs(e.getY() - mInitialTouchY) < mTouchSlop && action == MotionEvent.ACTION_UP) - { - notifyRecyclerViewTouchEvent(e); - } - handleCustomClickEvent(e); - mVelocityTracker.clear(); - releaseGlows(true, true); - } - break; - - } - mIsTouching = false; - return true; - } - - protected void handleOnTouchUpEventWhenStartFling(float xVel, float yVel) - { - - } - - public void cancelTouch() - { - if (mVelocityTracker != null) - { - mVelocityTracker.clear(); - } - releaseGlows(false, true); - setScrollState(SCROLL_STATE_IDLE); - - } - - public void forceCancelTouch() - { - if (mVelocityTracker != null) - { - mVelocityTracker.clear(); - } - setScrollState(SCROLL_STATE_IDLE); - } - - - /* private */void onPointerUp(MotionEvent e) - { - final int actionIndex = e.getActionIndex(); - if (e.getPointerId(actionIndex) == mScrollPointerId) - { - // Pick a new pointer to pick up the slack. - final int newIndex = actionIndex == 0 ? 1 : 0; - mScrollPointerId = e.getPointerId(newIndex); - mInitialTouchX = mLastTouchX = (int) (e.getX(newIndex) + 0.5f); - mInitialTouchY = mLastTouchY = (int) (e.getY(newIndex) + 0.5f); - } - } - - @Override - protected void onMeasure(int widthSpec, int heightSpec) - { - if (mAdapterUpdateDuringMeasure) - { - eatRequestLayout(); - updateChildViews(); - mAdapterUpdateDuringMeasure = false; - resumeRequestLayout(false); - } - - if (mAdapter != null) - { - mState.mItemCount = mAdapter.getItemCount(); - mState.mHeaderCount = mAdapter.getHeaderViewCount(); - mState.mFooterCount = mAdapter.getFooterViewCount(); - } - - // if (mWaterMarkCustomView != null) - // { - // mWaterMarkCustomView.measure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthSpec), MeasureSpec.EXACTLY), - // MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightSpec), MeasureSpec.EXACTLY)); - // // if (mNeedWaterMark && (mForceWaterMark || getChildCount() <= 0)) { - // // addView(mWaterMarkCustomView); - // // } - // } - mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec); - - // getMeasuredWidth(); - // getMeasuredHeight(); - } - - /** - * Post a runnable to the next frame to run pending item animations. - * Only - * the first such request will be posted, governed by the - * mPostedAnimatorRunner flag. - */ - protected void postAnimationRunner() - { - if (!mPostedAnimatorRunner && mIsAttached) - { - ViewCompatTool.postOnAnimation(this, mItemAnimatorRunner); - mPostedAnimatorRunner = true; - } - } - - protected boolean predictiveItemAnimationsEnabled() - { - return (false && mLayout.supportsPredictiveItemAnimations()); - } - - protected boolean isAnimateChangeSimple(boolean needReCheck, boolean animateChangeSimple) - { - if (!needReCheck) - { - return false && mItemsAddedOrRemoved && !mItemsChanged; - } - else - { - return (animateChangeSimple && false); - } - } - - protected void dispatchLayout() - { - if (mAdapter == null) - { - // Log.e(TAG, "No adapter attached; skipping layout"); - return; - } - // Log.e(TAG, "dispatchLayout"); - eatRequestLayout(); - // simple animations are a subset of advanced animations (which will - // cause a - // prelayout step) - if (mItemsAddedOrRemoved || mItemsChanged || mState.mStructureChanged) - { - mAdapter.dataChanged(); - } - boolean animateChangesSimple = isAnimateChangeSimple(false, false); - final boolean animateChangesAdvanced = ENABLE_PREDICTIVE_ANIMATIONS && animateChangesSimple && predictiveItemAnimationsEnabled(); - mItemsAddedOrRemoved = mItemsChanged = false; - ArrayMap appearingViewInitialBounds = null; - mState.mCustomHeaderHeight = mAdapter.getCustomHeaderViewHeight(); - mState.mCustomFooterHeight = mAdapter.getCustomFooterViewHeight(); - mState.mCustomHeaderWidth = mAdapter.getCustomHeaderViewWidth(); - mState.mCustomFooterWidth = mAdapter.getCustomFooterViewWidth(); - mState.mInPreLayout = animateChangesAdvanced; - mState.mItemCount = mAdapter.getItemCount(); - // Log.e("leo", "dispatchLayout " + mState.mTotalHeight); - mState.mTotalHeight = mAdapter.getListTotalHeight(); - // Log.d("leo", "stateItem count=" + mState.mItemCount); - mState.mHeaderCount = mAdapter.getHeaderViewCount(); - mState.mFooterCount = mAdapter.getFooterViewCount(); - if (animateChangesSimple) - { - // Step 0: Find out where all non-removed items are, pre-layout - mState.mPreLayoutHolderMap.clear(); - mState.mPostLayoutHolderMap.clear(); - int count = getChildCountInItem(); - for (int i = 0; i < count; ++i) - { - final ViewHolder holder = getChildViewHolderInt(getChildAtInItem(i)); - final View view = holder.itemView; - mState.mPreLayoutHolderMap.put(holder, - new ItemHolderInfo(holder, view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), holder.mPosition)); - } - } - // Log.d("leo", "preholder-------------"); - if (animateChangesAdvanced) - { - - // Step 1: run prelayout: This will use the old positions of items. - // The layout manager - // is expected to layout everything, even removed items (though not - // to add removed - // items back to the container). This gives the pre-layout position - // of APPEARING views - // which come into existence as part of the real layout. - mInPreLayout = true; - final boolean didStructureChange = mState.mStructureChanged; - mState.mStructureChanged = false; - // temporarily disable flag because we are asking for previous - // layout - mLayout.onLayoutChildren(mRecycler, mState); - mState.mStructureChanged = didStructureChange; - mInPreLayout = false; - - appearingViewInitialBounds = new ArrayMap(); - for (int i = 0; i < getChildCountInItem(); ++i) - { - boolean found = false; - View child = getChildAt(i); - for (int j = 0; j < mState.mPreLayoutHolderMap.size(); ++j) - { - ViewHolder holder = mState.mPreLayoutHolderMap.keyAt(j); - if (holder.itemView == child) - { - found = true; - continue; - } - } - if (!found) - { - appearingViewInitialBounds.put(child, new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom())); - } - } - } - clearOldPositions(); - dispatchLayoutUpdates(); - mState.mItemCount = mAdapter.getItemCount(); - - // Step 2: Run layout - mState.mHeaderCountInScreen = 0; - mState.mFooterCountInScreen = 0; - mState.mInPreLayout = false; - mLayout.onLayoutChildren(mRecycler, mState); - - mState.mStructureChanged = false; - mPendingSavedState = null; - - // onLayoutChildren may have caused client code to disable item - // animations; re-check - animateChangesSimple = isAnimateChangeSimple(true, animateChangesSimple); - - if (animateChangesSimple) - { - // Step 3: Find out where things are now, post-layout - int count = getChildCountInItem(); - for (int i = 0; i < count; ++i) - { - ViewHolder holder = getChildViewHolderInt(getChildAtInItem(i)); - final View view = holder.itemView; - mState.mPostLayoutHolderMap.put(holder, - new ItemHolderInfo(holder, view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), holder.mPosition)); - } - // Step 4: Animate DISAPPEARING and REMOVED items - int preLayoutCount = mState.mPreLayoutHolderMap.size(); - for (int i = preLayoutCount - 1; i >= 0; i--) - { - ViewHolder itemHolder = mState.mPreLayoutHolderMap.keyAt(i); - if (!mState.mPostLayoutHolderMap.containsKey(itemHolder)) - { - ItemHolderInfo disappearingItem = mState.mPreLayoutHolderMap.valueAt(i); - mState.mPreLayoutHolderMap.removeAt(i); - - View disappearingItemView = disappearingItem.holder.itemView; - removeDetachedView(disappearingItemView, false); - mRecycler.unscrapView(disappearingItem.holder); - - animateDisappearance(disappearingItem); - } - } - // Step 5: Animate APPEARING and ADDED items - int postLayoutCount = mState.mPostLayoutHolderMap.size(); - if (postLayoutCount > 0) - { - for (int i = postLayoutCount - 1; i >= 0; i--) - { - ViewHolder itemHolder = mState.mPostLayoutHolderMap.keyAt(i); - ItemHolderInfo info = mState.mPostLayoutHolderMap.valueAt(i); - if ((mState.mPreLayoutHolderMap.isEmpty() || !mState.mPreLayoutHolderMap.containsKey(itemHolder))) - { - mState.mPostLayoutHolderMap.removeAt(i); - Rect initialBounds = (appearingViewInitialBounds != null) ? appearingViewInitialBounds.get(itemHolder.itemView) : null; - animateAppearance(itemHolder, initialBounds, info.left, info.top); - } - } - } - // Step 6: Animate PERSISTENT items - count = mState.mPostLayoutHolderMap.size(); - for (int i = 0; i < count; ++i) - { - ViewHolder postHolder = mState.mPostLayoutHolderMap.keyAt(i); - ItemHolderInfo postInfo = mState.mPostLayoutHolderMap.valueAt(i); - ItemHolderInfo preInfo = mState.mPreLayoutHolderMap.get(postHolder); - handleLayoutHolder(postHolder, preInfo, postInfo); - } - } - resumeRequestLayout(false); - handleDispatchLayoutEnd(); - mLayout.removeAndRecycleScrapInt(mRecycler, !animateChangesAdvanced, true); - mState.mPreviousLayoutItemCount = mState.mItemCount; - mState.mDeletedInvisibleItemCountSincePreviousLayout = 0; - if (!mPostedAnimatorRunner) - { - // Log.d("leo", "dispatchLayout-->!mPostedAnimatorRunner"); - setRecyclerViewTouchEnabled(true); - } - // mCount = mAdapter.getItemCount() + mAdapter.getHeaderViewCount() + - // mAdapter.getFooterViewCount(); - //niuniuyang: 对于itemchanged,选中的item移动到屏幕外时,此时执行删除操作,item是不会做动画的。 - //也就无法通过onAnimationsFinished退出编辑态,这里需要加一个事件,通知出去,退出编辑态 - if (animateChangesSimple && !mPostedAnimatorRunner) - { - handleRangeItemsChangedWithNoAnimation(); - } - } - - /** - * 局部的item变化,在没有动画的情况,需要通知变化结束的事件 - */ - protected void handleRangeItemsChangedWithNoAnimation() - { - - - } - - protected void handleLayoutHolder(ViewHolder postHolder, ItemHolderInfo preInfo, ItemHolderInfo postInfo) - { - if (preInfo != null && postInfo != null) - { - if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) - { - postHolder.setIsRecyclable(false); - if (DEBUG) - { - // Log.d(TAG, "PERSISTENT: " + postHolder + " with view " + postHolder.itemView); - } - } - } - } - - protected void handleDispatchLayoutEnd() - { - - } - - protected int getViewIndex(View view) - { - int count = getChildCount(); - for (int i = 0; i < count; i++) - { - if (getChildAt(i) == view) - { - return i; - } - } - return -1; - } - - protected void animateAppearance(ViewHolder itemHolder, Rect beforeBounds, int afterLeft, int afterTop) - { - View newItemView = itemHolder.itemView; - - if (beforeBounds != null && (beforeBounds.left != afterLeft || beforeBounds.top != afterTop)) - { - // slide items in if before/after locations differ - itemHolder.setIsRecyclable(false); - if (DEBUG) - { - // Log.d(TAG, "APPEARING: " + itemHolder + " with view " + newItemView); - } - } - else - { - if (DEBUG) - { - // Log.d(TAG, "ADDED: " + itemHolder + " with view " + newItemView); - } - itemHolder.setIsRecyclable(false); - } - } - - protected void animateDisappearance(ItemHolderInfo disappearingItem) - { - View disappearingItemView = disappearingItem.holder.itemView; - addAnimatingView(disappearingItemView); - int oldLeft = disappearingItem.left; - int oldTop = disappearingItem.top; - int newLeft = disappearingItemView.getLeft(); - int newTop = disappearingItemView.getTop(); - if (oldLeft != newLeft || oldTop != newTop) - { - disappearingItem.holder.setIsRecyclable(false); - disappearingItemView.layout(newLeft, newTop, newLeft + disappearingItemView.getWidth(), newTop + disappearingItemView.getHeight()); - if (DEBUG) - { - // Log.d(TAG, "DISAPPEARING: " + disappearingItem.holder + " with view " + disappearingItemView); - } - } - else - { - if (DEBUG) - { - // Log.d(TAG, "REMOVED: " + disappearingItem.holder + " with view " + disappearingItemView); - } - disappearingItem.holder.setIsRecyclable(false); - } - } - - protected void handleOnLayoutChange() - { - - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) - { - if (changed) - { - if (mAdapter != null) - { - mAdapter.dataChanged(); - } - handleOnLayoutChange(); - } - eatRequestLayout(); - dispatchLayout(); - resumeRequestLayout(false); - if (changed) - { - if (mIsChangingMode) - { - mIsChangingMode = false; - mRecycler.recycleCachedViews(); - } - } - mStopAtTitle = false; - } - - @Override - public void requestLayout() - { - if (!mEatRequestLayout) - { - super.requestLayout(); - } - else - { - mLayoutRequestEaten = true; - } - } - - void markItemDecorInsetsDirty() - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - final View child = getChildAt(i); - ((LayoutParams) child.getLayoutParams()).mInsetsDirty = true; - } - } - - @Override - public void draw(Canvas c) - { - super.draw(c); - - final int count = mItemDecorations.size(); - for (int i = 0; i < count; i++) - { - mItemDecorations.get(i).onDrawOver(c, this); - } - } - - @Override - public void onDraw(Canvas c) - { - try - { - super.onDraw(c); - - final int count = mItemDecorations.size(); - for (int i = 0; i < count; i++) - { - mItemDecorations.get(i).onDraw(c, this); - } - } - catch (IllegalArgumentException e) - { - } - catch (RuntimeException e) - { - } - } - - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) - { - return p instanceof LayoutParams && mLayout.checkLayoutParams((LayoutParams) p); - } - - @Override - protected ViewGroup.LayoutParams generateDefaultLayoutParams() - { - if (mLayout == null) - { - throw new IllegalStateException("RecyclerView has no LayoutManager"); - } - return mLayout.generateDefaultLayoutParams(); - } - - @Override - public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) - { - if (mLayout == null) - { - throw new IllegalStateException("RecyclerView has no LayoutManager"); - } - return mLayout.generateLayoutParams(getContext(), attrs); - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) - { - if (mLayout == null) - { - throw new IllegalStateException("RecyclerView has no LayoutManager"); - } - return mLayout.generateLayoutParams(p); - } - - /* private */int findPositionOffset(int position) - { - int offset = 0; - int count = mPendingLayoutUpdates.size(); - for (int i = 0; i < count; ++i) - { - UpdateOp op = mPendingLayoutUpdates.get(i); - if (op.positionStart <= position) - { - if (op.cmd == UpdateOp.REMOVE) - { - offset -= op.itemCount; - } - else if (op.cmd == UpdateOp.ADD) - { - offset += op.itemCount; - } - } - } - return position + offset; - } - - void dispatchLayoutUpdates() - { - final int opCount = mPendingLayoutUpdates.size(); - for (int i = 0; i < opCount; i++) - { - final UpdateOp op = mPendingLayoutUpdates.get(i); - switch (op.cmd) - { - case UpdateOp.ADD: - mLayout.onItemsAdded(this, op.positionStart, op.itemCount); - break; - case UpdateOp.REMOVE: - mLayout.onItemsRemoved(this, op.positionStart, op.itemCount); - break; - case UpdateOp.UPDATE: - break; - } - recycleUpdateOp(op); - } - mPendingLayoutUpdates.clear(); - } - - public void setChildrenEnabled(int start, int end, boolean enabled) - { - final int count = getChildCount(); - for (int i = 0; i < count; i++) - { - getChildAt(i).setEnabled(enabled); - } - } - - void updateChildViews() - { - final int opCount = mPendingUpdates.size(); - for (int i = 0; i < opCount; i++) - { - final UpdateOp op = mPendingUpdates.get(i); - switch (op.cmd) - { - case UpdateOp.ADD: - if (DEBUG) - { - // Log.d(TAG, "UpdateOp.ADD start=" + op.positionStart + " count=" + op.itemCount); - } - offsetPositionRecordsForInsert(op.positionStart, op.itemCount); - mItemsAddedOrRemoved = true; - break; - case UpdateOp.REMOVE: - if (DEBUG) - { - // Log.d(TAG, "UpdateOp.REMOVE start=" + op.positionStart + " count=" + op.itemCount); - } - if (op.mRemovePositions != null) - { - for (Integer position : op.mRemovePositions) - { - disableHolderRecyclable(position); - offsetPositionRecordsForRemove(position, 1, false); - } - requestLayout(); - } - else - { - for (int j = 0; j < op.itemCount; ++j) - { - disableHolderRecyclable(op.positionStart + j); - } - offsetPositionRecordsForRemove(op.positionStart, op.itemCount, true); - } - mItemsAddedOrRemoved = true; - break; - case UpdateOp.UPDATE: - if (DEBUG) - { - // Log.d(TAG, "UpdateOp.UPDATE start=" + op.positionStart + " count=" + op.itemCount); - } - - viewRangeUpdate(op.positionStart, op.itemCount); - break; - - } - mPendingLayoutUpdates.add(op); - // TODO: recycle the op if no animator (also don't bother stashing - // in pending layout updates?) - } - mPendingUpdates.clear(); - } - - private void disableHolderRecyclable(int position) - { - ViewHolder holder = findViewHolderForPosition(position, true); - if (holder != null) - { - holder.setIsRecyclable(false); - } - else - { - mState.mDeletedInvisibleItemCountSincePreviousLayout++; - } - } - - void clearOldPositions() - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - final ViewHolder holder = getChildViewHolderInt(getChildAt(i)); - if (holder != null) - { - holder.clearOldPosition(); - } - } - mRecycler.clearOldPositions(); - } - - void offsetPositionRecordsForInsert(int positionStart, int itemCount) - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - final ViewHolder holder = getChildViewHolderInt(getChildAt(i)); - if (holder != null && holder.mPosition >= positionStart) - { - if (DEBUG) - { - // Log.d(TAG, "offsetPositionRecordsForInsert attached child " + i + " holder " + holder + " now at position " - // + (holder.mPosition + itemCount)); - } - holder.offsetPosition(itemCount); - mState.mStructureChanged = true; - // holder.itemView.setEnabled(false); - } - } - mRecycler.offsetPositionRecordsForInsert(positionStart, itemCount); - requestLayout(); - } - - protected void offsetPositionRecordsForRemove(int positionStart, int itemCount, boolean layoutRightNow) - { - final int positionEnd = positionStart + itemCount; - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - final ViewHolder holder = getChildViewHolderInt(getChildAt(i)); - if (holder != null) - { - if (holder.mPosition >= positionEnd) - { - if (DEBUG) - { - // Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i + " holder " + holder + " now at position " - // + (holder.mPosition - itemCount)); - } - holder.offsetPosition(-itemCount); - mState.mStructureChanged = true; - // holder.itemView.setEnabled(false); - } - else if (holder.mPosition >= positionStart) - { - if (DEBUG) - { - // Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i + " holder " + holder + " now REMOVED"); - } - holder.addFlags(ViewHolder.FLAG_REMOVED); - mState.mStructureChanged = true; - } - - } - } - mRecycler.offsetPositionRecordsForRemove(positionStart, itemCount); - if (layoutRightNow) - { - requestLayout(); - } - } - - protected boolean canChangeOrder(int pos) - { - ViewHolder vh = findViewHolderForPosition(pos, true); - if (vh != null) - { - // QBViewHolder qbvh = (QBViewHolder) vh; - // return qbvh.canChangeOrder(); - return vh.canChangeOrder(); - } - return false; - } - - /** - * Rebind existing views for the given range, or create as needed. - * - * @param positionStart Adapter position to start at - * @param itemCount Number of views that must explicitly be rebound - */ - protected void viewRangeUpdate(int positionStart, int itemCount) - { - final int childCount = getChildCount(); - final int positionEnd = positionStart + itemCount; - - for (int i = 0; i < childCount; i++) - { - final ViewHolder holder = getChildViewHolderInt(getChildAt(i)); - if (holder == null) - { - continue; - } - int position = holder.mPosition; - if (position >= positionStart && position < positionEnd) - { - handleViewRangeUpdate(holder, positionStart, positionEnd, position, itemCount); - // holder.itemView.setEnabled(false); - } - } - mRecycler.viewRangeUpdate(positionStart, itemCount); - } - - protected void handleViewRangeUpdate(ViewHolder holder, int positionStart, int positionEnd, int position, int itemCount) - { - // Binding an attached view will request a layout if needed. - mAdapter.bindViewHolder(holder, holder.getPosition(), true, mLayoutType, mAdapter.getCardItemViewType(holder.getPosition())); - mItemsChanged = true; - } - - /** - * Mark all known views as invalid. Used in response to a, - * "the whole world might have changed" data change event. - */ - protected void markKnownViewsInvalid() - { - final int childCount = getChildCountInItem(); - - for (int i = 0; i < childCount; i++) - { - final ViewHolder holder = getChildViewHolderInt(getChildAtInItem(i)); - if (holder != null) - { - holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID); - } - } - mRecycler.markKnownViewsInvalid(); - } - - /** - * Schedule an updateStyle of data from the adapter to occur on the next - * frame. - * On newer platform versions this happens via the postOnAnimation mechanism - * and RecyclerView attempts to avoid relayouts if possible. On older - * platform versions the RecyclerView requests a layout the same way - * ListView does. - */ - public void postAdapterUpdate(UpdateOp op) - { - mPendingUpdates.add(op); - if (mPendingUpdates.size() == 1) - { - setRecyclerViewTouchEnabled(false); - if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) - { - ViewCompatTool.postOnAnimation(this, mUpdateChildViewsRunnable); - } - else - { - mAdapterUpdateDuringMeasure = true; - requestLayout(); - } - } - } - - /** - * Retrieve the {@link ViewHolder} for the given child view. - * - * @param child Child of this RecyclerView to query for its ViewHolder - * @return The child view's ViewHolder - */ - public ViewHolder getChildViewHolder(View child) - { - final ViewParent parent = child.getParent(); - if (parent != null && parent != this) - { - throw new IllegalArgumentException("View " + child + " is not a direct child of " + this); - } - return getChildViewHolderInt(child); - } - - protected static ViewHolder getChildViewHolderInt(View child) - { - if (child == null) - { - return null; - } - return ((LayoutParams) child.getLayoutParams()).mViewHolder; - } - - /** - * Return the adapter position that the given child view corresponds to. - * - * @param child Child View to query - * @return Adapter position corresponding to the given view or - * {@link #NO_POSITION} - */ - public int getChildPosition(View child) - { - final ViewHolder holder = getChildViewHolderInt(child); - return holder != null ? holder.getPosition() : NO_POSITION; - } - - /** - * Return the stable item id that the given child view corresponds to. - * - * @param child Child View to query - * @return Item id corresponding to the given view or {@link #NO_ID} - */ - public long getChildItemId(View child) - { - if (mAdapter == null || !mAdapter.hasStableIds()) - { - return NO_ID; - } - final ViewHolder holder = getChildViewHolderInt(child); - return holder != null ? holder.getItemId() : NO_ID; - } - - /** - * Return the ViewHolder for the item in the given position of the data set. - * - * @param position The position of the item in the data set of the adapter - * @return The ViewHolder at position - */ - public ViewHolder findViewHolderForPosition(int position) - { - return findViewHolderForPosition(position, false); - } - - ViewHolder findViewHolderForPosition(int position, boolean checkNewPosition) - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - final ViewHolder holder = getChildViewHolderInt(getChildAt(i)); - if (holder != null) - { - if (checkNewPosition) - { - if (holder.mPosition == position) - { - return holder; - } - } - else if (holder.getPosition() == position) - { - return holder; - } - } - } - return mRecycler.findViewHolderForPosition(position); - } - - /** - * Return the ViewHolder for the item with the given id. The RecyclerView - * must use an Adapter with {@link Adapter#setHasStableIds(boolean) - * stableIds} to return a non-null value. - * - * @param id The id for the requested item - * @return The ViewHolder with the given id, of null if there - * is no such item. - */ - public ViewHolder findViewHolderForItemId(long id) - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - final ViewHolder holder = getChildViewHolderInt(getChildAt(i)); - if (holder != null && holder.getItemId() == id) - { - return holder; - } - } - return mRecycler.findViewHolderForItemId(id); - } - - /** - * Find the topmost view under the given point. - * - * @param x Horizontal position in pixels to search - * @param y Vertical position in pixels to search - * @return The child view under (x, y) or null if no matching child is found - */ - public View findChildViewUnder(float x, float y) - { - final int count = getChildCount(); - for (int i = count - 1; i >= 0; i--) - { - final View child = getChildAt(i); - final float translationX = child.getTranslationX(); - final float translationY = child.getTranslationY(); - if (x >= child.getLeft() + translationX && x <= child.getRight() + translationX && y >= child.getTop() + translationY - && y <= child.getBottom() + translationY) - { - return child; - } - } - return null; - } - - /** - * Offset the bounds of all child views by dy pixels. Useful - * for implementing simple scrolling in {@link LayoutManager LayoutManagers} - * . - * - * @param dy Vertical pixel offset to apply to the bounds of all child - * views - */ - public void offsetChildrenVertical(int dy) - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - getChildAt(i).offsetTopAndBottom(dy); - } - } - - /** - * Called when an item view is attached to this RecyclerView. - *

- *

- * Subclasses of RecyclerView may want to perform extra bookkeeping or - * modifications of child views as they become attached. This will be called - * before a {@link LayoutManager} measures or lays out the view and is a - * good time to perform these changes. - *

- * - * @param child Child view that is now attached to this RecyclerView and its - * associated window - */ - public void onChildAttachedToWindow(View child) - { - } - - /** - * Called when an item view is detached from this RecyclerView. - *

- *

- * Subclasses of RecyclerView may want to perform extra bookkeeping or - * modifications of child views as they become detached. This will be called - * as a {@link LayoutManager} fully detaches the child view from the parent - * and its window. - *

- * - * @param child Child view that is now detached from this RecyclerView and - * its - * associated window - */ - public void onChildDetachedFromWindow(View child) - { - } - - /** - * Offset the bounds of all child views by dx pixels. Useful - * for implementing simple scrolling in {@link LayoutManager LayoutManagers} - * . - * - * @param dx Horizontal pixel offset to apply to the bounds of all child - * views - */ - public void offsetChildrenHorizontal(int dx) - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - getChildAt(i).offsetLeftAndRight(dx); - } - } - - public Rect getItemDecorInsetsForChild(View child) - { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (!lp.mInsetsDirty) - { - return lp.mDecorInsets; - } - - final Rect insets = lp.mDecorInsets; - insets.set(0, 0, 0, 0); - final int decorCount = mItemDecorations.size(); - for (int i = 0; i < decorCount; i++) - { - mTempRect.set(0, 0, 0, 0); - mItemDecorations.get(i).getItemOffsets(mTempRect, lp.getViewPosition(), this); - insets.left += mTempRect.left; - insets.top += mTempRect.top; - insets.right += mTempRect.right; - insets.bottom += mTempRect.bottom; - } - lp.mInsetsDirty = false; - return insets; - } - - - public class ViewFlinger implements Runnable - { - /* private */int mLastFlingX; - /* private */int mLastFlingY; - /* private */Scroller mScroller; - /* private */Interpolator mInterpolator = sQuinticInterpolator; - /* private */boolean mCareSpringBackMaxDistance = false; - - // When set to true, postOnAnimation callbacks are delayed until the run - // method completes - /* private */boolean mEatRunOnAnimationRequest = false; - - // Tracks if postAnimationCallback should be re-attached when it is done - /* private */boolean mReSchedulePostAnimationCallback = false; - - public ViewFlinger() - { - mScroller = new Scroller(getContext()); - } - - public OnScrollFinishListener mScrollFinishListener; - public int mTargetPosition = Integer.MAX_VALUE; - - public Scroller getScroller() - { - return mScroller; - } - - @Override - public void run() - { - // disableRunOnAnimationRequests(); - consumePendingUpdateOperations(); - // keep a local reference so that if it is changed during - // onAnimation method, it wont cause - // unexpected behaviors - final Scroller scroller = mScroller; - final SmoothScroller smoothScroller = mLayout.mSmoothScroller; - //Log.e("leo", "run"); - if (scroller.computeScrollOffset()) - { - final int x = scroller.getCurrX(); - final int y = scroller.getCurrY(); - int dx = x - mLastFlingX; - int dy = y - mLastFlingY; - mLastFlingX = x; - mLastFlingY = y; - if (DEBUG) - { - // Log.d("leo", "fling runnable is running,dy=" + dy + ",currVelocity=" + scroller.getCurrVelocity()); - } - int overscrollX = 0, overscrollY = 0; - if (mAdapter != null) - { - eatRequestLayout(); - if (dx != 0) - { - dx = computeDxDy(dx, 0, mCareSpringBackMaxDistance, scroller, false)[0]; - final int hresult = mLayout.scrollHorizontallyBy(dx, mRecycler, mState); - overscrollX = dx - hresult; - } - if (dy != 0) - { - dy = computeDxDy(0, dy, mCareSpringBackMaxDistance, scroller, false)[1]; - // Log.d("leo", "scrollby caused by fling"); - final int vresult = mLayout.scrollVerticallyBy(dy, mRecycler, mState); - overscrollY = dy - vresult; - } - - if (smoothScroller != null && !smoothScroller.isPendingInitialRun() && smoothScroller.isRunning()) - { - smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY); - } - resumeRequestLayout(false); - } - if (!mItemDecorations.isEmpty()) - { - invalidate(); - } - checkRefreshHeadOnFlingRun(); - - if (mScrollListener != null && (x != 0 || y != 0)) - { - mScrollListener.onScrolled(dx, dy); - } - invalidate(); - - } - // call this after the onAnimation is complete not to have - // inconsistent callbacks etc. - if (smoothScroller != null && smoothScroller.isPendingInitialRun()) - { - smoothScroller.onAnimation(0, 0); - } - // enableRunOnAnimationRequests(); - //Log.e("leo", "before scroller.isFinished()"); - if (scroller.isFinished()) - { - //Log.e("leo", "scroller.isFinished()"); - reportFinishState(); - handleRefreshHeadOnFlingRunEnd(); - setScrollState(SCROLL_STATE_IDLE); - releaseGlows(!mScroller.isFling(), false); - resetStopAtTitle(); - // if (needNotifyFooter) - // { - // needNotifyFooter = false; - // mRecycler.notifyLastFooterAppeared(); - // } - } - else - { - postOnAnimation(); - } - } - - /* private */void disableRunOnAnimationRequests() - { - mReSchedulePostAnimationCallback = false; - mEatRunOnAnimationRequest = true; - // Log.d("leo", "disableRunOnAnimationRequests: eat animation request = true"); - } - - /* private */void enableRunOnAnimationRequests() - { - mEatRunOnAnimationRequest = false; - if (mReSchedulePostAnimationCallback) - { - postOnAnimation(); - } - } - - public void postOnAnimation() - { - if (mEatRunOnAnimationRequest) - { - // Log.d("leo", "postOnAnimation: eat animation request"); - mReSchedulePostAnimationCallback = true; - } - else - { - ViewCompatTool.postOnAnimation(RecyclerViewBase.this, this); - } - } - - public void fling(int velocityX, int velocityY) - { - mCareSpringBackMaxDistance = true; - setScrollState(SCROLL_STATE_SETTLING); - mLastFlingX = mLastFlingY = 0; - mScroller.fling(0, 0, velocityX, velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE); - postOnAnimation(); - } - - public void smoothScrollBy(int dx, int dy, boolean careSpringBackMaxDistance) - { - smoothScrollBy(dx, dy, 0, 0, careSpringBackMaxDistance); - } - - public void smoothScrollBy(int dx, int dy, int vx, int vy, boolean careSpringBackMaxDistance) - { - smoothScrollBy(dx, dy, computeScrollDuration(dx, dy, vx, vy), careSpringBackMaxDistance); - } - - /* private */float distanceInfluenceForSnapDuration(float f) - { - f -= 0.5f; // center the values about 0. - f *= 0.3f * Math.PI / 2.0f; - return (float) Math.sin(f); - } - - /* private */int computeScrollDuration(int dx, int dy, int vx, int vy) - { - final int absDx = Math.abs(dx); - final int absDy = Math.abs(dy); - final boolean horizontal = absDx > absDy; - final int velocity = (int) Math.sqrt(vx * vx + vy * vy); - final int delta = (int) Math.sqrt(dx * dx + dy * dy); - final int containerSize = horizontal ? getWidth() : getHeight(); - final int halfContainerSize = containerSize / 2; - float distanceRatio = 1.f; - if (containerSize != 0) - { - distanceRatio = Math.min(1.f, 1.f * delta / containerSize); - } - final float distance = halfContainerSize + halfContainerSize * distanceInfluenceForSnapDuration(distanceRatio); - - int duration; - if (velocity > 0) - { - duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); - } - else - { - float absDelta = (float) (horizontal ? absDx : absDy); - duration = 300; - if (containerSize != 0) - { - duration = (int) (((absDelta / containerSize) + 1) * 300); - } - } - return Math.min(duration, MAX_SCROLL_DURATION); - } - - public void smoothScrollBy(int dx, int dy, int duration, boolean careSpringBackMaxDistance) - { - smoothScrollBy(dx, dy, duration, sQuinticInterpolator, careSpringBackMaxDistance); - } - - public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator, boolean careSpringBackMaxDistance) - { - if (mInterpolator != interpolator) - { - mInterpolator = interpolator; - mScroller = new Scroller(getContext()); - } - mCareSpringBackMaxDistance = careSpringBackMaxDistance; - setScrollState(SCROLL_STATE_SETTLING); - mLastFlingX = mLastFlingY = 0; - mScroller.startScroll(0, 0, dx, dy, duration); - postOnAnimation(); - } - - private void reportFinishState() - { - // Log.d(TAG, "reportFinishState:mTargetPosition=" + mTargetPosition + ",y=" + mScroller.getCurrY()); - if (mScrollFinishListener != null) - { - //Log.e("leo", "reportFinishState:mTargetPosition=" + mTargetPosition + ",y=" + mScroller.getCurrY()); - if (checkShouldCallScrollFinish(mScroller, mTargetPosition)) - { - //Log.e("leo", "onScrollFinished"); - mScrollFinishListener.onScrollFinished(); - } - mScrollFinishListener = null; - mTargetPosition = Integer.MAX_VALUE; - } - } - - public void stop() - { - mScroller.abortAnimation(); // 放到最前面来执行 - reportFinishState(); - removeCallbacks(this); - - } - - } - - protected void checkRefreshHeadOnFlingRun() - { - - } - - protected void handleRefreshHeadOnFlingRunEnd() - { - - } - - protected boolean checkShouldCallScrollFinish(Scroller scroller, int targetPosition) - { - return scroller.getCurrY() == targetPosition; - } - - public View getChildAtInItem(int index) - { - if (index < getChildCount()) - { - return super.getChildAt(index + mState.mHeaderCountInScreen); - } - return null; - } - - public int getChildCountInItem() - { - return super.getChildCount() - mState.mHeaderCountInScreen - mState.mFooterCountInScreen; - } - - - /* private */class RecyclerViewDataObserver extends AdapterDataObserver - { - @Override - public void onChanged() - { - - markKnownViewsInvalid(); - removeAnimatingViews(); - mState.mDataChanged = true; - mState.mStructureChanged = true; - View first = mLayout.getChildClosestToStartByOrder(); - if (first != null) - { - int pendingPosition = mLayout.getPendingPosition(); - int pendingOffset = mLayout.getPendingOffset(); - // Log.d(TAG, "pendingPosition=" + pendingPosition); - if (pendingPosition == NO_POSITION) - { - pendingPosition = mLayout.getPosition(first); - // Log.d(TAG, "first position=" + pendingPosition); - if (pendingOffset == BaseLayoutManager.INVALID_OFFSET) - { - pendingOffset = mLayout.getDecoratedStart(first); - pendingOffset = mLayout.canScrollHorizontally() ? - pendingOffset + mState.mCustomHeaderWidth : pendingOffset + mState.mCustomHeaderHeight; - } - } - pendingPosition = validateAnchorItemPosition(pendingPosition); - // Log.d(TAG, "first position=" + pendingPosition); - scrollToPositionWithOffset(pendingPosition, pendingOffset); - } - else - { - requestLayout(); - } - - } - - @Override - public void onItemRangeChanged(int positionStart, int itemCount) - { - postAdapterUpdate(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount)); - } - - // @Override - // public void onItemRangeChanged(int positionStart, int itemCount, Object payload) - // { - // // 暂时不处理payload,视为全量更新 - // postAdapterUpdate(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount)); - // } - - @Override - public void onItemRangeInserted(int positionStart, int itemCount) - { - postAdapterUpdate(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount)); - } - - @Override - public void onItemRangeRemoved(int positionStart, int itemCount) - { - postAdapterUpdate(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount)); - } - - @Override - public void onItemsRemoved(ArrayList removeItemPositions) - { - UpdateOp op = obtainUpdateOp(UpdateOp.REMOVE, -1, -1); - op.mRemovePositions = removeItemPositions; - postAdapterUpdate(op); - } - } - - public static class ViewHolderArrayList extends ArrayList - { - @Override - public String toString() - { - return Arrays.toString(this.toArray()); - } - } - - public static class RecycledViewPool - { - public SparseArray mScrap = new SparseArray(); - protected SparseIntArray mMaxScrap = new SparseIntArray(); - /* private */int mAttachCount = 0; - - /* private */public int DEFAULT_MAX_SCRAP = 10; - - public void clear() - { - mScrap.clear(); - } - - /** - * use @setMaxRecycledViews instead for better performance by timo - * - * @param maxScrapNum - */ - @Deprecated - public void setMaxScrapNum(int maxScrapNum) - { - if (maxScrapNum <= DEFAULT_MAX_SCRAP) - { - return; - } - DEFAULT_MAX_SCRAP = maxScrapNum; - } - - public String dump() - { - if (DEBUG) - { - StringBuilder sb = new StringBuilder(); - sb.append("start dump recyclerViewPool!\n"); - sb.append("mMaxScrap=" + mMaxScrap.toString() + "\n"); - sb.append(mScrap + "\n"); - return sb.toString(); - } - else - { - return ""; - } - - } - - // TODO:这个地方要用起来,不同viewtype可能需要的缓存池不一样大。 - public void setMaxRecycledViews(int viewType, int max, Adapter adapter) - { - mMaxScrap.put(viewType, max); - final ArrayList scrapHeap = mScrap.get(viewType); - if (scrapHeap != null) - { - while (scrapHeap.size() > max) - { - ViewHolder vh = scrapHeap.remove(scrapHeap.size() - 1); - if (adapter != null) - { - adapter.onViewAbandon(vh); - } - } - } - } - - // public ViewHolder getRecycledView(int viewType) - // { - // if (DEBUG) - // { - //// Log.d(TAG, "getRecycledViewFromRecycler-->" + "type=" + viewType); - // } - // final ArrayList scrapHeap = mScrap.get(viewType); - // if (scrapHeap != null && !scrapHeap.isEmpty()) - // { - // final int index = scrapHeap.size() - 1; - // final ViewHolder scrap = scrapHeap.get(index); - // scrapHeap.remove(index); - // return scrap; - // } - // return null; - // } - - public ViewHolder getRecycledView(int viewType, String itemReuseKey) - { - if (DEBUG) - { - Log.d(TAG, "getRecycledViewFromRecycler-->" + "type=" + viewType); - } - final ArrayList scrapHeap = mScrap.get(viewType); - - if (scrapHeap != null && !scrapHeap.isEmpty()) - { - Log.d(TAG, "getRecycledView-->" + " scrapHeap.size : " + scrapHeap.size()); - ViewHolder viewHolderReuse = scrapHeap.get(scrapHeap.size() - 1); - if (!TextUtils.isEmpty(itemReuseKey)) - { - for (int i = 0; i < scrapHeap.size(); i++) - { - ViewHolder scrapHeapItem = scrapHeap.get(i); - //尽量能找到之前的那个viewHolder,这样这个holder的数据还是Postion对应的数据, - //不会导致UI的问题,主要用于拉取下一批数据回来后,会重新刷UI,减少View重新bindData - if (TextUtils.equals(itemReuseKey, scrapHeapItem.mHolderReuseKey)) - { - viewHolderReuse = scrapHeapItem; - Log.d(TAG, "getRecycledView-->" + "reqReuseKey: " + itemReuseKey + ",found key:" + scrapHeapItem.mHolderReuseKey); - break; - } - } - } - viewHolderReuse.mHolderReuseKey = itemReuseKey; - scrapHeap.remove(viewHolderReuse); - return viewHolderReuse; - } - return null; - } - - public void putRecycledView(ViewHolder scrap, Adapter adapter) - { - final int viewType = scrap.getItemViewType(); - final ArrayList scrapHeap = getScrapHeapForType(viewType); - if (mMaxScrap.get(viewType) <= scrapHeap.size()) - { - // 如果scrapHeap已经满了,就不再向里面添加,此时这个viewHolder就被废弃,需要通知出去给adapter - if (adapter != null) - { - adapter.onViewAbandon(scrap); - } - return; - } - if (DEBUG) - { - // Log.e(TAG, "putRecycledView...." + scrap); - } - scrap.mPosition = NO_POSITION; - scrap.mOldPosition = NO_POSITION; - scrap.mItemId = NO_ID; - scrap.clearFlagsForSharedPool(); - scrapHeap.add(scrap); - } - - void attach(Adapter adapter) - { - mAttachCount++; - } - - void detach() - { - mAttachCount--; - } - - void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter) - { - if (mAttachCount == 1) - { - clear(); - } - } - - /* private */ - public ArrayList getScrapHeapForType(int viewType) - { - ViewHolderArrayList scrap = mScrap.get(viewType); - if (scrap == null) - { - scrap = new ViewHolderArrayList(); - mScrap.put(viewType, scrap); - if (mMaxScrap.indexOfKey(viewType) < 0) - { - mMaxScrap.put(viewType, DEFAULT_MAX_SCRAP); - } - } - return scrap; - } - } - - /** - * A Recycler is responsible for managing scrapped or detached item views - * for reuse. - *

- *

- * A "scrapped" view is a view that is still attached to its parent - * RecyclerView but that has been marked for removal or reuse. - *

- *

- *

- * Typical use of a Recycler by a {@link LayoutManager} will be to obtain - * views for an adapter's data set representing the data at a given position - * or item ID. If the view to be reused is considered "dirty" the adapter - * will be asked to rebind it. If not, the view can be quickly reused by the - * LayoutManager with no further work. Clean views that have not - * {@link View#isLayoutRequested() requested layout} may be - * repositioned by a LayoutManager without remeasurement. - *

- */ - public class Recycler - { - /* private */public final ArrayList mAttachedScrap = new ArrayList(); - - /* private */public final ArrayList mCachedViews = new ArrayList(); - - /* private */final List mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap); - - /* private */int mViewCacheMax = DEFAULT_CACHE_SIZE; - - /* private */public RecycledViewPool mRecyclerPool; - - /* private */static final int DEFAULT_CACHE_SIZE = 2; - - /** - * Clear scrap views out of this recycler. Detached views contained - * within a recycled view pool will remain. - */ - public void clear() - { - mAttachedScrap.clear(); - recycleCachedViews(); - } - - public String dump() - { - if (DEBUG) - { - StringBuilder sb = new StringBuilder(); - sb.append("start dump recycler!\n"); - sb.append("mAttached has size of " + mAttachedScrap.size() + "\n"); - sb.append(Arrays.toString(mAttachedScrap.toArray()) + "\n"); - sb.append("mCachedViews has size of " + mCachedViews.size() + "\n"); - for (ViewHolder vh : mCachedViews) - { - sb.append(vh + "\n"); - } - sb.append(mRecyclerPool.dump()); - return sb.toString(); - } - else - { - return ""; - } - } - - /** - * Set the maximum number of detached, valid views we should retain for - * later use. - * - * @param viewCount Number of views to keep before sending views to the - * shared - * pool - */ - public void setViewCacheSize(int viewCount) - { - mViewCacheMax = viewCount; - while (mCachedViews.size() > viewCount) - { - mCachedViews.remove(mCachedViews.size() - 1); - } - } - - /** - * Returns an unmodifiable list of ViewHolders that are currently in the - * scrap list. - * - * @return List of ViewHolders in the scrap list. - */ - public List getScrapList() - { - return mUnmodifiableAttachedScrap; - } - - /** - * Helper method for getViewForPosition. - *

- * Checks whether a given view holder can be used for the provided - * position. - * - * @param holder ViewHolder - * @param offsetPosition The position which is updated by UPDATE_OP - * changes on the - * adapter - * @return true if ViewHolder matches the provided position, false - * otherwise - */ - boolean validateViewHolderForOffsetPosition(ViewHolder holder, int offsetPosition) - { - // if it is a removed holder, nothing to verify since we cannot ask - // adapter anymore - // if it is not removed, verify the type and id. - if (holder.isRemoved()) - { - return true; - } - if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) - { - if (DEBUG) - { - // Log.d(TAG, "validateViewHolderForOffsetPosition: invalid position, returning " + "false"); - } - return false; - } - final int type = mAdapter.getItemViewType(offsetPosition); - if (type != holder.getItemViewType()) - { - return false; - } - if (mAdapter.hasStableIds()) - { - return holder.getItemId() == mAdapter.getItemId(offsetPosition); - } - return true; - } - - public View getHeaderForPosition(int position) - { - return mAdapter.getHeaderView(position); - } - - public View getFooterForPosition(int position) - { - View view = getScrapFooterView(position - 1); - if (view != null) - { - return view; - } - return mAdapter.getFooterView(position); - } - - public void notifyLastFooterAppeared() - { - if (mAdapter != null) - { - // Log.d("leo", "notifyLastFooterAppeared,isReachedEnd=" + (mOffsetY + getHeight() >= getTotalHeight())); - mAdapter.notifyLastFooterAppeared(); - } - } - - /** - * get exact same suspend view for index from recycler - * - * @param position - * @return - */ - public View getSuspendViewForPosition(int position) - { - if (mAdapter == null) - { - return null; - } - if (DEBUG) - { - // Log.e(TAG, "getViewFroPosition-->" + position + "-------------------------------------"); - // Log.d(TAG, mRecycler.dump()); - } - ViewHolder holder = null; - final int offsetPosition = findPositionOffset(position); - if (mAdapter.hasCustomRecycler()) - { - holder = mAdapter.findSuspendHolderForPosition(offsetPosition, this); - } - if (holder == null) - { - if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) - { - return null; - } - else - { - holder = mAdapter.createSuspendViewHolderWithPos(RecyclerViewBase.this, offsetPosition, mAdapter.getItemViewType(offsetPosition)); - } - } - if (holder != null) - { - if (holder.mBindNextTime || holder.mForceBind || !holder.isRemoved() && (!holder.isBound() || holder.needsUpdate())) - { - holder.mBindNextTime = false; - if (DEBUG) - { - // Log.d(TAG, "getViewForPosition unbound holder or needs updateStyle; updating..."); - } - - mAdapter.bindViewHolder(holder, offsetPosition, !holder.isBound(), mLayoutType, mAdapter.getCardItemViewType(offsetPosition)); - - } - ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); - if (lp == null) - { - lp = generateDefaultLayoutParams(); - holder.itemView.setLayoutParams(lp); - } - else if (!checkLayoutParams(lp)) - { - lp = generateLayoutParams(lp); - holder.itemView.setLayoutParams(lp); - } - ((LayoutParams) lp).mViewHolder = holder; - if (DEBUG) - { - // Log.e(TAG, "getViewFroPosition-->" + position + "--------------END-----------------------"); - } - if (holder.mContentHolder != null) - { - dispatchViewStateChange(holder.mContentHolder.mContentView, IViewRecycleStateListener.NOTIFY_ON_USE); - } - return holder.itemView; - } - return null; - } - - /** - * Obtain a view initialized for the given position. - *

- *

- * This method should be used by {@link LayoutManager} implementations - * to obtain views to represent data from an {@link Adapter}. - *

- *

- *

- * The Recycler may reuse a scrap or detached view from a shared pool if - * one is available for the correct view type. If the adapter has not - * indicated that the data at the given position has changed, the - * Recycler will attempt to hand back a scrap view that was previously - * initialized for that data without rebinding. - *

- * - * @param position Position to obtain a view for - * @return A view representing the data at position from - * adapter - */ - public View getViewForPosition(int position) - { - if (mAdapter == null) - { - return null; - } - if (DEBUG) - { - // Log.e(TAG, "getViewFroPosition-->" + position + "-------------------------------------"); - // Log.d(TAG, mRecycler.dump()); - } - ViewHolder holder; - final int offsetPosition = findPositionOffset(position); - // if there is suspentionView(sticky = true), remove suspentionView first - if (getLayoutManager() instanceof BaseLayoutManager && !isRepeatableSuspensionMode()) - { - View currentSuspentionView = ((BaseLayoutManager) getLayoutManager()).getCurrentSuspentionView(); - if (currentSuspentionView != null && offsetPosition == ((BaseLayoutManager) getLayoutManager()).getCurrentSuspentionPosition()) - { - // set current suspentionView recycleable here - if (currentSuspentionView != null) - { - RecyclerViewBase.ViewHolder suspentionViewHolder = getChildViewHolder(currentSuspentionView); - if (suspentionViewHolder != null) - { - suspentionViewHolder.setIsRecyclable(true); - } - } - ((BaseLayoutManager) getLayoutManager()).removeSuspentions(); - } - } - if (mAdapter.hasCustomRecycler()) - { - holder = mAdapter.findBestHolderForPosition(offsetPosition, this); - } - else - { - holder = getViewHolderForPosition(offsetPosition); - } - if (holder == null) - { - if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) - { - return null; - } - else - { - // 优先走createViewHolderWithPos,如果为空走createViewHolder - holder = mAdapter.createViewHolderWithPos(RecyclerViewBase.this, offsetPosition, mAdapter.getItemViewType(offsetPosition)); - if (holder == null) - { - holder = mAdapter.createViewHolder(RecyclerViewBase.this, mAdapter.getItemViewType(offsetPosition)); - } - if (holder == null) - { - throw new RuntimeException("Must implement onCreateContentView or onCreateContentViewWithPos in your adapter"); - } - holder.mHolderReuseKey = mAdapter.getViewHolderReUseKey(offsetPosition); - if (DEBUG) - { - // Log.e(TAG, "getViewForPosition created new ViewHolder!!!"); - } - } - } - if (DEBUG) - { - // Log.d(TAG, "binding holder pos=" + offsetPosition + ",holder.mBindNextTime=" + holder.mBindNextTime); - } - handleBindViewHolderInGetView(holder, offsetPosition); - ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); - if (lp == null) - { - lp = generateDefaultLayoutParams(); - holder.itemView.setLayoutParams(lp); - } - else if (!checkLayoutParams(lp)) - { - lp = generateLayoutParams(lp); - holder.itemView.setLayoutParams(lp); - } - ((LayoutParams) lp).mViewHolder = holder; - if (DEBUG) - { - // Log.e(TAG, "getViewFroPosition-->" + position + "--------------END-----------------------"); - } - if (holder.mContentHolder != null) - { - dispatchViewStateChange(holder.mContentHolder.mContentView, IViewRecycleStateListener.NOTIFY_ON_USE); - } - return holder.itemView; - } - - protected void handleBindViewHolderInGetView(ViewHolder holder, int offsetPosition) - { - if (holder.mBindNextTime || holder.mForceBind || !holder.isRemoved() && (!holder.isBound() || holder.needsUpdate())) - { - holder.mBindNextTime = false; - if (DEBUG) - { - // Log.d(TAG, "getViewForPosition unbound holder or needs updateStyle; updating..."); - } - mAdapter.bindViewHolder(holder, offsetPosition, true, mLayoutType, mAdapter.getCardItemViewType(offsetPosition)); - } - } - - protected boolean checkShouldValidateViewHolder() - { - return true; - } - - public ViewHolder getViewHolderForPosition(int offsetPosition) - { - ViewHolder holder = getScrapViewForPosition(offsetPosition, INVALID_TYPE); - - if (DEBUG) - { - // Log.d(TAG, "offsetPosition-->" + offsetPosition); - } - if (holder != null) - { - if (checkShouldValidateViewHolder() && !validateViewHolderForOffsetPosition(holder, offsetPosition)) - { - // recycle this scrap - removeDetachedView(holder.itemView, false); - quickRecycleScrapView(holder.itemView); - - // if validate fails, we can query scrap again w/ type. that - // may return a - // different view holder from cache. - final int type = mAdapter.getItemViewType(offsetPosition); - if (mAdapter.hasStableIds()) - { - final long id = mAdapter.getItemId(offsetPosition); - holder = getScrapViewForId(id, type); - } - else - { - holder = getScrapViewForPosition(offsetPosition, type); - } - } - } - else - { - // try recycler. - - // if (DEBUG) - // { - // Log.d(TAG, "getViewForPosition-->try recycler"); - // Log.d(TAG, mRecycler.dump()); - // } - - holder = getRecycledViewPool().getRecycledView(mAdapter.getItemViewType(offsetPosition), - mAdapter.getViewHolderReUseKey(offsetPosition)); - } - return holder; - } - - /** - * Recycle a detached view. The specified view will be added to a pool - * of views for later rebinding and reuse. - *

- *

- * A view must be fully detached before it may be recycled. - *

- * - * @param view Removed view for recycling - */ - public void recycleView(View view) - { - recycleViewHolder(getChildViewHolderInt(view)); - } - - void recycleCachedViews() - { - final int count = mCachedViews.size(); - for (int i = count - 1; i >= 0; i--) - { - final ViewHolder cachedView = mCachedViews.get(i); - if (cachedView.isRecyclable()) - { - dispatchViewRecycled(cachedView); - getRecycledViewPool().putRecycledView(cachedView, mAdapter); - } - mCachedViews.remove(i); - } - } - - void recycleViewHolder(ViewHolder holder) - { - //Log.e(TAG, "start recycleViewHolder--1-->" + holder); - if (holder == null) - { - return; - } - // if (((QBViewHolder) holder).mViewType != QBViewHolder.TYPE_NORMAL && holder instanceof QBViewHolder) - if (holder.mViewType != ViewHolder.TYPE_NORMAL) - { - return; - } - - if (holder.isScrap() || holder.itemView.getParent() != null) - { - throw new IllegalArgumentException("Scrapped or attached views may not be recycled."); - } - // Log.e(TAG, "start recycleViewHolder--2-->" + holder); - boolean cached = false; - if (!holder.isInvalid() && (mInPreLayout || !holder.isRemoved())) - { - // Retire oldest cached views first - if (mCachedViews.size() == mViewCacheMax && !mCachedViews.isEmpty()) - { - for (int i = 0; i < mCachedViews.size(); i++) - { - final ViewHolder cachedView = mCachedViews.get(i); - if (cachedView.isRecyclable()) - { - mCachedViews.remove(i); - dispatchViewRecycled(cachedView); - getRecycledViewPool().putRecycledView(cachedView, mAdapter); - break; - } - } - } - if (mCachedViews.size() < mViewCacheMax) - { - mCachedViews.add(holder); - cached = true; - } - } - if (!cached && holder.isRecyclable()) - { - dispatchViewRecycled(holder); - getRecycledViewPool().putRecycledView(holder, mAdapter); - } - // Remove from pre/post maps that are used to animate items; a - // recycled holder - // should not be animated - mState.mPreLayoutHolderMap.remove(holder); - mState.mPostLayoutHolderMap.remove(holder); - } - - /** - * Used as a fast path for unscrapping and recycling a view during a - * bulk operation. The caller must call {@link #clearScrap()} when it's - * done to updateStyle the recycler's internal bookkeeping. - */ - void quickRecycleScrapView(View view) - { - final ViewHolder holder = getChildViewHolderInt(view); - holder.mScrapContainer = null; - recycleViewHolder(holder); - } - - /** - * Mark an attached view as scrap. - *

- *

- * "Scrap" views are still attached to their parent RecyclerView but are - * eligible for rebinding and reuse. Requests for a view for a given - * position may return a reused or rebound scrap view instance. - *

- * - * @param view View to scrap - */ - void scrapView(View view) - { - final ViewHolder holder = getChildViewHolderInt(view); - if (holder != null) - { - holder.setScrapContainer(this); - mAttachedScrap.add(holder); - } - } - - /** - * Remove a previously scrapped view from the pool of eligible scrap. - *

- *

- * This view will no longer be eligible for reuse until re-scrapped or - * until it is explicitly removed and recycled. - *

- */ - void unscrapView(ViewHolder holder) - { - mAttachedScrap.remove(holder); - holder.mScrapContainer = null; - } - - int getScrapCount() - { - return mAttachedScrap.size(); - } - - View getScrapViewAt(int index) - { - return mAttachedScrap.get(index).itemView; - } - - void clearScrap() - { - mAttachedScrap.clear(); - } - - public View getScrapFooterView(int position) - { - final int scrapCount = mAttachedScrap.size(); - - // Try first for an exact, non-invalid match from scrap. - for (int i = 0; i < scrapCount; i++) - { - ViewHolder holder = mAttachedScrap.get(i); - if (holder != null && holder.mPosition == position && holder.itemView instanceof IRecyclerViewFooter) - { - mAttachedScrap.remove(i); - return holder.itemView; - } - } - return null; - - } - - /** - * Returns a scrap view for the position. If type is not INVALID_TYPE, - * it also checks if ViewHolder's type matches the provided type. - * - * @param position Item position - * @param type View type - * @return a ViewHolder that can be re-used for this position. - */ - ViewHolder getScrapViewForPosition(int position, int type) - { - if (DEBUG) - { - // Log.d(TAG, "getScrapViewForPosition-->" + position + ",type=" + type); - } - final int scrapCount = mAttachedScrap.size(); - // Try first for an exact, non-invalid match from scrap. - if (DEBUG) - { - // Log.d(TAG, "getScrapViewForPosition-->Try first for an exact, non-invalid match from scrap"); - } - for (int i = 0; i < scrapCount; i++) - { - final ViewHolder holder = mAttachedScrap.get(i); - if (holder.getPosition() == position && !holder.isInvalid() && (mInPreLayout || !holder.isRemoved())) - { - if (type != INVALID_TYPE && holder.getItemViewType() != type) - { - if (DEBUG) - { - // Log.e(TAG, "Scrap view for position " + position + " isn't dirty but has" + " wrong view type! (found " - // + holder.getItemViewType() + " but expected " + type + ")"); - } - break; - } - mAttachedScrap.remove(i); - holder.setScrapContainer(null); - if (DEBUG) - { - // Log.d(TAG, "getScrapViewForPosition(" + position + ", " + type + ") found exact match in scrap: " + holder); - } - return holder; - } - } - - if (mNumAnimatingViews != 0) - { - View view = getAnimatingView(position, type); - handleAnimatingViewInGetScrapView(view); - } - if (DEBUG) - { - // Log.d(TAG, "getScrapViewForPosition-->Search in our first-level recycled view cache."); - // Log.d(TAG, mRecycler.dump()); - } - // Search in our first-level recycled view cache. - final int cacheSize = mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder.getPosition() == position) - { - mCachedViews.remove(i); - if (holder.isInvalid() || (type != INVALID_TYPE && holder.getItemViewType() != type)) - { - // Can't use it. We don't know where it's been. - if (DEBUG) - { - // Log.d(TAG, "getScrapViewForPosition(" + position + ", " + type - // + ") found position match, but holder is invalid with type " + holder.getItemViewType()); - } - dispatchViewRecycled(holder); - if (holder.isRecyclable()) - { - getRecycledViewPool().putRecycledView(holder, mAdapter); - } - // Even if the holder wasn't officially recycleable, - // dispatch that it - // was recycled anyway in case there are resources to - // unbind. - - - // Drop out of the cache search and try something else - // instead, - // we won't find another match here. - break; - } - if (DEBUG) - { - // Log.d(TAG, "getScrapViewForPosition(" + position + ", " + type + ") found match in cache: " + holder); - } - return holder; - } - } - - // Give up. Head to the shared pool. - if (DEBUG) - { - // Log.d(TAG, "getScrapViewForPosition(" + position + ", " + type + ") fetching from shared pool"); - } - return type == INVALID_TYPE ? null : getRecycledViewPool().getRecycledView(type, mAdapter.getViewHolderReUseKey(position)); - } - - protected void handleAnimatingViewInGetScrapView(View view) - { - - } - - ViewHolder getScrapViewForId(long id, int type) - { - // Look in our attached views first - final int count = mAttachedScrap.size(); - for (int i = 0; i < count; i++) - { - final ViewHolder holder = mAttachedScrap.get(i); - if (holder.getItemId() == id) - { - if (type == holder.getItemViewType()) - { - mAttachedScrap.remove(i); - holder.setScrapContainer(null); - return holder; - } - else - { - break; - } - } - } - - // Search the first-level cache - final int cacheSize = mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder.getItemId() == id) - { - mCachedViews.remove(i); - return holder; - } - } - - // That didn't work, look for an unordered view of the right type - // instead. - // The holder's position won't match so the calling code will need - // to have - // the adapter rebind it. - return getRecycledViewPool().getRecycledView(type, null); - } - - public void dispatchViewRecycled(ViewHolder holder) - { - // notify view to be recycled - if (mAdapter != null) - { - mAdapter.onViewRecycled(holder); - } - if (DEBUG) - { - // Log.d(TAG, "dispatchViewRecycled: " + holder); - } - dispatchViewStateChange(holder.mContentHolder.mContentView, IViewRecycleStateListener.NOTIFY_ON_RECYCLE); - } - - private void dispatchViewStateChange(View view, int state) - { - if (view instanceof IViewRecycleStateListener) - { - switch (state) - { - case IViewRecycleStateListener.NOTIFY_ON_USE: - ((IViewRecycleStateListener) view).onUse(); - break; - case IViewRecycleStateListener.NOTIFY_ON_RECYCLE: - ((IViewRecycleStateListener) view).onRecycle(); - break; - default: - break; - } - } - if (view instanceof ViewGroup) - { - int childCount = ((ViewGroup) view).getChildCount(); - for (int index = 0; index < childCount; index++) - { - dispatchViewStateChange(((ViewGroup) view).getChildAt(index), state); - } - } - } - - void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter) - { - clear(); - getRecycledViewPool().onAdapterChanged(oldAdapter, newAdapter); - } - - protected void offsetPositionRecordsForInsert(int insertedAt, int count) - { - final int cachedCount = mCachedViews.size(); - for (int i = 0; i < cachedCount; i++) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder != null && holder.getPosition() >= insertedAt) - { - if (DEBUG) - { - // Log.d(TAG, "offsetPositionRecordsForInsert cached " + i + " holder " + holder + " now at position " - // + (holder.mPosition + count)); - } - holder.offsetPosition(count); - } - } - } - - protected void offsetPositionRecordsForRemove(int removedFrom, int count) - { - final int removedEnd = removedFrom + count; - final int cachedCount = mCachedViews.size(); - for (int i = cachedCount - 1; i >= 0; i--) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder != null) - { - if (holder.getPosition() >= removedEnd) - { - if (DEBUG) - { - // Log.d(TAG, "offsetPositionRecordsForRemove cached " + i + " holder " + holder + " now at position " - // + (holder.mPosition - count)); - } - holder.offsetPosition(-count); - } - else if (holder.getPosition() >= removedFrom) - { - // Item for this view was removed. Dump it from the - // cache. - if (DEBUG) - { - // Log.d(TAG, "offsetPositionRecordsForRemove cached " + i + " holder " + holder + " now placed in pool"); - } - mCachedViews.remove(i); - dispatchViewRecycled(holder); - getRecycledViewPool().putRecycledView(holder, mAdapter); - } - } - } - } - - void setRecycledViewPool(RecycledViewPool pool) - { - if (mRecyclerPool != null) - { - mRecyclerPool.detach(); - } - mRecyclerPool = pool; - if (pool != null) - { - mRecyclerPool.attach(getAdapter()); - } - } - - public RecycledViewPool getRecycledViewPool() - { - if (mRecyclerPool == null) - { - mRecyclerPool = new RecycledViewPool(); - } - return mRecyclerPool; - } - - ViewHolder findViewHolderForPosition(int position) - { - final int cachedCount = mCachedViews.size(); - for (int i = 0; i < cachedCount; i++) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder != null && holder.getPosition() == position) - { - mCachedViews.remove(i); - return holder; - } - } - return null; - } - - ViewHolder findViewHolderForItemId(long id) - { - if (!mAdapter.hasStableIds()) - { - return null; - } - - final int cachedCount = mCachedViews.size(); - for (int i = 0; i < cachedCount; i++) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder != null && holder.getItemId() == id) - { - mCachedViews.remove(i); - return holder; - } - } - return null; - } - - void viewRangeUpdate(int positionStart, int itemCount) - { - final int positionEnd = positionStart + itemCount; - final int cachedCount = mCachedViews.size(); - for (int i = 0; i < cachedCount; i++) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder == null) - { - continue; - } - - final int pos = holder.getPosition(); - if (pos >= positionStart && pos < positionEnd) - { - holder.addFlags(ViewHolder.FLAG_UPDATE); - } - } - } - - void markKnownViewsInvalid() - { - final int cachedCount = mCachedViews.size(); - for (int i = 0; i < cachedCount; i++) - { - final ViewHolder holder = mCachedViews.get(i); - if (holder != null) - { - holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID); - } - } - recycleCachedViews(); - } - - void clearOldPositions() - { - final int cachedCount = mCachedViews.size(); - for (int i = 0; i < cachedCount; i++) - { - final ViewHolder holder = mCachedViews.get(i); - holder.clearOldPosition(); - } - } - - /** - * harryguo: 当@param index这个位置的条目被删除后,更新缓存中的holder信息 - */ - public void updateHolderPositionWhenDelete(int index) - { - // list里,删掉某个条目后,它后面的条目的位置都要减1(所以要遍历所有缓存中的holder) - if (index >= 0) - { - // 1. mCachedViews缓存 - final int cacheSize = mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) - { - final RecyclerViewBase.ViewHolder holder = mCachedViews.get(i); - if (holder.mPosition > index) - holder.mPosition--; - } - - // 2. mAttachedScrap缓存 - final int scrapCount = mAttachedScrap.size(); - // Try first for an exact, non-invalid match from scrap. - for (int i = 0; i < scrapCount; i++) - { - final RecyclerViewBase.ViewHolder holder = mAttachedScrap.get(i); - if (holder.mPosition > index) - holder.mPosition--; - } - - // 3. mScrap缓存 - int viewType = getAdapter().getItemViewType(index); - final ArrayList scrapHeap = getRecycledViewPool().mScrap.get(viewType); - if (scrapHeap != null && !scrapHeap.isEmpty()) - { - // traverse all scrap - for (RecyclerViewBase.ViewHolder holder : scrapHeap) - { - if (holder.getItemViewType() == viewType) - { - if (holder.mPosition > index) - holder.mPosition--; - } - } - } - } - } - } - - public static abstract class Adapter - { - public static final int LOCATION_LEFT = 0; - public static final int LOCATION_TOP = 1; - public static final int LOCATION_RIGHT = 2; - public static final int LOCATION_BOTTOM = 3; - protected boolean mDataChanged = true; - /* private */final AdapterDataObservable mObservable = new AdapterDataObservable(); - /* private */boolean mHasStableIds = false; - protected boolean mSuspentionDataChanged = false; - - - public abstract VH onCreateViewHolder(RecyclerViewBase parent, int viewType); - - public VH onCreateViewHolderWithPos(RecyclerViewBase parent, int position, int viewType) - { - return null; - } - - public VH onCreateSuspendViewHolderWithPos(RecyclerViewBase parent, int position, int viewType) - { - return null; - } - - public abstract void onBindViewHolder(VH holder, int position, int layoutType, int cardType); - - public final VH createViewHolder(RecyclerViewBase parent, int viewType) - { - final VH holder = onCreateViewHolder(parent, viewType); - if (holder == null) - return null; - holder.mItemViewType = viewType; - return holder; - } - - public final VH createViewHolderWithPos(RecyclerViewBase parent, int position, int viewType) - { - final VH holder = onCreateViewHolderWithPos(parent, position, viewType); - if (holder == null) - return null; - holder.mItemViewType = viewType; - return holder; - } - - public final VH createSuspendViewHolderWithPos(RecyclerViewBase parent, int position, int viewType) - { - final VH holder = onCreateSuspendViewHolderWithPos(parent, position, viewType); - if (holder == null) - return null; - holder.mItemViewType = viewType; - return holder; - } - - protected void onViewAttached() - { - - } - - protected void onViewDetached() - { - - } - - // 当viewHolder被废弃时 - protected void onViewAbandon(VH viewHolder) - { - - } - - public boolean doDeleteItem() - { - return true; - } - - public void dataChanged() - { - mDataChanged = true; - mSuspentionDataChanged = true; - } - - public void onSuddenStop() - { - - } - - // 提前多少像素进行预加载 - public int getPreloadThresholdInPixels() - { - return 0; - } - - // 提前多少item进行预加载 - public int getPreloadThresholdInItemNumber() - { - return 0; - } - - public int calcPreloadThresholdWithItemNumber() - { - return 0; - } - - public abstract int getHeightBefore(int pos); - - - public void onPreload() - { - // Log.d(TAG, "onPreload:" + ",currY=" + mParentRecyclerView.mOffsetY + ",threshold=" + getPreloadThresholdInPixels() + ",total=" - // + getTotalHeight() + ",height=" + mParentRecyclerView.getHeight()); - } - - public void startRefreshData() - { - - } - - public void onItemDeleted(int pos) - { - - } - - public boolean headerMayChange() - { - return false; - } - - public final void bindViewHolder(VH holder, int position, boolean doBind, int layoutType, int cardType) - { - holder.mPosition = position; - if (hasStableIds()) - { - holder.mItemId = getItemId(position); - } - if (doBind) - { - if (DEBUG) - { - // Log.e(TAG, "getViewForPosition dobind-->" + position); - } - onBindViewHolder(holder, position, layoutType, cardType); - } - holder.setFlags(ViewHolder.FLAG_BOUND, ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID); - } - - public boolean notifyOrderChanged(int fromPosition, int toPosition) - { - return true; - } - - /** - * Return the view type of the item at position for the - * purposes of view recycling. - *

- *

- * The default implementation of this method returns 0, making the - * assumption of a single view type for the adapter. Unlike ListView - * adapters, types need not be contiguous. Consider using id resources - * to uniquely identify item view types. - * - * @param position position to query - * @return integer value identifying the type of the view needed to - * represent the item at position. Type codes need - * not be contiguous. - */ - public int getItemViewType(int position) - { - return 0; - } - - public int getCardItemViewType(int position) - { - return 0; - } - - public void setHasStableIds(boolean hasStableIds) - { - if (hasObservers()) - { - throw new IllegalStateException("Cannot change whether this adapter has " + "stable IDs while the adapter has registered observers."); - } - mHasStableIds = hasStableIds; - } - - public void reset() - { - - } - - /** - * Return the stable ID for the item at position. If - * {@link #hasStableIds()} would return false this method should return - * {@link #NO_ID}. The default implementation of this method returns - * {@link #NO_ID}. - * - * @param position Adapter position to query - * @return the stable ID of the item at position - */ - public long getItemId(int position) - { - return NO_ID; - } - - public abstract int getItemCount(); - - public int getMarginCloseToParentH(int location, int position) - { - return 0; - } - - public int getMarginCloseToParentV(int location, int position) - { - return 0; - } - - public int getMarginBetweenItem(int location, int position) - { - return 0; - } - - public abstract int getItemHeight(int position); - - // public QBRecyclerView mParentRecyclerView; - - public abstract int getItemMaigin(int location, int position); - - public abstract int getTotalHeight(); - - public int getListTotalHeight() - { - int height = 0; - if (getHeaderViewCount() > 0) - { - int headerCount = getHeaderViewCount(); - for (int i = 1; i <= headerCount; i++) - { - height += getHeaderViewHeight(i); - } - } - // Log.e("leo", "getListTotalHeight getHeader " + height); - if (getFooterViewCount() > 0) - { - int footerCount = getFooterViewCount(); - for (int i = 1; i <= footerCount; i++) - { - height += getFooterViewHeight(i); - } - } - // Log.e("leo", "getListTotalHeight getHeader + getFooter " + height + ", " + this.toString()); - return getTotalHeight() + height; - } - - public abstract int getCustomHeaderViewHeight(); - - public abstract int getCustomFooterViewHeight(); - - public abstract int getCustomHeaderViewWidth(); - - public abstract int getCustomFooterViewWidth(); - - public abstract int getHeaderViewHeight(int position); - - public abstract int getHeaderViewCount(); - - public abstract View getHeaderView(int position); - - public abstract int getFooterViewHeight(int position); - - public abstract boolean getFooterViewInBottomMode(); - - public abstract int getFooterViewCount(); - - public abstract View getFooterView(int position); - - public abstract int[] getBeginPositionWithOffset(int targetOffset); - - public int getDefaultFooterHeight() - { - return 0; - } - - public void onItemsFill(int offset) - { - - } - - public void notifyLastFooterAppeared() - { - } - - public void notifyEndReached() - { - } - - /** - * Returns true if this adapter publishes a unique long - * value that can act as a key for the item at a given position in the - * data set. If that item is relocated in the data set, the ID returned - * for that item should be the same. - * - * @return true if this adapter's items have stable IDs - */ - public final boolean hasStableIds() - { - return mHasStableIds; - } - - protected void onViewRecycled(VH holder) - { - } - - public void onViewAttachedToWindow(VH holder) - { - } - - /** - * Called when a view created by this adapter has been detached from its - * window. - *

- *

- * Becoming detached from the window is not necessarily a permanent - * condition; the consumer of an Adapter's views may choose to cache - * views offscreen while they are not visible, attaching an detaching - * them as appropriate. - *

- * - * @param holder Holder of the view being detached - */ - public void onViewDetachedFromWindow(VH holder) - { - // mParentRecyclerView.notifyChildDetached(holder); - } - - /** - * Returns true if one or more observers are attached to this adapter. - * - * @return true if this adapter has observers - */ - public final boolean hasObservers() - { - return mObservable.hasObservers(); - } - - /** - * Register a new observer to listen for data changes. - *

- *

- * The adapter may publish a variety of events describing specific - * changes. Not all adapters may support all change types and some may - * fall back to a generic {@link AdapterDataObserver#onChanged() - * "something changed"} event if more specific data is not available. - *

- *

- *

- * Components registering observers with an adapter are responsible for - * {@link #unregisterAdapterDataObserver(AdapterDataObserver) - * unregistering} those observers when finished. - *

- * - * @param observer Observer to register - * @see #unregisterAdapterDataObserver(AdapterDataObserver) - */ - public void registerAdapterDataObserver(AdapterDataObserver observer) - { - mObservable.registerObserver(observer); - } - - /** - * Unregister an observer currently listening for data changes. - *

- *

- * The unregistered observer will no longer receive events about changes - * to the adapter. - *

- * - * @param observer Observer to unregister - * @see #registerAdapterDataObserver(AdapterDataObserver) - */ - public void unregisterAdapterDataObserver(AdapterDataObserver observer) - { - mObservable.unregisterObserver(observer); - } - - /** - * Notify any registered observers that the data set has changed. - *

- *

- * There are two different classes of data change events, item changes - * and structural changes. Item changes are when a single item has its - * data updated but no positional changes have occurred. Structural - * changes are when items are inserted, removed or moved within the data - * set. - *

- *

- *

- * This event does not specify what about the data set has changed, - * forcing any observers to assume that all existing items and structure - * may no longer be valid. LayoutManagers will be forced to fully rebind - * and relayout all visible views. - *

- *

- *

- * RecyclerView will attempt to synthesize visible - * structural change events for adapters that report that they have - * {@link #hasStableIds() stable IDs} when this method is used. This can - * help for the purposes of animation and visual object persistence but - * individual item views will still need to be rebound and relaid out. - *

- *

- *

- * If you are writing an adapter it will always be more efficient to use - * the more specific change events if you can. Rely on - * notifyDataSetChanged() as a last resort. - *

- * - * @see #notifyItemChanged(int) - * @see #notifyItemInserted(int) - * @see #notifyItemRemoved(int) - * @see #notifyItemRangeChanged(int, int) - * @see #notifyItemRangeInserted(int, int) - * @see #notifyItemRangeRemoved(int, int) - */ - public void notifyDataSetChanged() - { - // Log.d("ForwardingDrawable", "notifyDatasetChanged!"); - mObservable.notifyChanged(); - } - - /** - * Notify any registered observers that the item at - * position has changed. - *

- *

- * This is an item change event, not a structural change event. It - * indicates that any reflection of the data at position is - * out of date and should be updated. The item at position - * retains the same identity. - *

- * - * @param position Position of the item that has changed - * @see #notifyItemRangeChanged(int, int) - */ - public void notifyItemChanged(int position) - { - mObservable.notifyItemRangeChanged(position, 1); - } - - /** - * Notify any registered observers that the itemCount items - * starting at position positionStart have changed. - *

- *

- * This is an item change event, not a structural change event. It - * indicates that any reflection of the data in the given position range - * is out of date and should be updated. The items in the given range - * retain the same identity. - *

- * - * @param positionStart Position of the first item that has changed - * @param itemCount Number of items that have changed - * @see #notifyItemChanged(int) - */ - public void notifyItemRangeChanged(int positionStart, int itemCount) - { - mObservable.notifyItemRangeChanged(positionStart, itemCount); - } - - // /** - // * Notify any registered observers that the itemCount items starting at - // * position positionStart have changed. An optional payload can be - // * passed to each changed item. - // * - // *

This is an item change event, not a structural change event. It indicates that any - // * reflection of the data in the given position range is out of date and should be updated. - // * The items in the given range retain the same identity. - // *

- // * - // *

- // * Client can optionally pass a payload for partial change. These payloads will be merged - // * and may be passed to adapter's {@link #onBindViewHolder(ViewHolder, int, List)} if the - // * item is already represented by a ViewHolder and it will be rebound to the same - // * ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing - // * payloads on that item and prevent future payload until - // * {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume - // * that the payload will always be passed to onBindViewHolder(), e.g. when the view is not - // * attached, the payload will be simply dropped. - // * - // * @param positionStart Position of the first item that has changed - // * @param itemCount Number of items that have changed - // * @param payload Optional parameter, use null to identify a "full" updateStyle - // * - // * @see #notifyItemChanged(int) - // */ - // public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) { - // mObservable.notifyItemRangeChanged(positionStart, itemCount, payload); - // } - - /** - * Notify any registered observers that the item reflected at - * position has been newly inserted. The item previously at - * position is now at position position + 1. - *

- *

- * This is a structural change event. Representations of other existing - * items in the data set are still considered up to date and will not be - * rebound, though their positions may be altered. - *

- * - * @param position Position of the newly inserted item in the data set - * @see #notifyItemRangeInserted(int, int) - */ - public void notifyItemInserted(int position) - { - mObservable.notifyItemRangeInserted(position, 1); - } - - /** - * Notify any registered observers that the currently reflected - * itemCount items starting at positionStart - * have been newly inserted. The items previously located at - * positionStart and beyond can now be found starting at - * position positionStart + itemCount. - *

- *

- * This is a structural change event. Representations of other existing - * items in the data set are still considered up to date and will not be - * rebound, though their positions may be altered. - *

- * - * @param positionStart Position of the first item that was inserted - * @param itemCount Number of items inserted - * @see #notifyItemInserted(int) - */ - public void notifyItemRangeInserted(int positionStart, int itemCount) - { - mObservable.notifyItemRangeInserted(positionStart, itemCount); - } - - /** - * Notify any registered observers that the item previously located at - * position has been removed from the data set. The items - * previously located at and after position may now be - * found at oldPosition - 1. - *

- *

- * This is a structural change event. Representations of other existing - * items in the data set are still considered up to date and will not be - * rebound, though their positions may be altered. - *

- * - * @param position Position of the item that has now been removed - * @see #notifyItemRangeRemoved(int, int) - */ - public void notifyItemRemoved(int position) - { - mObservable.notifyItemRangeRemoved(position, 1); - } - - /** - * Notify any registered observers that the itemCount items - * previously located at positionStart have been removed - * from the data set. The items previously located at and after - * positionStart + itemCount may now be found at - * oldPosition - itemCount. - *

- *

- * This is a structural change event. Representations of other existing - * items in the data set are still considered up to date and will not be - * rebound, though their positions may be altered. - *

- * - * @param positionStart Previous position of the first item that was - * removed - * @param itemCount Number of items removed from the data set - */ - public void notifyItemRangeRemoved(int positionStart, int itemCount) - { - mObservable.notifyItemRangeRemoved(positionStart, itemCount); - } - - public void notifyItemsRemoved(ArrayList positions) - { - mObservable.notifyItemsRemoved(positions); - } - - - public boolean isDividerItem(int mCurrentPosition) - { - return false; - } - - public int findPrevSuspentedPos(int pos) - { - // TODO Auto-generated method stub - return -1; - } - - public boolean isSuspentedItem(int pos) - { - // TODO Auto-generated method stub - return false; - } - - public int findNextSuspentedPos(int pos) - { - // TODO Auto-generated method stub - return -1; - } - - public boolean hasCustomRecycler() - { - return false; - } - - public ViewHolder findBestHolderForPosition(int offsetPosition, Recycler recycler) - { - return null; - } - - public ViewHolder findSuspendHolderForPosition(int offsetPosition, Recycler recycler) - { - return null; - } - - public String getViewHolderReUseKey(int position) - { - return null; - } - } - - /** - * A LayoutManager is responsible for measuring and positioning - * item views within a RecyclerView as well as determining the - * policy for when to recycle item views that are no longer visible to the - * user. By changing the LayoutManager a - * RecyclerView can be used to implement a standard vertically - * scrolling list, a uniform grid, staggered grids, horizontally scrolling - * collections and more. Several stock layout managers are provided for - * general use. - */ - public static abstract class LayoutManager - { - public RecyclerViewBase mRecyclerView; - public SmoothScroller mSmoothScroller; - public boolean mPreventFixGap = false; - public static final int INVALID_OFFSET = Integer.MIN_VALUE; - /** - * When LayoutManager needs to scroll to a position, it sets this - * variable - * and requests a layout which will check this variable and re-layout - * accordingly. - */ - public int mPendingScrollPosition = RecyclerViewBase.NO_POSITION; - - /** - * Used to keep the offset value when - * {@link #scrollToPositionWithOffset(int, int)} is called. - */ - protected int mPendingScrollPositionOffset = INVALID_OFFSET; - - /** - * Calls {@code RecyclerView#requestLayout} on the underlying - * RecyclerView - */ - public void requestLayout() - { - if (mRecyclerView != null) - { - mRecyclerView.requestLayout(); - } - } - - public void scrollToPositionWidthGravity(int position, int gravity, int itemHeight) - { - - } - - public View getChildClosestToStartInScreen() - { - return null; - } - - public View getChildClosestToEndInScreen() - { - return null; - } - - public int getDecoratedStart(View child) - { - return 0; - } - - public int getDecoratedEnd(View child) - { - return 0; - } - - public View getChildClosestToEndByOrder() - { - return null; - } - - public View getChildClosestToStartByOrder() - { - return null; - } - - public boolean supportsPredictiveItemAnimations() - { - return false; - } - - /** - * Called when this LayoutManager is both attached to a RecyclerView and - * that RecyclerView is attached to a window. - *

- *

- * Subclass implementations should always call through to the superclass - * implementation. - *

- * - * @param view The RecyclerView this LayoutManager is bound to - */ - public void onAttachedToWindow(RecyclerViewBase view) - { - } - - /** - * Called when this LayoutManager is detached from its parent - * RecyclerView or when its parent RecyclerView is detached from its - * window. - *

- *

- * Subclass implementations should always call through to the superclass - * implementation. - *

- * - * @param view The RecyclerView this LayoutManager is bound to - */ - public void onDetachedFromWindow(RecyclerViewBase view) - { - } - - public void onLayoutChildren(Recycler recycler, State state) - { - // Log.e(TAG, "You must override onLayoutChildren(Recycler recycler, State state) "); - } - - public abstract LayoutParams generateDefaultLayoutParams(); - - /** - * Determines the validity of the supplied LayoutParams object. - *

- *

- * This should check to make sure that the object is of the correct type - * and all values are within acceptable ranges. The default - * implementation returns true for non-null params. - *

- * - * @param lp LayoutParams object to check - * @return true if this LayoutParams object is valid, false otherwise - */ - public boolean checkLayoutParams(LayoutParams lp) - { - return lp != null; - } - - public View getFirstItemAfterOffset(int offset) - { - final int count = getChildCount(); - for (int i = 0; i < count; i++) - { - View v = getChildAt(i); - if (getDecoratedStart(v) > offset) - { - return v; - } - } - return null; - } - - /** - * Create a LayoutParams object suitable for this LayoutManager, copying - * relevant values from the supplied LayoutParams object if possible. - *

- *

- * Important: if you use your own custom - * LayoutParams type you must also override - * {@link #checkLayoutParams(LayoutParams)}, - * {@link #generateLayoutParams(ViewGroup.LayoutParams)} - * and - * {@link #generateLayoutParams(Context, AttributeSet)} - * . - *

- * - * @param lp Source LayoutParams object to copy values from - * @return a new LayoutParams object - */ - public LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) - { - if (lp instanceof LayoutParams) - { - return new LayoutParams((LayoutParams) lp); - } - else if (lp instanceof MarginLayoutParams) - { - return new LayoutParams((MarginLayoutParams) lp); - } - else - { - return new LayoutParams(lp); - } - } - - /** - * Create a LayoutParams object suitable for this LayoutManager from an - * inflated layout resource. - *

- *

- * Important: if you use your own custom - * LayoutParams type you must also override - * {@link #checkLayoutParams(LayoutParams)}, - * {@link #generateLayoutParams(ViewGroup.LayoutParams)} - * and - * {@link #generateLayoutParams(Context, AttributeSet)} - * . - *

- * - * @param c Context for obtaining styled attributes - * @param attrs AttributeSet describing the supplied arguments - * @return a new LayoutParams object - */ - public LayoutParams generateLayoutParams(Context c, AttributeSet attrs) - { - return new LayoutParams(c, attrs); - } - - /** - * Scroll horizontally by dx pixels in screen coordinates and return the - * distance traveled. The default implementation does nothing and - * returns 0. - * - * @param dx distance to scroll by in pixels. X increases as scroll - * position approaches the right. - * @param recycler Recycler to use for fetching potentially cached views - * for - * a position - * @param state Transient state of RecyclerView - * @return The actual distance scrolled. The return value will be - * negative if dx was negative and scrolling proceeeded in that - * direction. Math.abs(result) may be less than dx - * if a boundary was reached. - */ - public int scrollHorizontallyBy(int dx, Recycler recycler, State state) - { - return 0; - } - - /** - * Scroll vertically by dy pixels in screen coordinates and return the - * distance traveled. The default implementation does nothing and - * returns 0. - * - * @param dy distance to scroll in pixels. Y increases as scroll - * position approaches the bottom. - * @param recycler Recycler to use for fetching potentially cached views - * for - * a position - * @param state Transient state of RecyclerView - * @return The actual distance scrolled. The return value will be - * negative if dy was negative and scrolling proceeeded in that - * direction. Math.abs(result) may be less than dy - * if a boundary was reached. - */ - public int scrollVerticallyBy(int dy, Recycler recycler, State state) - { - return 0; - } - - /** - * Query if horizontal scrolling is currently supported. The default - * implementation returns false. - * - * @return True if this LayoutManager can scroll the current contents - * horizontally - */ - public boolean canScrollHorizontally() - { - return false; - } - - /** - * Query if vertical scrolling is currently supported. The default - * implementation returns false. - * - * @return True if this LayoutManager can scroll the current contents - * vertically - */ - public boolean canScrollVertically() - { - return false; - } - - /** - * Scroll to the specified adapter position. - *

- * Actual position of the item on the screen depends on the - * LayoutManager implementation. - * - * @param position Scroll to this adapter position. - */ - public void scrollToPosition(int position) - { - if (DEBUG) - { - // Log.e(TAG, "You MUST implement scrollToPosition. It will soon become abstract"); - } - } - - public int getPendingOffset() - { - return 0; - } - - public int getPendingPosition() - { - return 0; - } - - /** - *

- * Scroll to the specified adapter position with the given offset from - * layout start. - *

- *

- *

- * Note that scroll position change will not be reflected until the next - * layout call. - *

- *

- *

- * If you are just trying to make a position visible, use - * {@link #scrollToPosition(int)}. - *

- * - * @param position Index (starting at 0) of the reference item. - * @param offset The distance (in pixels) between the start edge of the - * item view and start edge of the RecyclerView. - * @see #scrollToPosition(int) - */ - public abstract void scrollToPositionWithOffset(int position, int offset); - - /** - *

- * Smooth scroll to the specified adapter position. - *

- *

- * To support smooth scrolling, override this method, create your - * {@link SmoothScroller} instance and call - * {@link #startSmoothScroll(SmoothScroller)}. - *

- * - * @param recyclerView The RecyclerView to which this layout manager is - * attached - * @param state Current State of RecyclerView - * @param position Scroll to this adapter position. - */ - public void smoothScrollToPosition(RecyclerViewBase recyclerView, State state, int position) - { - // Log.e(TAG, - // "You must override smoothScrollToPosition to support smooth scrolling"); - } - - /** - *

- * Starts a smooth scroll using the provided SmoothScroller. - *

- *

- * Calling this method will cancel any previous smooth scroll request. - *

- * - * @param smoothScroller Unstance which defines how smooth scroll should - * be - * animated - */ - public void startSmoothScroll(SmoothScroller smoothScroller) - { - if (mSmoothScroller != null && smoothScroller != mSmoothScroller && mSmoothScroller.isRunning()) - { - mSmoothScroller.stop(); - } - mSmoothScroller = smoothScroller; - mSmoothScroller.start(mRecyclerView, this); - } - - /** - * @return true if RecycylerView is currently in the state of smooth - * scrolling. - */ - public boolean isSmoothScrolling() - { - return mSmoothScroller != null && mSmoothScroller.isRunning(); - } - - /** - * Add a view to the currently attached RecyclerView if needed. - * LayoutManagers should use this method to add views obtained from a - * {@link Recycler} using {@link Recycler#getViewForPosition(int)}. - * - * @param child View to add - * @param index Index to add child at - */ - public void addView(View child, int index) - { - if (mRecyclerView == null) - { - return; - } - if (mRecyclerView.mAnimatingViewIndex >= 0) - { - if (index > mRecyclerView.mAnimatingViewIndex) - { - throw new IndexOutOfBoundsException("index=" + index + " count=" + mRecyclerView.mAnimatingViewIndex); - } - mRecyclerView.mAnimatingViewIndex++; - } - final ViewHolder holder = getChildViewHolderInt(child); - if (holder.isScrap()) - { - holder.unScrap(); - mRecyclerView.attachViewToParent(child, index, child.getLayoutParams()); - if (DISPATCH_TEMP_DETACH) - { - // ViewCompat.dispatchFinishTemporaryDetach(child); - } - } - else - { - mRecyclerView.addView(child, index); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - lp.mInsetsDirty = true; - final Adapter adapter = mRecyclerView.getAdapter(); - if (adapter != null) - { - adapter.onViewAttachedToWindow(getChildViewHolderInt(child)); - } - mRecyclerView.onChildAttachedToWindow(child); - if (mSmoothScroller != null && mSmoothScroller.isRunning()) - { - mSmoothScroller.onChildAttachedToWindow(child); - } - } - } - - /** - * Add a view to the currently attached RecyclerView if needed. - * LayoutManagers should use this method to add views obtained from a - * {@link Recycler} using {@link Recycler#getViewForPosition(int)}. - * - * @param child View to add - */ - public void addView(View child) - { - if (child.getParent() != null) - { - ((ViewGroup) child.getParent()).removeView(child); - } - if (mRecyclerView.mAnimatingViewIndex >= 0) - { - addView(child, mRecyclerView.mAnimatingViewIndex); - } - else - { - addView(child, -1); - } - } - - /** - * Remove a view from the currently attached RecyclerView if needed. - * LayoutManagers should use this method to completely remove a child - * view that is no longer needed. LayoutManagers should strongly - * consider recycling removed views using - * {@link Recycler#recycleView(View)}. - * - * @param child View to remove - */ - public void removeView(View child) - { - final Adapter adapter = mRecyclerView.getAdapter(); - if (adapter != null) - { - adapter.onViewDetachedFromWindow(getChildViewHolderInt(child)); - } - mRecyclerView.onChildDetachedFromWindow(child); - mRecyclerView.removeView(child); - if (mRecyclerView.mAnimatingViewIndex >= 0) - { - mRecyclerView.mAnimatingViewIndex--; - } - } - - /** - * Remove a view from the currently attached RecyclerView if needed. - * LayoutManagers should use this method to completely remove a child - * view that is no longer needed. LayoutManagers should strongly - * consider recycling removed views using - * {@link Recycler#recycleView(View)}. - * - * @param index Index of the child view to remove - */ - public void removeViewAt(int index) - { - final View child = mRecyclerView.getChildAt(index); - if (child != null) - { - ViewGroup.LayoutParams lp = child.getLayoutParams(); - if (lp != null && lp instanceof RecyclerViewBase.LayoutParams) - { - RecyclerViewBase.LayoutParams rvLp = (RecyclerViewBase.LayoutParams) lp; - if (rvLp.mViewHolder != null) - { - ViewHolder vh = rvLp.mViewHolder; - if (vh.mViewType == ViewHolder.TYPE_FOOTER) - { - mRecyclerView.mState.mFooterCountInScreen--; - } - if (vh.mViewType == ViewHolder.TYPE_HEADERE) - { - mRecyclerView.mState.mHeaderCountInScreen--; - } - } - } - final Adapter adapter = mRecyclerView.getAdapter(); - if (adapter != null) - { - adapter.onViewDetachedFromWindow(getChildViewHolderInt(child)); - } - mRecyclerView.onChildDetachedFromWindow(child); - mRecyclerView.removeViewAt(index); - if (mRecyclerView.mAnimatingViewIndex >= 0) - { - mRecyclerView.mAnimatingViewIndex--; - } - } - } - - /** - * Remove all views from the currently attached RecyclerView. This will - * not recycle any of the affected views; the LayoutManager is - * responsible for doing so if desired. - */ - public void removeAllViews() - { - final Adapter adapter = mRecyclerView.getAdapter(); - // Only remove non-animating views - final int childCount = mRecyclerView.getChildCount() - mRecyclerView.mNumAnimatingViews; - - for (int i = 0; i < childCount; i++) - { - final View child = mRecyclerView.getChildAt(i); - if (adapter != null) - { - adapter.onViewDetachedFromWindow(getChildViewHolderInt(child)); - } - mRecyclerView.onChildDetachedFromWindow(child); - } - - for (int i = childCount - 1; i >= 0; i--) - { - mRecyclerView.removeViewAt(i); - if (mRecyclerView.mAnimatingViewIndex >= 0) - { - mRecyclerView.mAnimatingViewIndex--; - } - } - } - - /** - * Returns the adapter position of the item represented by the given - * View. - * - * @param view The view to query - * @return The adapter position of the item which is rendered by this - * View. - */ - public int getPosition(View view) - { - if (view == null || view.getLayoutParams() == null) - { - return NO_POSITION; - } - return ((RecyclerViewBase.LayoutParams) view.getLayoutParams()).getViewPosition(); - } - - /** - *

- * Finds the view which represents the given adapter position. - *

- *

- * This method traverses each child since it has no information about - * child order. Override this method to improve performance if your - * LayoutManager keeps data about child views. - *

- * - * @param position Position of the item in adapter - * @return The child view that represents the given position or null if - * the position is not visible - */ - public View findViewByPosition(int position) - { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) - { - View child = getChildAt(i); - if (getPosition(child) == position) - { - return child; - } - } - return null; - } - - public void detachView(View child) - { - if (DISPATCH_TEMP_DETACH) - { - // ViewCompat.dispatchStartTemporaryDetach(child); - } - if (child == null) - { - return; - } - if (child == mRecyclerView.findFocus()) - { - mRecyclerView.clearChildFocus(child); - } - if (child.hasFocus()) - { - child.clearFocus(); - } - mRecyclerView.detachViewFromParent(child); - } - - public void detachViewAt(int index) - { - if (DISPATCH_TEMP_DETACH) - { - // ViewCompat.dispatchStartTemporaryDetach(mRecyclerView.getChildAt(index)); - } - View child = mRecyclerView.getChildAt(index); - if (child == null) - { - return; - } - if (child == mRecyclerView.findFocus()) - { - mRecyclerView.clearChildFocus(child); - } - if (child instanceof IRecyclerViewFooter) - { - mRecyclerView.removeView(child); - } - else - { - mRecyclerView.detachViewFromParent(index); - } - if (mRecyclerView.mAnimatingViewIndex >= 0) - { - --mRecyclerView.mAnimatingViewIndex; - } - } - - public void attachView(View child, int index, LayoutParams lp) - { - mRecyclerView.attachViewToParent(child, index, lp); - if (mRecyclerView.mAnimatingViewIndex >= 0) - { - ++mRecyclerView.mAnimatingViewIndex; - } - if (DISPATCH_TEMP_DETACH) - { - // ViewCompat.dispatchFinishTemporaryDetach(child); - } - } - - public void attachView(View child, int index) - { - attachView(child, index, (LayoutParams) child.getLayoutParams()); - } - - public void attachView(View child) - { - attachView(child, -1); - } - - /** - * Finish removing a view that was previously temporarily - * {@link #detachView(View) detached}. - * - * @param child Detached child to remove - */ - public void removeDetachedView(View child) - { - mRecyclerView.removeDetachedView(child, false); - } - - /** - * Detach a child view and add it to a {@link Recycler Recycler's} scrap - * heap. - *

- *

- * Scrapping a view allows it to be rebound and reused to show updated - * or different data. - *

- * - * @param child Child to detach and scrap - * @param recycler Recycler to deposit the new scrap view into - */ - public void detachAndScrapView(View child, Recycler recycler) - { - detachView(child); - recycler.scrapView(child); - } - - /** - * Detach a child view and add it to a {@link Recycler Recycler's} scrap - * heap. - *

- *

- * Scrapping a view allows it to be rebound and reused to show updated - * or different data. - *

- * - * @param index Index of child to detach and scrap - * @param recycler Recycler to deposit the new scrap view into - */ - public void detachAndScrapViewAt(int index, Recycler recycler) - { - final View child = getChildAt(index); - detachViewAt(index); - recycler.scrapView(child); - } - - /** - * Remove a child view and recycle it using the given Recycler. - * - * @param child Child to remove and recycle - * @param recycler Recycler to use to recycle child - */ - public void removeAndRecycleView(View child, Recycler recycler) - { - removeView(child); - recycler.recycleView(child); - } - - /** - * Remove a child view and recycle it using the given Recycler. - * - * @param index Index of child to remove and recycle - * @param recycler Recycler to use to recycle child - */ - public void removeAndRecycleViewAt(int index, Recycler recycler) - { - final View view = getChildAt(index); - removeViewAt(index); - recycler.recycleView(view); - } - - /** - * Return the current number of child views attached to the parent - * RecyclerView. This does not include child views that were temporarily - * detached and/or scrapped. - * - * @return Number of attached children - */ - public int getChildCount() - { - return mRecyclerView != null ? mRecyclerView.getChildCount() - mRecyclerView.mNumAnimatingViews : 0; - } - - /** - * Return the child view at the given index - * - * @param index Index of child to return - * @return Child view at index - */ - public View getChildAt(int index) - { - return mRecyclerView != null ? mRecyclerView.getChildAt(index) : null; - } - - /** - * Return the width of the parent RecyclerView - * - * @return Width in pixels - */ - public int getWidth() - { - return mRecyclerView != null ? mRecyclerView.getWidth() : 0; - } - - /** - * Return the height of the parent RecyclerView - * - * @return Height in pixels - */ - public int getHeight() - { - return mRecyclerView != null ? mRecyclerView.getHeight() : 0; - } - - /** - * Return the left padding of the parent RecyclerView - * - * @return Padding in pixels - */ - public int getPaddingLeft() - { - return mRecyclerView != null ? mRecyclerView.getPaddingLeft() : 0; - } - - /** - * Return the top padding of the parent RecyclerView - * - * @return Padding in pixels - */ - public int getPaddingTop() - { - return mRecyclerView != null ? mRecyclerView.getPaddingTop() : 0; - } - - /** - * Return the right padding of the parent RecyclerView - * - * @return Padding in pixels - */ - public int getPaddingRight() - { - return mRecyclerView != null ? mRecyclerView.getPaddingRight() : 0; - } - - /** - * Return the bottom padding of the parent RecyclerView - * - * @return Padding in pixels - */ - public int getPaddingBottom() - { - return mRecyclerView != null ? mRecyclerView.getPaddingBottom() : 0; - } - - /** - * Return the start padding of the parent RecyclerView - * - * @return Padding in pixels - */ - // public int getPaddingStart() - // { - // return mRecyclerView != null ? - // ViewCompat.getPaddingStart(mRecyclerView) : 0; - // } - - /** - * Return the end padding of the parent RecyclerView - * - * @return Padding in pixels - */ - // public int getPaddingEnd() - // { - // return mRecyclerView != null ? - // ViewCompat.getPaddingEnd(mRecyclerView) : 0; - // } - - /** - * Returns true if the RecyclerView this LayoutManager is bound to has - * focus. - * - * @return True if the RecyclerView has focus, false otherwise. - * @see View#isFocused() - */ - public boolean isFocused() - { - return mRecyclerView != null && mRecyclerView.isFocused(); - } - - /** - * Returns true if the RecyclerView this LayoutManager is bound to has - * or contains focus. - * - * @return true if the RecyclerView has or contains focus - * @see View#hasFocus() - */ - public boolean hasFocus() - { - return mRecyclerView != null && mRecyclerView.hasFocus(); - } - - /** - * Return the number of items in the adapter bound to the parent - * RecyclerView - * - * @return Items in the bound adapter - */ - public int getItemCount() - { - final Adapter a = mRecyclerView != null ? mRecyclerView.getAdapter() : null; - return a != null ? a.getItemCount() : 0; - } - - /** - * Offset all child views attached to the parent RecyclerView by dx - * pixels along the horizontal axis. - * - * @param dx Pixels to offset by - */ - public void offsetChildrenHorizontal(int dx) - { - if (mRecyclerView != null) - { - mRecyclerView.offsetChildrenHorizontal(dx); - } - } - - /** - * Offset all child views attached to the parent RecyclerView by dy - * pixels along the vertical axis. - * - * @param dy Pixels to offset by - */ - public void offsetChildrenVertical(int dy) - { - if (mRecyclerView != null) - { - mRecyclerView.offsetChildrenVertical(dy); - } - } - - /** - * Temporarily detach and scrap all currently attached child views. - * Views will be scrapped into the given Recycler. The Recycler may - * prefer to reuse scrap views before other views that were previously - * recycled. - * - * @param recycler Recycler to scrap views into - */ - public void detachAndScrapAttachedViews(Recycler recycler) - { - if (mRecyclerView != null && mRecyclerView.needAdvancedStopDetachChildView()) - return; - // // 只有水印view时,不进行view摘除 - // if (mRecyclerView.mWaterMarkCustomView != null && mRecyclerView.mNeedWaterMark - // && (mRecyclerView.mForceWaterMark || mRecyclerView.mAdapter.getItemCount() <= 0)) - // { - // if (getChildCount() == 1 && getChildAt(0) == mRecyclerView.mWaterMarkCustomView) - // { - // return; - // } - // } - final int childCount = getChildCount(); - for (int i = childCount - 1; i >= 0; i--) - { - final View v = getChildAt(i); - detachViewAt(i); - if (v instanceof RecyclerViewItem) - { - recycler.scrapView(v); - } - } - } - - /** - * Recycles the scrapped views. - *

- * When a view is detached and removed, it does not trigger a ViewGroup - * invalidate. This is the expected behavior if scrapped views are used - * for animations. Otherwise, we need to call remove and invalidate - * RecyclerView to ensure UI updateStyle. - * - * @param recycler Recycler - * @param remove Whether scrapped views should be removed from ViewGroup - * or - * not. This method will invalidate RecyclerView if it - * removes any scrapped child. - */ - protected void removeAndRecycleScrapInt(Recycler recycler, boolean remove, boolean recycle) - { - final int scrapCount = recycler.getScrapCount(); - for (int i = 0; i < scrapCount; i++) - { - final View scrap = recycler.getScrapViewAt(i); - if (scrap instanceof RecyclerViewItem) - { - if (remove) - { - mRecyclerView.removeDetachedView(scrap, false); - } - if (recycle) - { - recycler.quickRecycleScrapView(scrap); - } - } - } - recycler.clearScrap(); - if (remove && scrapCount > 0) - { - mRecyclerView.invalidate(); - } - } - - /** - * Measure a child view using standard measurement policy, taking the - * padding of the parent RecyclerView and any added item decorations - * into account. - *

- *

- * If the RecyclerView can be scrolled in either dimension the caller - * may pass 0 as the widthUsed or heightUsed parameters as they will be - * irrelevant. - *

- * - * @param child Child view to measure - * @param widthUsed Width in pixels currently consumed by other views, - * if - * relevant - * @param heightUsed Height in pixels currently consumed by other views, - * if - * relevant - */ - public void measureChild(View child, int widthUsed, int heightUsed) - { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); - widthUsed += insets.left + insets.right; - heightUsed += insets.top + insets.bottom; - - final int widthSpec = getChildMeasureSpec(getWidth(), getPaddingLeft() + getPaddingRight() + widthUsed, lp.width, - canScrollHorizontally()); - final int heightSpec = getChildMeasureSpec(getHeight(), getPaddingTop() + getPaddingBottom() + heightUsed, lp.height, - canScrollVertically()); - child.measure(widthSpec, heightSpec); - } - - /** - * Measure a child view using standard measurement policy, taking the - * padding of the parent RecyclerView, any added item decorations and - * the child margins into account. - *

- *

- * If the RecyclerView can be scrolled in either dimension the caller - * may pass 0 as the widthUsed or heightUsed parameters as they will be - * irrelevant. - *

- * - * @param child Child view to measure - * @param widthUsed Width in pixels currently consumed by other views, - * if - * relevant - * @param heightUsed Height in pixels currently consumed by other views, - * if - * relevant - */ - public void measureChildWithMargins(View child, int widthUsed, int heightUsed) - { - LayoutParams lp = null; - if (child == null) - { - return; - } - if (child.getLayoutParams() != null) - { - lp = (LayoutParams) child.getLayoutParams(); - } - else - { - lp = generateDefaultLayoutParams(); - } - final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); - widthUsed += insets.left + insets.right; - heightUsed += insets.top + insets.bottom; - - int childWidth = lp.width; - int childHeight = lp.height; - // if (mRecyclerView.getAdapter() instanceof RecyclerAdapter) - // { - // boolean enableAutoItemHeight = ((RecyclerAdapter) mRecyclerView.getAdapter()).isAutoCalculateItemHeight(); - // if (enableAutoItemHeight && child instanceof RecyclerViewItem) - // { - // if (((RecyclerViewItem) child).getChildCount() > 0) - // { - // View contentView = ((RecyclerViewItem) child).getChildAt(0); - // childWidth = contentView.getMeasuredWidth(); - // childHeight = contentView.getMeasuredHeight(); - // } - // } - // } - - final int widthSpec = getChildMeasureSpec(getWidth(), getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin + widthUsed, - childWidth, canScrollHorizontally()); - final int heightSpec = getChildMeasureSpec(getHeight(), - getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin + heightUsed, childHeight, canScrollVertically()); - - child.measure(widthSpec, heightSpec); - } - - /** - * Calculate a MeasureSpec value for measuring a child view in one - * dimension. - * - * @param parentSize Size of the parent view where the child will be - * placed - * @param padding Total space currently consumed by other elements of - * parent - * @param childDimension Desired size of the child view, or - * MATCH_PARENT/WRAP_CONTENT. Generally obtained from the - * child view's LayoutParams - * @param canScroll true if the parent RecyclerView can scroll in this - * dimension - * @return a MeasureSpec value for the child view - */ - public static int getChildMeasureSpec(int parentSize, int padding, int childDimension, boolean canScroll) - { - int size = Math.max(0, parentSize - padding); - int resultSize = 0; - int resultMode = MeasureSpec.UNSPECIFIED; - - if (canScroll) - { - if (childDimension >= 0) - { - resultSize = childDimension; - resultMode = MeasureSpec.EXACTLY; - } - else - { - // MATCH_PARENT can't be applied since we can scroll in this - // dimension, wrap - // instead using UNSPECIFIED. - resultSize = 0; - resultMode = MeasureSpec.UNSPECIFIED; - } - } - else - { - if (childDimension >= 0) - { - resultSize = childDimension; - resultMode = MeasureSpec.EXACTLY; - } - else if (childDimension == LayoutParams.FILL_PARENT) - { - resultSize = size; - resultMode = MeasureSpec.EXACTLY; - } - else if (childDimension == LayoutParams.WRAP_CONTENT) - { - resultSize = size; - resultMode = MeasureSpec.AT_MOST; - } - } - return MeasureSpec.makeMeasureSpec(resultSize, resultMode); - } - - /** - * Returns the measured width of the given child, plus the additional - * size of any insets applied by {@link ItemDecoration ItemDecorations}. - * - * @param child Child view to query - * @return child's measured width plus ItemDecoration - * insets - * @see View#getMeasuredWidth() - */ - public int getDecoratedMeasuredWidth(View child) - { - final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; - return child.getMeasuredWidth() + insets.left + insets.right; - } - - /** - * Returns the measured height of the given child, plus the additional - * size of any insets applied by {@link ItemDecoration ItemDecorations}. - * - * @param child Child view to query - * @return child's measured height plus ItemDecoration - * insets - * @see View#getMeasuredHeight() - */ - public int getDecoratedMeasuredHeight(View child) - { - final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; - return child.getMeasuredHeight() + insets.top + insets.bottom; - } - - /** - * Lay out the given child view within the RecyclerView using - * coordinates that include any current {@link ItemDecoration - * ItemDecorations}. - *

- *

- * LayoutManagers should prefer working in sizes and coordinates that - * include item decoration insets whenever possible. This allows the - * LayoutManager to effectively ignore decoration insets within - * measurement and layout code. See the following methods: - *

- *
    - *
  • {@link #measureChild(View, int, int)}
  • - *
  • {@link #measureChildWithMargins(View, int, int)}
  • - *
  • {@link #getDecoratedLeft(View)}
  • - *
  • {@link #getDecoratedTop(View)}
  • - *
  • {@link #getDecoratedRight(View)}
  • - *
  • {@link #getDecoratedBottom(View)}
  • - *
  • {@link #getDecoratedMeasuredWidth(View)}
  • - *
  • {@link #getDecoratedMeasuredHeight(View)}
  • - *
- * - * @param child Child to lay out - * @param left Left edge, with item decoration insets included - * @param top Top edge, with item decoration insets included - * @param right Right edge, with item decoration insets included - * @param bottom Bottom edge, with item decoration insets included - * @see View#layout(int, int, int, int) - */ - public void layoutDecorated(View child, int left, int top, int right, int bottom) - { - final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; - child.layout(left + insets.left, top + insets.top, right - insets.right, bottom - insets.bottom); - } - - /** - * Returns the left edge of the given child view within its parent, - * offset by any applied {@link ItemDecoration ItemDecorations}. - * - * @param child Child to query - * @return Child left edge with offsets applied - */ - public int getDecoratedLeft(View child) - { - final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; - return child.getLeft() - insets.left; - } - - /** - * Returns the top edge of the given child view within its parent, - * offset by any applied {@link ItemDecoration ItemDecorations}. - * - * @param child Child to query - * @return Child top edge with offsets applied - */ - public int getDecoratedTop(View child) - { - final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; - return child.getTop() - insets.top; - } - - /** - * Returns the right edge of the given child view within its parent, - * offset by any applied {@link ItemDecoration ItemDecorations}. - * - * @param child Child to query - * @return Child right edge with offsets applied - */ - public int getDecoratedRight(View child) - { - final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; - return child.getRight() + insets.right; - } - - /** - * Returns the bottom edge of the given child view within its parent, - * offset by any applied {@link ItemDecoration ItemDecorations}. - * - * @param child Child to query - * @return Child bottom edge with offsets applied - */ - public int getDecoratedBottom(View child) - { - final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; - return child.getBottom() + insets.bottom; - } - - /** - * Called when searching for a focusable view in the given direction has - * failed for the current content of the RecyclerView. - *

- *

- * This is the LayoutManager's opportunity to populate views in the - * given direction to fulfill the request if it can. The LayoutManager - * should attach and return the view to be focused. The default - * implementation returns null. - *

- * - * @param focused The currently focused view - * @param direction One of {@link View#FOCUS_UP}, - * {@link View#FOCUS_DOWN}, {@link View#FOCUS_LEFT}, - * {@link View#FOCUS_RIGHT}, {@link View#FOCUS_BACKWARD}, - * {@link View#FOCUS_FORWARD} or - * 0 for not applicable - * @param recycler The recycler to use for obtaining views for currently - * offscreen items - * @param state Transient state of RecyclerView - * @return The chosen view to be focused - */ - public View onFocusSearchFailed(View focused, int direction, Recycler recycler, State state) - { - return null; - } - - public View onInterceptFocusSearch(View focused, int direction) - { - return null; - } - - /** - * Called when a child of the RecyclerView wants a particular rectangle - * to be positioned onto the screen. See - * {@link ViewParent#requestChildRectangleOnScreen(View, Rect, boolean)} - * for more details. - *

- *

- * The base implementation will attempt to perform a standard - * programmatic scroll to bring the given rect into view, within the - * padded area of the RecyclerView. - *

- * - * @param child The direct child making the request. - * @param rect The rectangle in the child's coordinates the child wishes - * to be on the screen. - * @param immediate True to forbid animated or delayed scrolling, false - * otherwise - * @return Whether the group scrolled to handle the operation - */ - public boolean requestChildRectangleOnScreen(RecyclerViewBase parent, View child, Rect rect, boolean immediate) - { - try - { - final int parentLeft = getPaddingLeft(); - final int parentTop = getPaddingTop(); - final int parentRight = getWidth() - getPaddingRight(); - final int parentBottom = getHeight() - getPaddingBottom(); - final int childLeft = child.getLeft() + rect.left; - final int childTop = child.getTop() + rect.top; - final int childRight = childLeft + rect.right; - final int childBottom = childTop + rect.bottom; - - final int offScreenLeft = Math.min(0, childLeft - parentLeft); - final int offScreenTop = Math.min(0, childTop - parentTop); - final int offScreenRight = Math.max(0, childRight - parentRight); - final int offScreenBottom = Math.max(0, childBottom - parentBottom); - - // Favor the "start" layout direction over the end when bringing - // one - // side or the other - // of a large rect into view. - final int dx; - { - dx = offScreenLeft != 0 ? offScreenLeft : offScreenRight; - } - - // Favor bringing the top into view over the bottom - final int dy = offScreenTop != 0 ? offScreenTop : offScreenBottom; - - if (dx != 0 || dy != 0) - { - if (immediate) - { - parent.scrollBy(dx, dy); - } - else - { - parent.smoothScrollBy(dx, dy, false); - } - if (parent.needNotifyFooter && !parent.checkNotifyFooterOnRelease) - { - // Log.d("leo", "ontouchevent needNotify" + ",offsetY=" - // + mOffsetY + "mTotalLength-height=" - // + (mAdapter.getListTotalHeight() - getHeight())); - parent.needNotifyFooter = false; - parent.mRecycler.notifyLastFooterAppeared(); - } - return true; - } - return false; - } - catch (StackOverflowError e) - { - return false; - } - } - - /** - * Called when a descendant view of the RecyclerView requests focus. - *

- *

- * A LayoutManager wishing to keep focused views aligned in a specific - * portion of the view may implement that behavior in an override of - * this method. - *

- *

- *

- * If the LayoutManager executes different behavior that should override - * the default behavior of scrolling the focused child on screen instead - * of running alongside it, this method should return true. - *

- * - * @param parent The RecyclerView hosting this LayoutManager - * @param child Direct child of the RecyclerView containing the newly - * focused view - * @param focused The newly focused view. This may be the same view as - * child - * @return true if the default scroll behavior should be suppressed - */ - public boolean onRequestChildFocus(RecyclerViewBase parent, View child, View focused) - { - return false; - } - - public void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter) - { - } - - /** - * Called to populate focusable views within the RecyclerView. - *

- *

- * The LayoutManager implementation should return true if - * the default behavior of - * {@link ViewGroup#addFocusables(ArrayList, int)} should be - * suppressed. - *

- *

- *

- * The default implementation returns false to trigger - * RecyclerView to fall back to the default ViewGroup behavior. - *

- * - * @param recyclerView The RecyclerView hosting this LayoutManager - * @param views List of output views. This method should add valid - * focusable views to this list. - * @param direction One of {@link View#FOCUS_UP}, - * {@link View#FOCUS_DOWN}, {@link View#FOCUS_LEFT}, - * {@link View#FOCUS_RIGHT}, {@link View#FOCUS_BACKWARD}, - * {@link View#FOCUS_FORWARD} - * @param focusableMode The type of focusables to be added. - * @return true to suppress the default behavior, false to add default - * focusables after this method returns. - * @see #FOCUSABLES_ALL - * @see #FOCUSABLES_TOUCH_MODE - */ - public boolean onAddFocusables(RecyclerViewBase recyclerView, ArrayList views, int direction, int focusableMode) - { - return false; - } - - /** - * Called when items have been added to the adapter. The LayoutManager - * may choose to requestLayout if the inserted items would require - * refreshing the currently visible set of child views. (e.g. currently - * empty space would be filled by appended items, etc.) - * - * @param recyclerView - * @param positionStart - * @param itemCount - */ - public void onItemsAdded(RecyclerViewBase recyclerView, int positionStart, int itemCount) - { - } - - /** - * Called when items have been removed from the adapter. - * - * @param recyclerView - * @param positionStart - * @param itemCount - */ - public void onItemsRemoved(RecyclerViewBase recyclerView, int positionStart, int itemCount) - { - } - - public int computeHorizontalScrollExtent(State state) - { - return 0; - } - - public int computeHorizontalScrollOffset(State state) - { - return 0; - } - - public int computeHorizontalScrollRange(State state) - { - return 0; - } - - public int computeVerticalScrollExtent(State state) - { - return 0; - } - - public int computeVerticalScrollOffset(State state) - { - return 0; - } - - public int computeVerticalScrollRange(State state) - { - return 0; - } - - /** - * Measure the attached RecyclerView. Implementations must call - * {@link #setMeasuredDimension(int, int)} before returning. - *

- *

- * The default implementation will handle EXACTLY measurements and - * respect the minimum width and height properties of the host - * RecyclerView if measured as UNSPECIFIED. AT_MOST measurements will be - * treated as EXACTLY and the RecyclerView will consume all available - * space. - *

- * - * @param recycler Recycler - * @param state Transient state of RecyclerView - * @param widthSpec Width {@link MeasureSpec} - * @param heightSpec Height {@link MeasureSpec} - */ - public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) - { - final int widthMode = MeasureSpec.getMode(widthSpec); - final int heightMode = MeasureSpec.getMode(heightSpec); - final int widthSize = MeasureSpec.getSize(widthSpec); - final int heightSize = MeasureSpec.getSize(heightSpec); - - int width = 0; - int height = 0; - - switch (widthMode) - { - case MeasureSpec.EXACTLY: - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - default: - width = getMinimumWidth(); - break; - } - - switch (heightMode) - { - case MeasureSpec.EXACTLY: - case MeasureSpec.AT_MOST: - height = heightSize; - break; - case MeasureSpec.UNSPECIFIED: - default: - height = getMinimumHeight(); - break; - } - - setMeasuredDimension(width, height); - } - - /** - * {@link View#setMeasuredDimension(int, int) Set the measured - * dimensions} of the host RecyclerView. - * - * @param widthSize Measured width - * @param heightSize Measured height - */ - public void setMeasuredDimension(int widthSize, int heightSize) - { - mRecyclerView.setMeasuredDimension(widthSize, heightSize); - } - - /** - * @return The host RecyclerView's {@link View#getMinimumWidth()} - */ - public int getMinimumWidth() - { - return ViewCompatTool.getMinimumWidth(mRecyclerView); - } - - /** - * @return The host RecyclerView's {@link View#getMinimumHeight()} - */ - public int getMinimumHeight() - { - return ViewCompatTool.getMinimumHeight(mRecyclerView); - } - - /** - *

- * Called when the LayoutManager should save its state. This is a good - * time to save your scroll position, configuration and anything else - * that may be required to restore the same layout state if the - * LayoutManager is recreated. - *

- *

- * RecyclerView does NOT verify if the LayoutManager has changed between - * state save and restore. This will let you share information between - * your LayoutManagers but it is also your responsibility to make sure - * they use the same parcelable class. - *

- * - * @return Necessary information for LayoutManager to be able to restore - * its state - */ - public Parcelable onSaveInstanceState() - { - return null; - } - - public void onRestoreInstanceState(Parcelable state) - { - - } - - void stopSmoothScroller() - { - if (mSmoothScroller != null) - { - mSmoothScroller.stop(); - } - } - - /* private */void onSmoothScrollerStopped(SmoothScroller smoothScroller) - { - if (mSmoothScroller == smoothScroller) - { - mSmoothScroller = null; - } - } - - void removeAndRecycleAllViews(Recycler recycler) - { - for (int i = getChildCount() - 1; i >= 0; i--) - { - removeAndRecycleViewAt(i, recycler); - } - } - - public View getFirstItemBeforeOffset(int offset) - { - final int count = getChildCount(); - for (int i = 0; i < count; i++) - { - View v = getChildAt(i); - if (getDecoratedStart(v) < offset) - { - return v; - } - } - return null; - } - - public void calculateOffsetMap(SparseIntArray offsetMap, int startOffset) - { - } - - public int getLayoutType() - { - return LAYOUT_TYPE_LIST; - } - - public RecyclerViewBase.LayoutParams onCreateItemLayoutParams(RecyclerView.ViewHolderWrapper holder, int position, int layoutType, - int cardType) - { - return new RecyclerViewBase.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - } - - public void clear() - { - - } - - public int getTotalHeight() - { - return Integer.MIN_VALUE; - } - } - - public static abstract class ItemDecoration - { - /** - * Draw any appropriate decorations into the Canvas supplied to the - * RecyclerView. Any content drawn by this method will be drawn before - * the item views are drawn, and will thus appear underneath the views. - * - * @param c Canvas to draw into - * @param parent RecyclerView this ItemDecoration is drawing into - */ - public void onDraw(Canvas c, RecyclerViewBase parent) - { - } - - /** - * Draw any appropriate decorations into the Canvas supplied to the - * RecyclerView. Any content drawn by this method will be drawn after - * the item views are drawn and will thus appear over the views. - * - * @param c Canvas to draw into - * @param parent RecyclerView this ItemDecoration is drawing into - */ - public void onDrawOver(Canvas c, RecyclerViewBase parent) - { - } - - /** - * Retrieve any offsets for the given item. Each field of - * outRect specifies the number of pixels that the item - * view should be inset by, similar to padding or margin. The default - * implementation sets the bounds of outRect to 0 and returns. - *

- *

- * If this ItemDecoration does not affect the positioning of item views - * it should set all four fields of outRect (left, top, - * right, bottom) to zero before returning. - *

- * - * @param outRect Rect to receive the output. - * @param itemPosition Adapter position of the item to offset - * @param parent RecyclerView this ItemDecoration is decorating - */ - public void getItemOffsets(Rect outRect, int itemPosition, RecyclerViewBase parent) - { - outRect.set(0, 0, 0, 0); - } - } - - /** - * An OnItemTouchListener allows the application to intercept touch events - * in progress at the view hierarchy level of the RecyclerView before those - * touch events are considered for RecyclerView's own scrolling behavior. - *

- *

- * This can be useful for applications that wish to implement various forms - * of gestural manipulation of item views within the RecyclerView. - * OnItemTouchListeners may intercept a touch interaction already in - * progress even if the RecyclerView is already handling that gesture stream - * itself for the purposes of scrolling. - *

- */ - public interface OnItemTouchListener - { - /** - * Silently observe and/or take over touch events sent to the - * RecyclerView before they are handled by either the RecyclerView - * itself or its child views. - *

- *

- * The onInterceptTouchEvent methods of each attached - * OnItemTouchListener will be run in the order in which each listener - * was added, before any other touch processing by the RecyclerView - * itself or child views occurs. - *

- * - * @param e MotionEvent describing the touch event. All coordinates - * are in the RecyclerView's coordinate system. - * @return true if this OnItemTouchListener wishes to begin intercepting - * touch events, false to continue with the current behavior and - * continue observing future events in the gesture. - */ - boolean onInterceptTouchEvent(RecyclerViewBase rv, MotionEvent e); - - /** - * Process a touch event as part of a gesture that was claimed by - * returning true from a previous call to {@link #onInterceptTouchEvent} - * . - * - * @param e MotionEvent describing the touch event. All coordinates - * are in the RecyclerView's coordinate system. - */ - void onTouchEvent(RecyclerViewBase rv, MotionEvent e); - } - - public interface OnScrollListener - { - void onScrollStateChanged(int oldState, int newState); - - void onScrolled(int dx, int dy); - } - - public interface OnScrollFinishListener - { - void onScrollFinished(); - } - - // public interface RecyclerListener - // { - // - // /** - // * This method is called whenever the view in the ViewHolder is - // * recycled. - // * - // * @param holder The ViewHolder containing the view that was recycled - // */ - // public void onViewRecycled(ViewHolder holder); - // } - - /** - * A ViewHolder describes an item view and metadata about its place within - * the RecyclerView. - *

- *

- * {@link Adapter} implementations should subclass ViewHolder and add fields - * for caching potentially expensive {@link View#findViewById(int)} results. - *

- *

- *

- * While {@link LayoutParams} belong to the {@link LayoutManager}, - * {@link ViewHolder ViewHolders} belong to the adapter. Adapters should - * feel free to use their own custom ViewHolder implementations to store - * data that makes binding view contents easier. Implementations should - * assume that individual item views will hold strong references to - * ViewHolder objects and that RecyclerView - * instances may hold strong references to extra off-screen item views for - * caching purposes - *

- */ - public static abstract class ViewHolder - { - public final View itemView; - public View mContent; - public ContentHolder mContentHolder; - public int mPosition = NO_POSITION; - public int mOldPosition = NO_POSITION; - public long mItemId = NO_ID; - public int mItemViewType = INVALID_TYPE; - - public static final int TYPE_HEADERE = -1; - public static final int TYPE_FOOTER = -2; - public static final int TYPE_NORMAL = -3; - public static final int TYPE_CUSTOM_HEADERE = -4; - public static final int TYPE_CUSTOM_FOOTER = -5; - public int mViewType = TYPE_NORMAL; - /** - * This ViewHolder has been bound to a position; mPosition, mItemId and - * mItemViewType are all valid. - */ - protected static final int FLAG_BOUND = 1; - - /** - * The data this ViewHolder's view reflects is stale and needs to be - * rebound by the adapter. mPosition and mItemId are consistent. - */ - public static final int FLAG_UPDATE = 1 << 1; - - /** - * This ViewHolder's data is invalid. The identity implied by mPosition - * and mItemId are not to be trusted and may no longer match the item - * view type. This ViewHolder must be fully rebound to different data. - */ - protected static final int FLAG_INVALID = 1 << 2; - - /** - * This ViewHolder points at data that represents an item previously - * removed from the data set. Its view may still be used for things like - * outgoing animations. - */ - static final int FLAG_REMOVED = 1 << 3; - - /** - * This ViewHolder should not be recycled. This flag is set via - * setIsRecyclable() and is intended to keep views around during - * animations. - */ - static final int FLAG_NOT_RECYCLABLE = 1 << 4; - - protected int mFlags; - - public boolean mForceBind = false; - - public boolean mBindNextTime = false; - - /* private */int mIsRecyclableCount = 0; - - // If non-null, view is currently considered scrap and may be reused for - // other data by the - // scrap container. - /* private */Recycler mScrapContainer = null; - - public boolean mPosDirty; - - protected RecyclerViewBase mParent; - - /** - * 用于view的复用时,不会在View的缓存池里面随机取view,根据reuseKey来获取最适合的view - * 尽量保证刷新list的时候,用到自己之前的那个view,这样不会导致闪烁的问题 - */ - public String mHolderReuseKey = null; - - public ViewHolder(View itemView, RecyclerViewBase rv) - { - this.mParent = rv; - if (itemView == null) - { - throw new IllegalArgumentException("itemView may not be null"); - } - this.itemView = itemView; - } - - public void offsetPosition(int offset) - { - if (mOldPosition == NO_POSITION) - { - mOldPosition = mPosition; - } - mPosition += offset; - } - - void clearOldPosition() - { - mOldPosition = NO_POSITION; - } - - public int getPosition() - { - return mOldPosition == NO_POSITION ? mPosition : mOldPosition; - } - - public final long getItemId() - { - return mItemId; - } - - public final int getItemViewType() - { - return mItemViewType; - } - - public final void setItemViewType(int type) - { - mItemViewType = type; - } - - boolean isScrap() - { - return mScrapContainer != null; - } - - void unScrap() - { - mScrapContainer.unscrapView(this); - mScrapContainer = null; - } - - public void setScrapContainer(Recycler recycler) - { - mScrapContainer = recycler; - } - - public boolean isInvalid() - { - return (mFlags & FLAG_INVALID) != 0; - } - - public boolean needsUpdate() - { - return (mFlags & FLAG_UPDATE) != 0; - } - - public boolean isBound() - { - return (mFlags & FLAG_BOUND) != 0; - } - - public boolean isRemoved() - { - return (mFlags & FLAG_REMOVED) != 0; - } - - void setFlags(int flags, int mask) - { - mFlags = (mFlags & ~mask) | (flags & mask); - } - - public void addFlags(int flags) - { - mFlags |= flags; - } - - public void clearFlagsForSharedPool() - { - mFlags = 0; - } - - @Override - public String toString() - { - final StringBuilder sb = new StringBuilder("ViewHolder{" + Integer.toHexString(hashCode()) + " position=" + mPosition + " id=" + mItemId); - if (isScrap()) - sb.append(" scrap"); - if (isInvalid()) - sb.append(" invalid"); - if (!isBound()) - sb.append(" unbound"); - if (needsUpdate()) - sb.append(" updateStyle"); - if (isRemoved()) - sb.append(" removed"); - sb.append(" type=" + mItemViewType); - sb.append("}"); - return sb.toString(); - } - - /** - * Informs the recycler whether this item can be recycled. Views which - * are not recyclable will not be reused for other items until - * setIsRecyclable() is later set to true. Calls to setIsRecyclable() - * should always be paired (one call to setIsRecyclabe(false) should - * always be matched with a later call to setIsRecyclable(true)). Pairs - * of calls may be nested, as the state is internally reference-counted. - * - * @param recyclable Whether this item is available to be recycled. - * Default - * value is true. - */ - public final void setIsRecyclable(boolean recyclable) - { - mIsRecyclableCount = recyclable ? mIsRecyclableCount - 1 : mIsRecyclableCount + 1; - if (mIsRecyclableCount < 0) - { - mIsRecyclableCount = 0; - // Log.e(VIEW_LOG_TAG, "isRecyclable decremented below 0: " + - // "unmatched pair of setIsRecyable() calls"); - } - else if (!recyclable && mIsRecyclableCount == 1) - { - mFlags |= FLAG_NOT_RECYCLABLE; - } - else if (recyclable && mIsRecyclableCount == 0) - { - mFlags &= ~FLAG_NOT_RECYCLABLE; - } - } - - /** - * @return true if this item is available to be recycled, false - * otherwise. - * @see {@link #setIsRecyclable(boolean)} - */ - public final boolean isRecyclable() - { - return (mFlags & FLAG_NOT_RECYCLABLE) == 0; - } - - public abstract void inTraversals(int tracersalPurpose); - - public boolean canChangeOrder() - { - return false; - } - } - - /** - * Queued operation to happen when child views are updated. - */ - public static class UpdateOp - { - public static final int ADD = 0; - public static final int REMOVE = 1; - public static final int UPDATE = 2; - static final int POOL_SIZE = 30; - - public int cmd; - public int positionStart; - public int itemCount; - public ArrayList mRemovePositions = null; - - public UpdateOp(int cmd, int positionStart, int itemCount) - { - this.cmd = cmd; - this.positionStart = positionStart; - this.itemCount = itemCount; - } - } - - public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount) - { - UpdateOp op = mUpdateOpPool.acquire(); - if (op == null) - { - op = new UpdateOp(cmd, positionStart, itemCount); - } - else - { - op.cmd = cmd; - op.positionStart = positionStart; - op.itemCount = itemCount; - op.mRemovePositions = null; - } - return op; - } - - void recycleUpdateOp(UpdateOp op) - { - mUpdateOpPool.release(op); - } - - public static class LayoutParams extends MarginLayoutParams - { - public ViewHolder mViewHolder; - protected final Rect mDecorInsets = new Rect(); - protected boolean mInsetsDirty = true; - - public LayoutParams(Context c, AttributeSet attrs) - { - super(c, attrs); - } - - public LayoutParams(int width, int height) - { - super(width, height); - } - - public LayoutParams(MarginLayoutParams source) - { - super(source); - } - - public LayoutParams(ViewGroup.LayoutParams source) - { - super(source); - } - - public LayoutParams(LayoutParams source) - { - super((ViewGroup.LayoutParams) source); - } - - /** - * Returns true if the view this LayoutParams is attached to needs to - * have its content updated from the corresponding adapter. - * - * @return true if the view should have its content updated - */ - public boolean viewNeedsUpdate() - { - if (mViewHolder == null) - { - return false; - } - return mViewHolder.needsUpdate(); - } - - /** - * Returns true if the view this LayoutParams is attached to is now - * representing potentially invalid data. A LayoutManager should - * scrap/recycle it. - * - * @return true if the view is invalid - */ - public boolean isViewInvalid() - { - if (mViewHolder == null) - { - return false; - } - return mViewHolder.isInvalid(); - } - - /** - * Returns true if the adapter data item corresponding to the view this - * LayoutParams is attached to has been removed from the data set. A - * LayoutManager may choose to treat it differently in order to animate - * its outgoing or disappearing state. - * - * @return true if the item the view corresponds to was removed from the - * data set - */ - public boolean isItemRemoved() - { - if (mViewHolder == null) - { - return true; - } - return mViewHolder.isRemoved(); - } - - /** - * Returns the position that the view this LayoutParams is attached to - * corresponds to. - * - * @return the adapter position this view was bound from - */ - public int getViewPosition() - { - if (mViewHolder == null) - { - return 0; - } - return mViewHolder.mPosition; - } - } - - /** - * Observer base class for watching changes to an {@link Adapter}. See - * {@link Adapter#registerAdapterDataObserver(AdapterDataObserver)}. - */ - public static abstract class AdapterDataObserver - { - public void onChanged() - { - // Do nothing - } - - public void onItemRangeChanged(int positionStart, int itemCount) - { - // do nothing - } - - // public void onItemRangeChanged(int positionStart, int itemCount, Object payload) - // { - // // do nothing - // } - - public void onItemRangeInserted(int positionStart, int itemCount) - { - // do nothing - } - - public void onItemRangeRemoved(int positionStart, int itemCount) - { - // do nothing - } - - public void onItemsRemoved(ArrayList removeItemPositions) - { - - } - } - - public static abstract class SmoothScroller - { - - /* private */int mTargetPosition = RecyclerViewBase.NO_POSITION; - - /* private */RecyclerViewBase mRecyclerView; - - /* private */LayoutManager mLayoutManager; - - /* private */boolean mPendingInitialRun; - - /* private */boolean mRunning; - - /* private */View mTargetView; - - /* private */final Action mRecyclingAction; - - public SmoothScroller() - { - mRecyclingAction = new Action(0, 0); - } - - void start(RecyclerViewBase recyclerView, LayoutManager layoutManager) - { - mRecyclerView = recyclerView; - mLayoutManager = layoutManager; - if (mTargetPosition == RecyclerViewBase.NO_POSITION) - { - throw new IllegalArgumentException("Invalid target position"); - } - mRecyclerView.mState.mTargetPosition = mTargetPosition; - mRunning = true; - mPendingInitialRun = true; - mTargetView = findViewByPosition(getTargetPosition()); - onStart(); - mRecyclerView.mViewFlinger.postOnAnimation(); - } - - public void setTargetPosition(int targetPosition) - { - mTargetPosition = targetPosition; - } - - /** - * @return The LayoutManager to which this SmoothScroller is attached - */ - public LayoutManager getLayoutManager() - { - return mLayoutManager; - } - - final protected void stop() - { - if (!mRunning) - { - return; - } - onStop(); - mRecyclerView.mState.mTargetPosition = RecyclerViewBase.NO_POSITION; - mTargetView = null; - mTargetPosition = RecyclerViewBase.NO_POSITION; - mPendingInitialRun = false; - mRunning = false; - // trigger a cleanup - mLayoutManager.onSmoothScrollerStopped(this); - // clear references to avoid any potential leak by a custom smooth - // scroller - mLayoutManager = null; - mRecyclerView = null; - } - - /** - * Returns true if SmoothScroller has beens started but has not received - * the first animation callback yet. - * - * @return True if this SmoothScroller is waiting to start - */ - public boolean isPendingInitialRun() - { - return mPendingInitialRun; - } - - /** - * @return True if SmoothScroller is currently active - */ - public boolean isRunning() - { - return mRunning; - } - - public int getTargetPosition() - { - return mTargetPosition; - } - - /* private */void onAnimation(int dx, int dy) - { - if (!mRunning || mTargetPosition == RecyclerViewBase.NO_POSITION) - { - stop(); - } - mPendingInitialRun = false; - if (mTargetView != null) - { - // verify target position - if (getChildPosition(mTargetView) == mTargetPosition) - { - onTargetFound(mTargetView, mRecyclerView.mState, mRecyclingAction); - mRecyclingAction.runInNecessary(mRecyclerView); - stop(); - } - else - { - // Log.e(TAG, - // "Passed over target position while smooth scrolling."); - mTargetView = null; - } - } - if (mRunning) - { - onSeekTargetStep(dx, dy, mRecyclerView.mState, mRecyclingAction); - mRecyclingAction.runInNecessary(mRecyclerView); - } - } - - public int getChildPosition(View view) - { - return mRecyclerView.getChildPosition(view); - } - - public int getChildCount() - { - return mRecyclerView.getChildCount(); - } - - public View findViewByPosition(int position) - { - return mRecyclerView.mLayout.findViewByPosition(position); - } - - public void instantScrollToPosition(int position) - { - mRecyclerView.scrollToPosition(position); - } - - protected void onChildAttachedToWindow(View child) - { - if (getChildPosition(child) == getTargetPosition()) - { - mTargetView = child; - if (DEBUG) - { - // Log.d(TAG, "smooth scroll target view has been attached"); - } - } - } - - /** - * Normalizes the vector. - * - * @param scrollVector The vector that points to the target scroll - * position - */ - protected void normalize(PointF scrollVector) - { - final double magnitute = Math.sqrt(scrollVector.x * scrollVector.x + scrollVector.y * scrollVector.y); - scrollVector.x /= magnitute; - scrollVector.y /= magnitute; - } - - /** - * Called when smooth scroll is started. This might be a good time to do - * setup. - */ - abstract protected void onStart(); - - /** - * Called when smooth scroller is stopped. This is a good place to - * cleanup your state etc. - * - * @see #stop() - */ - abstract protected void onStop(); - - /** - *

- * RecyclerView will call this method each time it scrolls until it can - * find the target position in the layout. - *

- *

- * SmoothScroller should check dx, dy and if scroll should be changed, - * updateStyle the provided {@link Action} to define the next scroll. - *

- * - * @param dx Last scroll amount horizontally - * @param dy Last scroll amount verticaully - * @param state Transient state of RecyclerView - * @param action If you want to trigger a new smooth scroll and cancel - * the - * previous one, updateStyle this object. - */ - abstract protected void onSeekTargetStep(int dx, int dy, State state, Action action); - - /** - * Called when the target position is laid out. This is the last - * callback SmoothScroller will receive and it should updateStyle the - * provided {@link Action} to define the scroll details towards the - * target view. - * - * @param targetView The view element which render the target position. - * @param state Transient state of RecyclerView - * @param action Action instance that you should updateStyle to define - * final - * scroll action towards the targetView - * @return An {@link Action} to finalize the smooth scrolling - */ - abstract protected void onTargetFound(View targetView, State state, Action action); - - /** - * Holds information about a smooth scroll request by a - * {@link SmoothScroller}. - */ - public static class Action - { - - public static final int UNDEFINED_DURATION = Integer.MIN_VALUE; - - /* private */int mDx; - - /* private */int mDy; - - /* private */int mDuration; - - /* private */Interpolator mInterpolator; - - /* private */boolean changed = false; - - // we track this variable to inform custom implementer if they are - // updating the action - // in every animation callback - /* private */int consecutiveUpdates = 0; - - /** - * @param dx Pixels to scroll horizontally - * @param dy Pixels to scroll vertically - */ - public Action(int dx, int dy) - { - this(dx, dy, UNDEFINED_DURATION, null); - } - - /** - * @param dx Pixels to scroll horizontally - * @param dy Pixels to scroll vertically - * @param duration Duration of the animation in milliseconds - */ - public Action(int dx, int dy, int duration) - { - this(dx, dy, duration, null); - } - - /** - * @param dx Pixels to scroll horizontally - * @param dy Pixels to scroll vertically - * @param duration Duration of the animation in milliseconds - * @param interpolator Interpolator to be used when calculating - * scroll - * position in each animation step - */ - public Action(int dx, int dy, int duration, Interpolator interpolator) - { - mDx = dx; - mDy = dy; - mDuration = duration; - mInterpolator = interpolator; - } - - /* private */void runInNecessary(RecyclerViewBase recyclerView) - { - if (changed) - { - validate(); - if (mInterpolator == null) - { - if (mDuration == UNDEFINED_DURATION) - { - recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, false); - } - else - { - recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, false); - } - } - else - { - recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator, false); - } - consecutiveUpdates++; - if (consecutiveUpdates > 10) - { - // A new action is being set in every animation step. - // This looks like a bad - // implementation. Inform developer. - // Log.e(TAG, - // "Smooth Scroll action is being updated too frequently. Make sure" - // + " you are not changing it unless necessary"); - } - changed = false; - } - else - { - consecutiveUpdates = 0; - } - } - - /* private */void validate() - { - if (mInterpolator != null && mDuration < 1) - { - throw new IllegalStateException("If you provide an interpolator, you must" + " set a positive duration"); - } - else if (mDuration < 1) - { - throw new IllegalStateException("Scroll duration must be a positive number"); - } - } - - public int getDx() - { - return mDx; - } - - public void setDx(int dx) - { - changed = true; - mDx = dx; - } - - public int getDy() - { - return mDy; - } - - public void setDy(int dy) - { - changed = true; - mDy = dy; - } - - public int getDuration() - { - return mDuration; - } - - public void setDuration(int duration) - { - changed = true; - mDuration = duration; - } - - public Interpolator getInterpolator() - { - return mInterpolator; - } - - /** - * Sets the interpolator to calculate scroll steps - * - * @param interpolator The interpolator to use. If you specify an - * interpolator, you must also set the duration. - * @see #setDuration(int) - */ - public void setInterpolator(Interpolator interpolator) - { - changed = true; - mInterpolator = interpolator; - } - - /** - * Updates the action with given parameters. - * - * @param dx Pixels to scroll horizontally - * @param dy Pixels to scroll vertically - * @param duration Duration of the animation in milliseconds - * @param interpolator Interpolator to be used when calculating - * scroll - * position in each animation step - */ - public void update(int dx, int dy, int duration, Interpolator interpolator) - { - mDx = dx; - mDy = dy; - mDuration = duration; - mInterpolator = interpolator; - changed = true; - } - } - } - - static class AdapterDataObservable extends Observable - { - public boolean hasObservers() - { - return !mObservers.isEmpty(); - } - - public void notifyChanged() - { - // since onChanged() is implemented by the app, it could do - // anything, including - // removing itself from {@link mObservers} - and that could cause - // problems if - // an iterator is used on the ArrayList {@link mObservers}. - // to avoid such problems, just march thru the list in the reverse - // order. - for (int i = mObservers.size() - 1; i >= 0; i--) - { - mObservers.get(i).onChanged(); - } - } - - public void notifyItemRangeChanged(int positionStart, int itemCount) - { - // since onItemRangeChanged() is implemented by the app, it could do - // anything, including - // removing itself from {@link mObservers} - and that could cause - // problems if - // an iterator is used on the ArrayList {@link mObservers}. - // to avoid such problems, just march thru the list in the reverse - // order. - for (int i = mObservers.size() - 1; i >= 0; i--) - { - mObservers.get(i).onItemRangeChanged(positionStart, itemCount); - } - } - - // public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) - // { - // // since onItemRangeChanged() is implemented by the app, it could do - // // anything, including - // // removing itself from {@link mObservers} - and that could cause - // // problems if - // // an iterator is used on the ArrayList {@link mObservers}. - // // to avoid such problems, just march thru the list in the reverse - // // order. - // for (int i = mObservers.size() - 1; i >= 0; i--) - // { - // mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload); - // } - // } - - public void notifyItemRangeInserted(int positionStart, int itemCount) - { - // since onItemRangeInserted() is implemented by the app, it could - // do anything, - // including removing itself from {@link mObservers} - and that - // could cause problems if - // an iterator is used on the ArrayList {@link mObservers}. - // to avoid such problems, just march thru the list in the reverse - // order. - for (int i = mObservers.size() - 1; i >= 0; i--) - { - mObservers.get(i).onItemRangeInserted(positionStart, itemCount); - } - } - - public void notifyItemRangeRemoved(int positionStart, int itemCount) - { - // since onItemRangeRemoved() is implemented by the app, it could do - // anything, including - // removing itself from {@link mObservers} - and that could cause - // problems if - // an iterator is used on the ArrayList {@link mObservers}. - // to avoid such problems, just march thru the list in the reverse - // order. - for (int i = mObservers.size() - 1; i >= 0; i--) - { - mObservers.get(i).onItemRangeRemoved(positionStart, itemCount); - } - } - - public void notifyItemsRemoved(ArrayList positions) - { - for (int i = mObservers.size() - 1; i >= 0; i--) - { - mObservers.get(i).onItemsRemoved(positions); - } - } - } - - static class SavedState extends BaseSavedState - { - - Parcelable mLayoutState; - - /** - * called by CREATOR - */ - SavedState(Parcel in) - { - super(in); - mLayoutState = in.readParcelable(LayoutManager.class.getClassLoader()); - } - - /** - * Called by onSaveInstanceState - */ - SavedState(Parcelable superState) - { - super(superState); - } - - @Override - public void writeToParcel(Parcel dest, int flags) - { - super.writeToParcel(dest, flags); - dest.writeParcelable(mLayoutState, 0); - } - - /* private */void copyFrom(SavedState other) - { - mLayoutState = other.mLayoutState; - } - - public static final Creator CREATOR = new Creator() - { - @Override - public SavedState createFromParcel(Parcel in) - { - return new SavedState(in); - } - - @Override - public SavedState[] newArray(int size) - { - return new SavedState[size]; - } - }; - } - - /** - *

- * Contains useful information about the current RecyclerView state like - * target scroll position or view focus. State object can also keep - * arbitrary data, identified by resource ids. - *

- *

- * Often times, RecyclerView components will need to pass information - * between each other. To provide a well defined data bus between - * components, RecyclerView passes the same State object to component - * callbacks and these components can use it to exchange data. - *

- *

- * If you implement custom components, you can use State's put/get/remove - * methods to pass data between your components without needing to manage - * their lifecycles. - *

- */ - public static class State - { - - /* private */int mTargetPosition = RecyclerViewBase.NO_POSITION; - /* private */ArrayMap mPreLayoutHolderMap = new ArrayMap(); - /* private */ArrayMap mPostLayoutHolderMap = new ArrayMap(); - - /* private */SparseArray mData; - public boolean mDataChanged = false; - /** - * Number of items adapter has. - */ - public int mItemCount = 0; - - public int mTotalHeight; - /** - * Number of Header adapter has. - */ - public int mHeaderCount = 0; - public boolean overscroll = true; - /** - * Number of Footer adapter has. - */ - public int mFooterCount = 0; - - /** - * Number of items adapter had in the previous layout. - */ - /* private */int mPreviousLayoutItemCount = 0; - - /** - * Number of items that were NOT laid out but has been deleted from the - * adapter after the previous layout. - */ - /* private */int mDeletedInvisibleItemCountSincePreviousLayout = 0; - - /* private */boolean mStructureChanged = false; - - /* private */boolean mInPreLayout = false; - - public int mHeaderCountInScreen = 0; - public int mFooterCountInScreen = 0; - public int mCustomHeaderHeight = 0; - public int mCustomFooterHeight = 0; - public int mCustomHeaderWidth = 0; - public int mCustomFooterWidth = 0; - - State reset() - { - mTargetPosition = RecyclerViewBase.NO_POSITION; - if (mData != null) - { - mData.clear(); - } - mItemCount = 0; - mHeaderCount = 0; - mFooterCount = 0; - mStructureChanged = false; - return this; - } - - public boolean isPreLayout() - { - return mInPreLayout; - } - - /** - * Removes the mapping from the specified id, if there was any. - * - * @param resourceId Id of the resource you want to remove. It is - * suggested to - * use R.id.* to preserve cross functionality and avoid - * conflicts. - */ - public void remove(int resourceId) - { - if (mData == null) - { - return; - } - mData.remove(resourceId); - } - - /** - * Gets the Object mapped from the specified id, or null if - * no such data exists. - * - * @param resourceId Id of the resource you want to remove. It is - * suggested to - * use R.id.* to preserve cross functionality and avoid - * conflicts. - */ - public T get(int resourceId) - { - if (mData == null) - { - return null; - } - return (T) mData.get(resourceId); - } - - /** - * Adds a mapping from the specified id to the specified value, - * replacing the previous mapping from the specified key if there was - * one. - * - * @param resourceId Id of the resource you want to add. It is suggested - * to use - * R.id.* to preserve cross functionality and avoid - * conflicts. - * @param data The data you want to associate with the resourceId. - */ - public void put(int resourceId, Object data) - { - if (mData == null) - { - mData = new SparseArray(); - } - mData.put(resourceId, data); - } - - public int getTargetScrollPosition() - { - return mTargetPosition; - } - - /** - * Returns if current scroll has a target position. - * - * @return true if scroll is being triggered to make a certain position - * visible - * @see #getTargetScrollPosition() - */ - public boolean hasTargetScrollPosition() - { - return mTargetPosition != RecyclerViewBase.NO_POSITION; - } - - /** - * @return true if the structure of the data set has changed since the - * last call to onLayoutChildren, false otherwise - */ - public boolean didStructureChange() - { - return mStructureChanged; - } - - /** - * @return Total number of items to be laid out. Note that, this number - * is not necessarily equal to the number of items in the - * adapter, so you should always use this number for your - * position calculations and never call adapter directly. - */ - public int getItemCount() - { - return mInPreLayout ? (mPreviousLayoutItemCount - mDeletedInvisibleItemCountSincePreviousLayout) : mItemCount; - } - } - - - /** - * Internal data structure that holds information about an item's bounds. - * This information is used in calculating item animations. - */ - public static class ItemHolderInfo - { - public ViewHolder holder; - public int left, top; - - ItemHolderInfo(ViewHolder holder, int left, int top, int right, int bottom, int position) - { - this.holder = holder; - this.left = left; - this.top = top; - } - } - - public void setRecyclerViewTouchEnabled(boolean enabled) - { - mAnimatingBlockTouch = !enabled || forceBlockTouch; - if (blockTouchListener != null) { - blockTouchListener.onRecyclerViewTouchEnabled(!mAnimatingBlockTouch); - } - } - - public void setBlockTouchListener(IBlockTouchListener blockTouchListener) { - this.blockTouchListener = blockTouchListener; - } - - protected void enter(int pos) - { - mEnterPos = pos; - mEnterCalled = true; - if (mExitCalled && mEnterPos != mExitPos) - { - int smaller = mEnterPos > mExitPos ? mExitPos : mEnterPos; - int bigger = mEnterPos + mExitPos - smaller; - mExchangeFromBigger = bigger == mExitPos; - mEnterCalled = false; - mExitCalled = false; - } - } - - protected void exit(int pos) - { - mExitPos = pos; - mExitCalled = true; - if (mEnterCalled && mEnterPos != mExitPos) - { - int smaller = mEnterPos > mExitPos ? mExitPos : mEnterPos; - int bigger = mEnterPos + mExitPos - smaller; - mExchangeFromBigger = bigger == mExitPos; - mEnterCalled = false; - mExitCalled = false; - } - } - - protected boolean dirtyInRange(int start, int end) - { - int first = getFirstVisibleItemPos(); - if (first == -1) - { - return true; - } - start -= first; - end -= first; - - int smaller = start >= end ? end : start; - int bigger = start + end - smaller; - // Log.d(TAG, "dirtyInRange" + "start=" + smaller + ",end=" + bigger); - for (int i = smaller; i <= bigger; i++) - { - RecyclerViewItem item = (RecyclerViewItem) getChildAtInItem(i); - if (item != null && item.mHolder != null) - { - if (item.mHolder.mPosDirty) - { - // Log.d(TAG, "dirtyInRange" + "result=" + true + "pos=" + - // item.mHolder.mDraggedPosition); - return true; - } - } - } - // Log.d(TAG, "dirtyInRange" + "result=" + false); - return false; - } - - public int getFirstVisibleItemPos() - { - for (int i = 0; i < getChildCountInItem(); i++) - { - View item = getChildAtInItem(i); - if (item instanceof RecyclerViewItem) - { - return ((RecyclerViewItem) item).mHolder.mPosition; - } - } - return -1; - } - - /* private */int getFirstVisibleItemPosWithHeader() - { - for (int i = 0; i < getChildCount(); i++) - { - View item = getChildAt(i); - if (item instanceof RecyclerViewItem) - { - return ((RecyclerViewItem) item).mHolder.mPosition; - } - } - return Integer.MAX_VALUE; - - - } - - public View findViewByPosition(int position) - { - if (mLayout != null) - { - return mLayout.findViewByPosition(position); - } - return null; - } - - protected boolean isTransformedTouchPointInView(float x, float y, RecyclerViewItem child, PointF outLocalPoint) - { - float localX = x - getScrollX() - child.getLeft(); - float localY = y - getScrollY() - child.getTop(); - final boolean isInView = child.isPointInView(localX, localY); - if (isInView && outLocalPoint != null) - { - outLocalPoint.set(localX, localY); - } - return isInView; - } - - protected boolean isAutoScrolling = false; - protected boolean mHorizontalCanScroll = true; - protected boolean mVerticalCanScroll = true; - protected boolean mUpOverScrollEnabled; - protected boolean mDownOverScrollEnabled; - - public class AutoScrollRunnable implements Runnable - { - - public int dir = DIRECTION_UP; - public boolean cancel; - - //public int mY = 4; - - - public void cancelPost(boolean cancled) - { - cancel = cancled; - } - - @Override - public void run() - { - boolean canOverScroll = dir > 0 ? mDownOverScrollEnabled : mUpOverScrollEnabled; - setOverScrollEnabled(false); - scrollBy(0, getAutoScrollVelocity() * dir); - if (!cancel) - { - postDelayed(this, 16); - } - setOverScrollEnabled(canOverScroll); - } - } - - // @Override - // public void removeOnScrollFinishListener() - // { - // mViewFlinger.mScrollFinishListener = null; - // mViewFlinger.mTargetPosition = Integer.MAX_VALUE; - // - // } - - public void scrollToTop(OnScrollFinishListener listener) - { - if (mLayout.canScrollHorizontally()) - { - smoothScrollBy(-mOffsetX + mState.mCustomHeaderWidth, 0, false, true); - mViewFlinger.mScrollFinishListener = listener; - mViewFlinger.mTargetPosition = -mOffsetX + mState.mCustomHeaderWidth; - } - else - { - smoothScrollBy(0, -mOffsetY + mState.mCustomHeaderHeight, false, true); - mViewFlinger.mScrollFinishListener = listener; - mViewFlinger.mTargetPosition = -mOffsetY + mState.mCustomHeaderHeight; - } - } - - public void scrollToTopAtOnce() - { - if (mAdapter == null) - { - return; - } - int[] target = mAdapter.getBeginPositionWithOffset(0); - scrollToPosition(target[0], target[1]); - } - - protected void refreshCachedViews() - { - traversal(TRAVERSAL_PURPOSE_MODECHANGE); - } - - public boolean isScrolling() - { - return mScrollState == SCROLL_STATE_DRAGGING || mScrollState == SCROLL_STATE_SETTLING; - } - - public int getHeightBefore(int pos) - { - return 0; - } - - protected boolean canTranversal(int purpose, ViewHolder holder) - { - return true; - } - - public void traversal(int tracersalPurpose) - { - int count = getChildCount(); - if (tracersalPurpose != TRAVERSAL_PURPOSE_MODECHANGE) - { - if (count > 0) - { - for (int i = 0; i < count; i++) - { - View child = getChildAt(i); - ViewHolder holder = getChildViewHolderInt(child); - if (holder != null) - { - if (canTranversal(tracersalPurpose, holder)) - { - holder.inTraversals(tracersalPurpose); - } - // if (tracersalPurpose == TRAVERSAL_PURPOSE_SWITBACKGROUND) - // { - // if (holder.itemView instanceof QBViewInterface && holder.mContentHolder != null) - // { - // if (!holder.mContentHolder.mUseCustomCardType) - // { - // ((QBViewInterface) holder.itemView).getQBViewResourceManager() - // .setCardBackground(mAdapter.getCardItemViewType(holder.mPosition)); - // } - // } - // } - // else - // { - // if (canTranversal(tracersalPurpose, holder)) - // { - // holder.inTraversals(tracersalPurpose); - // } - // } - } - } - } - } - - final int attachedScrap = mRecycler.mAttachedScrap.size(); - for (int i = 0; i < attachedScrap; i++) - { - final ViewHolder holder = mRecycler.mAttachedScrap.get(i); - if (holder != null) - { - if (canTranversal(tracersalPurpose, holder)) - { - holder.inTraversals(tracersalPurpose); - } - } - } - - final int cacheSize = mRecycler.mCachedViews.size(); - for (int i = 0; i < cacheSize; i++) - { - final ViewHolder holder = mRecycler.mCachedViews.get(i); - if (holder != null) - { - if (canTranversal(tracersalPurpose, holder)) - { - holder.inTraversals(tracersalPurpose); - } - } - } - - final int unmodifiableAttachedScrapScrap = mRecycler.mUnmodifiableAttachedScrap.size(); - for (int i = 0; i < unmodifiableAttachedScrapScrap; i++) - { - final ViewHolder holder = mRecycler.mUnmodifiableAttachedScrap.get(i); - if (holder != null) - { - if (canTranversal(tracersalPurpose, holder)) - { - holder.inTraversals(tracersalPurpose); - } - } - } - - // if (tracersalPurpose == TRAVERSAL_PURPOSE_SWITCHSKIN) - // { - final int scrapSize = getRecycledViewPool().mScrap.size(); - for (int i = 0; i < scrapSize; i++) - { - ArrayList scrapHeap = getRecycledViewPool().mScrap.valueAt(i); - if (scrapHeap != null) - { - final int scrapHeapSize = scrapHeap.size(); - for (int j = 0; j < scrapHeapSize; j++) - { - ViewHolder holder = scrapHeap.get(j); - if (holder != null) - { - holder.inTraversals(tracersalPurpose); - } - } - } - } - // } - } - - public void setOverScrollEnabled(boolean enable) - { - mUpOverScrollEnabled = enable; - mDownOverScrollEnabled = enable; - } - - public boolean getOverScrollEnabled() - { - return mUpOverScrollEnabled; - } - - public void setHasSuspentedItem(boolean has) - { - mHasSuspentedItem = has; - } - - public boolean hasSuspentedItem() - { - return mHasSuspentedItem; - } - - public void setRepeatableSuspensionMode(boolean use) - { - mUseRepeatableSuspensionMode = use; - } - - public boolean isRepeatableSuspensionMode() - { - return mUseRepeatableSuspensionMode; - } - - public void scrollToPositionWithOffset(int pos, int offset) - { - if (mLayout != null) - { - mLayout.scrollToPositionWithOffset(pos, offset); - } - } - - // TODO: vertical & horizontal 可滚动 - // @Override - // public boolean verticalCanScroll(int direction) - // { - // if (mLayout != null) - // { - // return mVerticalCanScroll && mLayout.canScrollVertically(); - // } - // return false; - // } - // - // @Override - // public boolean horizontalCanScroll(int direction) - // { - // if (mLayout != null) - // { - // return mHorizontalCanScroll && mLayout.canScrollHorizontally(); - // } - // return false; - // } - - public boolean isInOverScrollArea() - { - if (mLayout != null && mLayout.canScrollHorizontally()) //list横向滑动 - { - return mOffsetX > mState.mTotalHeight - getWidth() || mOffsetX < 0; - } - return mOffsetY > mState.mTotalHeight - getHeight() || mOffsetY < 0; //list纵向滑动 - } - - public int validateAnchorItemPosition(int anchorItemPosition) - { - if (mAdapter == null) - { - return anchorItemPosition; - } - int headerCount = mAdapter.getHeaderViewCount(); - // TODO: GRID调用 - // if (mLayoutType == LAYOUT_TYPE_GRID && mLayout instanceof GridLayoutManager) - // { - // int column = ((GridLayoutManager) mLayout).mColumns; - // if (anchorItemPosition >= 0 && (anchorItemPosition) % column != 0) - // { - // anchorItemPosition -= (anchorItemPosition) % column; - // } - // } - int footerCount = mAdapter.getFooterViewCount(); - int min = -headerCount; - if (anchorItemPosition < 0 && mAdapter.headerMayChange()) - { - return min; - } - int itemcount = mAdapter.getItemCount(); - int max = footerCount + itemcount; - if (anchorItemPosition >= max || anchorItemPosition <= min) - { - return min; - } - else - { - return anchorItemPosition; - } - } - - public int getCachedTotalHeight() - { - return mState.mTotalHeight; - } - - public int findPrevSuspentedPos(int pos) - { - return -1; - } - - public int findNextSuspentedPos(int pos) - { - return -1; - } - - public boolean isRefreshing() - { - return false; - } - - public void setCanScroll(boolean horizontal, boolean vertical) - { - mHorizontalCanScroll = horizontal; - mVerticalCanScroll = vertical; - } - - // @Override - // public void removeCallbacksDelegate(Runnable runnable) - // { - // removeCallbacks(runnable); - // } - // - // @Override - // public void postDelayedDelegate(Runnable runnable, long l) - // { - // postDelayed(runnable, l); - // } - - public void setOverScrollEnabled(boolean up, boolean down) - { - mUpOverScrollEnabled = up; - mDownOverScrollEnabled = down; - } - - public boolean onStartScroll(int dy) - { - return true; - } - - public boolean hasNoItem() - { - return mAdapter != null && mAdapter.getItemCount() == 0 && mAdapter.getFooterViewCount() == 0 && mAdapter.getHeaderViewCount() == 0; - } - - public void setEnableRecyclerViewTouchEventListener(boolean enableTouchEventListner) - { - mEnableRecyclerViewTouchListener = enableTouchEventListner; - } - - public void notifyRecyclerViewTouchEvent(MotionEvent event) - { - - } - - public void setPrebindItem(boolean prebind) - { - this.mShouldPrebindItem = prebind; - } - - public boolean shouldPrebindItem() - { - return this.mShouldPrebindItem; - } - - protected void handleCustomClickEvent(MotionEvent event) - { - - } - - protected boolean needAdvancedStopDetachChildView() - { - return false; - } - - public ViewHolder createViewHolder(View itemView, RecyclerViewBase rv) - { - return null; - } - - public void onItemsFill(int offset) - { - - } - - public void checkNotifyFooterAppearWithFewChild(int endOffset) - { - - } - - public void handleInTraversal(int traversalPurpose, int position, View contentView) - { - - } - - protected boolean isTouchStopWhenFastFling() - { - return true; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerViewItem.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerViewItem.java deleted file mode 100644 index 92ccb52326f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/RecyclerViewItem.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -import android.content.Context; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -public class RecyclerViewItem extends FrameLayout -{ - public int id; - protected RecyclerViewBase mParentRecyclerView; - public RecyclerView.ViewHolderWrapper mHolder; - public View mContentView; - /* private */boolean mTouchEnabled = true; - public static int ITEM_VIEW_DEFAULT_HEIGHT = 360; //(int) PixelUtil.dp2px(120); - - public RecyclerViewItem(Context context, RecyclerViewBase recyclerView) - { - super(context); - mParentRecyclerView = recyclerView; - } - - public void setParentRecyclerView(RecyclerViewBase mParentRecyclerView) - { - this.mParentRecyclerView = mParentRecyclerView; - } - - @Override - protected void onAttachedToWindow() - { - try - { - super.onAttachedToWindow(); - } - catch (NullPointerException e) - { - - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) - { - // TODO Auto-generated method stub - mBlockRequestLayout = true; - super.onLayout(changed, left, top, right, bottom); - mBlockRequestLayout = false; - } - - public void addContentView(View contentView, boolean hasDivider) - { - if (contentView != null) - { - mContentView = contentView; - ViewGroup.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - mContentView.setLayoutParams(lp); - //mContentView.setId(CONTENTVIEW_ID); - addView(mContentView); - - } - } - - public void onPreAnimate(int which, boolean enter, boolean checked) - { - - } - - public void onStartAnimate(int which) - { - } - - public void onAnimate(float percent, int which, boolean enter) - { - } - - public void onPostAnimate(int which, boolean enter) - { - - } - - public final boolean isPointInView(float localX, float localY) - { - return localX >= 0 && localX < (getRight() - getLeft()) && localY >= 0 && localY < (getBottom() - getTop()); - } - - public View getContentView() - { - return mContentView; - } - - @Override - public void setEnabled(boolean enabled) - { - super.setEnabled(enabled); - mTouchEnabled = enabled; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) - { - // TODO Auto-generated method stub - if (!mTouchEnabled) - { - return true; - } - return super.dispatchTouchEvent(ev); - } - - // TODO: vertical滚动调用 - // @Override - // public boolean verticalCanScroll(int dis) - // { - // return false; - // } - - // /* private */float getContentViewTranslationX() - // { - // if (mContentView != null) - // { - // return mContentView.getTranslationX(); - // } - // return 0; - // } - - // TODO: horizontal滚动调用 - // @Override - // public boolean horizontalCanScroll(int dis) - // { - // if (getContentViewTranslationX() != 0) - // { - // return true; - // } - // if (mParentRecyclerView != null && mHolder != null && mHolder.mContentHolder != null) - // { - // return /* mParentRecyclerView.canSwipeDelete() && */mHolder.mContentHolder.canSwipeDelete() && dis > 0; - // } - // return false; - // } - - /* private */ViewTreeObserver.OnPreDrawListener mLayoutListener; - /* private */boolean mBlockRequestLayout = false; - /* private */boolean mLayoutListenerPosted; -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/ScrollInterpolator.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/ScrollInterpolator.java deleted file mode 100644 index 78166a9c8e4..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/ScrollInterpolator.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -public class ScrollInterpolator -{ - private float mVelocity = 2500; - private float mPhysicsTimeStep = 1 / 120f; - private float mSpringTightness = 7; - private float mSpringDampening = 15; - private float mMinStep = 1.5f; - - private float Spring(float velocity, int position, int restPosition, float tightness, float dampening) - { - float d = position - restPosition; - if (d < 0) - { - d = -d; - } - return (-tightness * d) - (dampening * velocity); - } - - public int getStep(int current, int distance, int toPosition) - { - if (distance == 0) - { - return 0; - } - float F = Spring(mVelocity, current, toPosition, mSpringTightness, mSpringDampening); - mVelocity += F * mPhysicsTimeStep; - float step = mVelocity / 50; - if (step < mMinStep) - { - step = mMinStep; - } - return (int) step; - } - - public void initVelocity(int distance) - { - mVelocity = Math.abs(distance) * 8; - } -} - diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/Scroller.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/Scroller.java deleted file mode 100644 index 54b8cef753f..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/recyclerview/Scroller.java +++ /dev/null @@ -1,654 +0,0 @@ -package com.tencent.mtt.supportui.views.recyclerview; - -/** - * Created by leonardgong on 2017/12/7 0007. - */ - -import android.content.Context; -import android.hardware.SensorManager; -import android.view.ViewConfiguration; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; - -/** - * This class encapsulates scrolling. The duration of the scroll can be passed - * in the constructor and specifies the maximum time that the scrolling - * animation should take. Past this time, the scrolling is automatically moved - * to its final stage and computeScrollOffset() will always return false to - * indicate that scrolling is over. - */ -public class Scroller -{ - public static final int ILLEGAL_DURING = Integer.MAX_VALUE; - - public static boolean mUseIphoneAlgorithm = true; - - private boolean mIsUpOrLeft = false; - - private int mMode; - - private int mStartX; - private int mStartY; - private int mFinalX; - private int mFinalY; - private float mCurrVelocity; - private int mMinX; - private int mMaxX; - private int mMinY; - private int mMaxY; - - private int mCurrX; - private int mCurrY; - private long mStartTime; - private int mDuration; - private float mDurationReciprocal; - private float mDeltaX; - private float mDeltaY; - private boolean mFinished; - public Interpolator mInterpolator; - private boolean mFlywheel; - - private float mVelocity; - - private static final int DEFAULT_DURATION = 250; - private static final int SCROLL_MODE = 0; - private static final int FLING_MODE = 1; - - private long mLastComputeTime = -1; - - private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9)); - public static float ALPHA = 200; // pixels - // / - // seconds - private static float START_TENSION = 0.175f; // Tension - // at - // start: - // (0.4 - // * - // total - // T, - // 1.0 - // * - // Distance) - private static float END_TENSION = /* 1.0f - START_TENSION */0.35f; - private static final int NB_SAMPLES = 100; - private static final float[] SPLINE = new float[NB_SAMPLES + 1]; - - private float mDeceleration; - private final float mPpi; - - private ScrollInterpolator mScrollInterpolator = new ScrollInterpolator(); - - private float mDistance; - - static - { - float x_min = 0.0f; - for (int i = 0; i <= NB_SAMPLES; i++) - { - final float t = (float) i / NB_SAMPLES; - float x_max = 1.0f; - float x, tx, coef; - while (true) - { - x = x_min + (x_max - x_min) / 2.0f; - coef = 3.0f * x * (1.0f - x); - tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x; - if (Math.abs(tx - t) < 1E-5) - break; - if (tx > t) - x_max = x; - else - x_min = x; - } - final float d = coef + x * x * x; - SPLINE[i] = d; - } - SPLINE[NB_SAMPLES] = 1.0f; - - // This controls the viscous fluid effect (how much of it) - sViscousFluidScale = 8.0f; - // must be set to 1.0 (used in viscousFluid()) - sViscousFluidNormalize = 1.0f; - sViscousFluidNormalize = 1.0f / viscousFluid(1.0f); - } - - private static float sViscousFluidScale; - private static float sViscousFluidNormalize; - - /** - * Create a Scroller with the default duration and interpolator. - */ - public Scroller(Context context) - { - this(context, null); - } - - /** - * Create a Scroller with the specified interpolator. If the interpolator is - * null, the default (viscous) interpolator will be used. "Flywheel" - * behavior will be in effect for apps targeting Honeycomb or newer. - */ - public Scroller(Context context, Interpolator interpolator) - { - this(context, interpolator, true); - } - - /** - * Create a Scroller with the specified interpolator. If the interpolator is - * null, the default (viscous) interpolator will be used. Specify whether or - * not to support progressive "flywheel" behavior in flinging. - */ - public Scroller(Context context, Interpolator interpolator, boolean flywheel) - { - mFinished = true; - mInterpolator = interpolator; - mPpi = context.getResources().getDisplayMetrics().density * 160.0f; - mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); - mFlywheel = flywheel; - } - - /** - * The amount of friction applied to flings. The default value is - * {@link ViewConfiguration#getScrollFriction}. - * - * @param friction - * A scalar dimension-less value representing the coefficient of - * friction. - */ - public final void setFriction(float friction) - { - mDeceleration = computeDeceleration(friction); - } - - private float computeDeceleration(float friction) - { - return SensorManager.GRAVITY_EARTH // g (m/s^2) - * 39.37f // inch/meter - * mPpi // pixels per inch - * friction; - } - - /** - * - * Returns whether the scroller has finished scrolling. - * - * @return True if the scroller has finished scrolling, false otherwise. - */ - public final boolean isFinished() - { - return mFinished; - } - - /** - * Force the finished field to a particular value. - * - * @param finished - * The new finished value. - */ - public final void forceFinished(boolean finished) - { - // Log.d("leo", "forceFinished"); - mFinished = finished; - } - - /** - * Returns how long the scroll event will take, in milliseconds. - * - * @return The duration of the scroll in milliseconds. - */ - public final int getDuration() - { - return mDuration; - } - - /** - * Returns the current X offset in the scroll. - * - * @return The new X offset as an absolute distance from the origin. - */ - public final int getCurrX() - { - return mCurrX; - } - - /** - * Returns the current Y offset in the scroll. - * - * @return The new Y offset as an absolute distance from the origin. - */ - public final int getCurrY() - { - return mCurrY; - } - - /** - * Returns the current velocity. - * - * @return The original velocity less the deceleration. Result may be - * negative. - */ - public float getCurrVelocity() - { - return mMode == FLING_MODE ? mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f; - } - - public void clearVelocity() - { - mVelocity = 0; - mCurrVelocity = 0; - } - - /** - * Returns the start X offset in the scroll. - * - * @return The start X offset as an absolute distance from the origin. - */ - public final int getStartX() - { - return mStartX; - } - - /** - * Returns the start Y offset in the scroll. - * - * @return The start Y offset as an absolute distance from the origin. - */ - public final int getStartY() - { - return mStartY; - } - - /** - * Returns where the scroll will end. Valid only for "fling" scrolls. - * - * @return The final X offset as an absolute distance from the origin. - */ - public final int getFinalX() - { - return mFinalX; - } - - /** - * Returns where the scroll will end. Valid only for "fling" scrolls. - * - * @return The final Y offset as an absolute distance from the origin. - */ - public final int getFinalY() - { - return mFinalY; - } - - /** - * Call this when you want to know the new location. If it returns true, the - * animation is not yet finished. loc will be altered to provide the new - * location. - */ - public boolean computeScrollOffset() - { - if (mFinished) - { - return false; - } - - int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime); - - if (mDuration == ILLEGAL_DURING) - { - switch (mMode) - { - case SCROLL_MODE: - if (Math.abs(System.currentTimeMillis() - mLastComputeTime) <= 2) - { - break; - } - mLastComputeTime = System.currentTimeMillis(); - if (mIsUpOrLeft) - { - int distanceX = mFinalX - mStartX; - int distanceY = mFinalY - mStartY; - mCurrX -= mScrollInterpolator.getStep(mCurrX, distanceX, mFinalX); - mCurrY -= mScrollInterpolator.getStep(mCurrY, distanceY, mFinalY); - if ((distanceX == 0 && distanceY == 0) || (distanceY != 0 && mCurrY <= mFinalY) || (distanceX != 0 && mCurrX <= mFinalX)) - { - mCurrX = mFinalX; - mCurrY = mFinalY; - mFinished = true; - if (AnimationUtils.currentAnimationTimeMillis() - mStartTime > 700) - { - mUseIphoneAlgorithm = false; - } - } - } - else - { - int distanceX = mFinalX - mStartX; - int distanceY = mFinalY - mStartY; - mCurrX += mScrollInterpolator.getStep(mCurrX, distanceX, mFinalX); - mCurrY += mScrollInterpolator.getStep(mCurrY, distanceY, mFinalY); - if ((distanceX == 0 && distanceY == 0) || (distanceY != 0 && mCurrY >= mFinalY) || (distanceX != 0 && mCurrX >= mFinalX)) - { - mCurrX = mFinalX; - mCurrY = mFinalY; - mFinished = true; - if (AnimationUtils.currentAnimationTimeMillis() - mStartTime > 700) - { - mUseIphoneAlgorithm = false; - } - } - } - break; - } - } - else - { - if (timePassed < mDuration) - { - switch (mMode) - { - case SCROLL_MODE: - float x = timePassed * mDurationReciprocal; - if (mInterpolator == null) - x = viscousFluid(x); - else - x = mInterpolator.getInterpolation(x); - - mCurrX = mStartX + Math.round(x * mDeltaX); - mCurrY = mStartY + Math.round(x * mDeltaY); - break; - case FLING_MODE: - final float t = (float) timePassed / mDuration; - - final int index = (int) (NB_SAMPLES * t); - final float t_inf = (float) index / NB_SAMPLES; - final float t_sup = (float) (index + 1) / NB_SAMPLES; - final float d_inf = SPLINE[index]; - final float d_sup = SPLINE[index + 1]; - final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf); - final float velocityCoef = (d_sup - d_inf) / (t_sup - t_inf); - mCurrVelocity = velocityCoef * mDistance / mDuration * 1000f; - mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX)); - // Pin to mMinX <= mCurrX <= mMaxX - mCurrX = Math.min(mCurrX, mMaxX); - mCurrX = Math.max(mCurrX, mMinX); - - mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY)); - // Pin to mMinY <= mCurrY <= mMaxY - mCurrY = Math.min(mCurrY, mMaxY); - mCurrY = Math.max(mCurrY, mMinY); - - if (mCurrX == mFinalX && mCurrY == mFinalY) - { - mFinished = true; - } - - break; - } - } - else - { - // Log.d("leo", "computeScroll"); - mCurrX = mFinalX; - mCurrY = mFinalY; - mFinished = true; - } - } - return true; - } - - /** - * Start scrolling by providing a starting point and the distance to travel. - * The scroll will use the default value of 250 milliseconds for the - * duration. - * - * @param startX - * Starting horizontal scroll offset in pixels. Positive numbers - * will scroll the content to the left. - * @param startY - * Starting vertical scroll offset in pixels. Positive numbers - * will scroll the content up. - * @param dx - * Horizontal distance to travel. Positive numbers will scroll - * the content to the left. - * @param dy - * Vertical distance to travel. Positive numbers will scroll the - * content up. - */ - public void startScroll(int startX, int startY, int dx, int dy) - { - startScroll(startX, startY, dx, dy, DEFAULT_DURATION); - } - - /** - * Start scrolling by providing a starting point and the distance to travel. - * - * @param startX - * Starting horizontal scroll offset in pixels. Positive numbers - * will scroll the content to the left. - * @param startY - * Starting vertical scroll offset in pixels. Positive numbers - * will scroll the content up. - * @param dx - * Horizontal distance to travel. Positive numbers will scroll - * the content to the left. - * @param dy - * Vertical distance to travel. Positive numbers will scroll the - * content up. - * @param duration - * Duration of the scroll in milliseconds. - */ - public void startScroll(int startX, int startY, int dx, int dy, int duration) - { - mMode = SCROLL_MODE; - mFinished = false; - mDuration = duration; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mStartX = startX; - mStartY = startY; - mFinalX = startX + dx; - mFinalY = startY + dy; - mDeltaX = dx; - mDeltaY = dy; - mCurrX = mStartX; - mCurrY = mStartY; - if (mStartX == mFinalX) - { - mIsUpOrLeft = mFinalY < mStartY; - mScrollInterpolator.initVelocity(mFinalY - mStartY); - } - else if (mStartY == mFinalY) - { - mIsUpOrLeft = mFinalX < mStartX; - mScrollInterpolator.initVelocity(mFinalX - mStartX); - } - mDurationReciprocal = 1.0f / (float) mDuration; - } - - public boolean isFling() - { - return mMode == FLING_MODE; - } - - /** - * Start scrolling based on a fling gesture. The distance travelled will - * depend on the initial velocity of the fling. - * - * @param startX - * Starting point of the scroll (X) - * @param startY - * Starting point of the scroll (Y) - * @param velocityX - * Initial velocity of the fling (X) measured in pixels per - * second. - * @param velocityY - * Initial velocity of the fling (Y) measured in pixels per - * second - * @param minX - * Minimum X value. The scroller will not scroll past this point. - * @param maxX - * Maximum X value. The scroller will not scroll past this point. - * @param minY - * Minimum Y value. The scroller will not scroll past this point. - * @param maxY - * Maximum Y value. The scroller will not scroll past this point. - */ - public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) - { - // Continue a scroll or fling in progress - if (mFlywheel && !mFinished) - { - float oldVel = getCurrVelocity(); - - float dx = (float) (mFinalX - mStartX); - float dy = (float) (mFinalY - mStartY); - float hyp = (float) Math.sqrt(dx * dx + dy * dy); - - float ndx = dx / hyp; - float ndy = dy / hyp; - - float oldVelocityX = ndx * oldVel; - float oldVelocityY = ndy * oldVel; - if (Math.signum(velocityX) == Math.signum(oldVelocityX) && Math.signum(velocityY) == Math.signum(oldVelocityY)) - { - velocityX += oldVelocityX; - velocityY += oldVelocityY; - } - } - - mMode = FLING_MODE; - mFinished = false; - - float velocity = (float) Math.sqrt((double) velocityX * (double) velocityX + (double) velocityY * (double) velocityY); - - mVelocity = velocity; - final double l = Math.log(START_TENSION * velocity / ALPHA); - mDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0))); - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mStartX = startX; - mStartY = startY; - - float coeffX = velocity == 0 ? 1.0f : velocityX / velocity; - float coeffY = velocity == 0 ? 1.0f : velocityY / velocity; - - int totalDistance = (int) (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l)); - mDistance = (int) (totalDistance * Math.signum(velocity)); - // float absVelocity = Math.abs(velocity); - // if (absVelocity > 1000) - // { - // totalDistance = (int) (totalDistance * (0.4f - Math.min(0.1f, velocity / 20000f))); - // } - // Log.e("TMYS", "duration=" + mDuration + ",totalDistance=" + totalDistance); - mMinX = minX; - mMaxX = maxX; - mMinY = minY; - mMaxY = maxY; - - mFinalX = startX + Math.round(totalDistance * coeffX); - // Pin to mMinX <= mFinalX <= mMaxX - mFinalX = Math.min(mFinalX, mMaxX); - mFinalX = Math.max(mFinalX, mMinX); - - mFinalY = startY + Math.round(totalDistance * coeffY); - // Pin to mMinY <= mFinalY <= mMaxY - mFinalY = Math.min(mFinalY, mMaxY); - mFinalY = Math.max(mFinalY, mMinY); - } - - public static float viscousFluid(float x) - { - x *= sViscousFluidScale; - if (x < 1.0f) - { - x -= (1.0f - (float) Math.exp(-x)); - } - else - { - float start = 0.36787944117f; // 1/e == exp(-1) - x = 1.0f - (float) Math.exp(1.0f - x); - x = start + x * (1.0f - start); - } - x *= sViscousFluidNormalize; - return x; - } - - /** - * Stops the animation. Contrary to {@link #forceFinished(boolean)}, - * aborting the animating cause the scroller to move to the final x and y - * position - * - * @see #forceFinished(boolean) - */ - public void abortAnimation() - { - mCurrX = mFinalX; - mCurrY = mFinalY; - // Log.d("leo", "abortAnimation"); - mFinished = true; - } - - /** - * Extend the scroll animation. This allows a running animation to scroll - * further and longer, when used with {@link #setFinalX(int)} or - * {@link #setFinalY(int)}. - * - * @param extend - * Additional time to scroll in milliseconds. - * @see #setFinalX(int) - * @see #setFinalY(int) - */ - public void extendDuration(int extend) - { - int passed = timePassed(); - mDuration = passed + extend; - mDurationReciprocal = 1.0f / mDuration; - mFinished = false; - } - - /** - * Returns the time elapsed since the beginning of the scrolling. - * - * @return The elapsed time in milliseconds. - */ - public int timePassed() - { - return (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime); - } - - /** - * Sets the final position (X) for this scroller. - * - * @param newX - * The new X offset as an absolute distance from the origin. - * @see #extendDuration(int) - * @see #setFinalY(int) - */ - public void setFinalX(int newX) - { - mFinalX = newX; - mDeltaX = mFinalX - mStartX; - mFinished = false; - } - - /** - * Sets the final position (Y) for this scroller. - * - * @param newY - * The new Y offset as an absolute distance from the origin. - * @see #extendDuration(int) - * @see #setFinalX(int) - */ - public void setFinalY(int newY) - { - mFinalY = newY; - mDeltaY = mFinalY - mStartY; - mFinished = false; - } - - /** - * @hide - */ - public boolean isScrollingInDirection(float xvel, float yvel) - { - return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) && Math.signum(yvel) == Math.signum(mFinalY - mStartY); - } -} diff --git a/android/sdk/src/main/java/com/tencent/smtt/flexbox/CalledByNative.java b/android/sdk/src/main/java/com/tencent/smtt/flexbox/CalledByNative.java deleted file mode 100644 index b911bba61ac..00000000000 --- a/android/sdk/src/main/java/com/tencent/smtt/flexbox/CalledByNative.java +++ /dev/null @@ -1,29 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.smtt.flexbox; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.CLASS) -public @interface CalledByNative { - - @SuppressWarnings("unused") String value() default ""; -} diff --git a/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexNode.java b/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexNode.java deleted file mode 100644 index 0e5a0f4c118..00000000000 --- a/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexNode.java +++ /dev/null @@ -1,812 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.smtt.flexbox; - -import com.tencent.mtt.hippy.dom.flex.FlexAlign; -import com.tencent.mtt.hippy.dom.flex.FlexCSSDirection; -import com.tencent.mtt.hippy.dom.flex.FlexConstants; -import com.tencent.mtt.hippy.dom.flex.FlexDirection; -import com.tencent.mtt.hippy.dom.flex.FlexJustify; -import com.tencent.mtt.hippy.dom.flex.FlexMeasureMode; -import com.tencent.mtt.hippy.dom.flex.FlexNodeAPI; -import com.tencent.mtt.hippy.dom.flex.FlexOverflow; -import com.tencent.mtt.hippy.dom.flex.FlexPositionType; -import com.tencent.mtt.hippy.dom.flex.FlexWrap; -import com.tencent.mtt.hippy.dom.flex.FloatUtil; -import com.tencent.mtt.hippy.utils.I18nUtil; -import com.tencent.smtt.flexbox.FlexNodeStyle.Edge; - -import java.util.ArrayList; -import java.util.List; - -@SuppressWarnings({"unused", "JavaJniMissingFunction"}) -public class FlexNode implements FlexNodeAPI { - - private FlexNode mParent; - private List mChildren; - private final long mNativeFlexNode; - protected FlexNodeStyle mFlexNodeStyle; - private final boolean mDirty = true; - - private final static int MARGIN = 1; - private final static int PADDING = 2; - private final static int BORDER = 4; - - - private int mEdgeSetFlag = 0; - private boolean mHasSetPosition = false; - private float mWidth = Float.NaN; - private float mHeight = Float.NaN; - private float mTop = Float.NaN; - private float mLeft = Float.NaN; - private float mMarginLeft = 0; - private float mMarginTop = 0; - private float mMarginRight = 0; - private float mMarginBottom = 0; - private float mPaddingLeft = 0; - private float mPaddingTop = 0; - private float mPaddingRight = 0; - private float mPaddingBottom = 0; - private float mBorderLeft = 0; - private float mBorderTop = 0; - private float mBorderRight = 0; - private float mBorderBottom = 0; - private boolean mHasNewLayout = true; - - public FlexNodeStyle Style() { - return mFlexNodeStyle; - } - - @CalledByNative - private long measureFunc(float width, int widthMode, float height, int heightMode) { - return measure(width, widthMode, height, heightMode); - } - - protected String resultToString() { - return "layout: {" + - "left: " + getLayoutX() + ", " + - "top: " + getLayoutY() + ", " + - "width: " + getLayoutWidth() + ", " + - "height: " + getLayoutHeight() + ", " + - "}"; - - } - - protected void toStringWithIndentation(StringBuilder result, int level) { - // Spaces and tabs are dropped by IntelliJ logcat integration, so rely on __ instead. - StringBuilder indentation = new StringBuilder(); - for (int i = 0; i < level; ++i) { - indentation.append("__"); - } - - result.append(indentation.toString()); - result.append(mFlexNodeStyle.toString()); - result.append(resultToString()); - - if (getChildCount() == 0) { - return; - } - - result.append(", children: [\n"); - for (int i = 0; i < getChildCount(); i++) { - getChildAt(i).toStringWithIndentation(result, level + 1); - result.append("\n"); - } - result.append(indentation).append("]"); - } - - private native void nativeFlexNodeNodeSetHasBaselineFunc(long nativeFlexNode, - boolean hasMeasureFunc); - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - this.toStringWithIndentation(sb, 0); - return sb.toString(); - } - - private native long nativeFlexNodeNew(); - - public FlexNode() { - mNativeFlexNode = nativeFlexNodeNew(); - if (mNativeFlexNode == 0) { - throw new IllegalStateException("Failed to allocate native memory"); - } - mFlexNodeStyle = new FlexNodeStyle(mNativeFlexNode); - reset(); - } - - private native void nativeFlexNodeFree(long nativeFlexNode); - - protected void finalize() throws Throwable { - try { - nativeFlexNodeFree(mNativeFlexNode); - mFlexNodeStyle = null; - } finally { - super.finalize(); - } - } - - private int TotalChildCount() { - if (mChildren == null) { - return 0; - } - - int count = getChildCount(); - for (int i = 0; i < mChildren.size(); i++) { - count = count + mChildren.get(i).TotalChildCount(); - } - return count; - } - - private int TotalDirtyChildCount() { - if (mChildren == null) { - return 0; - } - - int count = getDirtyChildCount(); - for (int i = 0; i < mChildren.size(); i++) { - count = count + mChildren.get(i).TotalDirtyChildCount(); - } - return count; - } - - public int getChildCount() { - return mChildren == null ? 0 : mChildren.size(); - } - - public int getDirtyChildCount() { - - if (mChildren == null) { - return 0; - } - - int count = 0; - for (int i = 0; i < mChildren.size(); i++) { - if (mChildren.get(i).isDirty()) { - count++; - } - } - return count; - - } - - public FlexNode getChildAt(int i) { - return mChildren.get(i); - } - - private native void nativeFlexNodeInsertChild(long nativeFlexNode, long childPointer, int index); - - public void addChildAt(FlexNode child, int i) { - if (child.mParent != null) { - throw new IllegalStateException("Child already has a parent, it must be removed first."); - } - - if (mChildren == null) { - mChildren = new ArrayList<>(4); - } - mChildren.add(i, child); - child.mParent = this; - nativeFlexNodeInsertChild(mNativeFlexNode, child.mNativeFlexNode, i); - } - - private native void nativeFlexNodeRemoveChild(long nativeFlexNode, long childPointer); - - public FlexNode removeChildAt(int i) { - - final FlexNode child = mChildren.remove(i); - child.mParent = null; - nativeFlexNodeRemoveChild(mNativeFlexNode, child.mNativeFlexNode); - return child; - } - - public FlexNode getParent() { - return mParent; - } - - public int indexOf(FlexNode child) { - return mChildren == null ? -1 : mChildren.indexOf(child); - } - - private native void nativeFlexNodeCalculateLayout(long nativeFlexNode, float width, float height, - long[] nativeNodes, FlexNode[] nodes, int direction); - - public void calculateLayout(float width, float height, FlexDirection direction) { - //long startTime = System.currentTimeMillis(); - //Log.e("layout", "3calculateLayout time start"); - long[] nativeNodes; - FlexNode[] nodes; - ArrayList n = new ArrayList<>(); - n.add(this); - for (int i = 0; i < n.size(); ++i) { - List children = n.get(i).mChildren; - if (children != null) { - n.addAll(children); - } - } - //noinspection ToArrayCallWithZeroLengthArrayArgument - nodes = n.toArray(new FlexNode[n.size()]); - nativeNodes = new long[nodes.length]; - for (int i = 0; i < nodes.length; ++i) { - nativeNodes[i] = nodes[i].mNativeFlexNode; - } - - //Log.e("layout", "calculateLayout time:"+ (System.currentTimeMillis() - startTime)); - nativeFlexNodeCalculateLayout(mNativeFlexNode, width, height, - nativeNodes, nodes, direction.ordinal()); - } - - private native float nativeFlexNodeGetWidth(long nativeFlexNode); - - private native void nativeFlexNodeSetWidth(long nativeFlexNode, float Width); - - private native float nativeFlexNodeGetHeight(long nativeFlexNode); - - private native void nativeFlexNodeSetHeight(long nativeFlexNode, float Height); - - - private native float nativeFlexNodeGetTop(long nativeFlexNode); - - private native void nativeFlexNodeSetTop(long nativeFlexNode, float Top); - - - private native float nativeFlexNodeGetLeft(long nativeFlexNode); - - private native void nativeFlexNodeSetLeft(long nativeFlexNode, float Left); - - - private native float nativeFlexNodeGetRight(long nativeFlexNode); - - private native void nativeFlexNodeSetRight(long nativeFlexNode, float Right); - - - private native float nativeFlexNodeGetBottom(long nativeFlexNode); - - private native void nativeFlexNodeSetBottom(long nativeFlexNode, float Bottom); - - private native float nativeFlexNodeGetMarginLeft(long nativeFlexNode); - - private native void nativeFlexNodeSetMarginLeft(long nativeFlexNode, float MarginLeft); - - - private native float nativeFlexNodeGetMarginTop(long nativeFlexNode); - - private native void nativeFlexNodeSetMarginTop(long nativeFlexNode, float MarginTop); - - - private native float nativeFlexNodeGetMarginRight(long nativeFlexNode); - - private native void nativeFlexNodeSetMarginRight(long nativeFlexNode, float MarginRight); - - private native float nativeFlexNodeGetMarginBottom(long nativeFlexNode); - - private native void nativeFlexNodeSetMarginBottom(long nativeFlexNode, float MarginBottom); - - - private native float nativeFlexNodeGetPaddingLeft(long nativeFlexNode); - - private native void nativeFlexNodeSetPaddingLeft(long nativeFlexNode, float PaddingLeft); - - - private native float nativeFlexNodeGetPaddingTop(long nativeFlexNode); - - private native void nativeFlexNodeSetPaddingTop(long nativeFlexNode, float PaddingTop); - - - private native float nativeFlexNodeGetPaddingRight(long nativeFlexNode); - - private native void nativeFlexNodeSetPaddingRight(long nativeFlexNode, float PaddingRight); - - private native float nativeFlexNodeGetPaddingBottom(long nativeFlexNode); - - private native void nativeFlexNodeSetPaddingBottom(long nativeFlexNode, float PaddingBottom); - - - private native float nativeFlexNodeGetBorderLeft(long nativeFlexNode); - - private native void nativeFlexNodeSetBorderLeft(long nativeFlexNode, float BorderLeft); - - - private native float nativeFlexNodeGetBorderTop(long nativeFlexNode); - - private native void nativeFlexNodeSetBorderTop(long nativeFlexNode, float BorderTop); - - - private native float nativeFlexNodeGetBorderRight(long nativeFlexNode); - - private native void nativeFlexNodeSetBorderRight(long nativeFlexNode, float BorderRight); - - - private native float nativeFlexNodeGetBorderBottom(long nativeFlexNode); - - private native void nativeFlexNodeSetBorderBottom(long nativeFlexNode, float BorderBottom); - - - private Object mData; - - public void setData(Object data) { - mData = data; - } - - public Object getData() { - return mData; - } - - private native void nativeFlexNodeNodeMarkDirty(long nativePointer); - - public void dirty() { - nativeFlexNodeNodeMarkDirty(mNativeFlexNode); - } - - private native boolean nativeFlexNodeNodeIsDirty(long nativePointer); - - public boolean isDirty() { - return nativeFlexNodeNodeIsDirty(mNativeFlexNode); - } - - private native void nativeFlexNodeNodeSetHasMeasureFunc(long nativePointer, - boolean hasMeasureFunc); - - public final long measure(float width, int widthMode, float height, int heightMode) { - if (!isMeasureDefined()) { - throw new RuntimeException("Measure function isn't defined!"); - } - - return mMeasureFunction.measure( - this, - width, - FlexMeasureMode.fromInt(widthMode), - height, - FlexMeasureMode.fromInt(heightMode)); - } - - public boolean isMeasureDefined() { - return mMeasureFunction != null; - } - - public float getLayoutX() { - return mLeft; - } - - public float getLayoutY() { - return mTop; - } - - public float getLayoutWidth() { - return mWidth; - } - - public float getLayoutHeight() { - return mHeight; - } - - private MeasureFunction mMeasureFunction = null; - - @Override - public void setMeasureFunction( - MeasureFunction measureFunction) { - // TODO Auto-generated method stub - mMeasureFunction = measureFunction; - nativeFlexNodeNodeSetHasMeasureFunc(mNativeFlexNode, measureFunction != null); - } - - @Override - public void calculateLayout() { - // TODO Auto-generated method stub - // 1 == FlexDirection::LTR - calculateLayout(FlexConstants.UNDEFINED, FlexConstants.UNDEFINED, getStyleDirection()); - } - - private native void nativeFlexNodemarkHasNewLayout(long nativeFlexNode); - - - private native boolean nativeFlexNodehasNewLayout(long nativeFlexNode); - - @Override - public boolean hasNewLayout() { - // TODO Auto-generated method stub - return mHasNewLayout; - } - - private native void nativeFlexNodemarkLayoutSeen(long nativeFlexNode); - - @Override - public void markLayoutSeen() { - // TODO Auto-generated method stub - mHasNewLayout = false; - nativeFlexNodemarkLayoutSeen(mNativeFlexNode); - } - - @Override - public boolean valuesEqual(float f1, float f2) { - // TODO Auto-generated method stub - return FloatUtil.floatsEqual(f1, f2); - } - - @Override - public FlexDirection getStyleDirection() { - // TODO Auto-generated method stub - return Style().getDirection(); - } - - @Override - public void setDirection(FlexDirection direction) { - // TODO Auto-generated method stub - Style().setDirection(direction); - } - - public FlexDirection getDirection() { - // TODO Auto-generated method stubnativeFlexNodereset - return Style().getDirection(); - } - - @Override - public FlexCSSDirection getFlexDirection() { - // TODO Auto-generated method stub - return Style().getFlexDirection(); - } - - @Override - public void setFlexDirection(FlexCSSDirection flexDirection) { - // TODO Auto-generated method stub - Style().setFlexDirection(flexDirection); - } - - @Override - public FlexJustify getJustifyContent() { - // TODO Auto-generated method stubnativeFlexNodereset - return Style().getJustifyContent(); - } - - @Override - public void setJustifyContent(FlexJustify justifyContent) { - // TODO Auto-generated method stub - Style().setJustifyContent(justifyContent); - } - - @Override - public FlexAlign getAlignItems() { - // TODO Auto-generated method stub - return Style().getAlignItems(); - } - - @Override - public void setAlignItems(FlexAlign alignItems) { - // TODO Auto-generated method stub - Style().setAlignItems(alignItems); - } - - @Override - public FlexAlign getAlignSelf() { - // TODO Auto-generated method stub - return Style().getAlignSelf(); - } - - @Override - public void setAlignSelf(FlexAlign alignSelf) { - // TODO Auto-generated method stub - Style().setAlignSelf(alignSelf); - } - - @Override - public FlexAlign getAlignContent() { - // TODO Auto-generated method stub - return Style().getAlignContent(); - } - - @Override - public void setAlignContent(FlexAlign alignContent) { - // TODO Auto-generated method stub - Style().setAlignContent(alignContent); - } - - @Override - public FlexPositionType getPositionType() { - // TODO Auto-generated method stub - return Style().getPositionType(); - } - - @Override - public void setPositionType(FlexPositionType positionType) { - // TODO Auto-generated method stub - Style().setPositionType(positionType); - } - - @Override - public void setWrap(FlexWrap flexWrap) { - // TODO Auto-generated method stub - Style().setWrap(flexWrap); - } - - @Override - public void setFlex(float flex) { - // TODO Auto-generated method stubnativeFlexNodereset - Style().setFlex(flex); - } - - @Override - public void setDisplay(FlexNodeStyle.Display display) { - Style().setDisplay(display); - } - - - @Override - public float getFlexGrow() { - // TODO Auto-generated method stub - return Style().getFlexGrow(); - } - - @Override - public void setFlexGrow(float flexGrow) { - // TODO Auto-generated method stub - Style().setFlexGrow(flexGrow); - } - - @Override - public float getFlexShrink() { - // TODO Auto-generated method stub return; - return Style().getFlexShrink(); - } - - @Override - public void setFlexShrink(float flexShrink) { - // TODO Auto-generated method stub - Style().setFlexShrink(flexShrink); - } - - @Override - public float getFlexBasis() { - // TODO Auto-generated method stub - return Style().getFlexBasis().value(); - } - - @Override - public void setFlexBasis(float flexBasis) { - // TODO Auto-generated method stub - Style().setFlexBasis(flexBasis); - } - - @Override - public float getMargin(int spacingType) { - // TODO Auto-generated method stub - switch (Edge.fromInt(spacingType)) { - case EDGE_LEFT: - case EDGE_START: - return mMarginLeft; - case EDGE_TOP: - return mMarginTop; - case EDGE_RIGHT: - case EDGE_END: - return mMarginRight; - case EDGE_BOTTOM: - return mMarginBottom; - default: - return Style().getMargin(Edge.fromInt(spacingType)).value(); - } - } - - @Override - public void setMargin(int spacingType, float margin) { - // TODO Auto-generated method stub - mEdgeSetFlag |= MARGIN; - Style().setMargin(Edge.fromInt(spacingType), margin); - } - - @Override - public float getPadding(int spacingType) { - // TODO Auto-generated method stub - //we did not support RTL Layout for text, - //so EDGE_START == EDGE_LEFT - //EDGE_END == EDGE_RIGHT - //ianwang 2018.3.8. - switch (Edge.fromInt(spacingType)) { - case EDGE_LEFT: - case EDGE_START: - return mPaddingLeft; - case EDGE_TOP: - return mPaddingTop; - case EDGE_RIGHT: - case EDGE_END: - return mPaddingRight; - case EDGE_BOTTOM: - return mPaddingBottom; - default: - return Style().getPadding(Edge.fromInt(spacingType)).value(); - } - } - - @Override - public void setPadding(int spacingType, float padding) { - // TODO Auto-generated method stub - mEdgeSetFlag |= PADDING; - Style().setPadding(Edge.fromInt(spacingType), padding); - } - - @Override - public float getBorder(int spacingType) { - // TODO Auto-generated method stub - switch (Edge.fromInt(spacingType)) { - case EDGE_LEFT: - case EDGE_START: - return mBorderLeft; - case EDGE_TOP: - return mBorderTop; - case EDGE_RIGHT: - case EDGE_END: - return mBorderRight; - case EDGE_BOTTOM: - return mBorderBottom; - default: - return Style().getBorder(Edge.fromInt(spacingType)).value(); - } - } - - @Override - public void setBorder(int spacingType, float border) { - // TODO Auto-generated method stub - mEdgeSetFlag |= BORDER; - Style().setBorder(Edge.fromInt(spacingType), border); - } - - @Override - public float getPosition(int spacingType) { - // TODO Auto-generated method stub - return Style().getPosition(Edge.fromInt(spacingType)).value(); - } - - @Override - public void setPosition(int spacingType, float position) { - // TODO Auto-generated method stub - mHasSetPosition = true; - Style().setPosition(Edge.fromInt(spacingType), position); - } - - @Override - public float getStyleWidth() { - // TODO Auto-generated method stub - return Style().getWidth().value(); - } - - @Override - public void setStyleWidth(float width) { - // TODO Auto-generated method stub - Style().setWidth(width); - } - - @Override - public float getStyleHeight() { - // TODO Auto-generated method stub - return Style().getHeight().value(); - } - - @Override - public void setStyleHeight(float height) { - // TODO Auto-generated method stub - Style().setHeight(height); - } - - @Override - public float getStyleMaxWidth() { - // TODO Auto-generated method stub - return Style().getMaxWidth().value(); - } - - @Override - public void setStyleMaxWidth(float maxWidth) { - // TODO Auto-generated method stub - Style().setMaxWidth(maxWidth); - } - - @Override - public float getStyleMinWidth() { - // TODO Auto-generated method stub - return Style().getMinWidth().value(); - } - - @Override - public void setStyleMinWidth(float minWidth) { - // TODO Auto-generated method stub - Style().setMinWidth(minWidth); - } - - @Override - public float getStyleMaxHeight() { - // TODO Auto-generated method stub - return Style().getMaxHeight().value(); - } - - @Override - public void setStyleMaxHeight(float maxHeight) { - // TODO Auto-generated method stub - Style().setMaxHeight(maxHeight); - } - - @Override - public float getStyleMinHeight() { - // TODO Auto-generated method stub - return Style().getMinHeight().value(); - } - - @Override - public void setStyleMinHeight(float minHeight) { - // TODO Auto-generated method stub - Style().setMinHeight(minHeight); - } - - @Override - public FlexDirection getLayoutDirection() { - // TODO Auto-generated method stub - return Style().getDirection(); - } - - @Override - public FlexOverflow getOverflow() { - // TODO Auto-generated method stub - return Style().getOverflow(); - } - - @Override - public void setOverflow(FlexOverflow overflow) { - // TODO Auto-generated method stub - Style().setOverflow(overflow); - } - - private native void nativeFlexNodereset(long nativeFlexNode); - - @Override - public void reset() { - // TODO Auto-generated method stub - if (mParent != null || (mChildren != null && mChildren.size() > 0)) { - return; - } - nativeFlexNodereset(mNativeFlexNode); - FlexDirection flexDirection = I18nUtil.isRTL() ? FlexDirection.RTL : FlexDirection.LTR; - this.setDirection(flexDirection); - this.setFlexDirection(FlexCSSDirection.COLUMN); - this.setJustifyContent(FlexJustify.FLEX_START); - this.setAlignContent(FlexAlign.FLEX_START); - this.setAlignItems(FlexAlign.STRETCH); - this.setAlignSelf(FlexAlign.AUTO); - this.setPositionType(FlexPositionType.RELATIVE); - this.setWrap(FlexWrap.NOWRAP); - this.setOverflow(FlexOverflow.VISIBLE); - this.setFlexGrow(0); - this.setFlexShrink(0); - this.setFlexBasis(FlexConstants.UNDEFINED); - mMeasureFunction = null; - - mEdgeSetFlag = 0; - mHasSetPosition = false; - mHasNewLayout = true; - - mWidth = Float.NaN; - mHeight = Float.NaN; - mTop = Float.NaN; - mLeft = Float.NaN; - mMarginLeft = 0; - mMarginTop = 0; - mMarginRight = 0; - mMarginBottom = 0; - mPaddingLeft = 0; - mPaddingTop = 0; - mPaddingRight = 0; - mPaddingBottom = 0; - mBorderLeft = 0; - mBorderTop = 0; - mBorderRight = 0; - mBorderBottom = 0; - } -} diff --git a/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexNodeStyle.java b/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexNodeStyle.java deleted file mode 100644 index 4c784046dad..00000000000 --- a/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexNodeStyle.java +++ /dev/null @@ -1,688 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.smtt.flexbox; - -import com.tencent.mtt.hippy.dom.flex.FlexAlign; -import com.tencent.mtt.hippy.dom.flex.FlexConstants; -import com.tencent.mtt.hippy.dom.flex.FlexDirection; -import com.tencent.mtt.hippy.dom.flex.FlexCSSDirection; -import com.tencent.mtt.hippy.dom.flex.FlexJustify; -import com.tencent.mtt.hippy.dom.flex.FlexOverflow; -import com.tencent.mtt.hippy.dom.flex.FlexPositionType; -import com.tencent.mtt.hippy.dom.flex.FlexWrap; - -@SuppressWarnings("all") -public class FlexNodeStyle { - - private long mNativePointer = 0; - - public FlexNodeStyle(long flexNode) { - mNativePointer = nativeFlexNodeStyleNew(); - if (mNativePointer == 0) { - throw new IllegalStateException("Failed to allocate native memory"); - } - nativeSetFlexNode(mNativePointer, flexNode); - } - - @Override - public String toString() { - - StringBuilder indentation = new StringBuilder(); - indentation.append("style: {"); - indentation - .append("flex-direction: " + this.getFlexDirection().toString().toLowerCase() + ", "); - - if (this.getFlexGrow() != 0) { - indentation.append("flex-grow: " + this.getFlexGrow() + ", "); - } - - if (this.getFlexBasis().value() != FlexConstants.UNDEFINED) { - indentation.append("flex-basis: " + this.getFlexBasis().value() + ", "); - } - - if (this.getFlexShrink() != 0) { - indentation.append("flex-shrink: " + this.getFlexShrink() + ", "); - } - - if (this.getJustifyContent() != FlexJustify.FLEX_START) { - indentation - .append("justifycontent: " + this.getJustifyContent().toString().toLowerCase() + ", "); - } - - if (this.getAlignContent() != FlexAlign.FLEX_START) { - indentation.append("aligncontent: " + this.getAlignContent().toString().toLowerCase() + ", "); - } - - if (this.getAlignItems() != FlexAlign.STRETCH) { - indentation.append("alignitems: " + this.getAlignItems().toString().toLowerCase() + ", "); - } - - if (this.getAlignSelf() != FlexAlign.AUTO) { - indentation.append("alignself: " + this.getAlignSelf().toString().toLowerCase() + ", "); - } - - if (this.getWrap() != FlexWrap.NOWRAP) { - indentation.append("wrap: " + this.getWrap().toString().toLowerCase() + ", "); - } - - if (this.getOverflow() != FlexOverflow.VISIBLE) { - indentation.append("overflow: " + this.getOverflow().toString().toLowerCase() + ", "); - } - - if (this.getPositionType() != FlexPositionType.RELATIVE) { - indentation.append("positionType: " + this.getPositionType().toString().toLowerCase() + ", "); - } - - if (this.getWidth().value() != 0) { - indentation.append("width: " + this.getWidth().value() + ", "); - } - - if (this.getHeight().value() != 0) { - indentation.append("height: " + getHeight().value() + ", "); - } - - if (this.getMaxWidth().value() != 0) { - indentation.append("max-width: " + getMaxWidth().value() + ", "); - } - - if (this.getMaxHeight().value() != 0) { - indentation.append("max-height: " + getMaxHeight().value() + ", "); - } - - if (this.getMinWidth().value() != 0) { - indentation.append("min-height: " + getMinWidth().value() + ", "); - } - - if (this.getMinHeight().value() != 0) { - indentation.append("min-height: " + getMinHeight().value() + ", "); - } - - indentation.append("}"); - return indentation.toString(); - } - - @CalledByNative - private static Object createFlexValue(float value, int unit) { - return new FlexValue(value, FlexValue.Unit.fromInt(unit)); - } - - private native long nativeFlexNodeStyleNew(); - - private native void nativeFlexNodeStyleFree(long nativeFlexNodeStyle); - - protected void finalize() throws Throwable { - try { - nativeFlexNodeStyleFree(mNativePointer); - mNativePointer = 0; - } finally { - super.finalize(); - } - } - - private native void nativeSetFlexNode(long nativeFlexNodeStyle, long nativeFlexNode); - - private FlexDirection mDirection = FlexDirection.LTR; - - private native int nativeFlexNodeStyleGetDirection(long nativeFlexNodeStyle); - - public FlexDirection getDirection() { - return mDirection; - } - - private native void nativeFlexNodeStyleSetDirection(long nativeFlexNodeStyle, int direction); - - public void setDirection(FlexDirection direction) { - mDirection = direction; - nativeFlexNodeStyleSetDirection(mNativePointer, direction.ordinal()); - } - - private FlexCSSDirection mFlexDirection; - - private native int nativeFlexNodeStyleGetFlexDirection(long nativeFlexNodeStyle); - - public FlexCSSDirection getFlexDirection() { - return mFlexDirection;//CSSFlexDirection.fromInt(nativeFlexNodeStyleGetFlexDirection(mNativePointer)); - } - - private native void nativeFlexNodeStyleSetFlexDirection(long nativeFlexNodeStyle, - int flexDirection); - - public void setFlexDirection(FlexCSSDirection flexDirection) { - mFlexDirection = flexDirection; - nativeFlexNodeStyleSetFlexDirection(mNativePointer, flexDirection.ordinal()); - } - - private FlexJustify mJustifyContent; - - private native int nativeFlexNodeStyleGetJustifyContent(long nativeFlexNodeStyle); - - public FlexJustify getJustifyContent() { - return mJustifyContent; - } - - private native void nativeFlexNodeStyleSetJustifyContent(long nativeFlexNodeStyle, - int justifyContent); - - public void setJustifyContent(FlexJustify justifyContent) { - int order = justifyContent.ordinal(); - mJustifyContent = justifyContent; - switch (order) {//FLEX_START - case 1: {//CENTER; - order = 2; - break; - } - case 2: {//FLEX_END; - order = 3; - break; - } - case 3: {//SPACE_BETWEEN; - order = 6; - break; - } - case 4: {//SPACE_AROUND; - order = 7; - break; - } - case 0: - default: { - order = 1;//default FLEX_START - break; - } - } - nativeFlexNodeStyleSetJustifyContent(mNativePointer, order); - } - - private FlexAlign mAlignItems; - - private native int nativeFlexNodeStyleGetAlignItems(long nativeFlexNodeStyle); - - public FlexAlign getAlignItems() { - return mAlignItems; - } - - private native void nativeFlexNodeStyleSetAlignItems(long nativeFlexNodeStyle, int alignItems); - - public void setAlignItems(FlexAlign alignItems) { - mAlignItems = alignItems; - nativeFlexNodeStyleSetAlignItems(mNativePointer, alignItems.ordinal()); - } - - private FlexAlign mAlignSelf; - - private native int nativeFlexNodeStyleGetAlignSelf(long nativeFlexNodeStyle); - - public FlexAlign getAlignSelf() { - return mAlignSelf; - } - - private native void nativeFlexNodeStyleSetAlignSelf(long nativeFlexNodeStyle, int alignSelf); - - public void setAlignSelf(FlexAlign alignSelf) { - mAlignSelf = alignSelf; - nativeFlexNodeStyleSetAlignSelf(mNativePointer, alignSelf.ordinal()); - } - - private FlexAlign mAlignContent; - - private native int nativeFlexNodeStyleGetAlignContent(long nativeFlexNodeStyle); - - public FlexAlign getAlignContent() { - return mAlignContent; - } - - private native void nativeFlexNodeStyleSetAlignContent(long nativeFlexNodeStyle, - int alignContent); - - public void setAlignContent(FlexAlign alignContent) { - mAlignContent = alignContent; - nativeFlexNodeStyleSetAlignContent(mNativePointer, alignContent.ordinal()); - } - - private FlexPositionType mPositionType; - - private native int nativeFlexNodeStyleGetPositionType(long nativeFlexNodeStyle); - - public FlexPositionType getPositionType() { - return mPositionType; - } - - private native void nativeFlexNodeStyleSetPositionType(long nativeFlexNodeStyle, - int positionType); - - public void setPositionType(FlexPositionType positionType) { - mPositionType = positionType; - nativeFlexNodeStyleSetPositionType(mNativePointer, positionType.ordinal()); - } - - private FlexWrap mFlexWrap; - - private native void nativeFlexNodeStyleSetFlexWrap(long nativeFlexNodeStyle, int wrapType); - - public void setWrap(FlexWrap flexWrap) { - mFlexWrap = flexWrap; - nativeFlexNodeStyleSetFlexWrap(mNativePointer, flexWrap.ordinal()); - } - - private native int nativeFlexNodeStyleGetFlexWrap(long nativeFlexNodeStyle); - - public FlexWrap getWrap() { - return mFlexWrap; - } - - private FlexOverflow mOverFlow; - - private native int nativeFlexNodeStyleGetOverflow(long nativeFlexNodeStyle); - - public FlexOverflow getOverflow() { - return mOverFlow; - } - - private native void nativeFlexNodeStyleSetOverflow(long nativeFlexNodeStyle, int overflow); - - public void setOverflow(FlexOverflow overflow) { - mOverFlow = overflow; - nativeFlexNodeStyleSetOverflow(mNativePointer, overflow.ordinal()); - } - - public enum Display { - DISPLAY_FLEX, - DISPLAY_NONE; - - public static Display fromInt(int value) { - switch (value) { - case 0: - return DISPLAY_FLEX; - case 1: - return DISPLAY_NONE; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } - } - - private Display mDisplay; - - private native int nativeFlexNodeStyleGetDisplay(long nativeFlexNodeStyle); - - public Display getDisplay() { - return mDisplay; - } - - private native void nativeFlexNodeStyleSetDisplay(long nativeFlexNodeStyle, int display); - - public void setDisplay(Display display) { - mDisplay = display; - nativeFlexNodeStyleSetDisplay(mNativePointer, display.ordinal()); - } - - private float mFlex = 0; - - private native float nativeFlexNodeStyleGetFlex(long nativeFlexNodeStyle); - - public float getFlex() { - return mFlex; - } - - private native void nativeFlexNodeStyleSetFlex(long nativeFlexNodeStyle, float flex); - - public void setFlex(float flex) { - mFlex = flex; - nativeFlexNodeStyleSetFlex(mNativePointer, flex); - } - - private float mFlexGrow; - - private native float nativeFlexNodeStyleGetFlexGrow(long nativeFlexNodeStyle); - - public float getFlexGrow() { - return mFlexGrow; - } - - private native void nativeFlexNodeStyleSetFlexGrow(long nativeFlexNodeStyle, float flexGrow); - - public void setFlexGrow(float flexGrow) { - mFlexGrow = flexGrow; - nativeFlexNodeStyleSetFlexGrow(mNativePointer, flexGrow); - } - - private float mFlexShrink = 0; - - private native float nativeFlexNodeStyleGetFlexShrink(long nativeFlexNodeStyle); - - public float getFlexShrink() { - return mFlexShrink; - } - - private native void nativeFlexNodeStyleSetFlexShrink(long nativeFlexNodeStyle, float flexShrink); - - public void setFlexShrink(float flexShrink) { - mFlexShrink = flexShrink; - nativeFlexNodeStyleSetFlexShrink(mNativePointer, flexShrink); - } - - private float mFlexBasis = 0; - - private native Object nativeFlexNodeStyleGetFlexBasis(long nativeFlexNodeStyle); - - public FlexValue getFlexBasis() { - return new FlexValue(mFlexBasis, FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetFlexBasis(long nativeFlexNodeStyle, float flexBasis); - - public void setFlexBasis(float flexBasis) { - mFlexBasis = flexBasis; - nativeFlexNodeStyleSetFlexBasis(mNativePointer, flexBasis); - } - - private native void nativeFlexNodeStyleSetFlexBasisPercent(long nativeFlexNodeStyle, - float percent); - - public void setFlexBasisPercent(float percent) { - nativeFlexNodeStyleSetFlexBasisPercent(mNativePointer, percent); - } - - private native void nativeFlexNodeStyleSetFlexBasisAuto(long nativeFlexNodeStyle); - - public void setFlexBasisAuto() { - nativeFlexNodeStyleSetFlexBasisAuto(mNativePointer); - } - - public enum Edge { - EDGE_LEFT, - EDGE_TOP, - EDGE_RIGHT, - EDGE_BOTTOM, - EDGE_START, - EDGE_END, - EDGE_HORIZONTAL, - EDGE_VERTICAL, - EDGE_ALL; - - public static Edge fromInt(int value) { - switch (value) { - case 0: - return EDGE_LEFT; - case 1: - return EDGE_TOP; - case 2: - return EDGE_RIGHT; - case 3: - return EDGE_BOTTOM; - case 4: - return EDGE_START; - case 5: - return EDGE_END; - case 6: - return EDGE_HORIZONTAL; - case 7: - return EDGE_VERTICAL; - case 8: - return EDGE_ALL; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } - } - - private final float[] mMargin = new float[Edge.EDGE_ALL.ordinal() + 1]; - private final float[] mPadding = new float[Edge.EDGE_ALL.ordinal() + 1]; - private final float[] mBorder = new float[Edge.EDGE_ALL.ordinal() + 1]; - private final float[] mPosition = new float[Edge.EDGE_ALL.ordinal() + 1]; - - private native Object nativeFlexNodeStyleGetMargin(long nativeFlexNodeStyle, int edge); - - public FlexValue getMargin(Edge edge) { - return new FlexValue(mMargin[edge.ordinal()], FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetMargin(long nativeFlexNodeStyle, int edge, - float margin); - - public void setMargin(Edge edge, float margin) { - mMargin[edge.ordinal()] = margin; - nativeFlexNodeStyleSetMargin(mNativePointer, edge.ordinal(), margin); - } - - private native void nativeFlexNodeStyleSetMarginPercent(long nativeFlexNodeStyle, int edge, - float percent); - - public void setMarginPercent(Edge edge, float percent) { - nativeFlexNodeStyleSetMarginPercent(mNativePointer, edge.ordinal(), percent); - } - - private native void nativeFlexNodeStyleSetMarginAuto(long nativeFlexNodeStyle, int edge); - - public void setMarginAuto(Edge edge) { - nativeFlexNodeStyleSetMarginAuto(mNativePointer, edge.ordinal()); - } - - private native Object nativeFlexNodeStyleGetPadding(long nativeFlexNodeStyle, int edge); - - public FlexValue getPadding(Edge edge) { - return new FlexValue(mPadding[edge.ordinal()], FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetPadding(long nativeFlexNodeStyle, int edge, - float padding); - - public void setPadding(Edge edge, float padding) { - mPadding[edge.ordinal()] = padding; - nativeFlexNodeStyleSetPadding(mNativePointer, edge.ordinal(), padding); - } - - private native void nativeFlexNodeStyleSetPaddingPercent(long nativeFlexNodeStyle, int edge, - float percent); - - public void setPaddingPercent(Edge edge, float percent) { - nativeFlexNodeStyleSetPaddingPercent(mNativePointer, edge.ordinal(), percent); - } - - private native Object nativeFlexNodeStyleGetBorder(long nativeFlexNodeStyle, int edge); - - public FlexValue getBorder(Edge edge) { - return new FlexValue(mBorder[edge.ordinal()], FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetBorder(long nativeFlexNodeStyle, int edge, - float border); - - public void setBorder(Edge edge, float border) { - mBorder[edge.ordinal()] = border; - nativeFlexNodeStyleSetBorder(mNativePointer, edge.ordinal(), border); - } - - private native Object nativeFlexNodeStyleGetPosition(long nativeFlexNodeStyle, int edge); - - public FlexValue getPosition(Edge edge) { - return new FlexValue(mPosition[edge.ordinal()], FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetPosition(long nativeFlexNodeStyle, int edge, - float position); - - public void setPosition(Edge edge, float position) { - mPosition[edge.ordinal()] = position; - nativeFlexNodeStyleSetPosition(mNativePointer, edge.ordinal(), position); - } - - private native void nativeFlexNodeStyleSetPositionPercent(long nativeFlexNodeStyle, int edge, - float percent); - - public void setPositionPercent(Edge edge, float percent) { - nativeFlexNodeStyleSetPositionPercent(mNativePointer, edge.ordinal(), percent); - } - - private float mWidth = 0; - - private native Object nativeFlexNodeStyleGetWidth(long nativeFlexNodeStyle); - - public FlexValue getWidth() { - return new FlexValue(mWidth, FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetWidth(long nativeFlexNodeStyle, float width); - - public void setWidth(float width) { - mWidth = width; - nativeFlexNodeStyleSetWidth(mNativePointer, width); - } - - private native void nativeFlexNodeStyleSetWidthPercent(long nativeFlexNodeStyle, float percent); - - public void setWidthPercent(float percent) { - nativeFlexNodeStyleSetWidthPercent(mNativePointer, percent); - } - - private native void nativeFlexNodeStyleSetWidthAuto(long nativeFlexNodeStyle); - - public void setWidthAuto() { - nativeFlexNodeStyleSetWidthAuto(mNativePointer); - } - - private float mHeight = 0; - - private native Object nativeFlexNodeStyleGetHeight(long nativeFlexNodeStyle); - - public FlexValue getHeight() { - return new FlexValue(mHeight, FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetHeight(long nativeFlexNodeStyle, float height); - - public void setHeight(float height) { - mHeight = height; - nativeFlexNodeStyleSetHeight(mNativePointer, height); - } - - private native void nativeFlexNodeStyleSetHeightPercent(long nativeFlexNodeStyle, float percent); - - public void setHeightPercent(float percent) { - nativeFlexNodeStyleSetHeightPercent(mNativePointer, percent); - } - - private native void nativeFlexNodeStyleSetHeightAuto(long nativeFlexNodeStyle); - - public void setHeightAuto() { - nativeFlexNodeStyleSetHeightAuto(mNativePointer); - } - - private float mMinWidth; - - private native Object nativeFlexNodeStyleGetMinWidth(long nativeFlexNodeStyle); - - public FlexValue getMinWidth() { - return new FlexValue(mMinWidth, - FlexValue.Unit.POINT);//(FlexValue) nativeFlexNodeStyleGetMinWidth(mNativePointer); - } - - private native void nativeFlexNodeStyleSetMinWidth(long nativeFlexNodeStyle, float minWidth); - - public void setMinWidth(float minWidth) { - mMinWidth = minWidth; - nativeFlexNodeStyleSetMinWidth(mNativePointer, minWidth); - } - - private native void nativeFlexNodeStyleSetMinWidthPercent(long nativeFlexNodeStyle, - float percent); - - public void setMinWidthPercent(float percent) { - nativeFlexNodeStyleSetMinWidthPercent(mNativePointer, percent); - } - - private float mMinHeight; - - private native Object nativeFlexNodeStyleGetMinHeight(long nativeFlexNodeStyle); - - public FlexValue getMinHeight() { - return new FlexValue(mMinHeight, FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetMinHeight(long nativeFlexNodeStyle, float minHeight); - - public void setMinHeight(float minHeight) { - mMinHeight = minHeight; - nativeFlexNodeStyleSetMinHeight(mNativePointer, minHeight); - } - - private native void nativeFlexNodeStyleSetMinHeightPercent(long nativeFlexNodeStyle, - float percent); - - public void setMinHeightPercent(float percent) { - nativeFlexNodeStyleSetMinHeightPercent(mNativePointer, percent); - } - - private float mMaxWidth; - - private native Object nativeFlexNodeStyleGetMaxWidth(long nativeFlexNodeStyle); - - public FlexValue getMaxWidth() { - return new FlexValue(mMaxWidth, FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetMaxWidth(long nativeFlexNodeStyle, float maxWidth); - - public void setMaxWidth(float maxWidth) { - mMaxWidth = maxWidth; - nativeFlexNodeStyleSetMaxWidth(mNativePointer, maxWidth); - } - - private native void nativeFlexNodeStyleSetMaxWidthPercent(long nativeFlexNodeStyle, - float percent); - - public void setMaxWidthPercent(float percent) { - nativeFlexNodeStyleSetMaxWidthPercent(mNativePointer, percent); - } - - private float mMaxHeight; - - private native Object nativeFlexNodeStyleGetMaxHeight(long nativeFlexNodeStyle); - - public FlexValue getMaxHeight() { - return new FlexValue(mMaxHeight, FlexValue.Unit.POINT); - } - - private native void nativeFlexNodeStyleSetMaxHeight(long nativeFlexNodeStyle, float maxHeight); - - public void setMaxHeight(float maxHeight) { - mMaxHeight = maxHeight; - nativeFlexNodeStyleSetMaxHeight(mNativePointer, maxHeight); - } - - private native void nativeFlexNodeStyleSetMaxHeightPercent(long nativeFlexNodeStyle, - float percent); - - public void setMaxHeightPercent(float percent) { - nativeFlexNodeStyleSetMaxHeightPercent(mNativePointer, percent); - } - - private float mAspectRatio; - - private native float nativeFlexNodeStyleGetAspectRatio(long nativeFlexNodeStyle); - - public float getAspectRatio() { - return mAspectRatio; - } - - private native void nativeFlexNodeStyleSetAspectRatio(long nativeFlexNodeStyle, - float aspectRatio); - - public void setAspectRatio(float aspectRatio) { - mAspectRatio = aspectRatio; - nativeFlexNodeStyleSetAspectRatio(mNativePointer, aspectRatio); - } - -} diff --git a/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexValue.java b/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexValue.java deleted file mode 100644 index 7c7f3890bc3..00000000000 --- a/android/sdk/src/main/java/com/tencent/smtt/flexbox/FlexValue.java +++ /dev/null @@ -1,59 +0,0 @@ -/* Tencent is pleased to support the open source community by making Hippy available. - * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. - * - * 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 com.tencent.smtt.flexbox; - -@SuppressWarnings("unused") -public class FlexValue { - - public enum Unit { - UNDEFINED, - POINT, - PERCENT, - AUTO; - - public static Unit fromInt(int value) { - switch (value) { - case 0: - return UNDEFINED; - case 1: - return POINT; - case 2: - return PERCENT; - case 3: - return AUTO; - default: - throw new IllegalArgumentException("Unknown enum value: " + value); - } - } - } - - public final float value; - public final Unit unit; - - public FlexValue(float value, Unit unit) { - this.value = value; - this.unit = unit; - } - - - FlexValue(float value, int unit) { - this(value, Unit.fromInt(unit)); - } - - float value() { - return value; - } -} diff --git a/android/sdk/src/main/jni/CMakeLists.txt b/android/sdk/src/main/jni/CMakeLists.txt deleted file mode 100644 index 1a477789bbe..00000000000 --- a/android/sdk/src/main/jni/CMakeLists.txt +++ /dev/null @@ -1,157 +0,0 @@ -cmake_minimum_required(VERSION 3.4.1) - -project("hippy") - -set(CMAKE_VERBOSE_MAKEFILE on) -set(CMAKE_CXX_VISIBILITY_PRESET hidden) - -if (${ANDROID_STL} STREQUAL "c++_static") - string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,--exclude-libs,libc++_static.a") - string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,--exclude-libs,libc++abi.a") -endif() - -# region ABI_COMPILE_OPTIONS -set(ABI_COMPILE_OPTIONS - -fno-rtti - -fno-threadsafe-statics - -fvisibility-inlines-hidden - -std=c++14 - --param=ssp-buffer-size=4 - -Werror - -fno-exceptions - -fno-strict-aliasing - -Wall - -fexceptions - -Wno-unused-parameter - -Wno-missing-field-initializers - -pipe - -fPIC - -Wno-unused-local-typedefs - -funwind-tables - -fstack-protector - -fno-short-enums - -Os - -g - -fdata-sections - -ffunction-sections - -fomit-frame-pointer) - -message("ANDROID_ABI: ${ANDROID_ABI}") -if (${ANDROID_ABI} STREQUAL "armeabi-v7a") - set(ABI_COMPILE_OPTIONS ${ABI_COMPILE_OPTIONS} - -march=armv7-a - -mtune=generic-armv7-a - -mfpu=vfpv3-d16 - -mfloat-abi=softfp - -mthumb) -elseif (${ANDROID_ABI} STREQUAL "arm64-v8a") - # (Empty) -elseif (${ANDROID_ABI} STREQUAL "x86") - set(ABI_COMPILE_OPTIONS ${ABI_COMPILE_OPTIONS} - -march=i686 - -mtune=intel - -m32 - -mssse3 - -mfpmath=sse) -elseif (${ANDROID_ABI} STREQUAL "x86_64") - set(ABI_COMPILE_OPTIONS ${ABI_COMPILE_OPTIONS} - -march=x86-64 - -mtune=intel - -m64 - -mpopcnt - -msse4.2) -else() - message(FATAL_ERROR "${ANDROID_ABI} is not supported") -endif() - -if (${HIDDEN_LIBRARY_SYMBOL} STREQUAL "true") - set(ABI_COMPILE_OPTIONS ${ABI_COMPILE_OPTIONS} -fvisibility=hidden) -endif() - -message("ABI_COMPILE_OPTIONS: ${ABI_COMPILE_OPTIONS}") -add_compile_options(${ABI_COMPILE_OPTIONS}) -# endregion - -# region subdirectory -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../../../core/third_party/base out) -set(ENABLE_INSPECTOR true) -if (${JS_ENGINE} STREQUAL "V8") - get_filename_component(V8_COMPONENT_PATH ${V8_COMPONENT} ABSOLUTE) - add_subdirectory(${V8_COMPONENT_PATH}) -endif() -# endregion - -# region global definitions -if (${ENABLE_INSPECTOR} STREQUAL "true") - add_definitions("-DENABLE_INSPECTOR") -endif() -add_definitions("-DOS_ANDROID") -add_definitions("-DANDROID") -# endregion - -# region source -get_filename_component(CORE_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../core" REALPATH) -file(GLOB_RECURSE CORE_SRC ${CORE_SRC_DIR}/src/*.cc) -file(GLOB_RECURSE JNI_SRC ${PROJECT_SOURCE_DIR}/src/*.cc) -if (${ENABLE_INSPECTOR} STREQUAL "false") - file(GLOB_RECURSE INSPECTOR_SRC ${PROJECT_SOURCE_DIR}/src/inspector/*) - list(REMOVE_ITEM JNI_SRC ${INSPECTOR_SRC}) -endif() - -message("CORE_SRC_DIR: ${CORE_SRC_DIR}") -message("CORE_SRC: ${CORE_SRC}") -message("JNI_SRC: ${JNI_SRC}") -# endregion - -set(HIPPY_DEPS android log tdf_base) - -message("JS_ENGINE:" ${JS_ENGINE}) -if (${JS_ENGINE} STREQUAL "V8") - # region remove jsc code - file(GLOB_RECURSE JSC_SRC ${CORE_SRC_DIR}/src/napi/jsc/*) - message("JSC_SRC: ${JSC_SRC}") - list(REMOVE_ITEM CORE_SRC ${JSC_SRC}) - # endregion - # region library - if (${V8_LINKING_MODE} STREQUAL "shared") - add_library(v8 SHARED IMPORTED) - elseif (${V8_LINKING_MODE} STREQUAL "static") - string(APPEND CMAKE_SHARED_LINKER_FLAGS " -Wl,--exclude-libs,${V8_LIBRARY_NAME}") - add_library(v8 STATIC IMPORTED) - else() - message(FATAL_ERROR "V8_LINKING_MODE expected to be `shared` or `static`, but received ${V8_LINKING_MODE}") - endif() - set_property(TARGET v8 PROPERTY IMPORTED_LOCATION ${V8_LIBRARY_PATH}/${V8_LIBRARY_NAME}) - list(APPEND HIPPY_DEPS v8) - # endregion - foreach(INCLUDE_DIRECTORY ${V8_INCLUDE_DIRECTORIES}) - include_directories(${INCLUDE_DIRECTORY}) - endforeach() - foreach(DEFINITION ${V8_DEFINITIONS}) - add_definitions(${DEFINITION}) - endforeach() -elseif (${JS_ENGINE} STREQUAL "JSC") - # region remove v8 code - file(GLOB_RECURSE V8_SRC ${CORE_SRC_DIR}/src/napi/v8/*) - message("V8_SRC: ${V8_SRC}") - list(REMOVE_ITEM CORE_SRC ${V8_SRC}) - # endregion -else() - message(FATAL_ERROR "${JS_ENGINE} is not supported") -endif() - -include_directories(${PROJECT_SOURCE_DIR}/include) -include_directories(${CORE_SRC_DIR}/include) -include_directories(${PROJECT_SOURCE_DIR}) -include_directories(${CORE_SRC_DIR}/third_party/base/include) - -add_library(${CMAKE_PROJECT_NAME} SHARED ${CORE_SRC} ${URL_PARSER_SRC} ${JNI_SRC}) -target_link_libraries(${CMAKE_PROJECT_NAME} ${HIPPY_DEPS}) - -if ((${JS_ENGINE} STREQUAL "V8") AND (${V8_LINKING_MODE} STREQUAL "shared")) - foreach(LIBRARY_DEP ${V8_LIBRARY_DEPS}) - add_custom_command( - TARGET ${CMAKE_PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${V8_LIBRARY_PATH}/${LIBRARY_DEP} $) - endforeach() -endif() diff --git a/android/sdk/src/main/jni/CPPLINT.cfg b/android/sdk/src/main/jni/CPPLINT.cfg deleted file mode 100644 index 461484956c8..00000000000 --- a/android/sdk/src/main/jni/CPPLINT.cfg +++ /dev/null @@ -1,2 +0,0 @@ -root=. -exclude_files=(third_party/*) diff --git a/android/sdk/src/main/jni/HippyAndroidSdk.sln b/android/sdk/src/main/jni/HippyAndroidSdk.sln deleted file mode 100644 index ec8a2ca23e9..00000000000 --- a/android/sdk/src/main/jni/HippyAndroidSdk.sln +++ /dev/null @@ -1,59 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.452 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HippyAndroidSdk", "HippyAndroidSdk.vcxproj", "{E0581439-C51A-4F6C-9ABF-D697C33333B0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "..\..\..\..\..\core\core.vcxproj", "{33620009-97B0-440A-88C7-AF0AFD05DAD8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM - Debug|ARM64 = Debug|ARM64 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|ARM = Release|ARM - Release|ARM64 = Release|ARM64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|ARM.ActiveCfg = Debug|ARM - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|ARM.Build.0 = Debug|ARM - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|ARM.Deploy.0 = Debug|ARM - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|ARM64.Build.0 = Debug|ARM64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|x64.ActiveCfg = Debug|x64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|x64.Build.0 = Debug|x64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|x86.ActiveCfg = Debug|x86 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Debug|x86.Build.0 = Debug|x86 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|ARM.ActiveCfg = Release|ARM - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|ARM.Build.0 = Release|ARM - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|ARM.Deploy.0 = Release|ARM - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|ARM64.ActiveCfg = Release|ARM64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|ARM64.Build.0 = Release|ARM64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|x64.ActiveCfg = Release|x64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|x64.Build.0 = Release|x64 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|x86.ActiveCfg = Release|x86 - {E0581439-C51A-4F6C-9ABF-D697C33333B0}.Release|x86.Build.0 = Release|x86 - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Debug|ARM.ActiveCfg = Debug|ARM - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Debug|ARM.Build.0 = Debug|ARM - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Debug|ARM64.Build.0 = Debug|ARM64 - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Debug|x64.ActiveCfg = Debug|ARM - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Debug|x86.ActiveCfg = Debug|ARM - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Release|ARM.ActiveCfg = Release|ARM - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Release|ARM.Build.0 = Release|ARM - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Release|ARM64.ActiveCfg = Release|ARM64 - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Release|ARM64.Build.0 = Release|ARM64 - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Release|x64.ActiveCfg = Release|ARM - {33620009-97B0-440A-88C7-AF0AFD05DAD8}.Release|x86.ActiveCfg = Release|ARM - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {F20660D0-F7FD-4BDF-8ABF-B6935DA89A50} - EndGlobalSection -EndGlobal diff --git a/android/sdk/src/main/jni/HippyAndroidSdk.vcxproj b/android/sdk/src/main/jni/HippyAndroidSdk.vcxproj deleted file mode 100644 index 20431e3a29b..00000000000 --- a/android/sdk/src/main/jni/HippyAndroidSdk.vcxproj +++ /dev/null @@ -1,224 +0,0 @@ - - - - - Debug - ARM - - - Release - ARM - - - Debug - ARM64 - - - Release - ARM64 - - - - - - - - {33620009-97b0-440a-88c7-af0afd05dad8} - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {e0581439-c51a-4f6c-9abf-d697c33333b0} - Android - hippy - 14.0 - Android - 3.0 - - - - DynamicLibrary - true - Clang_5_0 - android-28 - - - DynamicLibrary - false - Clang_5_0 - - - DynamicLibrary - true - Clang_5_0 - android-16 - - - DynamicLibrary - false - Clang_5_0 - android-16 - - - - - - - - $(ProjectDir)..\..\..\build\outputs\arm64-v8a\ - $(ProjectDir)..\..\..\build\intermediates\$(Platform)\$(Configuration)\ - .;$(IncludePath) - - - - - .;$(IncludePath) - $(ProjectDir)..\..\..\build\outputs\armeabi-v7a\ - $(ProjectDir)..\..\..\build\intermediates\$(Platform)\$(Configuration)\ - lib$(RootNamespace)bridge - - - .;$(IncludePath) - $(ProjectDir)..\..\..\build\outputs\armeabi-v7a\ - $(ProjectDir)..\..\..\build\intermediates\$(Platform)\$(Configuration)\ - - - - NotUsing - - - c++14 - __ANDROID_API__=$(AndroidAPILevelNumber);OS_ANDROID;DEBUG - - - cd ../../../.. && set skipCmakeAndNinja=1 && gradle :example:assembleDebug - Building example-debug.apk - - - $(ProjectDir)..\..\..\build\outputs\arm64-v8a\$(TargetName)$(TargetExt) - third_party\v8\arm64-v8a\libmtt_shared.so;third_party\v8\arm64-v8a\libmttv8.so - -lm - - - - - NotUsing - - - c++14 - - - - - Use - ../../../../../core/include/core/core.h - c++14 - __ANDROID_API__=$(AndroidAPILevelNumber);OS_ANDROID;DEBUG;V8_IMMINENT_DEPRECATION_WARNINGS;V8_DEPRECATION_WARNINGS - .\third_party\v8\maintenance\x5-lite\include;.;.\include;..\..\..\..\..\core\include;..\..\..\..\..\core\third_party\base\include;%(AdditionalIncludeDirectories) - - - third_party\v8\maintenance\x5-lite\libs\armeabi-v7a\libmtt_shared.so;third_party\v8\maintenance\x5-lite\libs\armeabi-v7a\libmttv8.so - $(ProjectDir)..\..\..\build\outputs\armeabi-v7a\$(TargetName)$(TargetExt) - - - m;atomic;%(LibraryDependencies) - - - cd ../../../../../examples/android-demo && set skipCmakeAndNinja=1 && gradlew :example:assembleDebug - - - Building example-debug.apk - - - - - - - - - - - - - NotUsing - - - c++14 - __ANDROID_API__=$(AndroidAPILevelNumber);OS_ANDROID - MinSize - true - - - third_party\v8\armeabi-v7a\libmtt_shared.so;third_party\v8\armeabi-v7a\libmttv8.so - $(ProjectDir)..\..\..\build\outputs\armeabi-v7a\$(TargetName)$(TargetExt) - -lm - - - cd ../../../.. && set skipCmakeAndNinja=1 && gradlew :example:assembleDebug - - - Building example-debug.apk - - - - - diff --git a/android/sdk/src/main/jni/HippyAndroidSdk.vcxproj.user b/android/sdk/src/main/jni/HippyAndroidSdk.vcxproj.user deleted file mode 100644 index 58087a787cc..00000000000 --- a/android/sdk/src/main/jni/HippyAndroidSdk.vcxproj.user +++ /dev/null @@ -1,15 +0,0 @@ - - - - true - - - $(ProjectDir)..\..\..\..\..\examples\android-demo\example\build\outputs\apk\debug\example-debug.apk - AndroidDebugger - $(ProjectDir)..\..\..\build\intermediates\ARM\Debug - - - $(ProjectDir)..\..\..\..\example\build\outputs\apk\example-debug.apk - AndroidDebugger - - \ No newline at end of file diff --git a/android/sdk/src/main/jni/include/bridge/entry.h b/android/sdk/src/main/jni/include/bridge/entry.h deleted file mode 100644 index a0110c02f91..00000000000 --- a/android/sdk/src/main/jni/include/bridge/entry.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -namespace hippy { -namespace bridge { - -void InitNativeLogHandler(JNIEnv* j_env, jobject j_object, jobject j_logger); - -jlong InitInstance(JNIEnv* j_env, - jobject j_object, - jbyteArray j_global_config, - jboolean j_single_thread_mode, - jboolean j_bridge_param_json, - jboolean j_is_dev_module, - jobject j_callback, - jlong j_group_id); - -void DestroyInstance(JNIEnv* j_env, - jobject j_object, - jlong j_runtime_id, - jboolean j_single_thread_mode, - jobject j_callback); - -jboolean RunScriptFromUri(JNIEnv* j_env, - jobject j_obj, - jstring j_uri, - jobject j_aasset_manager, - jboolean j_can_use_code_cache, - jstring j_code_cache_dir, - jlong j_runtime_id, - jobject j_cb); - -} // namespace bridge -} // namespace hippy diff --git a/android/sdk/src/main/jni/include/bridge/runtime.h b/android/sdk/src/main/jni/include/bridge/runtime.h deleted file mode 100644 index 8eb4eec5cc7..00000000000 --- a/android/sdk/src/main/jni/include/bridge/runtime.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 -#include - -#include - -#include "core/core.h" -#include "jni/turbo_module_runtime.h" -#include "jni/scoped_java_ref.h" -#ifdef ENABLE_INSPECTOR -#include "inspector/v8_inspector_client_impl.h" -#endif - -class Runtime { - public: - Runtime(std::shared_ptr bridge, bool enable_v8_serialization, bool is_dev); - - inline bool IsEnableV8Serialization() { return enable_v8_serialization_; } - inline bool IsDebug() { return is_debug_; } - inline int32_t GetId() { return id_; } - inline int64_t GetGroupId() { return group_id_; } - inline std::shared_ptr GetBridge() { return bridge_; } - inline std::shared_ptr GetEngine() { return engine_; } - inline std::shared_ptr GetScope() { return scope_; } - inline std::shared_ptr GetBridgeFunc() { - return bridge_func_; - } - inline std::string& GetBuffer() { return serializer_reused_buffer_; } - - inline void SetGroupId(int64_t id) { group_id_ = id; } - inline void SetBridgeFunc(std::shared_ptr func) { - bridge_func_ = func; - } - inline void SetEngine(std::shared_ptr engine) { engine_ = engine; } - inline void SetScope(std::shared_ptr scope) { scope_ = scope; } - - inline std::shared_ptr GetTurboModuleRuntime() { - return turbo_module_runtime_; - } - inline void SetTurboModuleRuntime( - std::shared_ptr turbo_module_runtime) { - turbo_module_runtime_ = turbo_module_runtime; - } - - static void Insert(std::shared_ptr runtime); - static std::shared_ptr Find(int32_t id); - static std::shared_ptr Find(v8::Isolate* isolate); - static bool Erase(int32_t id); - static bool Erase(std::shared_ptr runtime); - static bool ReleaseKey(int64_t id); - - private: - bool enable_v8_serialization_; - bool is_debug_; - int64_t group_id_; - std::shared_ptr bridge_; - std::string serializer_reused_buffer_; - std::shared_ptr engine_; - std::shared_ptr scope_; - std::shared_ptr bridge_func_; - int32_t id_; - std::shared_ptr turbo_module_runtime_; -}; diff --git a/android/sdk/src/main/jni/include/bridge/serializer.h b/android/sdk/src/main/jni/include/bridge/serializer.h deleted file mode 100644 index b79a8c2dee7..00000000000 --- a/android/sdk/src/main/jni/include/bridge/serializer.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include "v8/v8.h" - -class Serializer : public v8::ValueSerializer::Delegate { - public: - Serializer(v8::Isolate* isolate, - v8::Local context, - std::string& reused_buffer); - ~Serializer(); - - Serializer(const Serializer&) = delete; - Serializer& operator=(const Serializer&) = delete; - - v8::Maybe WriteValue(v8::Local value); - void WriteHeader(); - std::pair Release(); - - protected: - void ThrowDataCloneError(v8::Local message) override; - void* ReallocateBufferMemory(void* old_buffer, - size_t size, - size_t* actual_size) override; - void FreeBufferMemory(void* buffer) override; - - private: - v8::Isolate* isolate_; - v8::Global context_global_; - v8::ValueSerializer serializer_; - std::string& reused_buffer_; -}; diff --git a/android/sdk/src/main/jni/include/hippy.h b/android/sdk/src/main/jni/include/hippy.h deleted file mode 100644 index 7a5e2a2588c..00000000000 --- a/android/sdk/src/main/jni/include/hippy.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 "bridge/entry.h" -#include "bridge/java2js.h" -#include "bridge/js2java.h" -#include "bridge/runtime.h" -#include "bridge/serializer.h" -#include "jni/exception_handler.h" -#include "jni/jni_env.h" -#include "jni/jni_register.h" -#include "jni/jni_utils.h" -#include "jni/scoped_java_ref.h" -#include "loader/adr_loader.h" -#ifdef ENABLE_INSPECTOR -#include "inspector/v8_channel_impl.h" -#include "inspector/v8_inspector_client_impl.h" -#endif -#include "v8/v8.h" diff --git a/android/sdk/src/main/jni/include/inspector/v8_channel_impl.h b/android/sdk/src/main/jni/include/inspector/v8_channel_impl.h deleted file mode 100644 index bc45ff98752..00000000000 --- a/android/sdk/src/main/jni/include/inspector/v8_channel_impl.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include "jni/jni_env.h" -#include "jni/jni_utils.h" -#include "jni/scoped_java_ref.h" -#include "v8/v8-inspector.h" - -namespace hippy { -namespace inspector { - -class V8ChannelImpl : public v8_inspector::V8Inspector::Channel { - public: - explicit V8ChannelImpl(std::shared_ptr bridge); - ~V8ChannelImpl() override = default; - - inline std::shared_ptr GetBridge() { return bridge_; } - - inline void SetBridge(std::shared_ptr bridge) { bridge_ = bridge; } - - void sendResponse( - int callId, - std::unique_ptr message) override; - void sendNotification( - std::unique_ptr message) override; - void flushProtocolNotifications() override {} - - private: - friend class V8InspectorClientImpl; - std::shared_ptr bridge_; -}; - -} // namespace inspector -} // namespace hippy diff --git a/android/sdk/src/main/jni/include/inspector/v8_inspector_client_impl.h b/android/sdk/src/main/jni/include/inspector/v8_inspector_client_impl.h deleted file mode 100644 index 883c7e7d492..00000000000 --- a/android/sdk/src/main/jni/include/inspector/v8_inspector_client_impl.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 -#include - -#include "base/unicode_string_view.h" -#include "core/core.h" -#include "jni/scoped_java_ref.h" -#include "v8_channel_impl.h" - -namespace hippy { -namespace inspector { - -class V8InspectorClientImpl : public v8_inspector::V8InspectorClient { - public: - using unicode_string_view = tdf::base::unicode_string_view; - - explicit V8InspectorClientImpl(std::shared_ptr scope); - ~V8InspectorClientImpl() = default; - - void Reset(std::shared_ptr scope, std::shared_ptr bridge); - void Connect(std::shared_ptr bridge); - - void SendMessageToV8(const unicode_string_view& params); - void CreateContext(); - void DestroyContext(); - v8::Local ensureDefaultContextInGroup( - int contextGroupId) override; - - void runMessageLoopOnPause(int contextGroupId) override; - void quitMessageLoopOnPause() override; - void runIfWaitingForDebugger(int contextGroupId) override; - - void muteMetrics(int contextGroupId) override {} - void unmuteMetrics(int contextGroupId) override {} - - void beginUserGesture() override {} - void endUserGesture() override {} - - std::unique_ptr valueSubtype( - v8::Local) override { - return nullptr; - } - bool formatAccessorsAsProperties(v8::Local) override { - return false; - } - bool isInspectableHeapObject(v8::Local) override { return true; } - - void beginEnsureAllContextsInGroup(int contextGroupId) override {} - void endEnsureAllContextsInGroup(int contextGroupId) override {} - - void installAdditionalCommandLineAPI(v8::Local, - v8::Local) override {} - void consoleAPIMessage(int contextGroupId, - v8::Isolate::MessageErrorLevel level, - const v8_inspector::StringView& message, - const v8_inspector::StringView& url, - unsigned lineNumber, - unsigned columnNumber, - v8_inspector::V8StackTrace*) override {} - - v8::MaybeLocal memoryInfo(v8::Isolate*, - v8::Local) override { - return v8::MaybeLocal(); - } - - void consoleTime(const v8_inspector::StringView& title) override {} - void consoleTimeEnd(const v8_inspector::StringView& title) override {} - void consoleTimeStamp(const v8_inspector::StringView& title) override {} - void consoleClear(int contextGroupId) override {} - double currentTimeMS() override { return 0; } - typedef void (*TimerCallback)(void*); - void startRepeatingTimer(double, TimerCallback, void* data) override {} - void cancelTimer(void* data) override {} - - // TODO(dgozman): this was added to support service worker shadow page. We - // should not connect at all. - bool canExecuteScripts(int contextGroupId) override { return true; } - - void maxAsyncCallStackDepthChanged(int depth) override {} - - private: - std::shared_ptr scope_; - std::unique_ptr inspector_; - std::unique_ptr channel_; - std::unique_ptr session_; -}; - -} // namespace inspector -} // namespace hippy diff --git a/android/sdk/src/main/jni/include/jni/convert_utils.h b/android/sdk/src/main/jni/include/jni/convert_utils.h deleted file mode 100644 index 66adc06c191..00000000000 --- a/android/sdk/src/main/jni/include/jni/convert_utils.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include "core/napi/js_native_api_types.h" -#include "hippy.h" - -#ifndef ANDROID_DEMO_CONVERT_UTILS_H -#define ANDROID_DEMO_CONVERT_UTILS_H - -struct JNIArgs { - JNIArgs(size_t count) : args_(count) {} - - std::vector args_; - std::vector global_refs_; -}; - -template -std::string ToString(T v) { - std::ostringstream stream; - stream << v; - return stream.str(); -} - -struct MethodInfo { - std::string signature_; - jmethodID method_id_ = nullptr; -}; - -class ConvertUtils { - public: - static bool Init(); - - static bool Destory(); - - static std::vector GetMethodArgTypesFromSignature( - const std::string &method_signature); - - static std::shared_ptr ConvertJSIArgsToJNIArgs( - hippy::napi::TurboEnv &turbo_env, - const std::string &module_name, - const std::string &method_name, - const std::vector &method_arg_types, - const std::vector> &arg_values); - - static std::shared_ptr ConvertMethodResultToJSValue( - hippy::napi::TurboEnv &turbo_env, - const jobject &obj, - const MethodInfo &method_info, - const jvalue *args); - - static jobject ToJObject(hippy::napi::TurboEnv &turbo_env, - const std::shared_ptr &value); - - static jobject ToHippyMap( - hippy::napi::TurboEnv &turbo_env, - const std::shared_ptr &value); - - static jobject ToHippyArray( - hippy::napi::TurboEnv &turbo_env, - const std::shared_ptr &value); - - static std::shared_ptr ToJsValueInArray( - hippy::napi::TurboEnv &turbo_env, - const jobject &array, - int index); - - static std::shared_ptr ToJsArray( - hippy::napi::TurboEnv &turbo_env, - const jobject &array); - - static std::shared_ptr ToJsMap( - hippy::napi::TurboEnv &turbo_env, - const jobject &map); - - static bool HandleBasicType( - hippy::napi::TurboEnv &turbo_env, - const std::string &type, - jvalue &j_args, - const std::shared_ptr &value); - - static bool HandleObjectType( - hippy::napi::TurboEnv &turbo_env, - const std::string &module_name, - const std::string &method_name, - const std::string &type, - jvalue &j_args, - const std::shared_ptr &value, - std::vector &global_refs); - - static void ThrowException(const std::shared_ptr &ctx, - const std::string &info); - - static std::unordered_map GetMethodMap( - const std::string &method_map_str); - - static std::shared_ptr ToHostObject( - hippy::napi::TurboEnv &turbo_env, - jobject &j_obj, - std::string name); -}; - -static jclass hippy_array_clazz; -static jmethodID hippy_array_constructor; -static jmethodID hippy_array_push_object; -// get -static jmethodID hippy_array_size; -static jmethodID hippy_array_get_sig; -static jmethodID hippy_array_get; - -static jclass hippy_map_clazz; -static jmethodID hippy_map_constructor; -static jmethodID hippy_map_push_object; -static jmethodID to_hippy_array; - -static jclass integer_clazz; -static jclass double_clazz; -static jclass float_clazz; -static jclass long_clazz; -static jclass boolean_clazz; -static jmethodID integer_constructor; -static jmethodID double_constructor; -static jmethodID double_value; -static jmethodID float_constructor; -static jmethodID long_constructor; -static jmethodID boolean_constructor; -static jmethodID boolean_value; - -static jclass promise_clazz; -static jmethodID promise_constructor; - -const std::string kint = "I"; -const std::string kdouble = "D"; -const std::string kfloat = "F"; -const std::string klong = "J"; -const std::string kboolean = "Z"; -const std::string kInteger = "Ljava/lang/Integer;"; -const std::string kDouble = "Ljava/lang/Double;"; -const std::string kFloat = "Ljava/lang/Float;"; -const std::string kLong = "Ljava/lang/Long;"; -const std::string kString = "Ljava/lang/String;"; -const std::string kBoolean = "Ljava/lang/Boolean;"; -const std::string kHippyArray = "Lcom/tencent/mtt/hippy/common/HippyArray;"; -const std::string kHippyMap = "Lcom/tencent/mtt/hippy/common/HippyMap;"; -const std::string kPromise = "Lcom/tencent/mtt/hippy/modules/Promise;"; -const std::string kvoid = "V"; -const std::string kUnSupportedType = "Lcom/invalid;"; - -#endif // ANDROID_DEMO_CONVERT_UTILS_H diff --git a/android/sdk/src/main/jni/include/jni/exception_handler.h b/android/sdk/src/main/jni/include/jni/exception_handler.h deleted file mode 100644 index ef2beef5924..00000000000 --- a/android/sdk/src/main/jni/include/jni/exception_handler.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 -#include - -#include "bridge/runtime.h" - -class JNIEnvironment; - -class ExceptionHandler { - public: - using unicode_string_view = tdf::base::unicode_string_view; - - ExceptionHandler() = default; - ~ExceptionHandler() = default; - static void ReportJsException(std::shared_ptr runtime, - const unicode_string_view& desc, - const unicode_string_view& stack); -}; diff --git a/android/sdk/src/main/jni/include/jni/java_turbo_module.h b/android/sdk/src/main/jni/include/jni/java_turbo_module.h deleted file mode 100644 index f53c9adfbe8..00000000000 --- a/android/sdk/src/main/jni/include/jni/java_turbo_module.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include - -#include "convert_utils.h" -#include "core/napi/js_native_turbo.h" -#include "core/napi/v8/js_native_turbo_v8.h" -#include "hippy.h" - -#ifndef HIPPYJSI_JAVATURBOMODULE_H -#define HIPPYJSI_JAVATURBOMODULE_H - -class JavaTurboModule : public hippy::napi::HippyTurboModule { - public: - JavaTurboModule(const std::string &name, std::shared_ptr &impl); - - ~JavaTurboModule(); - - std::shared_ptr impl_; - - jclass impl_j_clazz_; - - // methodName, signature - std::unordered_map method_map_; - - virtual std::shared_ptr InvokeJavaMethod( - hippy::napi::TurboEnv &turbo_env, - const std::shared_ptr &prop_name, - const std::shared_ptr &this_val, - const std::shared_ptr *args, - size_t count); - - void InitPropertyMap(); - - virtual std::shared_ptr Get( - hippy::napi::TurboEnv &, - const std::shared_ptr &prop_name) override; - - virtual void DeleteGlobalRef(const std::shared_ptr &jni_args); - - static void Init(); - - static void Destory(); -}; - -#endif // HIPPYJSI_JAVATURBOMODULE_H diff --git a/android/sdk/src/main/jni/include/jni/jni_env.h b/android/sdk/src/main/jni/include/jni/jni_env.h deleted file mode 100644 index 6757ff20378..00000000000 --- a/android/sdk/src/main/jni/include/jni/jni_env.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include -#include - -class JNIEnvironment { - public: - struct JNIWrapper { - jmethodID j_call_natives_direct_method_id = nullptr; - jmethodID j_call_natives_method_id = nullptr; - jmethodID j_report_exception_method_id = nullptr; - jmethodID j_inspector_channel_method_id = nullptr; - jmethodID j_fetch_resource_method_id = nullptr; - }; - - public: - static std::shared_ptr GetInstance(); - static bool ClearJEnvException(JNIEnv* env); - static void DestroyInstance(); - - JNIEnvironment() = default; - ~JNIEnvironment() = default; - - inline JNIWrapper GetMethods() { return wrapper_; } - void init(JavaVM* vm, JNIEnv* env); - JNIEnv* AttachCurrentThread(); - void DetachCurrentThread(); - - private: - static std::shared_ptr instance_; - static std::mutex mutex_; - - JavaVM* j_vm_; - JNIWrapper wrapper_; -}; diff --git a/android/sdk/src/main/jni/include/jni/jni_utils.h b/android/sdk/src/main/jni/include/jni/jni_utils.h deleted file mode 100644 index 54e12a76d56..00000000000 --- a/android/sdk/src/main/jni/include/jni/jni_utils.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include - -#include "base/unicode_string_view.h" -#include "v8/v8.h" - -struct HippyBuffer; - -class JniUtils { - using unicode_string_view = tdf::base::unicode_string_view; - using bytes = std::string; - - public: - JniUtils() = default; - ~JniUtils() = default; - - public: - static unicode_string_view JByteArrayToStrView(JNIEnv* j_env, - jbyteArray j_byte_array, - jsize j_offset = 0, - jsize j_length = -1); - - static jstring StrViewToJString(JNIEnv* j_env, - const unicode_string_view& str_view); - static bytes AppendJavaByteArrayToBytes(JNIEnv* j_env, - jbyteArray byte_array, - jsize j_offset = 0, - jsize j_length = -1); - static std::u16string CovertJStringToChars(JNIEnv* j_env, jstring j_str); - - static unicode_string_view::u8string ToU8String(JNIEnv* j_env, jstring j_str); - - static unicode_string_view ToStrView(JNIEnv* j_env, jstring j_str); - static void printCurrentThreadID(); -}; diff --git a/android/sdk/src/main/jni/include/jni/scoped_java_ref.h b/android/sdk/src/main/jni/include/jni/scoped_java_ref.h deleted file mode 100644 index 809cba5d689..00000000000 --- a/android/sdk/src/main/jni/include/jni/scoped_java_ref.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include "core/core.h" - -class JavaRef { - public: - JavaRef(JNIEnv* env, jobject obj); - ~JavaRef(); - jobject GetObj() { return obj_; } - - private: - jobject obj_; - - DISALLOW_COPY_AND_ASSIGN(JavaRef); -}; diff --git a/android/sdk/src/main/jni/include/jni/turbo_module_manager.h b/android/sdk/src/main/jni/include/jni/turbo_module_manager.h deleted file mode 100644 index 0b0443c8842..00000000000 --- a/android/sdk/src/main/jni/include/jni/turbo_module_manager.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -class TurboModuleManager { - public: - static void Init(); - - static void Destory(); -}; - -int Install(JNIEnv *, jobject, jlong); - -void Uninstall(JNIEnv *, jobject, jlong); diff --git a/android/sdk/src/main/jni/include/jni/turbo_module_runtime.h b/android/sdk/src/main/jni/include/jni/turbo_module_runtime.h deleted file mode 100644 index a18cfcc6a32..00000000000 --- a/android/sdk/src/main/jni/include/jni/turbo_module_runtime.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include - -#include "jni_env.h" - -#ifndef ANDROID_DEMO_TURBOMODULERUNTIME_H -#define ANDROID_DEMO_TURBOMODULERUNTIME_H - -class TurboModuleRuntime { - public: - jobject turbo_module_manager_obj_; - std::shared_ptr turbo_env_; - std::unordered_map> - module_cache_; - - explicit TurboModuleRuntime(jobject obj) { - JNIEnv* env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - turbo_module_manager_obj_ = env->NewGlobalRef(obj); - env->DeleteLocalRef(obj); - } - - ~TurboModuleRuntime() { - TDF_BASE_DLOG(INFO) << "~TurboModuleRuntime()"; - JNIEnv* env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - if (turbo_module_manager_obj_) { - env->DeleteGlobalRef(turbo_module_manager_obj_); - } - - if (turbo_env_) { - turbo_env_.reset(); - } - - if (!module_cache_.empty()) { - module_cache_.clear(); - } - } -}; - -#endif // ANDROID_DEMO_TURBOMODULERUNTIME_H diff --git a/android/sdk/src/main/jni/include/jni/uri.h b/android/sdk/src/main/jni/include/jni/uri.h deleted file mode 100644 index 83e4d2d7b3d..00000000000 --- a/android/sdk/src/main/jni/include/jni/uri.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include - -#include "base/unicode_string_view.h" - -class Uri { - public: - using unicode_string_view = tdf::base::unicode_string_view; - - static std::shared_ptr Create(const unicode_string_view& uri); - explicit Uri(const unicode_string_view& uri); - ~Uri(); - unicode_string_view GetPath(); - unicode_string_view GetScheme(); - unicode_string_view Normalize(); - static bool Init(); - static bool Destory(); - - private: - jobject j_obj_uri_; -}; diff --git a/android/sdk/src/main/jni/include/loader/adr_loader.h b/android/sdk/src/main/jni/include/loader/adr_loader.h deleted file mode 100644 index c9012f5d02c..00000000000 --- a/android/sdk/src/main/jni/include/loader/adr_loader.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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 - -#include - -#include "core/core.h" -#include "jni/scoped_java_ref.h" - -template -bool ReadAsset(const tdf::base::unicode_string_view& path, - AAssetManager* aasset_manager, - std::basic_string& bytes, - bool is_auto_fill) { - tdf::base::unicode_string_view owner(""_u8s); - const char* asset_path = hippy::base::StringViewUtils::ToConstCharPointer(path, owner); - std::string file_path = std::string(asset_path); - if (file_path.length() > 0 && file_path[0] == '/') { - file_path = file_path.substr(1); - asset_path = file_path.c_str(); - } - TDF_BASE_DLOG(INFO) << "asset_path = " << asset_path; - - auto asset = - AAssetManager_open(aasset_manager, asset_path, AASSET_MODE_STREAMING); - if (asset) { - int size = AAsset_getLength(asset); - if (is_auto_fill) { - size += 1; - } - bytes.resize(size); - int offset = 0; - int readbytes; - while ((readbytes = AAsset_read(asset, &bytes[0] + offset, - bytes.size() - offset)) > 0) { - offset += readbytes; - } - if (is_auto_fill) { - bytes.back() = '\0'; - } - AAsset_close(asset); - TDF_BASE_DLOG(INFO) << "path = " << path << ", len = " << bytes.length() - << ", file_data = " - << reinterpret_cast(bytes.c_str()); - return true; - } - TDF_BASE_DLOG(INFO) << "ReadFile fail, file_path = " << file_path; - return false; -} - -class ADRLoader : public hippy::base::UriLoader { - public: - using unicode_string_view = tdf::base::unicode_string_view; - using u8string = unicode_string_view::u8string; - - ADRLoader(); - virtual ~ADRLoader() {} - - virtual bool RequestUntrustedContent(const unicode_string_view& uri, - std::function cb); - virtual bool RequestUntrustedContent(const unicode_string_view& uri, - u8string& str); - - inline void SetBridge(std::shared_ptr bridge) { bridge_ = bridge; } - inline void SetAAssetManager(AAssetManager* aasset_manager) { - aasset_manager_ = aasset_manager; - } - inline void SetWorkerTaskRunner(std::weak_ptr runner) { - runner_ = runner; - } - std::function GetRequestCB(int64_t request_id); - int64_t SetRequestCB(std::function cb); - - private: - bool LoadByFile(const unicode_string_view& path, - std::function cb); - bool LoadByAsset(const unicode_string_view& file_path, - std::function cb, - bool is_auto_fill = false); - bool LoadByHttp(const unicode_string_view& uri, - std::function cb); - - std::shared_ptr bridge_; - AAssetManager* aasset_manager_; - std::weak_ptr runner_; - std::unordered_map> request_map_; -}; diff --git a/android/sdk/src/main/jni/src/bridge/entry.cc b/android/sdk/src/main/jni/src/bridge/entry.cc deleted file mode 100644 index 6b1138ee7ec..00000000000 --- a/android/sdk/src/main/jni/src/bridge/entry.cc +++ /dev/null @@ -1,612 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "bridge/entry.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "bridge/java2js.h" -#include "bridge/js2java.h" -#include "bridge/runtime.h" -#include "core/base/string_view_utils.h" -#include "core/core.h" -#include "jni/turbo_module_manager.h" -#include "jni/exception_handler.h" -#include "jni/java_turbo_module.h" -#include "jni/jni_env.h" -#include "jni/jni_register.h" -#include "jni/uri.h" -#include "loader/adr_loader.h" - -namespace hippy { -namespace bridge { - -REGISTER_STATIC_JNI("com/tencent/mtt/hippy/HippyEngine", - "initNativeLogHandler", - "(Lcom/tencent/mtt/hippy/IHippyNativeLogHandler;)V", - InitNativeLogHandler) - -REGISTER_JNI("com/tencent/mtt/hippy/bridge/HippyBridgeImpl", - "initJSFramework", - "([BZZZLcom/tencent/mtt/hippy/bridge/NativeCallback;J)J", - InitInstance) - -REGISTER_JNI("com/tencent/mtt/hippy/bridge/HippyBridgeImpl", - "runScriptFromUri", - "(Ljava/lang/String;Landroid/content/res/AssetManager;ZLjava/lang/" - "String;JLcom/tencent/mtt/hippy/bridge/NativeCallback;)Z", - RunScriptFromUri) - -REGISTER_JNI("com/tencent/mtt/hippy/bridge/HippyBridgeImpl", - "destroy", - "(JZLcom/tencent/mtt/hippy/bridge/NativeCallback;)V", - DestroyInstance) - -using unicode_string_view = tdf::base::unicode_string_view; -using u8string = unicode_string_view::u8string; -using RegisterMap = hippy::base::RegisterMap; -using RegisterFunction = hippy::base::RegisterFunction; -using Ctx = hippy::napi::Ctx; -using StringViewUtils = hippy::base::StringViewUtils; -using HippyFile = hippy::base::HippyFile; -using V8VM = hippy::napi::V8VM; -#ifdef ENABLE_INSPECTOR -using V8InspectorClientImpl = hippy::inspector::V8InspectorClientImpl; -std::shared_ptr global_inspector = nullptr; -#endif - -static std::unordered_map, uint32_t>> - reuse_engine_map; -static std::mutex engine_mutex; - -static const int64_t kDefaultEngineId = -1; -static const int64_t kDebuggerEngineId = -9999; -static const uint32_t kRuntimeSlotIndex = 0; - -enum INIT_CB_STATE { - RUN_SCRIPT_ERROR = -1, - SUCCESS = 0, -}; - -void InitNativeLogHandler(JNIEnv* j_env, jobject j_object, jobject j_logger) { - if (!j_logger) { - return; - } - - jclass j_cls = j_env->GetObjectClass(j_logger); - if (!j_cls) { - return; - } - - jmethodID j_method = - j_env->GetMethodID(j_cls, "onReceiveNativeLogMessage", "(Ljava/lang/String;)V"); - if (!j_method) { - return; - } - std::shared_ptr logger = std::make_shared(j_env, j_logger); - tdf::base::LogMessage::SetDelegate([logger, j_method]( - const std::ostringstream& stream, - tdf::base::LogSeverity severity) { - std::shared_ptr instance = JNIEnvironment::GetInstance(); - JNIEnv* j_env = instance->AttachCurrentThread(); - - std::string str = stream.str(); - jstring j_logger_str = j_env->NewStringUTF((str.c_str())); - j_env->CallVoidMethod(logger->GetObj(), j_method, j_logger_str); - j_env->DeleteLocalRef(j_logger_str); - }); -} - -bool RunScript(std::shared_ptr runtime, - const unicode_string_view& file_name, - bool is_use_code_cache, - const unicode_string_view& code_cache_dir, - const unicode_string_view& uri, - AAssetManager* asset_manager) { - TDF_BASE_LOG(INFO) << "RunScript begin, file_name = " << file_name - << ", is_use_code_cache = " << is_use_code_cache - << ", code_cache_dir = " << code_cache_dir - << ", uri = " << uri - << ", asset_manager = " << asset_manager; - unicode_string_view script_content; - bool read_script_flag; - unicode_string_view code_cache_content; - uint64_t modify_time = 0; - - std::shared_ptr task_runner; - unicode_string_view code_cache_path; - if (is_use_code_cache) { - if (!asset_manager) { - auto time1 = std::chrono::time_point_cast( - std::chrono::system_clock::now()) - .time_since_epoch() - .count(); - modify_time = HippyFile::GetFileModifytime(uri); - auto time2 = std::chrono::time_point_cast( - std::chrono::system_clock::now()) - .time_since_epoch() - .count(); - - TDF_BASE_DLOG(INFO) << "GetFileModifytime cost %lld microseconds" - << time2 - time1; - } - - code_cache_path = code_cache_dir + file_name + unicode_string_view("_") + - unicode_string_view(std::to_string(modify_time)); - - std::promise read_file_promise; - std::future read_file_future = read_file_promise.get_future(); - std::unique_ptr task = std::make_unique(); - task->func_ = - hippy::base::MakeCopyable([p = std::move(read_file_promise), - code_cache_path, code_cache_dir]() mutable { - u8string content; - HippyFile::ReadFile(code_cache_path, content, true); - if (content.empty()) { - TDF_BASE_DLOG(INFO) << "Read code cache failed"; - int ret = HippyFile::RmFullPath(code_cache_dir); - TDF_BASE_DLOG(INFO) << "RmFullPath ret = " << ret; - HIPPY_USE(ret); - } else { - TDF_BASE_DLOG(INFO) << "Read code cache succ"; - } - p.set_value(std::move(content)); - }); - - std::shared_ptr engine = runtime->GetEngine(); - task_runner = engine->GetWorkerTaskRunner(); - task_runner->PostTask(std::move(task)); - u8string content; - read_script_flag = runtime->GetScope()->GetUriLoader() - ->RequestUntrustedContent(uri, content); - if (read_script_flag) { - script_content = unicode_string_view(std::move(content)); - } - code_cache_content = read_file_future.get(); - } else { - u8string content; - read_script_flag = runtime->GetScope()->GetUriLoader() - ->RequestUntrustedContent(uri, content); - if (read_script_flag) { - script_content = unicode_string_view(std::move(content)); - } - } - - TDF_BASE_DLOG(INFO) << "uri = " << uri - << "read_script_flag = " << read_script_flag - << ", script content = " << script_content; - - if (!read_script_flag || StringViewUtils::IsEmpty(script_content)) { - TDF_BASE_LOG(WARNING) << "read_script_flag = " << read_script_flag - << ", script content empty, uri = " << uri; - return false; - } - - auto ret = std::static_pointer_cast( - runtime->GetScope()->GetContext()) - ->RunScript(script_content, file_name, is_use_code_cache, - &code_cache_content); - if (is_use_code_cache) { - if (!StringViewUtils::IsEmpty(code_cache_content)) { - std::unique_ptr task = std::make_unique(); - task->func_ = [code_cache_path, code_cache_dir, code_cache_content] { - int check_dir_ret = HippyFile::CheckDir(code_cache_dir, F_OK); - TDF_BASE_DLOG(INFO) << "check_parent_dir_ret = " << check_dir_ret; - if (check_dir_ret) { - HippyFile::CreateDir(code_cache_dir, S_IRWXU); - } - - size_t pos = - StringViewUtils::FindLastOf(code_cache_path, EXTEND_LITERAL('/')); - unicode_string_view code_cache_parent_dir = - StringViewUtils::SubStr(code_cache_path, 0, pos); - int check_parent_dir_ret = - HippyFile::CheckDir(code_cache_parent_dir, F_OK); - TDF_BASE_DLOG(INFO) - << "check_parent_dir_ret = " << check_parent_dir_ret; - if (check_parent_dir_ret) { - HippyFile::CreateDir(code_cache_parent_dir, S_IRWXU); - } - - std::string u8_code_cache_content = - StringViewUtils::ToU8StdStr(code_cache_content); - bool save_file_ret = - HippyFile::SaveFile(code_cache_path, u8_code_cache_content); - TDF_BASE_LOG(INFO) << "code cache save_file_ret = " << save_file_ret; - HIPPY_USE(save_file_ret); - }; - task_runner->PostTask(std::move(task)); - } - } - - bool flag = !!ret; - TDF_BASE_LOG(INFO) << "runScript end, flag = " << flag; - return flag; -} - -jboolean RunScriptFromUri(JNIEnv* j_env, - jobject j_obj, - jstring j_uri, - jobject j_aasset_manager, - jboolean j_can_use_code_cache, - jstring j_code_cache_dir, - jlong j_runtime_id, - jobject j_cb) { - TDF_BASE_DLOG(INFO) << "runScriptFromUri begin, j_runtime_id = " - << j_runtime_id; - std::shared_ptr runtime = Runtime::Find(j_runtime_id); - if (!runtime) { - TDF_BASE_DLOG(WARNING) - << "HippyBridgeImpl runScriptFromUri, j_runtime_id invalid"; - return false; - } - - auto time_begin = std::chrono::time_point_cast( - std::chrono::system_clock::now()) - .time_since_epoch() - .count(); - if (!j_uri) { - TDF_BASE_DLOG(WARNING) << "HippyBridgeImpl runScriptFromUri, j_uri invalid"; - return false; - } - const unicode_string_view uri = JniUtils::ToStrView(j_env, j_uri); - const unicode_string_view code_cache_dir = - JniUtils::ToStrView(j_env, j_code_cache_dir); - auto pos = StringViewUtils::FindLastOf(uri, EXTEND_LITERAL('/')); - size_t len = StringViewUtils::GetLength(uri); - unicode_string_view script_name = StringViewUtils::SubStr(uri, pos + 1, len); - unicode_string_view base_path = StringViewUtils::SubStr(uri, 0, pos + 1); - TDF_BASE_DLOG(INFO) << "runScriptFromUri uri = " << uri - << ", script_name = " << script_name - << ", base_path = " << base_path - << ", code_cache_dir = " << code_cache_dir; - - auto runner = runtime->GetEngine()->GetJSRunner(); - std::shared_ptr ctx = runtime->GetScope()->GetContext(); - std::shared_ptr task = std::make_shared(); - task->callback = [ctx, base_path] { - ctx->SetGlobalStrVar("__HIPPYCURDIR__", base_path); - }; - runner->PostTask(task); - - std::shared_ptr loader = std::make_shared(); - loader->SetBridge(runtime->GetBridge()); - loader->SetWorkerTaskRunner(runtime->GetEngine()->GetWorkerTaskRunner()); - runtime->GetScope()->SetUriLoader(loader); - AAssetManager* aasset_manager = nullptr; - if (j_aasset_manager) { - aasset_manager = AAssetManager_fromJava(j_env, j_aasset_manager); - loader->SetAAssetManager(aasset_manager); - } - - std::shared_ptr save_object = std::make_shared(j_env, j_cb); - task = std::make_shared(); - task->callback = [runtime, save_object_ = std::move(save_object), script_name, - j_can_use_code_cache, code_cache_dir, uri, aasset_manager, - time_begin] { - TDF_BASE_DLOG(INFO) << "runScriptFromUri enter tast"; - bool flag = RunScript(runtime, script_name, j_can_use_code_cache, - code_cache_dir, uri, aasset_manager); - auto time_end = std::chrono::time_point_cast( - std::chrono::system_clock::now()) - .time_since_epoch() - .count(); - - TDF_BASE_DLOG(INFO) << "runScriptFromUri = " << (time_end - time_begin) - << ", uri = " << uri; - - if (flag) { - hippy::bridge::CallJavaMethod(save_object_->GetObj(), - INIT_CB_STATE::SUCCESS); - } else { - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jstring j_msg = JniUtils::StrViewToJString(j_env, u"run script error"); - CallJavaMethod(save_object_->GetObj(), INIT_CB_STATE::RUN_SCRIPT_ERROR, - j_msg); - j_env->DeleteLocalRef(j_msg); - } - return flag; - }; - - runner->PostTask(task); - - return true; -} - -void HandleUncaughtJsError(v8::Local message, - v8::Local error) { - TDF_BASE_DLOG(INFO) << "HandleUncaughtJsError begin"; - - if (error.IsEmpty()) { - TDF_BASE_DLOG(ERROR) << "HandleUncaughtJsError error is empty"; - return; - } - - v8::Isolate* isolate = message->GetIsolate(); - std::shared_ptr runtime = Runtime::Find(isolate); - if (!runtime) { - return; - } - - std::shared_ptr ctx = - std::static_pointer_cast( - runtime->GetScope()->GetContext()); - TDF_BASE_LOG(ERROR) << "HandleUncaughtJsError error desc = " - << ctx->GetMsgDesc(message) - << ", stack = " << ctx->GetStackInfo(message); - ExceptionHandler::ReportJsException(runtime, ctx->GetMsgDesc(message), - ctx->GetStackInfo(message)); - ctx->ThrowExceptionToJS( - std::make_shared(isolate, error)); - - TDF_BASE_DLOG(INFO) << "HandleUncaughtJsError end"; -} - -jlong InitInstance(JNIEnv* j_env, - jobject j_object, - jbyteArray j_global_config, - jboolean j_single_thread_mode, - jboolean j_enable_v8_serialization, - jboolean j_is_dev_module, - jobject j_callback, - jlong j_group_id) { - TDF_BASE_LOG(INFO) << "InitInstance begin, j_single_thread_mode = " - << static_cast(j_single_thread_mode) - << ", j_bridge_param_json = " - << static_cast(j_enable_v8_serialization) - << ", j_is_dev_module = " - << static_cast(j_is_dev_module) - << ", j_group_id = " << j_group_id; - std::shared_ptr runtime = - std::make_shared(std::make_shared(j_env, j_object), - j_enable_v8_serialization, j_is_dev_module); - int32_t runtime_id = runtime->GetId(); - Runtime::Insert(runtime); - RegisterFunction vm_cb = [runtime_id](void* vm) { - V8VM* v8_vm = reinterpret_cast(vm); - v8::Isolate* isolate = v8_vm->isolate_; - v8::HandleScope handle_scope(isolate); - isolate->AddMessageListener(HandleUncaughtJsError); - isolate->SetData(kRuntimeSlotIndex, reinterpret_cast(runtime_id)); - }; - - std::unique_ptr engine_cb_map = std::make_unique(); - engine_cb_map->insert(std::make_pair(hippy::base::kVMCreateCBKey, vm_cb)); - - unicode_string_view global_config = - JniUtils::JByteArrayToStrView(j_env, j_global_config); - - TDF_BASE_LOG(INFO) << "global_config = " << global_config; - std::shared_ptr task = std::make_shared(); - std::shared_ptr save_object = - std::make_shared(j_env, j_callback); - - RegisterFunction context_cb = [runtime, global_config, - runtime_id](void* scopeWrapper) { - TDF_BASE_LOG(INFO) << "InitInstance register hippyCallNatives, runtime_id = " << runtime_id; - TDF_BASE_DCHECK(scopeWrapper); - ScopeWrapper* wrapper = reinterpret_cast(scopeWrapper); - TDF_BASE_DCHECK(wrapper); - std::shared_ptr scope = wrapper->scope_.lock(); - if (!scope) { - TDF_BASE_DLOG(ERROR) << "register hippyCallNatives, scope error"; - return; - } -#ifdef ENABLE_INSPECTOR - if (runtime->IsDebug()) { - if (!global_inspector) { - global_inspector = std::make_shared(scope); - global_inspector->Connect(runtime->GetBridge()); - } else { - global_inspector->Reset(scope, runtime->GetBridge()); - } - global_inspector->CreateContext(); - } -#endif - std::shared_ptr ctx = scope->GetContext(); - ctx->RegisterGlobalInJs(); - hippy::base::RegisterFunction fn = - TO_REGISTER_FUNCTION(hippy::bridge::CallJava, hippy::napi::CBDataTuple); - ctx->RegisterNativeBinding("hippyCallNatives", fn, reinterpret_cast(runtime_id)); - bool ret = ctx->SetGlobalJsonVar("__HIPPYNATIVEGLOBAL__", global_config); - if (!ret) { - TDF_BASE_DLOG(ERROR) << "register __HIPPYNATIVEGLOBAL__ failed"; - ExceptionHandler::ReportJsException(runtime, u"global_config parse error", - global_config); - } - }; - std::unique_ptr scope_cb_map = std::make_unique(); - scope_cb_map->insert( - std::make_pair(hippy::base::kContextCreatedCBKey, context_cb)); - - RegisterFunction scope_cb = [save_object_ = std::move(save_object)](void*) { - TDF_BASE_LOG(INFO) << "run scope cb"; - hippy::bridge::CallJavaMethod(save_object_->GetObj(), - INIT_CB_STATE::SUCCESS); - }; - - scope_cb_map->insert( - std::make_pair(hippy::base::KScopeInitializedCBKey, scope_cb)); - - int64_t group = j_group_id; - std::shared_ptr engine; - if (j_is_dev_module) { - std::lock_guard lock(engine_mutex); - TDF_BASE_DLOG(INFO) << "debug mode"; - group = kDebuggerEngineId; - auto it = reuse_engine_map.find(group); - if (it != reuse_engine_map.end()) { - engine = std::get>(it->second); - runtime->SetEngine(engine); - - std::shared_ptr v8_vm = std::static_pointer_cast(engine->GetVM()); - v8::Isolate* isolate = v8_vm->isolate_; - isolate->SetData(kRuntimeSlotIndex, reinterpret_cast(runtime_id)); - } else { - engine = std::make_shared(std::move(engine_cb_map)); - runtime->SetEngine(engine); - reuse_engine_map[group] = std::make_pair(engine, 1); - } - } else if (group != kDefaultEngineId) { - std::lock_guard lock(engine_mutex); - auto it = reuse_engine_map.find(group); - if (it != reuse_engine_map.end()) { - TDF_BASE_DLOG(INFO) << "engine reuse"; - engine = std::get>(it->second); - runtime->SetEngine(engine); - std::get(it->second) += 1; - std::shared_ptr v8_vm = std::static_pointer_cast(engine->GetVM()); - v8::Isolate* isolate = v8_vm->isolate_; - isolate->SetData(kRuntimeSlotIndex, reinterpret_cast(-1)); - // -1 means single isolate multi-context mode - TDF_BASE_DLOG(INFO) << "engine cnt = " << std::get(it->second) - << ", use_count = " << engine.use_count(); - } else { - TDF_BASE_DLOG(INFO) << "engine create"; - engine = std::make_shared(std::move(engine_cb_map)); - runtime->SetEngine(engine); - reuse_engine_map[group] = std::make_pair(engine, 1); - } - } else { // kDefaultEngineId - TDF_BASE_DLOG(INFO) << "default create engine"; - engine = std::make_shared(std::move(engine_cb_map)); - runtime->SetEngine(engine); - } - runtime->SetScope( - runtime->GetEngine()->CreateScope("", std::move(scope_cb_map))); - TDF_BASE_DLOG(INFO) << "group = " << group; - runtime->SetGroupId(group); - TDF_BASE_LOG(INFO) << "InitInstance end, runtime_id = " << runtime_id; - - return runtime_id; -} - -void DestroyInstance(JNIEnv* j_env, - jobject j_object, - jlong j_runtime_id, - jboolean j_single_thread_mode, - jobject j_callback) { - TDF_BASE_DLOG(INFO) << "DestroyInstance begin, j_runtime_id = " - << j_runtime_id; - int32_t runtime_id = static_cast(j_runtime_id); - std::shared_ptr runtime = Runtime::Find(runtime_id); - if (!runtime) { - TDF_BASE_DLOG(WARNING) << "HippyBridgeImpl destroy, j_runtime_id invalid"; - return; - } - - std::shared_ptr task = std::make_shared(); - task->callback = [runtime, runtime_id] { - TDF_BASE_LOG(INFO) << "js destroy begin, runtime_id " << runtime_id; -#ifdef ENABLE_INSPECTOR - if (runtime->IsDebug()) { - global_inspector->DestroyContext(); - global_inspector->Reset(nullptr, runtime->GetBridge()); - } else { - runtime->GetScope()->WillExit(); - } -#else - runtime->GetScope()->WillExit(); -#endif - TDF_BASE_LOG(INFO) << "SetScope nullptr"; - runtime->SetScope(nullptr); - TDF_BASE_LOG(INFO) << "erase runtime"; - Runtime::Erase(runtime); - TDF_BASE_LOG(INFO) << "js destroy end"; - }; - int64_t group = runtime->GetGroupId(); - if (group == kDebuggerEngineId) { - runtime->GetScope()->WillExit(); - } - runtime->GetEngine()->GetJSRunner()->PostTask(task); - TDF_BASE_DLOG(INFO) << "destroy, group = " << group; - if (group == kDebuggerEngineId) { - } else if (group == kDefaultEngineId) { - runtime->GetEngine()->TerminateRunner(); - } else { - std::lock_guard lock(engine_mutex); - auto it = reuse_engine_map.find(group); - if (it != reuse_engine_map.end()) { - auto engine = std::get>(it->second); - uint32_t cnt = std::get(it->second); - TDF_BASE_DLOG(INFO) << "reuse_engine_map cnt = " << cnt; - if (cnt == 1) { - reuse_engine_map.erase(it); - engine->TerminateRunner(); - } else { - std::get(it->second) = cnt - 1; - } - } else { - TDF_BASE_DLOG(FATAL) << "engine not find"; - } - } - hippy::bridge::CallJavaMethod(j_callback, INIT_CB_STATE::SUCCESS); - TDF_BASE_DLOG(INFO) << "destroy end"; -} - -} // namespace bridge -} // namespace hippy - -jint JNI_OnLoad(JavaVM* j_vm, void* reserved) { - JNIEnv* j_env; - jint onLoad_err = -1; - if ((j_vm)->GetEnv(reinterpret_cast(&j_env), JNI_VERSION_1_4) != - JNI_OK) { - return onLoad_err; - } - if (!j_env) { - return onLoad_err; - } - - bool ret = JNIRegister::RegisterMethods(j_env); - if (!ret) { - return onLoad_err; - } - - JNIEnvironment::GetInstance()->init(j_vm, j_env); - - Uri::Init(); - JavaTurboModule::Init(); - ConvertUtils::Init(); - TurboModuleManager::Init(); - - return JNI_VERSION_1_4; -} - -void JNI_OnUnload(JavaVM* j_vm, void* reserved) { - hippy::napi::V8VM::PlatformDestroy(); - - Uri::Destory(); - JavaTurboModule::Destory(); - ConvertUtils::Destory(); - TurboModuleManager::Destory(); - - JNIEnvironment::DestroyInstance(); -} diff --git a/android/sdk/src/main/jni/src/bridge/java2js.cc b/android/sdk/src/main/jni/src/bridge/java2js.cc deleted file mode 100644 index e6bbb4a665d..00000000000 --- a/android/sdk/src/main/jni/src/bridge/java2js.cc +++ /dev/null @@ -1,239 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "bridge/java2js.h" - -#include "bridge/js2java.h" -#include "bridge/runtime.h" -#include "core/base/string_view_utils.h" -#include "jni/jni_register.h" - -namespace hippy { -namespace bridge { - -enum CALLFUNCTION_CB_STATE { - NO_METHOD_ERROR = -2, - DESERIALIZER_FAILED = -1, - SUCCESS = 0, -}; - -REGISTER_JNI( - "com/tencent/mtt/hippy/bridge/HippyBridgeImpl", - "callFunction", - "(Ljava/lang/String;JLcom/tencent/mtt/hippy/bridge/NativeCallback;[BII)V", - CallFunctionByHeapBuffer) - -REGISTER_JNI("com/tencent/mtt/hippy/bridge/HippyBridgeImpl", - "callFunction", - "(Ljava/lang/String;JLcom/tencent/mtt/hippy/bridge/" - "NativeCallback;Ljava/nio/ByteBuffer;II)V", - CallFunctionByDirectBuffer) - -using unicode_string_view = tdf::base::unicode_string_view; -using bytes = std::string; - -using Ctx = hippy::napi::Ctx; -using CtxValue = hippy::napi::CtxValue; -using StringViewUtils = hippy::base::StringViewUtils; -#ifdef ENABLE_INSPECTOR -using V8InspectorClientImpl = hippy::inspector::V8InspectorClientImpl; -extern std::shared_ptr global_inspector; -#endif - -const char kHippyBridgeName[] = "hippyBridge"; - -void CallFunction(JNIEnv* j_env, - jobject j_obj, - jstring j_action, - jlong j_runtime_id, - jobject j_callback, - bytes buffer_data, - std::shared_ptr buffer_owner) { - TDF_BASE_DLOG(INFO) << "CallFunction j_runtime_id = " << j_runtime_id; - std::shared_ptr runtime = Runtime::Find(j_runtime_id); - if (!runtime) { - TDF_BASE_DLOG(WARNING) << "CallFunction j_runtime_id invalid"; - return; - } - std::shared_ptr runner = - runtime->GetEngine()->GetJSRunner(); - if (!j_action) { - TDF_BASE_DLOG(WARNING) << "CallFunction j_action invalid"; - return; - } - unicode_string_view action_name = JniUtils::ToStrView(j_env, j_action); - std::shared_ptr cb = std::make_shared(j_env, j_callback); - std::shared_ptr task = std::make_shared(); - task->callback = [runtime, cb_ = std::move(cb), action_name, - buffer_data_ = std::move(buffer_data), - buffer_owner_ = std::move(buffer_owner)] { - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - std::shared_ptr scope = runtime->GetScope(); - if (!scope) { - TDF_BASE_DLOG(WARNING) << "CallFunction scope invalid"; - return; - } - std::shared_ptr context = scope->GetContext(); - if (!runtime->GetBridgeFunc()) { - TDF_BASE_DLOG(INFO) << "init bridge func"; - unicode_string_view name(kHippyBridgeName); - std::shared_ptr fn = context->GetJsFn(name); - bool is_fn = context->IsFunction(fn); - TDF_BASE_DLOG(INFO) << "is_fn = " << is_fn; - - if (!is_fn) { - jstring j_msg = - JniUtils::StrViewToJString(j_env, u"hippyBridge not find"); - CallJavaMethod(cb_->GetObj(), CALLFUNCTION_CB_STATE::NO_METHOD_ERROR, - j_msg); - j_env->DeleteLocalRef(j_msg); - return; - } else { - runtime->SetBridgeFunc(fn); - } - } - TDF_BASE_DCHECK(action_name.encoding() == - unicode_string_view::Encoding::Utf16); - if (runtime->IsDebug() && - !action_name.utf16_value().compare(u"onWebsocketMsg")) { -#ifdef ENABLE_INSPECTOR - std::u16string str(reinterpret_cast(&buffer_data_[0]), - buffer_data_.length() / sizeof(char16_t)); - global_inspector->SendMessageToV8( - std::move(unicode_string_view(std::move(str)))); -#endif - CallJavaMethod(cb_->GetObj(), CALLFUNCTION_CB_STATE::SUCCESS); - return; - } - - std::shared_ptr action = context->CreateString(action_name); - std::shared_ptr params; - if (runtime->IsEnableV8Serialization()) { - v8::Isolate* isolate = std::static_pointer_cast( - runtime->GetEngine()->GetVM()) - ->isolate_; - v8::HandleScope handle_scope(isolate); - v8::Local ctx = std::static_pointer_cast( - runtime->GetScope()->GetContext()) - ->context_persistent_.Get(isolate); - hippy::napi::V8TryCatch try_catch(true, context); - v8::ValueDeserializer deserializer( - isolate, reinterpret_cast(buffer_data_.c_str()), - buffer_data_.length()); - TDF_BASE_CHECK(deserializer.ReadHeader(ctx).FromMaybe(false)); - v8::MaybeLocal ret = deserializer.ReadValue(ctx); - if (!ret.IsEmpty()) { - params = std::make_shared( - isolate, ret.ToLocalChecked()); - } else { - jstring j_msg; - if (try_catch.HasCaught()) { - unicode_string_view msg = try_catch.GetExceptionMsg(); - j_msg = JniUtils::StrViewToJString(j_env, msg); - } else { - j_msg = JniUtils::StrViewToJString(j_env, u"deserializer error"); - } - CallJavaMethod( - cb_->GetObj(), - hippy::bridge::CALLFUNCTION_CB_STATE::DESERIALIZER_FAILED, j_msg); - j_env->DeleteLocalRef(j_msg); - return; - } - } else { - std::u16string str(reinterpret_cast(&buffer_data_[0]), - buffer_data_.length() / sizeof(char16_t)); - unicode_string_view buf_str(std::move(str)); - TDF_BASE_DLOG(INFO) << "action_name = " << action_name - << ", buf_str = " << buf_str; - params = context->CreateObject(buf_str); - } - if (!params) { - params = context->CreateNull(); - } - std::shared_ptr argv[] = {action, params}; - context->CallFunction(runtime->GetBridgeFunc(), 2, argv); - - CallJavaMethod(cb_->GetObj(), CALLFUNCTION_CB_STATE::SUCCESS); - }; - - runner->PostTask(task); -} - -void CallFunctionByHeapBuffer(JNIEnv* j_env, - jobject j_obj, - jstring j_action, - jlong j_runtime_id, - jobject j_callback, - jbyteArray j_byte_array, - jint j_offset, - jint j_length) { - CallFunction(j_env, j_obj, j_action, j_runtime_id, j_callback, - JniUtils::AppendJavaByteArrayToBytes(j_env, j_byte_array, - j_offset, j_length), - nullptr); -} - -void CallFunctionByDirectBuffer(JNIEnv* j_env, - jobject j_obj, - jstring j_action, - jlong j_runtime_id, - jobject j_callback, - jobject j_buffer, - jint j_offset, - jint j_length) { - char* buffer_address = - static_cast(j_env->GetDirectBufferAddress(j_buffer)); - TDF_BASE_CHECK(buffer_address != nullptr); - CallFunction(j_env, j_obj, j_action, j_runtime_id, j_callback, - bytes(buffer_address + j_offset, j_length), - std::make_shared(j_env, j_buffer)); -} - -void CallJavaMethod(jobject j_obj, jlong j_value, jstring j_msg) { - if (!j_obj) { - TDF_BASE_DLOG(INFO) << "CallJavaMethod j_obj is nullptr"; - return; - } - - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jclass j_class = j_env->GetObjectClass(j_obj); - if (!j_class) { - TDF_BASE_LOG(ERROR) << "CallJavaMethod j_class error"; - return; - } - - jmethodID j_cb_id = - j_env->GetMethodID(j_class, "Callback", "(JLjava/lang/String;)V"); - if (!j_cb_id) { - TDF_BASE_LOG(ERROR) << "CallJavaMethod j_cb_id error"; - return; - } - - j_env->CallVoidMethod(j_obj, j_cb_id, j_value, j_msg); - JNIEnvironment::ClearJEnvException(j_env); - if (j_class) { - j_env->DeleteLocalRef(j_class); - } -} - -} // namespace bridge -} // namespace hippy diff --git a/android/sdk/src/main/jni/src/bridge/js2java.cc b/android/sdk/src/main/jni/src/bridge/js2java.cc deleted file mode 100644 index 7be21f62477..00000000000 --- a/android/sdk/src/main/jni/src/bridge/js2java.cc +++ /dev/null @@ -1,178 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "bridge/js2java.h" - -#include - -#include "base/logging.h" -#include "base/unicode_string_view.h" -#include "bridge/runtime.h" -#include "bridge/serializer.h" -#include "core/base/string_view_utils.h" -#include "jni/jni_env.h" - -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; - -namespace hippy { -namespace bridge { - -void CallJava(hippy::napi::CBDataTuple *data) { - TDF_BASE_DLOG(INFO) << "CallJava"; - int32_t runtime_id = static_cast(reinterpret_cast(data->cb_tuple_.data_)); - std::shared_ptr runtime = Runtime::Find(runtime_id); - if (!runtime) { - return; - } - - const v8::FunctionCallbackInfo &info = data->info_; - v8::Isolate *isolate = info.GetIsolate(); - if (!isolate) { - TDF_BASE_DLOG(ERROR) << "CallJava isolate error"; - return; - } - - v8::HandleScope handle_scope(isolate); - std::shared_ptr v8_ctx = - std::static_pointer_cast( - runtime->GetScope()->GetContext()); - v8::Local context = v8_ctx->context_persistent_.Get(isolate); - v8::Context::Scope context_scope(context); - if (context.IsEmpty()) { - TDF_BASE_DLOG(ERROR) << "CallJava context empty"; - return; - } - - jstring j_module_name = nullptr; - std::shared_ptr instance = JNIEnvironment::GetInstance(); - JNIEnv *j_env = instance->AttachCurrentThread(); - if (info.Length() >= 1 && !info[0].IsEmpty()) { - v8::MaybeLocal module_maybe_str = info[0]->ToString(context); - if (module_maybe_str.IsEmpty()) { - isolate->ThrowException( - v8::Exception::TypeError( - v8::String::NewFromOneByte(isolate, - reinterpret_cast("module name error")) - .ToLocalChecked())); - return; - } - unicode_string_view module_name = v8_ctx->ToStringView(module_maybe_str.ToLocalChecked()); - j_module_name = JniUtils::StrViewToJString(j_env, module_name); - TDF_BASE_DLOG(INFO) << "CallJava module_name = " << module_name; - } else { - isolate->ThrowException( - v8::Exception::Error( - v8::String::NewFromOneByte(isolate, - reinterpret_cast("info error")) - .ToLocalChecked())); - return; - } - - jstring j_module_func = nullptr; - if (info.Length() >= 2 && !info[1].IsEmpty()) { - v8::MaybeLocal func_maybe_str = info[1]->ToString(context); - if (func_maybe_str.IsEmpty()) { - isolate->ThrowException( - v8::Exception::TypeError( - v8::String::NewFromOneByte(isolate, - reinterpret_cast("func name error")) - .ToLocalChecked())); - return; - } - unicode_string_view module_func = v8_ctx->ToStringView(func_maybe_str.ToLocalChecked()); - j_module_func = JniUtils::StrViewToJString(j_env, module_func); - TDF_BASE_DLOG(INFO) << "CallJava module_func = " << module_func; - } else { - isolate->ThrowException( - v8::Exception::Error( - v8::String::NewFromOneByte(isolate, - reinterpret_cast("info error")) - .ToLocalChecked())); - return; - } - - jstring j_cb_id = nullptr; - if (info.Length() >= 3 && !info[2].IsEmpty()) { - v8::MaybeLocal cb_id_maybe_str = info[2]->ToString(context); - if (!cb_id_maybe_str.IsEmpty()) { - unicode_string_view cb_id = v8_ctx->ToStringView(cb_id_maybe_str.ToLocalChecked()); - j_cb_id = JniUtils::StrViewToJString(j_env, cb_id); - TDF_BASE_DLOG(INFO) << "CallJava cb_id = " << cb_id; - } - } - - std::string buffer_data; - if (info.Length() >= 4 && !info[3].IsEmpty() && info[3]->IsObject()) { - if (runtime->IsEnableV8Serialization()) { - Serializer serializer(isolate, context, runtime->GetBuffer()); - serializer.WriteHeader(); - serializer.WriteValue(info[3]); - std::pair pair = serializer.Release(); - buffer_data = - std::string(reinterpret_cast(pair.first), pair.second); - } else { - std::shared_ptr obj = - std::make_shared(isolate, info[3]); - unicode_string_view json; - TDF_BASE_DCHECK(v8_ctx->GetValueJson(obj, &json)); - TDF_BASE_DLOG(INFO) << "CallJava json = " << json; - buffer_data = StringViewUtils::ToU8StdStr(json); - } - } - - uint8_t transfer_type = 0; - if (info.Length() >= 5 && !info[4].IsEmpty() && info[4]->IsNumber()) { - transfer_type = - static_cast(info[4]->NumberValue(context).FromMaybe(0)); - } - TDF_BASE_DLOG(INFO) << "CallNative transfer_type = " << transfer_type; - - jobject j_buffer = nullptr; - jmethodID j_method = nullptr; - if (transfer_type == 1) { // Direct - j_buffer = j_env->NewDirectByteBuffer( - const_cast(reinterpret_cast(buffer_data.c_str())), - buffer_data.length()); - j_method = instance->GetMethods().j_call_natives_direct_method_id; - } else { // Default - j_buffer = j_env->NewByteArray(buffer_data.length()); - j_env->SetByteArrayRegion( - reinterpret_cast(j_buffer), 0, buffer_data.length(), - reinterpret_cast(buffer_data.c_str())); - j_method = instance->GetMethods().j_call_natives_method_id; - } - - j_env->CallVoidMethod(runtime->GetBridge()->GetObj(), j_method, j_module_name, - j_module_func, j_cb_id, j_buffer); - - JNIEnvironment::ClearJEnvException(j_env); - - // delete local ref - j_env->DeleteLocalRef(j_module_name); - j_env->DeleteLocalRef(j_module_func); - j_env->DeleteLocalRef(j_cb_id); - j_env->DeleteLocalRef(j_buffer); -} - -} // namespace bridge -} // namespace hippy diff --git a/android/sdk/src/main/jni/src/bridge/runtime.cc b/android/sdk/src/main/jni/src/bridge/runtime.cc deleted file mode 100644 index 47db489e1dd..00000000000 --- a/android/sdk/src/main/jni/src/bridge/runtime.cc +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "bridge/runtime.h" - -#include -#include - -using V8Ctx = hippy::napi::V8Ctx; - -static std::unordered_map> RuntimeMap; -static std::mutex mutex; - -static std::atomic global_runtime_key{0}; - -Runtime::Runtime(std::shared_ptr bridge, bool enable_v8_serialization, bool is_dev) - : enable_v8_serialization_(enable_v8_serialization), is_debug_(is_dev), bridge_(bridge) { - id_ = global_runtime_key.fetch_add(1); -} - -void Runtime::Insert(std::shared_ptr runtime) { - std::lock_guard lock(mutex); - RuntimeMap[runtime->id_] = runtime; -} - -std::shared_ptr Runtime::Find(int32_t id) { - std::lock_guard lock(mutex); - const auto it = RuntimeMap.find(id); - if (it == RuntimeMap.end()) { - return nullptr; - } - - return it->second; -} - -static const uint32_t kRuntimeSlotIndex = 0; -std::shared_ptr Runtime::Find(v8::Isolate *isolate) { - if (!isolate) { - return nullptr; - } - int32_t runtime_id = - static_cast(reinterpret_cast(isolate->GetData(kRuntimeSlotIndex))); - if (runtime_id == -1) {// -1 means single isolate multi context mode - v8::Local context = isolate->GetCurrentContext(); - std::lock_guard lock(mutex); - for (auto p: RuntimeMap) { - std::shared_ptr scope = p.second->GetScope(); - std::shared_ptr ctx = std::static_pointer_cast(scope->GetContext()); - if (ctx->context_persistent_ == context) { - return p.second; - } - } - } else { - return Runtime::Find(runtime_id); - } - return nullptr; -} - -bool Runtime::Erase(int32_t id) { - std::lock_guard lock(mutex); - const auto it = RuntimeMap.find(id); - if (it == RuntimeMap.end()) { - return false; - } - - RuntimeMap.erase(it); - return true; -} - -bool Runtime::Erase(std::shared_ptr runtime) { - return Runtime::Erase(runtime->id_); -} diff --git a/android/sdk/src/main/jni/src/bridge/serializer.cc b/android/sdk/src/main/jni/src/bridge/serializer.cc deleted file mode 100644 index 7ba3a00d3cc..00000000000 --- a/android/sdk/src/main/jni/src/bridge/serializer.cc +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "bridge/serializer.h" - -#include "v8/v8.h" - -const int kMaxReusedBuffersSize = 128 * 1024; // 128k - -Serializer::Serializer(v8::Isolate* isolate, - v8::Local context, - std::string& reused_buffer) - : isolate_(isolate), - context_global_(isolate_, context), - serializer_(isolate, this), - reused_buffer_(reused_buffer) {} - -Serializer::~Serializer() { - context_global_.Reset(); -} - -v8::Maybe Serializer::WriteValue(v8::Local value) { - return serializer_.WriteValue(context_global_.Get(isolate_), value); -} - -void Serializer::WriteHeader() { - return serializer_.WriteHeader(); -} - -std::pair Serializer::Release() { - return serializer_.Release(); -} - -void Serializer::ThrowDataCloneError(v8::Local message) { - v8::HandleScope handle_scope(isolate_); - isolate_->ThrowException(v8::Exception::Error(message)); -} - -void* Serializer::ReallocateBufferMemory(void* old_buffer, - size_t size, - size_t* actual_size) { - if (reused_buffer_.length() < size) { - reused_buffer_.resize(std::max(reused_buffer_.capacity() * 2, size)); - } - *actual_size = reused_buffer_.length(); - return static_cast(&reused_buffer_[0]); -} - -void Serializer::FreeBufferMemory(void* buffer) { - if (reused_buffer_.length() > kMaxReusedBuffersSize) { - reused_buffer_.resize(0); - reused_buffer_.shrink_to_fit(); - } -} diff --git a/android/sdk/src/main/jni/src/inspector/v8_channel_impl.cc b/android/sdk/src/main/jni/src/inspector/v8_channel_impl.cc deleted file mode 100644 index 814d8e1849f..00000000000 --- a/android/sdk/src/main/jni/src/inspector/v8_channel_impl.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "inspector/v8_channel_impl.h" - -#include - -#include "jni/jni_env.h" - -namespace hippy { -namespace inspector { - -V8ChannelImpl::V8ChannelImpl(std::shared_ptr bridge) - : bridge_(bridge) {} - -void V8ChannelImpl::sendResponse( - int callId, - std::unique_ptr message) { - if (message->string().is8Bit()) { - return; - } - - const uint16_t* source = message->string().characters16(); - int len = message->string().length(); - std::shared_ptr instance = JNIEnvironment::GetInstance(); - JNIEnv* j_env = instance->AttachCurrentThread(); - jbyteArray msg = j_env->NewByteArray(len * sizeof(*source)); - j_env->SetByteArrayRegion( - msg, 0, len * sizeof(*source), - reinterpret_cast(reinterpret_cast(source))); - - if (instance->GetMethods().j_inspector_channel_method_id && bridge_) { - j_env->CallVoidMethod(bridge_->GetObj(), - instance->GetMethods().j_inspector_channel_method_id, - msg); - } - - j_env->DeleteLocalRef(msg); -} - -void V8ChannelImpl::sendNotification( - std::unique_ptr message) { - if (message->string().is8Bit()) { - return; - } - - const uint16_t* source = message->string().characters16(); - int len = message->string().length(); - std::shared_ptr instance = JNIEnvironment::GetInstance(); - JNIEnv* j_env = instance->AttachCurrentThread(); - jbyteArray msg = j_env->NewByteArray(len * sizeof(*source)); - j_env->SetByteArrayRegion( - msg, 0, len * sizeof(*source), - reinterpret_cast(reinterpret_cast(source))); - - if (instance->GetMethods().j_inspector_channel_method_id && bridge_) { - j_env->CallVoidMethod(bridge_->GetObj(), - instance->GetMethods().j_inspector_channel_method_id, - msg); - } - - j_env->DeleteLocalRef(msg); -} - -} // namespace inspector -} // namespace hippy diff --git a/android/sdk/src/main/jni/src/inspector/v8_inspector_client_impl.cc b/android/sdk/src/main/jni/src/inspector/v8_inspector_client_impl.cc deleted file mode 100644 index 1813c1e5758..00000000000 --- a/android/sdk/src/main/jni/src/inspector/v8_inspector_client_impl.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "inspector/v8_inspector_client_impl.h" - -#include "core/core.h" - -namespace hippy { -namespace inspector { - -V8InspectorClientImpl::V8InspectorClientImpl(std::shared_ptr scope) - : scope_(scope) { - std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); - v8::Isolate* isolate = ctx->isolate_; - v8::HandleScope handle_scope(isolate); - inspector_ = v8_inspector::V8Inspector::create(isolate, this); -} - -void V8InspectorClientImpl::Reset(std::shared_ptr scope, - std::shared_ptr bridge) { - scope_ = scope; - channel_->SetBridge(bridge); -} - -void V8InspectorClientImpl::Connect(std::shared_ptr bridge) { - channel_ = std::make_unique(bridge); - session_ = inspector_->connect(1, channel_.get(), v8_inspector::StringView()); -} - -void V8InspectorClientImpl::CreateContext() { - std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); - v8::Isolate* isolate = ctx->isolate_; - v8::HandleScope handle_scope(isolate); - v8::Local context = - v8::Local::New(isolate, ctx->context_persistent_); - v8::Context::Scope context_scope(context); - uint8_t name_uint8[] = "Hippy"; - inspector_->contextCreated(v8_inspector::V8ContextInfo( - context, 1, v8_inspector::StringView(name_uint8, arraysize(name_uint8)))); -} - -void V8InspectorClientImpl::SendMessageToV8(const unicode_string_view& params) { - if (channel_) { - unicode_string_view::Encoding encoding = params.encoding(); - v8_inspector::StringView message_view; - switch (encoding) { - case unicode_string_view::Encoding::Latin1: { - std::string str = params.latin1_value(); - if (!str.compare("chrome_socket_closed")) { - session_ = inspector_->connect(1, channel_.get(), - v8_inspector::StringView()); - return; - } - message_view = v8_inspector::StringView( - reinterpret_cast(str.c_str()), str.length()); - break; - } - case unicode_string_view::Encoding::Utf16: { - std::u16string str = params.utf16_value(); - if (!str.compare(u"chrome_socket_closed")) { - session_ = inspector_->connect(1, channel_.get(), - v8_inspector::StringView()); - return; - } - message_view = v8_inspector::StringView( - reinterpret_cast(str.c_str()), str.length()); - break; - } - default: - TDF_BASE_DLOG(INFO) << "encoding = " << static_cast(encoding); - TDF_BASE_NOTREACHED(); - break; - } - session_->dispatchProtocolMessage(message_view); - } -} - -void V8InspectorClientImpl::DestroyContext() { - TDF_BASE_DLOG(INFO) << "V8InspectorClientImpl DestroyContext"; - std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); - if (!ctx) { - TDF_BASE_DLOG(ERROR) << "V8InspectorClientImpl ctx error"; - return; - } - v8::Isolate* isolate = ctx->isolate_; - v8::HandleScope handle_scope(isolate); - v8::Local context = - v8::Local::New(isolate, ctx->context_persistent_); - v8::Context::Scope context_scope(context); - TDF_BASE_DLOG(INFO) << "inspector contextDestroyed begin"; - inspector_->contextDestroyed(context); - TDF_BASE_DLOG(INFO) << "inspector contextDestroyed end"; -} - -v8::Local V8InspectorClientImpl::ensureDefaultContextInGroup( - int contextGroupId) { - std::shared_ptr ctx = - std::static_pointer_cast(scope_->GetContext()); - v8::Isolate* isolate = ctx->isolate_; - v8::HandleScope handle_scope(isolate); - v8::Local context = - v8::Local::New(isolate, ctx->context_persistent_); - v8::Context::Scope context_scope(context); - return context; -} - -void V8InspectorClientImpl::runMessageLoopOnPause(int contextGroupId) { - scope_->GetTaskRunner()->PauseThreadForInspector(); -} - -void V8InspectorClientImpl::quitMessageLoopOnPause() { - scope_->GetTaskRunner()->ResumeThreadForInspector(); -} - -void V8InspectorClientImpl::runIfWaitingForDebugger(int contextGroupId) { - scope_->GetTaskRunner()->ResumeThreadForInspector(); -} - -} // namespace inspector -} // namespace hippy diff --git a/android/sdk/src/main/jni/src/jni/convert_utils.cc b/android/sdk/src/main/jni/src/jni/convert_utils.cc deleted file mode 100644 index b7352cc17a2..00000000000 --- a/android/sdk/src/main/jni/src/jni/convert_utils.cc +++ /dev/null @@ -1,724 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/convert_utils.h" - -#include "core/napi/v8/js_native_turbo_v8.h" -#include "jni/java_turbo_module.h" - -using namespace hippy::napi; -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; - -bool IsBasicNumberType(const std::string &type) { - return type == kint || type == kdouble || type == kfloat || type == klong; -} - -bool IsNumberObject(const std::string &type) { - return type == kInteger || type == kDouble || type == kFloat || type == kLong; -} - -void ThrowConvertTypeException(const int64_t &index, const std::string &info) { - std::string exception_info = std::string("ConvertTypeException: ") - .append("argument index = ") - .append(ToString(index)) - .append(", ") - .append(info); - throw std::runtime_error(exception_info); -} - -/** - * -int/long/float/double/boolean - * -IsNullOrUndefined() - * -IsNumber() - * -IsString() - * -IsBoolean() - * IsArray() - * IsMap() - * - * @param scope - * @param method_name - * @param method_arg_types - * @param arg_values - * @return - */ -std::shared_ptr ConvertUtils::ConvertJSIArgsToJNIArgs( - TurboEnv &turbo_env, - const std::string &module_name, - const std::string &method_name, - const std::vector &method_arg_types, - const std::vector> &arg_values) { - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr context = std::static_pointer_cast(ctx); - - int actual_arg_count = arg_values.size(); - std::shared_ptr jni_args = - std::make_shared(actual_arg_count); - auto &global_refs = jni_args->global_refs_; - - for (int i = 0; i < actual_arg_count; i++) { - try { - std::string type = method_arg_types.at(i); - - jvalue *j_args = &jni_args->args_[i]; - std::shared_ptr value = arg_values.at(i); - - // basic type - if (HandleBasicType(turbo_env, type, *j_args, value)) { - continue; - } - - // unSupport Object type - if (kUnSupportedType == type) { - throw std::runtime_error( - std::string("Unsupported type: ").append(type).c_str()); - } - - // NullOrUndefined - if (context->IsNullOrUndefined(value)) { - j_args->l = nullptr; - continue; - } - - // Object - HandleObjectType(turbo_env, module_name, method_name, type, *j_args, - value, global_refs); - } catch (std::runtime_error &error) { - ThrowConvertTypeException(i, error.what()); - } - } - - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - if (JNIEnvironment::ClearJEnvException(env)) { - throw std::runtime_error( - "JNI Exception occured when convertJSIArgsToJNIArgs"); - } - - return jni_args; -} - -bool ConvertUtils::HandleBasicType(TurboEnv &turbo_env, - const std::string &type, - jvalue &j_args, - const std::shared_ptr &value) { - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr context = std::static_pointer_cast(ctx); - - // number - if (IsBasicNumberType(type)) { - double num; - if (!context->GetValueNumber(value, &num)) { - throw std::runtime_error("Must be int/long/float/double."); - } - - if (type == kint) { // int - j_args.i = num; - } else if (type == kdouble) { // double - j_args.d = num; - } else if (type == kfloat) { // float - j_args.f = num; - } else if (type == klong) { // long - j_args.j = num; - } - return true; - } - - // boolean - if (type == "Z") { - bool b; - if (!context->GetValueBoolean(value, &b)) { - throw std::runtime_error("Must be boolean."); - } - - j_args.z = b; - return true; - } - - return false; -} - -bool ConvertUtils::HandleObjectType(TurboEnv &turbo_env, - const std::string &module_name, - const std::string &method_name, - const std::string &type, - jvalue &j_args, - const std::shared_ptr &value, - std::vector &global_refs) { - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr context = std::static_pointer_cast(ctx); - - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - - auto make_global = [&global_refs, env](jobject obj) -> jobject { - jobject global_obj = env->NewGlobalRef(obj); - global_refs.push_back(global_obj); - env->DeleteLocalRef(obj); - return global_obj; - }; - - // Promise - if (type == kPromise) { - unicode_string_view str_view; - std::string str; - if (turbo_env.context_->GetValueString(value, &str_view)) { - str = StringViewUtils::ToU8StdStr(str_view); - } else { - throw std::runtime_error("Must be String."); - } - - TDF_BASE_DLOG(INFO) << "Promise callId %s", str.c_str(); - - jstring module_name_str = env->NewStringUTF(module_name.c_str()); - jstring method_name_str = env->NewStringUTF(method_name.c_str()); - jstring call_id_str = env->NewStringUTF(str.c_str()); - jobject tmp = env->NewObject(promise_clazz, promise_constructor, nullptr, - module_name_str, method_name_str, call_id_str); - env->DeleteLocalRef(module_name_str); - env->DeleteLocalRef(method_name_str); - env->DeleteLocalRef(call_id_str); - j_args.l = make_global(tmp); - return true; - } - - // HippyArray - if (type == kHippyArray) { - if (!context->IsArray(value)) { - throw std::runtime_error("Must be Array."); - } - j_args.l = make_global(ToHippyArray(turbo_env, value)); - return true; - } - - // HippyMap - if (type == kHippyMap) { - if (!context->IsMap(value)) { - throw std::runtime_error("Must be Map."); - } - - j_args.l = make_global(ToHippyMap(turbo_env, value)); - return true; - } - - // Boolean - if (type == kBoolean) { - bool b; - if (!context->GetValueBoolean(value, &b)) { - throw std::runtime_error("Must be Boolean."); - } - j_args.l = - make_global(env->NewObject(boolean_clazz, boolean_constructor, b)); - return true; - } - - // String - if (type == kString) { - unicode_string_view str_view; - std::string str; - if (turbo_env.context_->GetValueString(value, &str_view)) { - str = StringViewUtils::ToU8StdStr(str_view); - } else { - throw std::runtime_error("Must be String."); - } - - j_args.l = make_global(env->NewStringUTF(str.c_str())); - return true; - } - - // Number Object - if (IsNumberObject(type)) { - double num; - if (!context->GetValueNumber(value, &num)) { - throw std::runtime_error("Integer/Double/Float/Long."); - } - - if (type == kInteger) { // Integer - j_args.l = make_global( - env->NewObject(integer_clazz, integer_constructor, (int)num)); - } else if (type == kDouble) { // Double - j_args.l = - make_global(env->NewObject(double_clazz, double_constructor, num)); - } else if (type == kFloat) { // Float - j_args.l = make_global( - env->NewObject(float_clazz, float_constructor, (float)num)); - } else if (type == kLong) { // Long - j_args.l = make_global( - env->NewObject(long_clazz, long_constructor, (int64_t)num)); - } else { - return false; - } - return true; - } - - std::shared_ptr host_object = turbo_env.GetHostObject(value); - if (host_object) { - std::shared_ptr j_turbo_module = - std::static_pointer_cast(host_object); - j_args.l = j_turbo_module->impl_->GetObj(); - return true; - } - return false; -} - -jobject ConvertUtils::ToHippyMap(TurboEnv &turbo_env, - const std::shared_ptr &value) { - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr context = std::static_pointer_cast(ctx); - - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jobject obj = env->NewObject(hippy_map_clazz, hippy_map_constructor); - std::shared_ptr array = context->ConvertMapToArray(value); - - int array_len = context->GetArrayLength(array); - for (int i = 0; i < array_len; i = i + 2) { - // key - std::shared_ptr key = context->CopyArrayElement(array, i); - unicode_string_view str_view; - std::string key_str; - if (turbo_env.context_->GetValueString(key, &str_view)) { - key_str = StringViewUtils::ToU8StdStr(str_view); - } else { - throw std::runtime_error("Key must be String in Map."); - } - - jobject key_j_obj = env->NewStringUTF(key_str.c_str()); - TDF_BASE_DLOG(INFO) << "key %s", key_str.c_str(); - - // value - std::shared_ptr item = context->CopyArrayElement(array, i + 1); - jobject value_j_obj = ToJObject(turbo_env, item); - env->CallVoidMethod(obj, hippy_map_push_object, key_j_obj, value_j_obj); - - env->DeleteLocalRef(key_j_obj); - env->DeleteLocalRef(value_j_obj); - } - return obj; -} - -jobject ConvertUtils::ToHippyArray(TurboEnv &turbo_env, - const std::shared_ptr &value) { - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr context = std::static_pointer_cast(ctx); - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jobject obj = env->NewObject(hippy_array_clazz, hippy_array_constructor); - int array_len = context->GetArrayLength(value); - for (int i = 0; i < array_len; i++) { - std::shared_ptr item = context->CopyArrayElement(value, i); - jobject j_obj = ToJObject(turbo_env, item); - env->CallVoidMethod(obj, hippy_array_push_object, j_obj); - env->DeleteLocalRef(j_obj); - } - return obj; -} - -jobject ConvertUtils::ToJObject(TurboEnv &turbo_env, - const std::shared_ptr &value) { - double num; - bool b; - std::string str; - jobject result; - - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr context = std::static_pointer_cast(ctx); - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - unicode_string_view str_view; - - if (context->GetValueNumber(value, &num)) { - result = env->NewObject(double_clazz, double_constructor, num); - } else if (context->GetValueString(value, &str_view)) { - str = StringViewUtils::ToU8StdStr(str_view); - result = env->NewStringUTF(str.c_str()); - } else if (context->GetValueBoolean(value, &b)) { - result = env->NewObject(boolean_clazz, boolean_constructor, b); - } else if (context->IsArray(value)) { - result = ToHippyArray(turbo_env, value); - } else if (context->IsMap(value)) { - result = ToHippyMap(turbo_env, value); - } else if (context->IsNullOrUndefined(value)) { - result = nullptr; - } else { - throw std::runtime_error("UnSupported Type in HippyArray or HippyMap."); - } - return result; -} - -std::unordered_map ConvertUtils::GetMethodMap( - const std::string &method_map_str) { - std::unordered_map method_map; - if (method_map_str.empty()) { - return method_map; - } - - TDF_BASE_DLOG(INFO) << "initMethodMap origin string %s", - method_map_str.c_str(); - - bool is_name = true; - std::string method_name; - std::string method_sig; - - for (auto it = method_map_str.begin(); it != method_map_str.end(); it += 1) { - if (is_name) { - for (; it != method_map_str.end(); it += 1) { - if (*it == '=') { - is_name = false; - break; - } - - if (*it == '{' || *it == ' ') { - continue; - } - - method_name += *it; - } - } else { - for (; it != method_map_str.end(); it += 1) { - if (*it == ',' || *it == '}') { - is_name = true; - MethodInfo method_info; - method_info.signature_ = method_sig; - method_map[method_name] = method_info; - TDF_BASE_DLOG(INFO) << "initMethodMap %s=%s", method_name.c_str(), - method_sig.c_str(); - method_name.clear(); - method_sig.clear(); - break; - } - - method_sig += *it; - } - } - } - - return method_map; -} - -std::vector ConvertUtils::GetMethodArgTypesFromSignature( - const std::string &method_signature) { - std::vector method_args; - - for (auto it = method_signature.begin(); it != method_signature.end(); - it += 1) { - if (*it == '(') { - continue; - } - - if (*it == ')') { - break; - } - - std::string type; - - if (*it == '[') { - type += *it; - it += 1; - } - - if (*it == 'L') { - for (; it != method_signature.end(); it += 1) { - type += *it; - - if (*it == ';') { - break; - } - } - } else { - type += *it; - } - - method_args.push_back(type); - } - - return method_args; -} - -void ConvertUtils::ThrowException(const std::shared_ptr &ctx, - const std::string &info) { - std::shared_ptr v8_ctx = std::static_pointer_cast(ctx); - v8::HandleScope handle_scope(v8_ctx->isolate_); - v8::Local context = - v8_ctx->context_persistent_.Get(v8_ctx->isolate_); - v8::Context::Scope context_scope(context); - - TDF_BASE_LOG(ERROR) << info.c_str(); - v8_ctx->isolate_->ThrowException( - v8::String::NewFromUtf8(v8_ctx->isolate_, info.c_str()).ToLocalChecked()); -} - -std::shared_ptr ConvertUtils::ToHostObject(TurboEnv &turbo_env, - jobject &j_obj, - std::string name) { - if (!j_obj) { - return turbo_env.context_->CreateNull(); - } - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - std::shared_ptr ret = std::make_shared(env, j_obj); - std::shared_ptr host_obj = - std::make_shared(name, ret); - return turbo_env.CreateObject(host_obj); -} - -std::shared_ptr ConvertUtils::ConvertMethodResultToJSValue( - TurboEnv &turbo_env, - const jobject &obj, - const MethodInfo &method_info, - const jvalue *args) { - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr ret = ctx->CreateUndefined(); - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - std::string return_type = method_info.signature_.substr( - method_info.signature_.find_last_of(')') + 1); - if (klong == return_type) { - jlong result = env->CallLongMethodA(obj, method_info.method_id_, args); - ret = ctx->CreateNumber(result); - } else if (kint == return_type) { - jint result = env->CallIntMethodA(obj, method_info.method_id_, args); - ret = ctx->CreateNumber(result); - } else if (kfloat == return_type) { - jfloat result = env->CallFloatMethodA(obj, method_info.method_id_, args); - ret = ctx->CreateNumber(result); - } else if (kdouble == return_type) { - jdouble result = env->CallDoubleMethodA(obj, method_info.method_id_, args); - ret = ctx->CreateNumber(result); - } else if (kString == return_type) { - auto result_str = - (jstring)env->CallObjectMethodA(obj, method_info.method_id_, args); - if (!result_str) { - ret = ctx->CreateNull(); - } else { - unicode_string_view str_view = JniUtils::ToStrView(env, result_str); - env->DeleteLocalRef(result_str); - ret = ctx->CreateString(str_view); - } - } else if (kboolean == return_type) { - auto result = - (jboolean)env->CallBooleanMethodA(obj, method_info.method_id_, args); - ret = ctx->CreateBoolean(result); - } else if (kvoid == return_type) { - env->CallVoidMethodA(obj, method_info.method_id_, args); - } else if (kHippyArray == return_type) { - auto array = env->CallObjectMethodA(obj, method_info.method_id_, args); - ret = ToJsArray(turbo_env, array); - env->DeleteLocalRef(array); - } else if (kHippyMap == return_type) { - auto map = env->CallObjectMethodA(obj, method_info.method_id_, args); - ret = ToJsMap(turbo_env, map); - env->DeleteLocalRef(map); - } else { - auto ret_obj = env->CallObjectMethodA(obj, method_info.method_id_, args); - ret = ToHostObject(turbo_env, ret_obj, method_info.signature_); - env->DeleteLocalRef(ret_obj); - } - return ret; -} - -std::shared_ptr ConvertUtils::ToJsValueInArray(TurboEnv &turbo_env, - const jobject &array, - int index) { - std::shared_ptr ctx = turbo_env.context_; - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - std::shared_ptr result = ctx->CreateNull(); - auto sig = (jstring)env->CallObjectMethod(array, hippy_array_get_sig, index); - if (!sig) { - return result; - } - - unicode_string_view str_view = JniUtils::ToStrView(env, sig); - std::string signature = StringViewUtils::ToU8StdStr(str_view); - env->DeleteLocalRef(sig); - TDF_BASE_DLOG(INFO) << "toJsValueInArray %s", signature.c_str(); - - if (kUnSupportedType == signature) { - std::string info = - std::string(kUnSupportedType).append(" when toJsValueInArray"); - throw std::runtime_error(info); - } - - auto obj = env->CallObjectMethod(array, hippy_array_get, index); - - if (IsNumberObject(signature)) { - jdouble d = env->CallDoubleMethod(obj, double_value); - result = ctx->CreateNumber(d); - } else if (kString == signature) { - unicode_string_view obj_str_view = JniUtils::ToStrView(env, (jstring)(obj)); - result = ctx->CreateString(obj_str_view); - } else if (kBoolean == signature) { - jboolean b = env->CallBooleanMethod(obj, boolean_value); - result = ctx->CreateBoolean(b); - } else if (kHippyArray == signature) { - result = ToJsArray(turbo_env, obj); - } else if (kHippyMap == signature) { - result = ToJsMap(turbo_env, obj); - } else if (!obj) { - result = turbo_env.context_->CreateNull(); - } else { - throw std::runtime_error("UnSupported Type in HippyArray or HippyMap"); - } - - env->DeleteLocalRef(obj); - return result; -} - -std::shared_ptr ConvertUtils::ToJsArray(TurboEnv &turbo_env, - const jobject &array) { - std::shared_ptr ctx = turbo_env.context_; - if (!array) { - return ctx->CreateNull(); - } - std::shared_ptr v8_ctx = std::static_pointer_cast(ctx); - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - int size = env->CallIntMethod(array, hippy_array_size); - - if (size <= 0) { - return ctx->CreateNull(); - } - - std::shared_ptr value[size]; - for (int i = 0; i < size; i++) { - value[i] = ToJsValueInArray(turbo_env, array, i); - } - return ctx->CreateArray(size, value); -} - -std::shared_ptr ConvertUtils::ToJsMap(TurboEnv &turbo_env, - const jobject &map) { - std::shared_ptr ctx = turbo_env.context_; - if (!map) { - return ctx->CreateNull(); - } - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - - jobject array = env->CallObjectMethod(map, to_hippy_array); - if (!array) { - return ctx->CreateNull(); - } - - int size = env->CallIntMethod(array, hippy_array_size); - if (size <= 0) { - return ctx->CreateNull(); - } - - std::shared_ptr v8_ctx = std::static_pointer_cast(ctx); - std::shared_ptr value[size]; - for (int i = 0; i < size; i++) { - value[i] = ToJsValueInArray(turbo_env, array, i); - } - return v8_ctx->CreateMap(size, value); -} - -bool ConvertUtils::Init() { - TDF_BASE_DLOG(INFO) << "enter init"; - - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jclass hippy_array_clazz_local = - env->FindClass("com/tencent/mtt/hippy/common/HippyArray"); - hippy_array_clazz = (jclass)env->NewGlobalRef(hippy_array_clazz_local); - hippy_array_constructor = - env->GetMethodID(hippy_array_clazz, "", "()V"); - hippy_array_push_object = env->GetMethodID(hippy_array_clazz, "pushObject", - "(Ljava/lang/Object;)V"); - hippy_array_size = env->GetMethodID(hippy_array_clazz, "size", "()I"); - hippy_array_get = - env->GetMethodID(hippy_array_clazz, "get", "(I)Ljava/lang/Object;"); - hippy_array_get_sig = env->GetMethodID(hippy_array_clazz, "getSignature", - "(I)Ljava/lang/String;"); - env->DeleteLocalRef(hippy_array_clazz_local); - - jclass hippy_map_clazz_local = - env->FindClass("com/tencent/mtt/hippy/common/HippyMap"); - hippy_map_clazz = (jclass)env->NewGlobalRef(hippy_map_clazz_local); - hippy_map_constructor = env->GetMethodID(hippy_map_clazz, "", "()V"); - hippy_map_push_object = env->GetMethodID( - hippy_map_clazz, "pushObject", "(Ljava/lang/String;Ljava/lang/Object;)V"); - to_hippy_array = - env->GetMethodID(hippy_map_clazz, "toHippyArray", - "()Lcom/tencent/mtt/hippy/common/HippyArray;"); - env->DeleteLocalRef(hippy_map_clazz_local); - - jclass integer_clazz_local = env->FindClass("java/lang/Integer"); - integer_clazz = (jclass)env->NewGlobalRef(integer_clazz_local); - integer_constructor = env->GetMethodID(integer_clazz, "", "(I)V"); - env->DeleteLocalRef(integer_clazz_local); - - jclass double_clazz_local = env->FindClass("java/lang/Double"); - double_clazz = (jclass)env->NewGlobalRef(double_clazz_local); - double_constructor = env->GetMethodID(double_clazz, "", "(D)V"); - double_value = env->GetMethodID(double_clazz, "doubleValue", "()D"); - env->DeleteLocalRef(double_clazz_local); - - jclass float_clazz_local = env->FindClass("java/lang/Float"); - float_clazz = (jclass)env->NewGlobalRef(float_clazz_local); - float_constructor = env->GetMethodID(float_clazz, "", "(F)V"); - env->DeleteLocalRef(float_clazz_local); - - jclass long_clazz_local = env->FindClass("java/lang/Long"); - long_clazz = (jclass)env->NewGlobalRef(long_clazz_local); - long_constructor = env->GetMethodID(long_clazz, "", "(J)V"); - env->DeleteLocalRef(long_clazz_local); - - jclass boolean_clazz_local = env->FindClass("java/lang/Boolean"); - boolean_clazz = (jclass)(env->NewGlobalRef(boolean_clazz_local)); - boolean_constructor = env->GetMethodID(boolean_clazz, "", "(Z)V"); - boolean_value = env->GetMethodID(boolean_clazz, "booleanValue", "()Z"); - env->DeleteLocalRef(boolean_clazz_local); - - jclass promise_clazz_local = - env->FindClass("com/tencent/mtt/hippy/modules/PromiseImpl"); - promise_clazz = (jclass)(env->NewGlobalRef(promise_clazz_local)); - promise_constructor = - env->GetMethodID(promise_clazz, "", - "(Lcom/tencent/mtt/hippy/HippyEngineContext;Ljava/lang/" - "String;Ljava/lang/String;Ljava/lang/String;)V"); - env->DeleteLocalRef(promise_clazz_local); - return true; -} - -bool ConvertUtils::Destory() { - TDF_BASE_DLOG(INFO) << "enter destroy"; - hippy_array_constructor = nullptr; - hippy_array_push_object = nullptr; - hippy_array_get_sig = nullptr; - hippy_array_get = nullptr; - hippy_array_size = nullptr; - - hippy_map_push_object = nullptr; - to_hippy_array = nullptr; - - integer_constructor = nullptr; - double_constructor = nullptr; - double_value = nullptr; - float_constructor = nullptr; - long_constructor = nullptr; - boolean_constructor = nullptr; - boolean_value = nullptr; - - promise_constructor = nullptr; - - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - env->DeleteGlobalRef(hippy_array_clazz); - env->DeleteGlobalRef(hippy_map_clazz); - env->DeleteGlobalRef(integer_clazz); - env->DeleteGlobalRef(double_clazz); - env->DeleteGlobalRef(float_clazz); - env->DeleteGlobalRef(long_clazz); - env->DeleteGlobalRef(boolean_clazz); - env->DeleteGlobalRef(promise_clazz); - return true; -} diff --git a/android/sdk/src/main/jni/src/jni/exception_handler.cc b/android/sdk/src/main/jni/src/jni/exception_handler.cc deleted file mode 100644 index 788c2fe9a4e..00000000000 --- a/android/sdk/src/main/jni/src/jni/exception_handler.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/exception_handler.h" - -#include "core/base/string_view_utils.h" -#include "core/core.h" -#include "jni/jni_env.h" -#include "jni/jni_utils.h" - -using StringViewUtils = hippy::base::StringViewUtils; - -void ExceptionHandler::ReportJsException(std::shared_ptr runtime, - const unicode_string_view& desc, - const unicode_string_view& stack) { - TDF_BASE_DLOG(INFO) << "ReportJsException begin"; - - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jstring j_exception = JniUtils::StrViewToJString(j_env, desc); - jstring j_stack_trace = JniUtils::StrViewToJString(j_env, stack); - - if (runtime->GetBridge()) { - j_env->CallVoidMethod(runtime->GetBridge()->GetObj(), - JNIEnvironment::GetInstance() - ->GetMethods() - .j_report_exception_method_id, - j_exception, j_stack_trace); - } - - j_env->DeleteLocalRef(j_exception); - j_env->DeleteLocalRef(j_stack_trace); - - TDF_BASE_DLOG(INFO) << "ReportJsException end"; -} diff --git a/android/sdk/src/main/jni/src/jni/java_turbo_module.cc b/android/sdk/src/main/jni/src/jni/java_turbo_module.cc deleted file mode 100644 index 525ffe80aa9..00000000000 --- a/android/sdk/src/main/jni/src/jni/java_turbo_module.cc +++ /dev/null @@ -1,235 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/java_turbo_module.h" - -#include "core/base/string_view_utils.h" -#include "core/napi/js_native_api_types.h" -#include "core/napi/v8/js_native_turbo_v8.h" -#include "hippy.h" -#include "jni/convert_utils.h" - -using namespace hippy::napi; -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; - -static jclass argument_utils_clazz; -static jmethodID get_methods_signature; - -std::shared_ptr JavaTurboModule::InvokeJavaMethod( - TurboEnv &turbo_env, - const std::shared_ptr &prop_name, - const std::shared_ptr &this_val, - const std::shared_ptr *args, - size_t count) { - TDF_BASE_DLOG(INFO) << "[turbo-perf] enter invokeJavaMethod"; - - std::shared_ptr ctx = turbo_env.context_; - std::shared_ptr v8_ctx = std::static_pointer_cast(ctx); - v8::HandleScope handle_scope(v8_ctx->isolate_); - v8::Local context = - v8_ctx->context_persistent_.Get(v8_ctx->isolate_); - v8::Context::Scope context_scope(context); - - // methodName & signature - unicode_string_view str_view; - std::string method; - if (v8_ctx->GetValueString(prop_name, &str_view)) { - method = StringViewUtils::ToU8StdStr(str_view); - } - - MethodInfo method_info = method_map_[method]; - if (method_info.signature_.empty()) { - std::string exception_info = std::string("MethodUnsupportedException: ") - .append(name_) - .append(".") - .append(method); - ConvertUtils::ThrowException(ctx, exception_info); - return ctx->CreateUndefined(); - } - TDF_BASE_DLOG(INFO) << "invokeJavaMethod, method= %s", method.c_str(); - - // arguments count - std::vector> arg_values; - arg_values.reserve(count); - for (int i = 0; i < count; i++) { - arg_values.push_back(args[i]); - } - std::string call_info = std::string(name_).append(".").append(method); - std::vector method_arg_types = - ConvertUtils::GetMethodArgTypesFromSignature(method_info.signature_); - int expected_count = method_arg_types.size(); - int actual_count = arg_values.size(); - if (expected_count != actual_count) { - std::string exception_info = std::string("ArgCountException: ") - .append(call_info) - .append(": ExpectedArgCount=") - .append(ToString(expected_count)) - .append(", ActualArgCount = ") - .append(ToString(actual_count)); - ConvertUtils::ThrowException(ctx, exception_info); - return ctx->CreateUndefined(); - } - - // methodId - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - if (!method_info.method_id_) { - method_info.method_id_ = env->GetMethodID(impl_j_clazz_, method.c_str(), - method_info.signature_.c_str()); - - if (!method_info.method_id_) { - JNIEnvironment::ClearJEnvException(env); - - std::string exception_info = std::string("NullMethodIdException: ") - .append(call_info) - .append(": Signature=") - .append(method_info.signature_); - ConvertUtils::ThrowException(ctx, exception_info); - return ctx->CreateUndefined(); - } - - method_map_[method] = method_info; - } - - std::shared_ptr jni_args = nullptr; - std::shared_ptr ret = ctx->CreateUndefined(); - - try { - // args convert - TDF_BASE_DLOG(INFO) << "[turbo-perf] enter convertJSIArgsToJNIArgs"; - jni_args = ConvertUtils::ConvertJSIArgsToJNIArgs( - turbo_env, name_, method, method_arg_types, arg_values); - TDF_BASE_DLOG(INFO) << "[turbo-perf] exit convertJSIArgsToJNIArgs"; - - TDF_BASE_DLOG(INFO) << "[turbo-perf] enter convertMethodResultToJSValue"; - - // call method - ret = ConvertUtils::ConvertMethodResultToJSValue( - turbo_env, impl_->GetObj(), method_info, jni_args->args_.data()); - TDF_BASE_DLOG(INFO) << "[turbo-perf] exit convertMethodResultToJSValue"; - - } catch (std::runtime_error &e) { - std::string exception_info = - std::string(call_info).append(" ").append(e.what()); - ConvertUtils::ThrowException(ctx, exception_info); - ret = ctx->CreateUndefined(); - } - - DeleteGlobalRef(jni_args); - TDF_BASE_DLOG(INFO) << "[turbo-perf] exit invokeJavaMethod"; - - if (JNIEnvironment::ClearJEnvException( - JNIEnvironment::GetInstance()->AttachCurrentThread())) { - TDF_BASE_LOG(ERROR) << "ClearJEnvException when %s", call_info.c_str(); - return ctx->CreateUndefined(); - } - - return ret; -} - -void JavaTurboModule::DeleteGlobalRef(const std::shared_ptr &jni_args) { - TDF_BASE_DLOG(INFO) << "enter deleteGlobalRef"; - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - if (!jni_args || jni_args->global_refs_.empty()) { - return; - } - - TDF_BASE_DLOG(INFO) << "deleteGlobalRef size %d", - jni_args->global_refs_.size(); - for (auto global_ref : jni_args->global_refs_) { - if (global_ref) { - env->DeleteGlobalRef(global_ref); - } - } -} - -void JavaTurboModule::InitPropertyMap() { - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jclass obj_clazz = env->GetObjectClass(impl_->GetObj()); - impl_j_clazz_ = (jclass)env->NewGlobalRef(obj_clazz); - auto methods_sig = (jstring)env->CallStaticObjectMethod( - argument_utils_clazz, get_methods_signature, impl_->GetObj()); - if (methods_sig) { - unicode_string_view str_view = JniUtils::ToStrView(env, methods_sig); - std::string method_map_str = StringViewUtils::ToU8StdStr(str_view); - method_map_ = ConvertUtils::GetMethodMap(method_map_str); - env->DeleteLocalRef(methods_sig); - } - - env->DeleteLocalRef(obj_clazz); -} - -JavaTurboModule::JavaTurboModule(const std::string &name, - std::shared_ptr &impl) - : HippyTurboModule(name), impl_(impl) { - InitPropertyMap(); -} - -JavaTurboModule::~JavaTurboModule() { - TDF_BASE_DLOG(INFO) << "~JavaTurboModule %s", name_.c_str(); - - if (impl_) { - impl_.reset(); - } - - if (impl_j_clazz_) { - JNIEnvironment::GetInstance()->AttachCurrentThread()->DeleteGlobalRef( - impl_j_clazz_); - } - - if (!method_map_.empty()) { - method_map_.clear(); - } -} - -std::shared_ptr JavaTurboModule::Get( - TurboEnv &turbo_env, - const std::shared_ptr &prop_name) { - return turbo_env.CreateFunction( - prop_name, 0, - [=](TurboEnv &env, const std::shared_ptr &thisVal, - const std::shared_ptr *args, size_t count) { - return InvokeJavaMethod(env, prop_name, thisVal, args, count); - }); -} - -void JavaTurboModule::Init() { - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jclass argument_utils_clazz_local = - env->FindClass("com/tencent/mtt/hippy/utils/ArgumentUtils"); - argument_utils_clazz = - (jclass)(env->NewGlobalRef(argument_utils_clazz_local)); - get_methods_signature = - env->GetStaticMethodID(argument_utils_clazz, "getMethodsSignature", - "(Ljava/lang/Object;)Ljava/lang/String;"); - env->DeleteLocalRef(argument_utils_clazz_local); -} - -void JavaTurboModule::Destory() { - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - - if (argument_utils_clazz) { - env->DeleteGlobalRef(argument_utils_clazz); - } - - get_methods_signature = nullptr; -} diff --git a/android/sdk/src/main/jni/src/jni/jni_env.cc b/android/sdk/src/main/jni/src/jni/jni_env.cc deleted file mode 100644 index e4c21a9ea49..00000000000 --- a/android/sdk/src/main/jni/src/jni/jni_env.cc +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/jni_env.h" - -#include - -#include "core/core.h" - -std::shared_ptr JNIEnvironment::instance_ = nullptr; -std::mutex JNIEnvironment::mutex_; - -void JNIEnvironment::init(JavaVM* j_vm, JNIEnv* j_env) { - j_vm_ = j_vm; - - jclass j_hippy_bridge_cls = - j_env->FindClass("com/tencent/mtt/hippy/bridge/HippyBridgeImpl"); - wrapper_.j_call_natives_direct_method_id = - j_env->GetMethodID(j_hippy_bridge_cls, "callNatives", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/" - "String;Ljava/nio/ByteBuffer;)V"); - wrapper_.j_call_natives_method_id = j_env->GetMethodID( - j_hippy_bridge_cls, "callNatives", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[B)V"); - wrapper_.j_report_exception_method_id = - j_env->GetMethodID(j_hippy_bridge_cls, "reportException", - "(Ljava/lang/String;Ljava/lang/String;)V"); - wrapper_.j_inspector_channel_method_id = - j_env->GetMethodID(j_hippy_bridge_cls, "InspectorChannel", "([B)V"); - - wrapper_.j_fetch_resource_method_id = j_env->GetMethodID( - j_hippy_bridge_cls, "fetchResourceWithUri", "(Ljava/lang/String;J)V"); - j_env->DeleteLocalRef(j_hippy_bridge_cls); - - if (j_env->ExceptionCheck()) { - j_env->ExceptionClear(); - } -} - -std::shared_ptr JNIEnvironment::GetInstance() { - std::lock_guard lock(mutex_); - if (!instance_) { - instance_ = std::make_shared(); - } - - return instance_; -} - -void JNIEnvironment::DestroyInstance() { - std::lock_guard lock(mutex_); - instance_ = nullptr; -} - -bool JNIEnvironment::ClearJEnvException(JNIEnv* j_env) { - jthrowable j_exc = j_env->ExceptionOccurred(); - - if (j_exc) { - j_env->ExceptionDescribe(); - j_env->ExceptionClear(); - - return true; - } - - return false; -} - -JNIEnv* JNIEnvironment::AttachCurrentThread() { - TDF_BASE_CHECK(j_vm_); - - JNIEnv* j_env = nullptr; - jint ret = j_vm_->GetEnv(reinterpret_cast(&j_env), JNI_VERSION_1_4); - if (ret == JNI_EDETACHED || !j_env) { - JavaVMAttachArgs args; - args.version = JNI_VERSION_1_4; - args.group = nullptr; - - // 16 is the maximum size for thread names on Android. - char thread_name[16]; - int err = prctl(PR_GET_NAME, thread_name); - if (err < 0) { - TDF_BASE_DLOG(ERROR) << "prctl(PR_GET_NAME) Error = " << err; - args.name = nullptr; - } else { - args.name = thread_name; - } - - ret = j_vm_->AttachCurrentThread(&j_env, &args); - TDF_BASE_DCHECK(JNI_OK == ret); - } - - return j_env; -} - -void JNIEnvironment::DetachCurrentThread() { - TDF_BASE_CHECK(j_vm_); - - if (j_vm_) { - j_vm_->DetachCurrentThread(); - } -} diff --git a/android/sdk/src/main/jni/src/jni/jni_register.cc b/android/sdk/src/main/jni/src/jni/jni_register.cc deleted file mode 100644 index 62e42bae965..00000000000 --- a/android/sdk/src/main/jni/src/jni/jni_register.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/jni_register.h" - -#include "base/unicode_string_view.h" -#include "core/base/string_view_utils.h" -#include "jni/jni_env.h" -#include "jni/uri.h" - -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; - -std::unique_ptr& JNIRegister::GetInstance() { - static std::unique_ptr instance = nullptr; - static std::once_flag flag; - - std::call_once(flag, [] { instance = std::make_unique(); }); - - return instance; -} - -bool JNIRegister::RegisterMethods(JNIEnv* j_env) { - const std::unordered_map>& - jni_modules = JNIRegister::GetInstance()->GetJniModules(); - - for (auto it = jni_modules.begin(); it != jni_modules.end(); ++it) { - std::vector methods; - jclass j_class; - const char* class_name = it->first.c_str(); - j_class = j_env->FindClass(class_name); - if (!j_class) { - TDF_BASE_DLOG(ERROR) - << "NativeAccess class " - << class_name - << "not found"; - return false; - } - std::vector datas = it->second; - for (auto data_it = datas.begin(); data_it != datas.end(); ++data_it) { - JNINativeMethod method = data_it->ToJNINativeMethod(); - jmethodID id; - bool is_static = data_it->IsStaticMethod(); - if (is_static) { - id = j_env->GetStaticMethodID(j_class, method.name, method.signature); - } else { - id = j_env->GetMethodID(j_class, method.name, method.signature); - } - if (!id) { - if (j_env->ExceptionCheck()) { - j_env->ExceptionDescribe(); - } - TDF_BASE_DLOG(ERROR) - << "Cannot find method name = " - << method.name - << " signature = " - << method.signature - << " is_static = " << is_static << " of NativeAccess"; - return false; - } - methods.push_back(method); - } - - j_env->RegisterNatives(j_class, methods.data(), methods.size()); - } - return true; -} - -JNIRegisterData::JNIRegisterData(const char* name, - const char* sign, - void* pointer, - bool is_static) - : name_(name), sign_(sign), pointer_(pointer), is_static_(is_static) {} - -JNINativeMethod JNIRegisterData::ToJNINativeMethod() { - return {name_.c_str(), sign_.c_str(), pointer_}; -} diff --git a/android/sdk/src/main/jni/src/jni/jni_utils.cc b/android/sdk/src/main/jni/src/jni/jni_utils.cc deleted file mode 100644 index b28b7a5f2c6..00000000000 --- a/android/sdk/src/main/jni/src/jni/jni_utils.cc +++ /dev/null @@ -1,127 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/jni_utils.h" // NOLINT(build/include_subdir) - -#include -#include -#include - -#include "core/base/string_view_utils.h" -#include "core/core.h" - -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; - -jsize SafeGetArrayLength(JNIEnv* j_env, const jbyteArray& j_byte_array) { - TDF_BASE_DCHECK(j_byte_array); - jsize j_size = j_env->GetArrayLength(j_byte_array); - return std::max(0, j_size); -} - -JniUtils::bytes JniUtils::AppendJavaByteArrayToBytes(JNIEnv* j_env, - jbyteArray j_byte_array, - jsize j_offset, - jsize j_length) { - if (!j_byte_array) { - return ""; - } - - jsize j_len; - if (j_length == -1) { - j_len = SafeGetArrayLength(j_env, j_byte_array); - } else { - j_len = j_length; - } - if (!j_len) { - return ""; - } - - bytes ret; - ret.resize(j_length); - j_env->GetByteArrayRegion(j_byte_array, j_offset, j_len, - reinterpret_cast(&ret[0])); - return ret; -} - -unicode_string_view JniUtils::JByteArrayToStrView(JNIEnv* j_env, - jbyteArray j_byte_array, - jsize j_offset, - jsize j_length) { - if (!j_byte_array) { - return ""; - } - - jsize j_len; - if (j_length == -1) { - j_len = SafeGetArrayLength(j_env, j_byte_array); - } else { - j_len = j_length; - } - if (!j_len) { - return ""; - } - - std::string ret; - ret.resize(j_len); - j_env->GetByteArrayRegion(j_byte_array, j_offset, j_len, - reinterpret_cast(&ret[0])); - - const char16_t* ptr = reinterpret_cast(ret.c_str()); - return unicode_string_view(ptr, ret.length() / sizeof(char16_t)); -} - -jstring JniUtils::StrViewToJString(JNIEnv* j_env, - const unicode_string_view& str_view) { - std::u16string str = - StringViewUtils::Convert(str_view, unicode_string_view::Encoding::Utf16) - .utf16_value(); - return j_env->NewString(reinterpret_cast(str.c_str()), - str.length()); -} - -unicode_string_view::u8string JniUtils::ToU8String(JNIEnv* j_env, - jstring j_str) { - TDF_BASE_DCHECK(j_str); - - const char* c_str = j_env->GetStringUTFChars(j_str, nullptr); - const int32_t len = j_env->GetStringLength(j_str); - unicode_string_view::u8string ret( - reinterpret_cast(c_str), len); - j_env->ReleaseStringUTFChars(j_str, c_str); - return ret; -} - -unicode_string_view JniUtils::ToStrView(JNIEnv* j_env, jstring j_str) { - TDF_BASE_DCHECK(j_str); - - const jchar* j_char = j_env->GetStringChars(j_str, nullptr); - int32_t len = j_env->GetStringLength(j_str); - unicode_string_view ret(reinterpret_cast(j_char), len); - j_env->ReleaseStringChars(j_str, j_char); - return ret; -} - -void JniUtils::printCurrentThreadID() { -#define LOG_DEBUG(FORMAT, ...) \ - __android_log_print(ANDROID_LOG_DEBUG, "Debug", FORMAT, ##__VA_ARGS__); -} diff --git a/android/sdk/src/main/jni/src/jni/turbo_module_manager.cc b/android/sdk/src/main/jni/src/jni/turbo_module_manager.cc deleted file mode 100644 index e1697aff356..00000000000 --- a/android/sdk/src/main/jni/src/jni/turbo_module_manager.cc +++ /dev/null @@ -1,224 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/turbo_module_manager.h" - -#include - -#include - -#include "bridge/runtime.h" -#include "core/core.h" -#include "core/napi/v8/js_native_api_v8.h" -#include "jni/java_turbo_module.h" -#include "jni/jni_utils.h" -#include "jni/scoped_java_ref.h" - -REGISTER_JNI("com/tencent/mtt/hippy/bridge/jsi/TurboModuleManager", - "install", - "(J)I", - Install) - -REGISTER_JNI("com/tencent/mtt/hippy/bridge/jsi/TurboModuleManager", - "uninstall", - "(J)V", - Uninstall) - -using namespace hippy::napi; -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; - -jclass turbo_module_manager_clazz; -jmethodID get_method_id; - -/** - * com.tencent.mtt.hippy.bridge.jsi.TurboModuleManager.get - */ -std::shared_ptr QueryTurboModuleImpl(std::shared_ptr &runtime, - const std::string &module_name) { - TDF_BASE_DLOG(INFO) << "enter QueryTurboModuleImpl %s", module_name.c_str(); - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jstring name = env->NewStringUTF(module_name.c_str()); - jobject module_impl = env->CallObjectMethod( - runtime->GetTurboModuleRuntime()->turbo_module_manager_obj_, - get_method_id, name); - auto result = std::make_shared(env, module_impl); - env->DeleteLocalRef(name); - env->DeleteLocalRef(module_impl); - return result; -} - -void GetTurboModule(const v8::FunctionCallbackInfo &info) { - TDF_BASE_DLOG(INFO) << "[turbo-perf] enter getTurboModule"; - auto data = info.Data().As(); - int64_t runtime_key = *(reinterpret_cast(data->Value())); - - std::shared_ptr runtime = Runtime::Find(runtime_key); - std::shared_ptr ctx = - std::static_pointer_cast(runtime->GetScope()->GetContext()); - std::shared_ptr v8_ctx = std::static_pointer_cast(ctx); - v8::HandleScope handle_scope(v8_ctx->isolate_); - v8::Local context = - v8_ctx->context_persistent_.Get(v8_ctx->isolate_); - v8::Context::Scope context_scope(context); - - if (info.Length() == 1 && !info[0].IsEmpty() && info[0]->IsString()) { - // 1. moduleName - v8::String::Utf8Value module_name(info.GetIsolate(), info[0]); - std::string name = module_name.operator*(); - - std::shared_ptr turbo_module_runtime = - runtime->GetTurboModuleRuntime(); - if (!turbo_module_runtime) { - TDF_BASE_LOG(ERROR) << "getTurboModule but turboModuleRuntime is null"; - info.GetReturnValue().SetUndefined(); - return; - } - - std::shared_ptr result = - turbo_module_runtime->module_cache_[name]; - if (!result) { - // 2. if not cached, query from Java - std::shared_ptr module_impl = - QueryTurboModuleImpl(runtime, name); - if (!module_impl->GetObj()) { - std::string exception_info = - std::string("Cannot find TurboModule: ").append(name); - TDF_BASE_LOG(ERROR) << "cannot find TurboModule = %s", name.c_str(); - ConvertUtils::ThrowException(ctx, exception_info); - return info.GetReturnValue().SetUndefined(); - } - - // 3. constructor c++ JavaTurboModule - std::shared_ptr java_turbo_module = - std::make_shared(name, module_impl); - - // 4. init v8TurboEnv - if (!turbo_module_runtime->turbo_env_) { - turbo_module_runtime->turbo_env_ = std::make_shared(ctx); - } - - // 5. bind c++ JavaTurboModule to js - result = - turbo_module_runtime->turbo_env_->CreateObject(java_turbo_module); - - // 6. add To Cache - turbo_module_runtime->module_cache_[name] = result; - TDF_BASE_DLOG(INFO) << "return module=%s", name.c_str(); - } else { - TDF_BASE_DLOG(INFO) << "return cached module=%s", name.c_str(); - } - - std::shared_ptr v8_result = - std::static_pointer_cast(result); - info.GetReturnValue().Set(v8_result->global_value_); - } else { - TDF_BASE_LOG(ERROR) << "cannot find TurboModule as param is invalid"; - info.GetReturnValue().SetUndefined(); - } - TDF_BASE_DLOG(INFO) << "[turbo-perf] exit getTurboModule"; -} - -void BindNativeFunction(std::shared_ptr runtime, - const unicode_string_view &name, - v8::FunctionCallback function_callback) { - TDF_BASE_DLOG(INFO) << "enter bindNativeFunction name " - << StringViewUtils::ToU8StdStr(name); - std::shared_ptr v8_ctx = - std::static_pointer_cast(runtime->GetScope()->GetContext()); - v8::HandleScope handle_scope(v8_ctx->isolate_); - v8::Local context = - v8_ctx->context_persistent_.Get(v8_ctx->isolate_); - v8::Context::Scope context_scope(context); - - v8::Local function_template = v8::FunctionTemplate::New( - v8_ctx->isolate_, function_callback, - v8::External::New(v8_ctx->isolate_, reinterpret_cast(runtime->GetId()))); - function_template->RemovePrototype(); - - v8::Local function_name = v8_ctx->CreateV8String(name); - v8::Local function = - function_template->GetFunction(context).ToLocalChecked(); - context->Global()->Set(context, function_name, function).ToChecked(); - TDF_BASE_DLOG(INFO) << "exit bindNativeFunction name " - << StringViewUtils::ToU8StdStr(name); -} - -void TurboModuleManager::Init() { - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jclass clazz = - env->FindClass("com/tencent/mtt/hippy/bridge/jsi/TurboModuleManager"); - turbo_module_manager_clazz = static_cast(env->NewGlobalRef(clazz)); - env->DeleteLocalRef(clazz); - - get_method_id = - env->GetMethodID(turbo_module_manager_clazz, "get", - "(Ljava/lang/String;)Lcom/tencent/mtt/hippy/modules/" - "nativemodules/HippyNativeModuleBase;"); -} - -void TurboModuleManager::Destory() { - JNIEnv *env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - if (turbo_module_manager_clazz) { - env->DeleteGlobalRef(turbo_module_manager_clazz); - } - - get_method_id = nullptr; -} - -int Install(JNIEnv *, jobject j_obj, jlong j_runtime_id) { - TDF_BASE_LOG(INFO) << "install TurboModuleManager"; - std::shared_ptr runtime = Runtime::Find(j_runtime_id); - if (!runtime) { - TDF_BASE_LOG(ERROR) << "TurboModuleManager install, v8RuntimePtr invalid"; - return -1; - } - - runtime->SetTurboModuleRuntime(std::make_shared(j_obj)); - - // v8的操作放到js线程 - std::shared_ptr runner = - runtime->GetEngine()->GetJSRunner(); - if (!runner) { - TDF_BASE_LOG(WARNING) << "TurboModuleManager install, runner invalid"; - return -1; - } - - std::shared_ptr task = std::make_shared(); - task->callback = [runtime] { - BindNativeFunction(runtime, "getTurboModule", GetTurboModule); - }; - runner->PostTask(task); - return 0; -} - -void Uninstall(JNIEnv *, jobject, jlong j_runtime_id) { - TDF_BASE_LOG(INFO) << "uninstall install TurboModuleManager"; - std::shared_ptr runtime = Runtime::Find(j_runtime_id); - if (!runtime) { - TDF_BASE_LOG(ERROR) << "TurboModuleManager install, v8RuntimePtr invalid"; - return; - } - if (runtime->GetTurboModuleRuntime()) { - runtime->GetTurboModuleRuntime().reset(); - } -} diff --git a/android/sdk/src/main/jni/src/jni/uri.cc b/android/sdk/src/main/jni/src/jni/uri.cc deleted file mode 100644 index 9c64c25332d..00000000000 --- a/android/sdk/src/main/jni/src/jni/uri.cc +++ /dev/null @@ -1,139 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "jni/uri.h" - -#include "base/unicode_string_view.h" -#include "core/base/string_view_utils.h" -#include "jni/jni_env.h" -#include "jni/jni_utils.h" - -static jclass j_clazz; -static jmethodID j_create_method_id; -static jmethodID j_normalize_method_id; -static jmethodID j_to_string_method_id; -static jmethodID j_get_scheme_method_id; -static jmethodID j_get_path_method_id; - -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; - -std::shared_ptr Uri::Create(const unicode_string_view& uri) { - auto ret = std::make_shared(uri); - if (!ret->j_obj_uri_) { - return nullptr; - } - return ret; -} - -bool Uri::Init() { - JNIEnv* env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jclass j_local_clazz = env->FindClass("java/net/URI"); - j_clazz = (jclass)env->NewGlobalRef(j_local_clazz); - j_create_method_id = env->GetStaticMethodID( - j_clazz, "create", "(Ljava/lang/String;)Ljava/net/URI;"); - j_normalize_method_id = - env->GetMethodID(j_clazz, "normalize", "()Ljava/net/URI;"); - j_to_string_method_id = - env->GetMethodID(j_clazz, "toString", "()Ljava/lang/String;"); - j_get_scheme_method_id = - env->GetMethodID(j_clazz, "getScheme", "()Ljava/lang/String;"); - j_get_path_method_id = - env->GetMethodID(j_clazz, "getPath", "()Ljava/lang/String;"); - return true; -} - -bool Uri::Destory() { - JNIEnv* env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - - j_get_path_method_id = nullptr; - j_get_scheme_method_id = nullptr; - j_to_string_method_id = nullptr; - j_normalize_method_id = nullptr; - j_create_method_id = nullptr; - - env->DeleteGlobalRef(j_clazz); - - return true; -} - -Uri::Uri(const unicode_string_view& uri) { - TDF_BASE_DCHECK(uri.encoding() != unicode_string_view::Encoding::Unkown); - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jstring j_str_uri = JniUtils::StrViewToJString(j_env, uri); - j_obj_uri_ = - j_env->CallStaticObjectMethod(j_clazz, j_create_method_id, j_str_uri); - j_env->DeleteLocalRef(j_str_uri); - if (j_env->ExceptionCheck()){ - j_obj_uri_ = nullptr; - j_env->ExceptionClear(); - } -} - -Uri::~Uri() { - if (j_obj_uri_) { - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - j_env->DeleteLocalRef(j_obj_uri_); - } -} - -unicode_string_view Uri::Normalize() { - TDF_BASE_DCHECK(j_obj_uri_); - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jobject j_normalize_uri = - (jstring)j_env->CallObjectMethod(j_obj_uri_, j_normalize_method_id); - jstring j_parsed_uri = - (jstring)j_env->CallObjectMethod(j_normalize_uri, j_to_string_method_id); - if (!j_parsed_uri) { - return u""; - } - unicode_string_view ret = JniUtils::ToStrView(j_env, j_parsed_uri); - j_env->DeleteLocalRef(j_parsed_uri); - j_env->DeleteLocalRef(j_normalize_uri); - return ret; -} - -unicode_string_view Uri::GetScheme() { - TDF_BASE_DCHECK(j_obj_uri_); - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jstring j_scheme = - (jstring)j_env->CallObjectMethod(j_obj_uri_, j_get_scheme_method_id); - if (!j_scheme) { - return u""; - } - unicode_string_view ret = JniUtils::ToStrView(j_env, j_scheme); - j_env->DeleteLocalRef(j_scheme); - return ret; -} - -unicode_string_view Uri::GetPath() { - TDF_BASE_DCHECK(j_obj_uri_); - JNIEnv* j_env = JNIEnvironment::GetInstance()->AttachCurrentThread(); - jstring j_path = - (jstring)j_env->CallObjectMethod(j_obj_uri_, j_get_path_method_id); - if (!j_path) { - return u""; - } - unicode_string_view ret = JniUtils::ToStrView(j_env, j_path); - j_env->DeleteLocalRef(j_path); - return ret; -} diff --git a/android/sdk/src/main/jni/src/loader/adr_loader.cc b/android/sdk/src/main/jni/src/loader/adr_loader.cc deleted file mode 100644 index b6d61414c3e..00000000000 --- a/android/sdk/src/main/jni/src/loader/adr_loader.cc +++ /dev/null @@ -1,252 +0,0 @@ -/* - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * 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. - * - */ - -#include "loader/adr_loader.h" - -#include - -#include "bridge/runtime.h" -#include "core/base/string_view_utils.h" -#include "core/core.h" -#include "jni/jni_env.h" -#include "jni/jni_register.h" -#include "jni/jni_utils.h" -#include "jni/uri.h" - -using unicode_string_view = tdf::base::unicode_string_view; -using StringViewUtils = hippy::base::StringViewUtils; -using HippyFile = hippy::base::HippyFile; -using u8string = unicode_string_view::u8string; -using char8_t_ = unicode_string_view::char8_t_; - -static std::atomic global_request_id{0}; - -ADRLoader::ADRLoader() : aasset_manager_(nullptr) {} - -bool ADRLoader::RequestUntrustedContent(const unicode_string_view& uri, - std::function cb) { - std::shared_ptr uri_obj = Uri::Create(uri); - if (!uri_obj) { - TDF_BASE_DLOG(ERROR) << "uri error, uri = " << uri; - cb(u8string()); - return false; - } - unicode_string_view schema = uri_obj->GetScheme(); - if (StringViewUtils::IsEmpty(schema)) { - TDF_BASE_DLOG(ERROR) << "schema error, uri = " << uri; - cb(u8string()); - return false; - } - unicode_string_view path = uri_obj->GetPath(); - if (StringViewUtils::IsEmpty(path)) { - TDF_BASE_DLOG(ERROR) << "path error, uri = " << uri; - cb(u8string()); - return false; - } - TDF_BASE_DCHECK(schema.encoding() == unicode_string_view::Encoding::Utf16); - std::u16string schema_str = schema.utf16_value(); - if (schema_str == u"file") { - return LoadByFile(path, cb); - } else if (schema_str == u"http" || schema_str == u"https" || - schema_str == u"debug") { - return LoadByHttp(uri, cb); - } else if (schema_str == u"asset") { - if (aasset_manager_) { - return LoadByAsset(path, cb, false); - } - TDF_BASE_DLOG(ERROR) << "aasset_manager error, uri = " << uri; - cb(u8string()); - return false; - } else { - TDF_BASE_DLOG(ERROR) << "schema error, schema = " << schema; - cb(u8string()); - return false; - } -} - -bool ADRLoader::RequestUntrustedContent(const unicode_string_view& uri, - u8string& content) { - std::shared_ptr uri_obj = Uri::Create(uri); - if (!uri_obj) { - TDF_BASE_DLOG(ERROR) << "uri error, uri = " << uri; - return false; - } - unicode_string_view schema = uri_obj->GetScheme(); - if (StringViewUtils::IsEmpty(schema)) { - TDF_BASE_DLOG(ERROR) << "schema error, uri = " << uri; - return false; - } - unicode_string_view path = uri_obj->GetPath(); - if (StringViewUtils::IsEmpty(path)) { - TDF_BASE_DLOG(ERROR) << "path error, uri = " << uri; - return false; - } - TDF_BASE_DCHECK(schema.encoding() == unicode_string_view::Encoding::Utf16); - std::u16string schema_str = schema.utf16_value(); - if (schema_str == u"file") { - return HippyFile::ReadFile(path, content, false); - } else if (schema_str == u"http" || schema_str == u"https" || - schema_str == u"debug") { - std::promise promise; - std::future read_file_future = promise.get_future(); - std::function cb = hippy::base::MakeCopyable( - [p = std::move(promise)](u8string bytes) mutable { - p.set_value(std::move(bytes)); - }); - bool ret = LoadByHttp(uri, cb); - content = read_file_future.get(); - return ret; - } else if (schema_str == u"asset") { - if (aasset_manager_) { - return ReadAsset(path, aasset_manager_, content, false); - } - - TDF_BASE_DLOG(ERROR) << "aasset_manager error, uri = " << uri; - return false; - } else { - TDF_BASE_DLOG(ERROR) << "schema error, schema = " << schema; - return false; - } -} - -bool ADRLoader::LoadByFile(const unicode_string_view& path, - std::function cb) { - std::shared_ptr runner = runner_.lock(); - if (!runner) { - return false; - } - std::unique_ptr task = std::make_unique(); - task->func_ = [path, cb] { - u8string ret; - HippyFile::ReadFile(path, ret, false); - cb(std::move(ret)); - }; - runner->PostTask(std::move(task)); - - return true; -} - -bool ADRLoader::LoadByAsset(const unicode_string_view& path, - std::function cb, - bool is_auto_fill) { - TDF_BASE_DLOG(INFO) << "ReadAssetFile file_path = " << path; - std::shared_ptr runner = runner_.lock(); - if (!runner) { - return false; - } - std::unique_ptr task = std::make_unique(); - task->func_ = [path, aasset_manager = aasset_manager_, is_auto_fill, cb] { - u8string ret; - ReadAsset(path, aasset_manager, ret, is_auto_fill); - cb(std::move(ret)); - }; - runner->PostTask(std::move(task)); - - return true; -} - -bool ADRLoader::LoadByHttp(const unicode_string_view& uri, - std::function cb) { - std::shared_ptr instance = JNIEnvironment::GetInstance(); - JNIEnv* j_env = instance->AttachCurrentThread(); - - if (instance->GetMethods().j_fetch_resource_method_id) { - int64_t id = SetRequestCB(cb); - jstring j_relative_path = JniUtils::StrViewToJString(j_env, uri); - j_env->CallVoidMethod(bridge_->GetObj(), - instance->GetMethods().j_fetch_resource_method_id, - j_relative_path, id); - j_env->DeleteLocalRef(j_relative_path); - return true; - } - - TDF_BASE_DLOG(ERROR) << "jni fetch_resource_method_id error"; - return false; -} - -void OnResourceReady(JNIEnv* j_env, - jobject j_object, - jobject j_byte_buffer, - jlong j_runtime_id, - jlong j_request_id) { - TDF_BASE_DLOG(INFO) << "HippyBridgeImpl onResourceReady j_runtime_id = " - << j_runtime_id; - std::shared_ptr runtime = Runtime::Find(j_runtime_id); - if (!runtime) { - TDF_BASE_DLOG(WARNING) - << "HippyBridgeImpl onResourceReady, j_runtime_id invalid"; - return; - } - std::shared_ptr scope = runtime->GetScope(); - if (!scope) { - TDF_BASE_DLOG(WARNING) << "HippyBridgeImpl onResourceReady, scope invalid"; - return; - } - - std::shared_ptr loader = - std::static_pointer_cast(scope->GetUriLoader()); - int64_t request_id = j_request_id; - TDF_BASE_DLOG(INFO) << "request_id = " << request_id; - auto cb = loader->GetRequestCB(request_id); - if (!cb) { - TDF_BASE_DLOG(WARNING) << "cb not found" << request_id; - return; - } - if (!j_byte_buffer) { - TDF_BASE_DLOG(INFO) << "HippyBridgeImpl onResourceReady, buff null"; - cb(u8string()); - return; - } - int64_t len = (j_env)->GetDirectBufferCapacity(j_byte_buffer); - TDF_BASE_DLOG(INFO) << "len = " << len; - if (len == -1) { - TDF_BASE_DLOG(ERROR) - << "HippyBridgeImpl onResourceReady, BufferCapacity error"; - cb(u8string()); - return; - } - void* buff = (j_env)->GetDirectBufferAddress(j_byte_buffer); - if (!buff) { - TDF_BASE_DLOG(INFO) << "HippyBridgeImpl onResourceReady, buff null"; - cb(u8string()); - return; - } - - u8string str(reinterpret_cast(buff), len); - cb(std::move(str)); -} - -REGISTER_JNI("com/tencent/mtt/hippy/bridge/HippyBridgeImpl", - "onResourceReady", - "(Ljava/nio/ByteBuffer;JJ)V", - OnResourceReady) - -std::function ADRLoader::GetRequestCB(int64_t request_id) { - auto it = request_map_.find(request_id); - return it != request_map_.end() ? it->second : nullptr; -} - -int64_t ADRLoader::SetRequestCB(std::function cb) { - int64_t id = global_request_id.fetch_add(1); - request_map_.insert({id, cb}); - return id; -} diff --git a/android/sdk/src/main/jni/third_party/layout/arm64-v8a/lib.unstripped/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/arm64-v8a/lib.unstripped/libflexbox.so deleted file mode 100644 index 75f14425054..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/arm64-v8a/lib.unstripped/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8b7cf3921281e59286584f6b6c5692cb51574a67bb68e80994d24a40c43e842a -size 2014456 diff --git a/android/sdk/src/main/jni/third_party/layout/arm64-v8a/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/arm64-v8a/libflexbox.so deleted file mode 100644 index 324c93b3b34..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/arm64-v8a/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dab82ba5341b38ce86efc6728b799482f9b34d7c58f53c66f7f81783d66a39ac -size 260152 diff --git a/android/sdk/src/main/jni/third_party/layout/armeabi-v7a/lib.unstripped/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/armeabi-v7a/lib.unstripped/libflexbox.so deleted file mode 100644 index 4c13aaa9cba..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/armeabi-v7a/lib.unstripped/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0627859d3d64971e16e3e311d2cbf6eb4a7c4faa192e0bb9b59d3e46f11fa291 -size 1615040 diff --git a/android/sdk/src/main/jni/third_party/layout/armeabi-v7a/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/armeabi-v7a/libflexbox.so deleted file mode 100644 index b2a7c414b18..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/armeabi-v7a/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:39998c94d16155c36b5e95e272bf360e04e91ddfe0d256d08ddba9453a4e08df -size 136796 diff --git a/android/sdk/src/main/jni/third_party/layout/x86/lib.unstripped/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/x86/lib.unstripped/libflexbox.so deleted file mode 100644 index e0327302ad7..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/x86/lib.unstripped/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:981db55c3461ca18c20eca1026165b21746a874b98df235f49507ae4114ee13c -size 1921984 diff --git a/android/sdk/src/main/jni/third_party/layout/x86/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/x86/libflexbox.so deleted file mode 100644 index 0def6999a04..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/x86/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:01c8cfc1651040ad91cc2c3251fb02bac5f68df8cb8dbb778d8329e3729a039d -size 272016 diff --git a/android/sdk/src/main/jni/third_party/layout/x86_64/lib.unstripped/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/x86_64/lib.unstripped/libflexbox.so deleted file mode 100644 index ec367be33a8..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/x86_64/lib.unstripped/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cd53c88519a7f085cef1b996a6456e4f958465d64857d659a20b2ce72733ac8d -size 2086600 diff --git a/android/sdk/src/main/jni/third_party/layout/x86_64/libflexbox.so b/android/sdk/src/main/jni/third_party/layout/x86_64/libflexbox.so deleted file mode 100644 index 561396722c7..00000000000 --- a/android/sdk/src/main/jni/third_party/layout/x86_64/libflexbox.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c70ef99c2603527ee3dad89e756aa7d11379d6e83db024550b08bbe206ec7ead -size 289096 diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/CMakeLists.txt b/android/sdk/src/main/jni/third_party/v8/latest/official-release/CMakeLists.txt deleted file mode 100644 index ca93711ceed..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 3.4.1) - -project(v8) - -set(V8_LIBRARY_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI} PARENT_SCOPE) -set(V8_LIBRARY_NAME libv8_monolith.a PARENT_SCOPE) - -set(V8_DEFINITIONS) -list(APPEND V8_DEFINITIONS "-DV8_IMMINENT_DEPRECATION_WARNINGS;") -list(APPEND V8_DEFINITIONS "-DV8_DEPRECATION_WARNINGS;") -if ((${ANDROID_ABI} STREQUAL "arm64-v8a") OR (${ANDROID_ABI} STREQUAL "x86_64")) - list(APPEND V8_DEFINITIONS "-DV8_COMPRESS_POINTERS;") -endif() -set(V8_DEFINITIONS ${V8_DEFINITIONS} PARENT_SCOPE) - -set(V8_INCLUDE_DIRECTORIES) -string(APPEND V8_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include;") -string(APPEND V8_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include/v8;") -set(V8_INCLUDE_DIRECTORIES ${V8_INCLUDE_DIRECTORIES} PARENT_SCOPE) - -set(V8_LINKING_MODE static PARENT_SCOPE) diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/README.md b/android/sdk/src/main/jni/third_party/v8/latest/official-release/README.md deleted file mode 100644 index d336fdb7df8..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/README.md +++ /dev/null @@ -1,8 +0,0 @@ -This v8 release is auto generated by Github Action([985784432][2]). - -_Do NOT modify this release manually._ - -Refs: [9.1.75][1] - -[1]: https://github.com/v8/v8/tree/9.1.75 -[2]: https://github.com/Tencent/Hippy/actions/runs/985784432 \ No newline at end of file diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/allocation.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/allocation.h deleted file mode 100644 index a3112dd61fb..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/allocation.h +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_ALLOCATION_H_ -#define INCLUDE_CPPGC_ALLOCATION_H_ - -#include -#include -#include -#include -#include -#include - -#include "cppgc/custom-space.h" -#include "cppgc/internal/api-constants.h" -#include "cppgc/internal/gc-info.h" -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -/** - * AllocationHandle is used to allocate garbage-collected objects. - */ -class AllocationHandle; - -namespace internal { - -class V8_EXPORT MakeGarbageCollectedTraitInternal { - protected: - static inline void MarkObjectAsFullyConstructed(const void* payload) { - // See api_constants for an explanation of the constants. - std::atomic* atomic_mutable_bitfield = - reinterpret_cast*>( - const_cast(reinterpret_cast( - reinterpret_cast(payload) - - api_constants::kFullyConstructedBitFieldOffsetFromPayload))); - // It's safe to split use load+store here (instead of a read-modify-write - // operation), since it's guaranteed that this 16-bit bitfield is only - // modified by a single thread. This is cheaper in terms of code bloat (on - // ARM) and performance. - uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed); - value |= api_constants::kFullyConstructedBitMask; - atomic_mutable_bitfield->store(value, std::memory_order_release); - } - - template - struct SpacePolicy { - static void* Allocate(AllocationHandle& handle, size_t size) { - // Custom space. - static_assert(std::is_base_of::value, - "Custom space must inherit from CustomSpaceBase."); - return MakeGarbageCollectedTraitInternal::Allocate( - handle, size, internal::GCInfoTrait::Index(), - CustomSpace::kSpaceIndex); - } - }; - - template - struct SpacePolicy { - static void* Allocate(AllocationHandle& handle, size_t size) { - // Default space. - return MakeGarbageCollectedTraitInternal::Allocate( - handle, size, internal::GCInfoTrait::Index()); - } - }; - - private: - static void* Allocate(cppgc::AllocationHandle& handle, size_t size, - GCInfoIndex index); - static void* Allocate(cppgc::AllocationHandle& handle, size_t size, - GCInfoIndex index, CustomSpaceIndex space_index); - - friend class HeapObjectHeader; -}; - -} // namespace internal - -/** - * Base trait that provides utilities for advancers users that have custom - * allocation needs (e.g., overriding size). It's expected that users override - * MakeGarbageCollectedTrait (see below) and inherit from - * MakeGarbageCollectedTraitBase and make use of the low-level primitives - * offered to allocate and construct an object. - */ -template -class MakeGarbageCollectedTraitBase - : private internal::MakeGarbageCollectedTraitInternal { - private: - static_assert(internal::IsGarbageCollectedType::value, - "T needs to be a garbage collected object"); - static_assert(!IsGarbageCollectedWithMixinTypeV || - sizeof(T) <= - internal::api_constants::kLargeObjectSizeThreshold, - "GarbageCollectedMixin may not be a large object"); - - protected: - /** - * Allocates memory for an object of type T. - * - * \param handle AllocationHandle identifying the heap to allocate the object - * on. - * \param size The size that should be reserved for the object. - * \returns the memory to construct an object of type T on. - */ - V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) { - static_assert( - std::is_base_of::value, - "U of GarbageCollected must be a base of T. Check " - "GarbageCollected base class inheritance."); - return SpacePolicy< - typename internal::GCInfoFolding< - T, typename T::ParentMostGarbageCollectedType>::ResultType, - typename SpaceTrait::Space>::Allocate(handle, size); - } - - /** - * Marks an object as fully constructed, resulting in precise handling by the - * garbage collector. - * - * \param payload The base pointer the object is allocated at. - */ - V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) { - internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed( - payload); - } -}; - -/** - * Passed to MakeGarbageCollected to specify how many bytes should be appended - * to the allocated object. - * - * Example: - * \code - * class InlinedArray final : public GarbageCollected { - * public: - * explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {} - * void Trace(Visitor*) const {} - - * size_t size; - * char* byte_array; - * }; - * - * auto* inlined_array = MakeGarbageCollectedbyte_array[i]); - * } - * \endcode - */ -struct AdditionalBytes { - constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {} - const size_t value; -}; - -/** - * Default trait class that specifies how to construct an object of type T. - * Advanced users may override how an object is constructed using the utilities - * that are provided through MakeGarbageCollectedTraitBase. - * - * Any trait overriding construction must - * - allocate through `MakeGarbageCollectedTraitBase::Allocate`; - * - mark the object as fully constructed using - * `MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed`; - */ -template -class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase { - public: - template - static T* Call(AllocationHandle& handle, Args&&... args) { - void* memory = - MakeGarbageCollectedTraitBase::Allocate(handle, sizeof(T)); - T* object = ::new (memory) T(std::forward(args)...); - MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object); - return object; - } - - template - static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes, - Args&&... args) { - void* memory = MakeGarbageCollectedTraitBase::Allocate( - handle, sizeof(T) + additional_bytes.value); - T* object = ::new (memory) T(std::forward(args)...); - MakeGarbageCollectedTraitBase::MarkObjectAsFullyConstructed(object); - return object; - } -}; - -/** - * Allows users to specify a post-construction callback for specific types. The - * callback is invoked on the instance of type T right after it has been - * constructed. This can be useful when the callback requires a - * fully-constructed object to be able to dispatch to virtual methods. - */ -template -struct PostConstructionCallbackTrait { - static void Call(T*) {} -}; - -/** - * Constructs a managed object of type T where T transitively inherits from - * GarbageCollected. - * - * \param args List of arguments with which an instance of T will be - * constructed. - * \returns an instance of type T. - */ -template -V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { - T* object = - MakeGarbageCollectedTrait::Call(handle, std::forward(args)...); - PostConstructionCallbackTrait::Call(object); - return object; -} - -/** - * Constructs a managed object of type T where T transitively inherits from - * GarbageCollected. Created objects will have additional bytes appended to - * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`. - * - * \param additional_bytes Denotes how many bytes to append to T. - * \param args List of arguments with which an instance of T will be - * constructed. - * \returns an instance of type T. - */ -template -V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, - AdditionalBytes additional_bytes, - Args&&... args) { - T* object = MakeGarbageCollectedTrait::Call(handle, additional_bytes, - std::forward(args)...); - PostConstructionCallbackTrait::Call(object); - return object; -} - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_ALLOCATION_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/common.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/common.h deleted file mode 100644 index b6dbff3dd6f..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/common.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_COMMON_H_ -#define INCLUDE_CPPGC_COMMON_H_ - -// TODO(chromium:1056170): Remove dependency on v8. -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -/** - * Indicator for the stack state of the embedder. - */ -enum class EmbedderStackState { - /** - * Stack may contain interesting heap pointers. - */ - kMayContainHeapPointers, - /** - * Stack does not contain any interesting heap pointers. - */ - kNoHeapPointers, -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_COMMON_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/cross-thread-persistent.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/cross-thread-persistent.h deleted file mode 100644 index c8751e1d641..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/cross-thread-persistent.h +++ /dev/null @@ -1,465 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ -#define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ - -#include - -#include "cppgc/internal/persistent-node.h" -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/persistent.h" -#include "cppgc/visitor.h" - -namespace cppgc { -namespace internal { - -// Wrapper around PersistentBase that allows accessing poisoned memory when -// using ASAN. This is needed as the GC of the heap that owns the value -// of a CTP, may clear it (heap termination, weakness) while the object -// holding the CTP may be poisoned as itself may be deemed dead. -class CrossThreadPersistentBase : public PersistentBase { - public: - CrossThreadPersistentBase() = default; - explicit CrossThreadPersistentBase(const void* raw) : PersistentBase(raw) {} - - V8_CLANG_NO_SANITIZE("address") const void* GetValueFromGC() const { - return raw_; - } - - V8_CLANG_NO_SANITIZE("address") - PersistentNode* GetNodeFromGC() const { return node_; } - - V8_CLANG_NO_SANITIZE("address") - void ClearFromGC() const { - raw_ = nullptr; - SetNodeSafe(nullptr); - } - - // GetNodeSafe() can be used for a thread-safe IsValid() check in a - // double-checked locking pattern. See ~BasicCrossThreadPersistent. - PersistentNode* GetNodeSafe() const { - return reinterpret_cast*>(&node_)->load( - std::memory_order_acquire); - } - - // The GC writes using SetNodeSafe() while holding the lock. - V8_CLANG_NO_SANITIZE("address") - void SetNodeSafe(PersistentNode* value) const { -#if defined(__has_feature) -#if __has_feature(address_sanitizer) -#define V8_IS_ASAN 1 -#endif -#endif - -#ifdef V8_IS_ASAN - __atomic_store(&node_, &value, __ATOMIC_RELEASE); -#else // !V8_IS_ASAN - // Non-ASAN builds can use atomics. This also covers MSVC which does not - // have the __atomic_store intrinsic. - reinterpret_cast*>(&node_)->store( - value, std::memory_order_release); -#endif // !V8_IS_ASAN - -#undef V8_IS_ASAN - } -}; - -template -class BasicCrossThreadPersistent final : public CrossThreadPersistentBase, - public LocationPolicy, - private WeaknessPolicy, - private CheckingPolicy { - public: - using typename WeaknessPolicy::IsStrongPersistent; - using PointeeType = T; - - ~BasicCrossThreadPersistent() { - // This implements fast path for destroying empty/sentinel. - // - // Simplified version of `AssignUnsafe()` to allow calling without a - // complete type `T`. Uses double-checked locking with a simple thread-safe - // check for a valid handle based on a node. - if (GetNodeSafe()) { - PersistentRegionLock guard; - const void* old_value = GetValue(); - // The fast path check (GetNodeSafe()) does not acquire the lock. Recheck - // validity while holding the lock to ensure the reference has not been - // cleared. - if (IsValid(old_value)) { - CrossThreadPersistentRegion& region = - this->GetPersistentRegion(old_value); - region.FreeNode(GetNode()); - SetNode(nullptr); - } else { - CPPGC_DCHECK(!GetNode()); - } - } - // No need to call SetValue() as the handle is not used anymore. This can - // leave behind stale sentinel values but will always destroy the underlying - // node. - } - - BasicCrossThreadPersistent( - const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicCrossThreadPersistent( - std::nullptr_t, const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicCrossThreadPersistent( - SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) - : CrossThreadPersistentBase(s), LocationPolicy(loc) {} - - BasicCrossThreadPersistent( - T* raw, const SourceLocation& loc = SourceLocation::Current()) - : CrossThreadPersistentBase(raw), LocationPolicy(loc) { - if (!IsValid(raw)) return; - PersistentRegionLock guard; - CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); - SetNode(region.AllocateNode(this, &Trace)); - this->CheckPointer(raw); - } - - class UnsafeCtorTag { - private: - UnsafeCtorTag() = default; - template - friend class BasicCrossThreadPersistent; - }; - - BasicCrossThreadPersistent( - UnsafeCtorTag, T* raw, - const SourceLocation& loc = SourceLocation::Current()) - : CrossThreadPersistentBase(raw), LocationPolicy(loc) { - if (!IsValid(raw)) return; - CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw); - SetNode(region.AllocateNode(this, &Trace)); - this->CheckPointer(raw); - } - - BasicCrossThreadPersistent( - T& raw, const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(&raw, loc) {} - - template ::value>> - BasicCrossThreadPersistent( - internal::BasicMember - member, - const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(member.Get(), loc) {} - - BasicCrossThreadPersistent( - const BasicCrossThreadPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(loc) { - // Invoke operator=. - *this = other; - } - - // Heterogeneous ctor. - template ::value>> - BasicCrossThreadPersistent( - const BasicCrossThreadPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicCrossThreadPersistent(loc) { - *this = other; - } - - BasicCrossThreadPersistent( - BasicCrossThreadPersistent&& other, - const SourceLocation& loc = SourceLocation::Current()) noexcept { - // Invoke operator=. - *this = std::move(other); - } - - BasicCrossThreadPersistent& operator=( - const BasicCrossThreadPersistent& other) { - PersistentRegionLock guard; - AssignSafe(guard, other.Get()); - return *this; - } - - template ::value>> - BasicCrossThreadPersistent& operator=( - const BasicCrossThreadPersistent& other) { - PersistentRegionLock guard; - AssignSafe(guard, other.Get()); - return *this; - } - - BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) { - if (this == &other) return *this; - Clear(); - PersistentRegionLock guard; - PersistentBase::operator=(std::move(other)); - LocationPolicy::operator=(std::move(other)); - if (!IsValid(GetValue())) return *this; - GetNode()->UpdateOwner(this); - other.SetValue(nullptr); - other.SetNode(nullptr); - this->CheckPointer(Get()); - return *this; - } - - /** - * Assigns a raw pointer. - * - * Note: **Not thread-safe.** - */ - BasicCrossThreadPersistent& operator=(T* other) { - AssignUnsafe(other); - return *this; - } - - // Assignment from member. - template ::value>> - BasicCrossThreadPersistent& operator=( - internal::BasicMember - member) { - return operator=(member.Get()); - } - - /** - * Assigns a nullptr. - * - * \returns the handle. - */ - BasicCrossThreadPersistent& operator=(std::nullptr_t) { - Clear(); - return *this; - } - - /** - * Assigns the sentinel pointer. - * - * \returns the handle. - */ - BasicCrossThreadPersistent& operator=(SentinelPointer s) { - PersistentRegionLock guard; - AssignSafe(guard, s); - return *this; - } - - /** - * Returns a pointer to the stored object. - * - * Note: **Not thread-safe.** - * - * \returns a pointer to the stored object. - */ - // CFI cast exemption to allow passing SentinelPointer through T* and support - // heterogeneous assignments between different Member and Persistent handles - // based on their actual types. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { - return static_cast(const_cast(GetValue())); - } - - /** - * Clears the stored object. - */ - void Clear() { - PersistentRegionLock guard; - AssignSafe(guard, nullptr); - } - - /** - * Returns a pointer to the stored object and releases it. - * - * Note: **Not thread-safe.** - * - * \returns a pointer to the stored object. - */ - T* Release() { - T* result = Get(); - Clear(); - return result; - } - - /** - * Conversio to boolean. - * - * Note: **Not thread-safe.** - * - * \returns true if an actual object has been stored and false otherwise. - */ - explicit operator bool() const { return Get(); } - - /** - * Conversion to object of type T. - * - * Note: **Not thread-safe.** - * - * \returns the object. - */ - operator T*() const { return Get(); } - - /** - * Dereferences the stored object. - * - * Note: **Not thread-safe.** - */ - T* operator->() const { return Get(); } - T& operator*() const { return *Get(); } - - template - BasicCrossThreadPersistent - To() const { - using OtherBasicCrossThreadPersistent = - BasicCrossThreadPersistent; - PersistentRegionLock guard; - return OtherBasicCrossThreadPersistent( - typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(), - static_cast(Get())); - } - - template ::IsStrongPersistent::value>::type> - BasicCrossThreadPersistent - Lock() const { - return BasicCrossThreadPersistent< - U, internal::StrongCrossThreadPersistentPolicy>(*this); - } - - private: - static bool IsValid(const void* ptr) { - return ptr && ptr != kSentinelPointer; - } - - static void Trace(Visitor* v, const void* ptr) { - const auto* handle = static_cast(ptr); - v->TraceRoot(*handle, handle->Location()); - } - - void AssignUnsafe(T* ptr) { - const void* old_value = GetValue(); - if (IsValid(old_value)) { - PersistentRegionLock guard; - old_value = GetValue(); - // The fast path check (IsValid()) does not acquire the lock. Reload - // the value to ensure the reference has not been cleared. - if (IsValid(old_value)) { - CrossThreadPersistentRegion& region = - this->GetPersistentRegion(old_value); - if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) { - SetValue(ptr); - this->CheckPointer(ptr); - return; - } - region.FreeNode(GetNode()); - SetNode(nullptr); - } else { - CPPGC_DCHECK(!GetNode()); - } - } - SetValue(ptr); - if (!IsValid(ptr)) return; - PersistentRegionLock guard; - SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace)); - this->CheckPointer(ptr); - } - - void AssignSafe(PersistentRegionLock&, T* ptr) { - PersistentRegionLock::AssertLocked(); - const void* old_value = GetValue(); - if (IsValid(old_value)) { - CrossThreadPersistentRegion& region = - this->GetPersistentRegion(old_value); - if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) { - SetValue(ptr); - this->CheckPointer(ptr); - return; - } - region.FreeNode(GetNode()); - SetNode(nullptr); - } - SetValue(ptr); - if (!IsValid(ptr)) return; - SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &Trace)); - this->CheckPointer(ptr); - } - - void ClearFromGC() const { - if (IsValid(GetValueFromGC())) { - WeaknessPolicy::GetPersistentRegion(GetValueFromGC()) - .FreeNode(GetNodeFromGC()); - CrossThreadPersistentBase::ClearFromGC(); - } - } - - // See Get() for details. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") - T* GetFromGC() const { - return static_cast(const_cast(GetValueFromGC())); - } - - friend class cppgc::Visitor; -}; - -template -struct IsWeak< - BasicCrossThreadPersistent> - : std::true_type {}; - -} // namespace internal - -namespace subtle { - -/** - * **DO NOT USE: Has known caveats, see below.** - * - * CrossThreadPersistent allows retaining objects from threads other than the - * thread the owning heap is operating on. - * - * Known caveats: - * - Does not protect the heap owning an object from terminating. - * - Reaching transitively through the graph is unsupported as objects may be - * moved concurrently on the thread owning the object. - */ -template -using CrossThreadPersistent = internal::BasicCrossThreadPersistent< - T, internal::StrongCrossThreadPersistentPolicy>; - -/** - * **DO NOT USE: Has known caveats, see below.** - * - * CrossThreadPersistent allows weakly retaining objects from threads other than - * the thread the owning heap is operating on. - * - * Known caveats: - * - Does not protect the heap owning an object from terminating. - * - Reaching transitively through the graph is unsupported as objects may be - * moved concurrently on the thread owning the object. - */ -template -using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent< - T, internal::WeakCrossThreadPersistentPolicy>; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/custom-space.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/custom-space.h deleted file mode 100644 index 757c4fde15e..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/custom-space.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_CUSTOM_SPACE_H_ -#define INCLUDE_CPPGC_CUSTOM_SPACE_H_ - -#include - -namespace cppgc { - -/** - * Index identifying a custom space. - */ -struct CustomSpaceIndex { - constexpr CustomSpaceIndex(size_t value) : value(value) {} // NOLINT - size_t value; -}; - -/** - * Top-level base class for custom spaces. Users must inherit from CustomSpace - * below. - */ -class CustomSpaceBase { - public: - virtual ~CustomSpaceBase() = default; - virtual CustomSpaceIndex GetCustomSpaceIndex() const = 0; - virtual bool IsCompactable() const = 0; -}; - -/** - * Base class custom spaces should directly inherit from. The class inheriting - * from `CustomSpace` must define `kSpaceIndex` as unique space index. These - * indices need for form a sequence starting at 0. - * - * Example: - * \code - * class CustomSpace1 : public CustomSpace { - * public: - * static constexpr CustomSpaceIndex kSpaceIndex = 0; - * }; - * class CustomSpace2 : public CustomSpace { - * public: - * static constexpr CustomSpaceIndex kSpaceIndex = 1; - * }; - * \endcode - */ -template -class CustomSpace : public CustomSpaceBase { - public: - /** - * Compaction is only supported on spaces that manually manage slots - * recording. - */ - static constexpr bool kSupportsCompaction = false; - - CustomSpaceIndex GetCustomSpaceIndex() const final { - return ConcreteCustomSpace::kSpaceIndex; - } - bool IsCompactable() const final { - return ConcreteCustomSpace::kSupportsCompaction; - } -}; - -/** - * User-overridable trait that allows pinning types to custom spaces. - */ -template -struct SpaceTrait { - using Space = void; -}; - -namespace internal { - -template -struct IsAllocatedOnCompactableSpaceImpl { - static constexpr bool value = CustomSpace::kSupportsCompaction; -}; - -template <> -struct IsAllocatedOnCompactableSpaceImpl { - // Non-custom spaces are by default not compactable. - static constexpr bool value = false; -}; - -template -struct IsAllocatedOnCompactableSpace { - public: - static constexpr bool value = - IsAllocatedOnCompactableSpaceImpl::Space>::value; -}; - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_CUSTOM_SPACE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/default-platform.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/default-platform.h deleted file mode 100644 index 2ccdeddd837..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/default-platform.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ -#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ - -#include -#include - -#include "cppgc/platform.h" -#include "libplatform/libplatform.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -/** - * Platform provided by cppgc. Uses V8's DefaultPlatform provided by - * libplatform internally. Exception: `GetForegroundTaskRunner()`, see below. - */ -class V8_EXPORT DefaultPlatform : public Platform { - public: - /** - * Use this method instead of 'cppgc::InitializeProcess' when using - * 'cppgc::DefaultPlatform'. 'cppgc::DefaultPlatform::InitializeProcess' - * will initialize cppgc and v8 if needed (for non-standalone builds). - * - * \param platform DefaultPlatform instance used to initialize cppgc/v8. - */ - static void InitializeProcess(DefaultPlatform* platform); - - using IdleTaskSupport = v8::platform::IdleTaskSupport; - explicit DefaultPlatform( - int thread_pool_size = 0, - IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, - std::unique_ptr tracing_controller = {}) - : v8_platform_(v8::platform::NewDefaultPlatform( - thread_pool_size, idle_task_support, - v8::platform::InProcessStackDumping::kDisabled, - std::move(tracing_controller))) {} - - cppgc::PageAllocator* GetPageAllocator() override { - return v8_platform_->GetPageAllocator(); - } - - double MonotonicallyIncreasingTime() override { - return v8_platform_->MonotonicallyIncreasingTime(); - } - - std::shared_ptr GetForegroundTaskRunner() override { - // V8's default platform creates a new task runner when passed the - // `v8::Isolate` pointer the first time. For non-default platforms this will - // require getting the appropriate task runner. - return v8_platform_->GetForegroundTaskRunner(kNoIsolate); - } - - std::unique_ptr PostJob( - cppgc::TaskPriority priority, - std::unique_ptr job_task) override { - return v8_platform_->PostJob(priority, std::move(job_task)); - } - - TracingController* GetTracingController() override { - return v8_platform_->GetTracingController(); - } - - protected: - static constexpr v8::Isolate* kNoIsolate = nullptr; - - std::unique_ptr v8_platform_; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/ephemeron-pair.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/ephemeron-pair.h deleted file mode 100644 index e16cf1f0aa2..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/ephemeron-pair.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_EPHEMERON_PAIR_H_ -#define INCLUDE_CPPGC_EPHEMERON_PAIR_H_ - -#include "cppgc/liveness-broker.h" -#include "cppgc/member.h" - -namespace cppgc { - -/** - * An ephemeron pair is used to conditionally retain an object. - * The `value` will be kept alive only if the `key` is alive. - */ -template -struct EphemeronPair { - EphemeronPair(K* k, V* v) : key(k), value(v) {} - WeakMember key; - Member value; - - void ClearValueIfKeyIsDead(const LivenessBroker& broker) { - if (!broker.IsHeapObjectAlive(key)) value = nullptr; - } -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_EPHEMERON_PAIR_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/explicit-management.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/explicit-management.h deleted file mode 100644 index cdb6af48586..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/explicit-management.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ -#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ - -#include - -#include "cppgc/allocation.h" -#include "cppgc/internal/logging.h" -#include "cppgc/type-traits.h" - -namespace cppgc { - -class HeapHandle; - -namespace internal { - -V8_EXPORT void FreeUnreferencedObject(HeapHandle&, void*); -V8_EXPORT bool Resize(void*, size_t); - -} // namespace internal - -namespace subtle { - -/** - * Informs the garbage collector that `object` can be immediately reclaimed. The - * destructor may not be invoked immediately but only on next garbage - * collection. - * - * It is up to the embedder to guarantee that no other object holds a reference - * to `object` after calling `FreeUnreferencedObject()`. In case such a - * reference exists, it's use results in a use-after-free. - * - * To aid in using the API, `FreeUnreferencedObject()` may be called from - * destructors on objects that would be reclaimed in the same garbage collection - * cycle. - * - * \param heap_handle The corresponding heap. - * \param object Reference to an object that is of type `GarbageCollected` and - * should be immediately reclaimed. - */ -template -void FreeUnreferencedObject(HeapHandle& heap_handle, T& object) { - static_assert(IsGarbageCollectedTypeV, - "Object must be of type GarbageCollected."); - internal::FreeUnreferencedObject(heap_handle, &object); -} - -/** - * Tries to resize `object` of type `T` with additional bytes on top of - * sizeof(T). Resizing is only useful with trailing inlined storage, see e.g. - * `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`. - * - * `Resize()` performs growing or shrinking as needed and may skip the operation - * for internal reasons, see return value. - * - * It is up to the embedder to guarantee that in case of shrinking a larger - * object down, the reclaimed area is not used anymore. Any subsequent use - * results in a use-after-free. - * - * The `object` must be live when calling `Resize()`. - * - * \param object Reference to an object that is of type `GarbageCollected` and - * should be resized. - * \param additional_bytes Bytes in addition to sizeof(T) that the object should - * provide. - * \returns true when the operation was successful and the result can be relied - * on, and false otherwise. - */ -template -bool Resize(T& object, AdditionalBytes additional_bytes) { - static_assert(IsGarbageCollectedTypeV, - "Object must be of type GarbageCollected."); - return internal::Resize(&object, sizeof(T) + additional_bytes.value); -} - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/garbage-collected.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/garbage-collected.h deleted file mode 100644 index a3839e1baa5..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/garbage-collected.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ -#define INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ - -#include - -#include "cppgc/internal/api-constants.h" -#include "cppgc/platform.h" -#include "cppgc/trace-trait.h" -#include "cppgc/type-traits.h" - -namespace cppgc { - -class Visitor; - -namespace internal { - -class GarbageCollectedBase { - public: - // Must use MakeGarbageCollected. - void* operator new(size_t) = delete; - void* operator new[](size_t) = delete; - // The garbage collector is taking care of reclaiming the object. Also, - // virtual destructor requires an unambiguous, accessible 'operator delete'. - void operator delete(void*) { -#ifdef V8_ENABLE_CHECKS - internal::Abort(); -#endif // V8_ENABLE_CHECKS - } - void operator delete[](void*) = delete; - - protected: - GarbageCollectedBase() = default; -}; - -} // namespace internal - -/** - * Base class for managed objects. Only descendent types of `GarbageCollected` - * can be constructed using `MakeGarbageCollected()`. Must be inherited from as - * left-most base class. - * - * Types inheriting from GarbageCollected must provide a method of - * signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed - * pointers to the visitor and delegates to garbage-collected base classes. - * The method must be virtual if the type is not directly a child of - * GarbageCollected and marked as final. - * - * \code - * // Example using final class. - * class FinalType final : public GarbageCollected { - * public: - * void Trace(cppgc::Visitor* visitor) const { - * // Dispatch using visitor->Trace(...); - * } - * }; - * - * // Example using non-final base class. - * class NonFinalBase : public GarbageCollected { - * public: - * virtual void Trace(cppgc::Visitor*) const {} - * }; - * - * class FinalChild final : public NonFinalBase { - * public: - * void Trace(cppgc::Visitor* visitor) const final { - * // Dispatch using visitor->Trace(...); - * NonFinalBase::Trace(visitor); - * } - * }; - * \endcode - */ -template -class GarbageCollected : public internal::GarbageCollectedBase { - public: - using IsGarbageCollectedTypeMarker = void; - using ParentMostGarbageCollectedType = T; - - protected: - GarbageCollected() = default; -}; - -/** - * Base class for managed mixin objects. Such objects cannot be constructed - * directly but must be mixed into the inheritance hierarchy of a - * GarbageCollected object. - * - * Types inheriting from GarbageCollectedMixin must override a virtual method - * of signature `void Trace(cppgc::Visitor*) const` that dispatchs all managed - * pointers to the visitor and delegates to base classes. - * - * \code - * class Mixin : public GarbageCollectedMixin { - * public: - * void Trace(cppgc::Visitor* visitor) const override { - * // Dispatch using visitor->Trace(...); - * } - * }; - * \endcode - */ -class GarbageCollectedMixin : public internal::GarbageCollectedBase { - public: - using IsGarbageCollectedMixinTypeMarker = void; - - /** - * This Trace method must be overriden by objects inheriting from - * GarbageCollectedMixin. - */ - virtual void Trace(cppgc::Visitor*) const {} -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_GARBAGE_COLLECTED_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-consistency.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-consistency.h deleted file mode 100644 index 8e603d5d8af..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-consistency.h +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ -#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ - -#include - -#include "cppgc/internal/write-barrier.h" -#include "cppgc/macros.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class HeapHandle; - -namespace subtle { - -/** - * **DO NOT USE: Use the appropriate managed types.** - * - * Consistency helpers that aid in maintaining a consistent internal state of - * the garbage collector. - */ -class HeapConsistency final { - public: - using WriteBarrierParams = internal::WriteBarrier::Params; - using WriteBarrierType = internal::WriteBarrier::Type; - - /** - * Gets the required write barrier type for a specific write. - * - * \param slot Slot containing the pointer to the object. The slot itself - * must reside in an object that has been allocated using - * `MakeGarbageCollected()`. - * \param value The pointer to the object. May be an interior pointer to an - * interface of the actual object. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - static V8_INLINE WriteBarrierType GetWriteBarrierType( - const void* slot, const void* value, WriteBarrierParams& params) { - return internal::WriteBarrier::GetWriteBarrierType(slot, value, params); - } - - /** - * Gets the required write barrier type for a specific write. - * - * \param slot Slot to some part of an object. The object must not necessarily - have been allocated using `MakeGarbageCollected()` but can also live - off-heap or on stack. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \param callback Callback returning the corresponding heap handle. The - * callback is only invoked if the heap cannot otherwise be figured out. The - * callback must not allocate. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - template - static V8_INLINE WriteBarrierType - GetWriteBarrierType(const void* slot, WriteBarrierParams& params, - HeapHandleCallback callback) { - return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback); - } - - /** - * Gets the required write barrier type for a specific write. - * This version is meant to be used in conjunction with with a marking write - * barrier barrier which doesn't consider the slot. - * - * \param value The pointer to the object. May be an interior pointer to an - * interface of the actual object. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - static V8_INLINE WriteBarrierType - GetWriteBarrierType(const void* value, WriteBarrierParams& params) { - return internal::WriteBarrier::GetWriteBarrierType(value, params); - } - - /** - * Conservative Dijkstra-style write barrier that processes an object if it - * has not yet been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param object The pointer to the object. May be an interior pointer to a - * an interface of the actual object. - */ - static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params, - const void* object) { - internal::WriteBarrier::DijkstraMarkingBarrier(params, object); - } - - /** - * Conservative Dijkstra-style write barrier that processes a range of - * elements if they have not yet been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param first_element Pointer to the first element that should be processed. - * The slot itself must reside in an object that has been allocated using - * `MakeGarbageCollected()`. - * \param element_size Size of the element in bytes. - * \param number_of_elements Number of elements that should be processed, - * starting with `first_element`. - * \param trace_callback The trace callback that should be invoked for each - * element if necessary. - */ - static V8_INLINE void DijkstraWriteBarrierRange( - const WriteBarrierParams& params, const void* first_element, - size_t element_size, size_t number_of_elements, - TraceCallback trace_callback) { - internal::WriteBarrier::DijkstraMarkingBarrierRange( - params, first_element, element_size, number_of_elements, - trace_callback); - } - - /** - * Steele-style write barrier that re-processes an object if it has already - * been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param object The pointer to the object which must point to an object that - * has been allocated using `MakeGarbageCollected()`. Interior pointers are - * not supported. - */ - static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params, - const void* object) { - internal::WriteBarrier::SteeleMarkingBarrier(params, object); - } - - /** - * Generational barrier for maintaining consistency when running with multiple - * generations. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param slot Slot containing the pointer to the object. The slot itself - * must reside in an object that has been allocated using - * `MakeGarbageCollected()`. - */ - static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params, - const void* slot) { - internal::WriteBarrier::GenerationalBarrier(params, slot); - } - - private: - HeapConsistency() = delete; -}; - -/** - * Disallows garbage collection finalizations. Any garbage collection triggers - * result in a crash when in this scope. - * - * Note that the garbage collector already covers paths that can lead to garbage - * collections, so user code does not require checking - * `IsGarbageCollectionAllowed()` before allocations. - */ -class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final { - CPPGC_STACK_ALLOCATED(); - - public: - /** - * \returns whether garbage collections are currently allowed. - */ - static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle); - - /** - * Enters a disallow garbage collection scope. Must be paired with `Leave()`. - * Prefer a scope instance of `DisallowGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Enter(HeapHandle& heap_handle); - - /** - * Leaves a disallow garbage collection scope. Must be paired with `Enter()`. - * Prefer a scope instance of `DisallowGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Leave(HeapHandle& heap_handle); - - /** - * Constructs a scoped object that automatically enters and leaves a disallow - * garbage collection scope based on its lifetime. - * - * \param heap_handle The corresponding heap. - */ - explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle); - ~DisallowGarbageCollectionScope(); - - DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) = - delete; - DisallowGarbageCollectionScope& operator=( - const DisallowGarbageCollectionScope&) = delete; - - private: - HeapHandle& heap_handle_; -}; - -/** - * Avoids invoking garbage collection finalizations. Already running garbage - * collection phase are unaffected by this scope. - * - * Should only be used temporarily as the scope has an impact on memory usage - * and follow up garbage collections. - */ -class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final { - CPPGC_STACK_ALLOCATED(); - - public: - /** - * Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer - * a scope instance of `NoGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Enter(HeapHandle& heap_handle); - - /** - * Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer - * a scope instance of `NoGarbageCollectionScope`. - * - * \param heap_handle The corresponding heap. - */ - static void Leave(HeapHandle& heap_handle); - - /** - * Constructs a scoped object that automatically enters and leaves a no - * garbage collection scope based on its lifetime. - * - * \param heap_handle The corresponding heap. - */ - explicit NoGarbageCollectionScope(HeapHandle& heap_handle); - ~NoGarbageCollectionScope(); - - NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete; - NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete; - - private: - HeapHandle& heap_handle_; -}; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-state.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-state.h deleted file mode 100644 index 3fd6b54a8a2..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-state.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_STATE_H_ -#define INCLUDE_CPPGC_HEAP_STATE_H_ - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class HeapHandle; - -namespace subtle { - -/** - * Helpers to peek into heap-internal state. - */ -class V8_EXPORT HeapState final { - public: - /** - * Returns whether the garbage collector is marking. This API is experimental - * and is expected to be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the garbage collector is currently marking, and false - * otherwise. - */ - static bool IsMarking(const HeapHandle& heap_handle); - - /* - * Returns whether the garbage collector is sweeping. This API is experimental - * and is expected to be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the garbage collector is currently sweeping, and false - * otherwise. - */ - static bool IsSweeping(const HeapHandle& heap_handle); - - /** - * Returns whether the garbage collector is in the atomic pause, i.e., the - * mutator is stopped from running. This API is experimental and is expected - * to be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the garbage collector is currently in the atomic pause, - * and false otherwise. - */ - static bool IsInAtomicPause(const HeapHandle& heap_handle); - - /** - * Returns whether the last garbage collection was finalized conservatively - * (i.e., with a non-empty stack). This API is experimental and is expected to - * be removed in future. - * - * \param heap_handle The corresponding heap. - * \returns true if the last garbage collection was finalized conservatively, - * and false otherwise. - */ - static bool PreviousGCWasConservative(const HeapHandle& heap_handle); - - private: - HeapState() = delete; -}; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_STATE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-statistics.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-statistics.h deleted file mode 100644 index 8e626596e5b..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap-statistics.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_STATISTICS_H_ -#define INCLUDE_CPPGC_HEAP_STATISTICS_H_ - -#include -#include -#include -#include - -namespace cppgc { - -/** - * `HeapStatistics` contains memory consumption and utilization statistics for a - * cppgc heap. - */ -struct HeapStatistics final { - /** - * Specifies the detail level of the heap statistics. Brief statistics contain - * only the top-level allocated and used memory statistics for the entire - * heap. Detailed statistics also contain a break down per space and page, as - * well as freelist statistics and object type histograms. Note that used - * memory reported by brief statistics and detailed statistics might differ - * slightly. - */ - enum DetailLevel : uint8_t { - kBrief, - kDetailed, - }; - - /** - * Object statistics for a single type. - */ - struct ObjectStatsEntry { - /** - * Number of allocated bytes. - */ - size_t allocated_bytes; - /** - * Number of allocated objects. - */ - size_t object_count; - }; - - /** - * Page granularity statistics. For each page the statistics record the - * allocated memory size and overall used memory size for the page. - */ - struct PageStatistics { - /** Overall committed amount of memory for the page. */ - size_t committed_size_bytes = 0; - /** Resident amount of memory held by the page. */ - size_t resident_size_bytes = 0; - /** Amount of memory actually used on the page. */ - size_t used_size_bytes = 0; - /** Statistics for object allocated on the page. Filled only when - * NameProvider::HideInternalNames() is false. */ - std::vector object_statistics; - }; - - /** - * Statistics of the freelist (used only in non-large object spaces). For - * each bucket in the freelist the statistics record the bucket size, the - * number of freelist entries in the bucket, and the overall allocated memory - * consumed by these freelist entries. - */ - struct FreeListStatistics { - /** bucket sizes in the freelist. */ - std::vector bucket_size; - /** number of freelist entries per bucket. */ - std::vector free_count; - /** memory size consumed by freelist entries per size. */ - std::vector free_size; - }; - - /** - * Space granularity statistics. For each space the statistics record the - * space name, the amount of allocated memory and overall used memory for the - * space. The statistics also contain statistics for each of the space's - * pages, its freelist and the objects allocated on the space. - */ - struct SpaceStatistics { - /** The space name */ - std::string name; - /** Overall committed amount of memory for the heap. */ - size_t committed_size_bytes = 0; - /** Resident amount of memory held by the heap. */ - size_t resident_size_bytes = 0; - /** Amount of memory actually used on the space. */ - size_t used_size_bytes = 0; - /** Statistics for each of the pages in the space. */ - std::vector page_stats; - /** Statistics for the freelist of the space. */ - FreeListStatistics free_list_stats; - }; - - /** Overall committed amount of memory for the heap. */ - size_t committed_size_bytes = 0; - /** Resident amount of memory help by the heap. */ - size_t resident_size_bytes = 0; - /** Amount of memory actually used on the heap. */ - size_t used_size_bytes = 0; - /** Detail level of this HeapStatistics. */ - DetailLevel detail_level; - - /** Statistics for each of the spaces in the heap. Filled only when - * `detail_level` is `DetailLevel::kDetailed`. */ - std::vector space_stats; - - /** - * Vector of `cppgc::GarbageCollected` type names. - */ - std::vector type_names; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_STATISTICS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap.h deleted file mode 100644 index 136c4fb44d0..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/heap.h +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_HEAP_H_ -#define INCLUDE_CPPGC_HEAP_H_ - -#include -#include -#include -#include - -#include "cppgc/common.h" -#include "cppgc/custom-space.h" -#include "cppgc/platform.h" -#include "v8config.h" // NOLINT(build/include_directory) - -/** - * cppgc - A C++ garbage collection library. - */ -namespace cppgc { - -class AllocationHandle; - -/** - * Implementation details of cppgc. Those details are considered internal and - * may change at any point in time without notice. Users should never rely on - * the contents of this namespace. - */ -namespace internal { -class Heap; -} // namespace internal - -/** - * Used for additional heap APIs. - */ -class HeapHandle; - -class V8_EXPORT Heap { - public: - /** - * Specifies the stack state the embedder is in. - */ - using StackState = EmbedderStackState; - - /** - * Specifies whether conservative stack scanning is supported. - */ - enum class StackSupport : uint8_t { - /** - * Conservative stack scan is supported. - */ - kSupportsConservativeStackScan, - /** - * Conservative stack scan is not supported. Embedders may use this option - * when using custom infrastructure that is unsupported by the library. - */ - kNoConservativeStackScan, - }; - - /** - * Specifies supported marking types - */ - enum class MarkingType : uint8_t { - /** - * Atomic stop-the-world marking. This option does not require any write - * barriers but is the most intrusive in terms of jank. - */ - kAtomic, - /** - * Incremental marking, i.e. interleave marking is the rest of the - * application on the same thread. - */ - kIncremental, - /** - * Incremental and concurrent marking. - */ - kIncrementalAndConcurrent - }; - - /** - * Specifies supported sweeping types - */ - enum class SweepingType : uint8_t { - /** - * Atomic stop-the-world sweeping. All of sweeping is performed at once. - */ - kAtomic, - /** - * Incremental and concurrent sweeping. Sweeping is split and interleaved - * with the rest of the application. - */ - kIncrementalAndConcurrent - }; - - /** - * Constraints for a Heap setup. - */ - struct ResourceConstraints { - /** - * Allows the heap to grow to some initial size in bytes before triggering - * garbage collections. This is useful when it is known that applications - * need a certain minimum heap to run to avoid repeatedly invoking the - * garbage collector when growing the heap. - */ - size_t initial_heap_size_bytes = 0; - }; - - /** - * Options specifying Heap properties (e.g. custom spaces) when initializing a - * heap through `Heap::Create()`. - */ - struct HeapOptions { - /** - * Creates reasonable defaults for instantiating a Heap. - * - * \returns the HeapOptions that can be passed to `Heap::Create()`. - */ - static HeapOptions Default() { return {}; } - - /** - * Custom spaces added to heap are required to have indices forming a - * numbered sequence starting at 0, i.e., their `kSpaceIndex` must - * correspond to the index they reside in the vector. - */ - std::vector> custom_spaces; - - /** - * Specifies whether conservative stack scan is supported. When conservative - * stack scan is not supported, the collector may try to invoke - * garbage collections using non-nestable task, which are guaranteed to have - * no interesting stack, through the provided Platform. If such tasks are - * not supported by the Platform, the embedder must take care of invoking - * the GC through `ForceGarbageCollectionSlow()`. - */ - StackSupport stack_support = StackSupport::kSupportsConservativeStackScan; - - /** - * Specifies which types of marking are supported by the heap. - */ - MarkingType marking_support = MarkingType::kIncrementalAndConcurrent; - - /** - * Specifies which types of sweeping are supported by the heap. - */ - SweepingType sweeping_support = SweepingType::kIncrementalAndConcurrent; - - /** - * Resource constraints specifying various properties that the internal - * GC scheduler follows. - */ - ResourceConstraints resource_constraints; - }; - - /** - * Creates a new heap that can be used for object allocation. - * - * \param platform implemented and provided by the embedder. - * \param options HeapOptions specifying various properties for the Heap. - * \returns a new Heap instance. - */ - static std::unique_ptr Create( - std::shared_ptr platform, - HeapOptions options = HeapOptions::Default()); - - virtual ~Heap() = default; - - /** - * Forces garbage collection. - * - * \param source String specifying the source (or caller) triggering a - * forced garbage collection. - * \param reason String specifying the reason for the forced garbage - * collection. - * \param stack_state The embedder stack state, see StackState. - */ - void ForceGarbageCollectionSlow( - const char* source, const char* reason, - StackState stack_state = StackState::kMayContainHeapPointers); - - /** - * \returns the opaque handle for allocating objects using - * `MakeGarbageCollected()`. - */ - AllocationHandle& GetAllocationHandle(); - - /** - * \returns the opaque heap handle which may be used to refer to this heap in - * other APIs. Valid as long as the underlying `Heap` is alive. - */ - HeapHandle& GetHeapHandle(); - - private: - Heap() = default; - - friend class internal::Heap; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_HEAP_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/api-constants.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/api-constants.h deleted file mode 100644 index 7253a470893..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/api-constants.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ -#define INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ - -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -// Embedders should not rely on this code! - -// Internal constants to avoid exposing internal types on the API surface. -namespace api_constants { - -constexpr size_t kKB = 1024; -constexpr size_t kMB = kKB * 1024; -constexpr size_t kGB = kMB * 1024; - -// Offset of the uint16_t bitfield from the payload contaning the -// in-construction bit. This is subtracted from the payload pointer to get -// to the right bitfield. -static constexpr size_t kFullyConstructedBitFieldOffsetFromPayload = - 2 * sizeof(uint16_t); -// Mask for in-construction bit. -static constexpr uint16_t kFullyConstructedBitMask = uint16_t{1}; - -static constexpr size_t kPageSize = size_t{1} << 17; - -static constexpr size_t kLargeObjectSizeThreshold = kPageSize / 2; - -#if defined(CPPGC_CAGED_HEAP) -constexpr size_t kCagedHeapReservationSize = static_cast(4) * kGB; -constexpr size_t kCagedHeapReservationAlignment = kCagedHeapReservationSize; -#endif - -} // namespace api_constants - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_API_CONSTANTS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/atomic-entry-flag.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/atomic-entry-flag.h deleted file mode 100644 index 5a7d3b8f8ac..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/atomic-entry-flag.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ -#define INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ - -#include - -namespace cppgc { -namespace internal { - -// A flag which provides a fast check whether a scope may be entered on the -// current thread, without needing to access thread-local storage or mutex. Can -// have false positives (i.e., spuriously report that it might be entered), so -// it is expected that this will be used in tandem with a precise check that the -// scope is in fact entered on that thread. -// -// Example: -// g_frobnicating_flag.MightBeEntered() && -// ThreadLocalFrobnicator().IsFrobnicating() -// -// Relaxed atomic operations are sufficient, since: -// - all accesses remain atomic -// - each thread must observe its own operations in order -// - no thread ever exits the flag more times than it enters (if used correctly) -// And so if a thread observes zero, it must be because it has observed an equal -// number of exits as entries. -class AtomicEntryFlag final { - public: - void Enter() { entries_.fetch_add(1, std::memory_order_relaxed); } - void Exit() { entries_.fetch_sub(1, std::memory_order_relaxed); } - - // Returns false only if the current thread is not between a call to Enter - // and a call to Exit. Returns true if this thread or another thread may - // currently be in the scope guarded by this flag. - bool MightBeEntered() const { - return entries_.load(std::memory_order_relaxed) != 0; - } - - private: - std::atomic_int entries_{0}; -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_ATOMIC_ENTRY_FLAG_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/caged-heap-local-data.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/caged-heap-local-data.h deleted file mode 100644 index 5b30d670292..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/caged-heap-local-data.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ -#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ - -#include - -#include "cppgc/internal/api-constants.h" -#include "cppgc/internal/logging.h" -#include "cppgc/platform.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -class HeapBase; - -#if defined(CPPGC_YOUNG_GENERATION) - -// AgeTable contains entries that correspond to 4KB memory regions. Each entry -// can be in one of three states: kOld, kYoung or kUnknown. -class AgeTable final { - static constexpr size_t kGranularityBits = 12; // 4KiB per byte. - - public: - enum class Age : uint8_t { kOld, kYoung, kUnknown }; - - static constexpr size_t kEntrySizeInBytes = 1 << kGranularityBits; - - Age& operator[](uintptr_t offset) { return table_[entry(offset)]; } - Age operator[](uintptr_t offset) const { return table_[entry(offset)]; } - - void Reset(PageAllocator* allocator); - - private: - static constexpr size_t kAgeTableSize = - api_constants::kCagedHeapReservationSize >> kGranularityBits; - - size_t entry(uintptr_t offset) const { - const size_t entry = offset >> kGranularityBits; - CPPGC_DCHECK(table_.size() > entry); - return entry; - } - - std::array table_; -}; - -static_assert(sizeof(AgeTable) == 1 * api_constants::kMB, - "Size of AgeTable is 1MB"); - -#endif // CPPGC_YOUNG_GENERATION - -struct CagedHeapLocalData final { - CagedHeapLocalData(HeapBase&, PageAllocator&); - - bool is_incremental_marking_in_progress = false; - HeapBase& heap_base; -#if defined(CPPGC_YOUNG_GENERATION) - AgeTable age_table; -#endif -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/compiler-specific.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/compiler-specific.h deleted file mode 100644 index 595b6398cb7..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/compiler-specific.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ -#define INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ - -namespace cppgc { - -#if defined(__has_attribute) -#define CPPGC_HAS_ATTRIBUTE(FEATURE) __has_attribute(FEATURE) -#else -#define CPPGC_HAS_ATTRIBUTE(FEATURE) 0 -#endif - -#if defined(__has_cpp_attribute) -#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) __has_cpp_attribute(FEATURE) -#else -#define CPPGC_HAS_CPP_ATTRIBUTE(FEATURE) 0 -#endif - -// [[no_unique_address]] comes in C++20 but supported in clang with -std >= -// c++11. -#if CPPGC_HAS_CPP_ATTRIBUTE(no_unique_address) -#define CPPGC_NO_UNIQUE_ADDRESS [[no_unique_address]] -#else -#define CPPGC_NO_UNIQUE_ADDRESS -#endif - -#if CPPGC_HAS_ATTRIBUTE(unused) -#define CPPGC_UNUSED __attribute__((unused)) -#else -#define CPPGC_UNUSED -#endif - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_COMPILER_SPECIFIC_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/finalizer-trait.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/finalizer-trait.h deleted file mode 100644 index 7bd6f83bf60..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/finalizer-trait.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ -#define INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ - -#include - -#include "cppgc/type-traits.h" - -namespace cppgc { -namespace internal { - -using FinalizationCallback = void (*)(void*); - -template -struct HasFinalizeGarbageCollectedObject : std::false_type {}; - -template -struct HasFinalizeGarbageCollectedObject< - T, void_t().FinalizeGarbageCollectedObject())>> - : std::true_type {}; - -// The FinalizerTraitImpl specifies how to finalize objects. -template -struct FinalizerTraitImpl; - -template -struct FinalizerTraitImpl { - private: - // Dispatch to custom FinalizeGarbageCollectedObject(). - struct Custom { - static void Call(void* obj) { - static_cast(obj)->FinalizeGarbageCollectedObject(); - } - }; - - // Dispatch to regular destructor. - struct Destructor { - static void Call(void* obj) { static_cast(obj)->~T(); } - }; - - using FinalizeImpl = - std::conditional_t::value, Custom, - Destructor>; - - public: - static void Finalize(void* obj) { - static_assert(sizeof(T), "T must be fully defined"); - FinalizeImpl::Call(obj); - } -}; - -template -struct FinalizerTraitImpl { - static void Finalize(void* obj) { - static_assert(sizeof(T), "T must be fully defined"); - } -}; - -// The FinalizerTrait is used to determine if a type requires finalization and -// what finalization means. -template -struct FinalizerTrait { - private: - // Object has a finalizer if it has - // - a custom FinalizeGarbageCollectedObject method, or - // - a destructor. - static constexpr bool kNonTrivialFinalizer = - internal::HasFinalizeGarbageCollectedObject::value || - !std::is_trivially_destructible::type>::value; - - static void Finalize(void* obj) { - internal::FinalizerTraitImpl::Finalize(obj); - } - - public: - static constexpr bool HasFinalizer() { return kNonTrivialFinalizer; } - - // The callback used to finalize an object of type T. - static constexpr FinalizationCallback kCallback = - kNonTrivialFinalizer ? Finalize : nullptr; -}; - -template -constexpr FinalizationCallback FinalizerTrait::kCallback; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_FINALIZER_TRAIT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/gc-info.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/gc-info.h deleted file mode 100644 index 82a0d053431..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/gc-info.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ -#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ - -#include -#include -#include - -#include "cppgc/internal/finalizer-trait.h" -#include "cppgc/internal/name-trait.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -using GCInfoIndex = uint16_t; - -struct V8_EXPORT EnsureGCInfoIndexTrait final { - // Acquires a new GC info object and returns the index. In addition, also - // updates `registered_index` atomically. - template - V8_INLINE static GCInfoIndex EnsureIndex( - std::atomic& registered_index) { - return EnsureGCInfoIndexTraitDispatch{}(registered_index); - } - - private: - template ::value, - bool = FinalizerTrait::HasFinalizer(), - bool = NameTrait::HasNonHiddenName()> - struct EnsureGCInfoIndexTraitDispatch; - - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback, - NameCallback); - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback); - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback, NameCallback); - static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic&, - TraceCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback, - - NameCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback, - FinalizationCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback, - NameCallback); - static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic&, - TraceCallback); -}; - -#define DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) \ - template \ - struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \ - T, is_polymorphic, has_finalizer, has_non_hidden_name> { \ - V8_INLINE GCInfoIndex \ - operator()(std::atomic& registered_index) { \ - return function; \ - } \ - }; - -// --------------------------------------------------------------------- // -// DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) -// --------------------------------------------------------------------- // -DISPATCH(true, true, true, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback, // - NameTrait::GetName)) // -DISPATCH(true, true, false, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback)) // -DISPATCH(true, false, true, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace, // - NameTrait::GetName)) // -DISPATCH(true, false, false, // - EnsureGCInfoIndexPolymorphic(registered_index, // - TraceTrait::Trace)) // -DISPATCH(false, true, true, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback, // - NameTrait::GetName)) // -DISPATCH(false, true, false, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace, // - FinalizerTrait::kCallback)) // -DISPATCH(false, false, true, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace, // - NameTrait::GetName)) // -DISPATCH(false, false, false, // - EnsureGCInfoIndexNonPolymorphic(registered_index, // - TraceTrait::Trace)) // - -#undef DISPATCH - -// Fold types based on finalizer behavior. Note that finalizer characteristics -// align with trace behavior, i.e., destructors are virtual when trace methods -// are and vice versa. -template -struct GCInfoFolding { - static constexpr bool kHasVirtualDestructorAtBase = - std::has_virtual_destructor::value; - static constexpr bool kBothTypesAreTriviallyDestructible = - std::is_trivially_destructible::value && - std::is_trivially_destructible::value; - static constexpr bool kHasCustomFinalizerDispatchAtBase = - internal::HasFinalizeGarbageCollectedObject< - ParentMostGarbageCollectedType>::value; -#ifdef CPPGC_SUPPORTS_OBJECT_NAMES - static constexpr bool kWantsDetailedObjectNames = true; -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - static constexpr bool kWantsDetailedObjectNames = false; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - - // Folding would regresses name resolution when deriving names from C++ - // class names as it would just folds a name to the base class name. - using ResultType = std::conditional_t<(kHasVirtualDestructorAtBase || - kBothTypesAreTriviallyDestructible || - kHasCustomFinalizerDispatchAtBase) && - !kWantsDetailedObjectNames, - ParentMostGarbageCollectedType, T>; -}; - -// Trait determines how the garbage collector treats objects wrt. to traversing, -// finalization, and naming. -template -struct GCInfoTrait final { - V8_INLINE static GCInfoIndex Index() { - static_assert(sizeof(T), "T must be fully defined"); - static std::atomic - registered_index; // Uses zero initialization. - const GCInfoIndex index = registered_index.load(std::memory_order_acquire); - return index ? index - : EnsureGCInfoIndexTrait::EnsureIndex(registered_index); - } -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/logging.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/logging.h deleted file mode 100644 index 79beaef7d4f..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/logging.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_LOGGING_H_ -#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_ - -#include "cppgc/source-location.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -void V8_EXPORT DCheckImpl(const char*, - const SourceLocation& = SourceLocation::Current()); -[[noreturn]] void V8_EXPORT -FatalImpl(const char*, const SourceLocation& = SourceLocation::Current()); - -// Used to ignore -Wunused-variable. -template -struct EatParams {}; - -#if DEBUG -#define CPPGC_DCHECK_MSG(condition, message) \ - do { \ - if (V8_UNLIKELY(!(condition))) { \ - ::cppgc::internal::DCheckImpl(message); \ - } \ - } while (false) -#else -#define CPPGC_DCHECK_MSG(condition, message) \ - (static_cast(::cppgc::internal::EatParams(condition), message)>{})) -#endif - -#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition) - -#define CPPGC_CHECK_MSG(condition, message) \ - do { \ - if (V8_UNLIKELY(!(condition))) { \ - ::cppgc::internal::FatalImpl(message); \ - } \ - } while (false) - -#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition) - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/name-trait.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/name-trait.h deleted file mode 100644 index 32a33478592..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/name-trait.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ -#define INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ - -#include -#include - -#include "cppgc/name-provider.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -#if CPPGC_SUPPORTS_OBJECT_NAMES && defined(__clang__) -#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 1 - -// Provides constexpr c-string storage for a name of fixed |Size| characters. -// Automatically appends terminating 0 byte. -template -struct NameBuffer { - char name[Size + 1]{}; - - static constexpr NameBuffer FromCString(const char* str) { - NameBuffer result; - for (size_t i = 0; i < Size; ++i) result.name[i] = str[i]; - result.name[Size] = 0; - return result; - } -}; - -template -const char* GetTypename() { - static constexpr char kSelfPrefix[] = - "const char *cppgc::internal::GetTypename() [T ="; - static_assert(__builtin_strncmp(__PRETTY_FUNCTION__, kSelfPrefix, - sizeof(kSelfPrefix) - 1) == 0, - "The prefix must match"); - static constexpr const char* kTypenameStart = - __PRETTY_FUNCTION__ + sizeof(kSelfPrefix); - static constexpr size_t kTypenameSize = - __builtin_strlen(__PRETTY_FUNCTION__) - sizeof(kSelfPrefix) - 1; - // NameBuffer is an indirection that is needed to make sure that only a - // substring of __PRETTY_FUNCTION__ gets materialized in the binary. - static constexpr auto buffer = - NameBuffer::FromCString(kTypenameStart); - return buffer.name; -} - -#else -#define CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME 0 -#endif - -struct HeapObjectName { - const char* value; - bool name_was_hidden; -}; - -class V8_EXPORT NameTraitBase { - protected: - static HeapObjectName GetNameFromTypeSignature(const char*); -}; - -// Trait that specifies how the garbage collector retrieves the name for a -// given object. -template -class NameTrait final : public NameTraitBase { - public: - static constexpr bool HasNonHiddenName() { -#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME - return true; -#elif CPPGC_SUPPORTS_OBJECT_NAMES - return true; -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - return std::is_base_of::value; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - } - - static HeapObjectName GetName(const void* obj) { - return GetNameFor(static_cast(obj)); - } - - private: - static HeapObjectName GetNameFor(const NameProvider* name_provider) { - return {name_provider->GetHumanReadableName(), false}; - } - - static HeapObjectName GetNameFor(...) { -#if CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME - return {GetTypename(), false}; -#elif CPPGC_SUPPORTS_OBJECT_NAMES - -#if defined(V8_CC_GNU) -#define PRETTY_FUNCTION_VALUE __PRETTY_FUNCTION__ -#elif defined(V8_CC_MSVC) -#define PRETTY_FUNCTION_VALUE __FUNCSIG__ -#else -#define PRETTY_FUNCTION_VALUE nullptr -#endif - - static const HeapObjectName leaky_name = - GetNameFromTypeSignature(PRETTY_FUNCTION_VALUE); - return {leaky_name, false}; - -#undef PRETTY_FUNCTION_VALUE - -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - return {NameProvider::kHiddenName, true}; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - } -}; - -using NameCallback = HeapObjectName (*)(const void*); - -} // namespace internal -} // namespace cppgc - -#undef CPPGC_SUPPORTS_COMPILE_TIME_TYPENAME - -#endif // INCLUDE_CPPGC_INTERNAL_NAME_TRAIT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/persistent-node.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/persistent-node.h deleted file mode 100644 index b5dba476a47..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/persistent-node.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ -#define INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ - -#include -#include -#include - -#include "cppgc/internal/logging.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -class CrossThreadPersistentRegion; - -// PersistentNode represents a variant of two states: -// 1) traceable node with a back pointer to the Persistent object; -// 2) freelist entry. -class PersistentNode final { - public: - PersistentNode() = default; - - PersistentNode(const PersistentNode&) = delete; - PersistentNode& operator=(const PersistentNode&) = delete; - - void InitializeAsUsedNode(void* owner, TraceCallback trace) { - CPPGC_DCHECK(trace); - owner_ = owner; - trace_ = trace; - } - - void InitializeAsFreeNode(PersistentNode* next) { - next_ = next; - trace_ = nullptr; - } - - void UpdateOwner(void* owner) { - CPPGC_DCHECK(IsUsed()); - owner_ = owner; - } - - PersistentNode* FreeListNext() const { - CPPGC_DCHECK(!IsUsed()); - return next_; - } - - void Trace(Visitor* visitor) const { - CPPGC_DCHECK(IsUsed()); - trace_(visitor, owner_); - } - - bool IsUsed() const { return trace_; } - - void* owner() const { - CPPGC_DCHECK(IsUsed()); - return owner_; - } - - private: - // PersistentNode acts as a designated union: - // If trace_ != nullptr, owner_ points to the corresponding Persistent handle. - // Otherwise, next_ points to the next freed PersistentNode. - union { - void* owner_ = nullptr; - PersistentNode* next_; - }; - TraceCallback trace_ = nullptr; -}; - -class V8_EXPORT PersistentRegion { - using PersistentNodeSlots = std::array; - - public: - PersistentRegion() = default; - // Clears Persistent fields to avoid stale pointers after heap teardown. - ~PersistentRegion(); - - PersistentRegion(const PersistentRegion&) = delete; - PersistentRegion& operator=(const PersistentRegion&) = delete; - - PersistentNode* AllocateNode(void* owner, TraceCallback trace) { - if (!free_list_head_) { - EnsureNodeSlots(); - } - PersistentNode* node = free_list_head_; - free_list_head_ = free_list_head_->FreeListNext(); - CPPGC_DCHECK(!node->IsUsed()); - node->InitializeAsUsedNode(owner, trace); - nodes_in_use_++; - return node; - } - - void FreeNode(PersistentNode* node) { - CPPGC_DCHECK(node); - CPPGC_DCHECK(node->IsUsed()); - node->InitializeAsFreeNode(free_list_head_); - free_list_head_ = node; - CPPGC_DCHECK(nodes_in_use_ > 0); - nodes_in_use_--; - } - - void Trace(Visitor*); - - size_t NodesInUse() const; - - void ClearAllUsedNodes(); - - private: - void EnsureNodeSlots(); - - template - void ClearAllUsedNodes(); - - std::vector> nodes_; - PersistentNode* free_list_head_ = nullptr; - size_t nodes_in_use_ = 0; - - friend class CrossThreadPersistentRegion; -}; - -// CrossThreadPersistent uses PersistentRegion but protects it using this lock -// when needed. -class V8_EXPORT PersistentRegionLock final { - public: - PersistentRegionLock(); - ~PersistentRegionLock(); - - static void AssertLocked(); -}; - -// Variant of PersistentRegion that checks whether the PersistentRegionLock is -// locked. -class V8_EXPORT CrossThreadPersistentRegion final : protected PersistentRegion { - public: - CrossThreadPersistentRegion() = default; - // Clears Persistent fields to avoid stale pointers after heap teardown. - ~CrossThreadPersistentRegion(); - - CrossThreadPersistentRegion(const CrossThreadPersistentRegion&) = delete; - CrossThreadPersistentRegion& operator=(const CrossThreadPersistentRegion&) = - delete; - - V8_INLINE PersistentNode* AllocateNode(void* owner, TraceCallback trace) { - PersistentRegionLock::AssertLocked(); - return PersistentRegion::AllocateNode(owner, trace); - } - - V8_INLINE void FreeNode(PersistentNode* node) { - PersistentRegionLock::AssertLocked(); - PersistentRegion::FreeNode(node); - } - - void Trace(Visitor*); - - size_t NodesInUse() const; - - void ClearAllUsedNodes(); -}; - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_PERSISTENT_NODE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/pointer-policies.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/pointer-policies.h deleted file mode 100644 index cdf0bb693d6..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/pointer-policies.h +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ -#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ - -#include -#include - -#include "cppgc/internal/write-barrier.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/source-location.h" -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { - -class HeapBase; -class PersistentRegion; -class CrossThreadPersistentRegion; - -// Tags to distinguish between strong and weak member types. -class StrongMemberTag; -class WeakMemberTag; -class UntracedMemberTag; - -struct DijkstraWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) { - // Since in initializing writes the source object is always white, having no - // barrier doesn't break the tri-color invariant. - } - static void AssigningBarrier(const void* slot, const void* value) { - WriteBarrier::Params params; - switch (WriteBarrier::GetWriteBarrierType(slot, value, params)) { - case WriteBarrier::Type::kGenerational: - WriteBarrier::GenerationalBarrier(params, slot); - break; - case WriteBarrier::Type::kMarking: - WriteBarrier::DijkstraMarkingBarrier(params, value); - break; - case WriteBarrier::Type::kNone: - break; - } - } -}; - -struct NoWriteBarrierPolicy { - static void InitializingBarrier(const void*, const void*) {} - static void AssigningBarrier(const void*, const void*) {} -}; - -class V8_EXPORT EnabledCheckingPolicy { - protected: - template - void CheckPointer(const T* ptr) { - if (!ptr || (kSentinelPointer == ptr)) return; - - CheckPointersImplTrampoline::Call(this, ptr); - } - - private: - void CheckPointerImpl(const void* ptr, bool points_to_payload); - - template > - struct CheckPointersImplTrampoline { - static void Call(EnabledCheckingPolicy* policy, const T* ptr) { - policy->CheckPointerImpl(ptr, false); - } - }; - - template - struct CheckPointersImplTrampoline { - static void Call(EnabledCheckingPolicy* policy, const T* ptr) { - policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV); - } - }; - - const HeapBase* heap_ = nullptr; -}; - -class DisabledCheckingPolicy { - protected: - void CheckPointer(const void*) {} -}; - -#if V8_ENABLE_CHECKS -using DefaultMemberCheckingPolicy = EnabledCheckingPolicy; -using DefaultPersistentCheckingPolicy = EnabledCheckingPolicy; -#else -using DefaultMemberCheckingPolicy = DisabledCheckingPolicy; -using DefaultPersistentCheckingPolicy = DisabledCheckingPolicy; -#endif -// For CT(W)P neither marking information (for value), nor objectstart bitmap -// (for slot) are guaranteed to be present because there's no synchonization -// between heaps after marking. -using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy; - -class KeepLocationPolicy { - public: - constexpr const SourceLocation& Location() const { return location_; } - - protected: - constexpr KeepLocationPolicy() = default; - constexpr explicit KeepLocationPolicy(const SourceLocation& location) - : location_(location) {} - - // KeepLocationPolicy must not copy underlying source locations. - KeepLocationPolicy(const KeepLocationPolicy&) = delete; - KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete; - - // Location of the original moved from object should be preserved. - KeepLocationPolicy(KeepLocationPolicy&&) = default; - KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default; - - private: - SourceLocation location_; -}; - -class IgnoreLocationPolicy { - public: - constexpr SourceLocation Location() const { return {}; } - - protected: - constexpr IgnoreLocationPolicy() = default; - constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {} -}; - -#if CPPGC_SUPPORTS_OBJECT_NAMES -using DefaultLocationPolicy = KeepLocationPolicy; -#else -using DefaultLocationPolicy = IgnoreLocationPolicy; -#endif - -struct StrongPersistentPolicy { - using IsStrongPersistent = std::true_type; - static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); -}; - -struct WeakPersistentPolicy { - using IsStrongPersistent = std::false_type; - static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); -}; - -struct StrongCrossThreadPersistentPolicy { - using IsStrongPersistent = std::true_type; - static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( - const void* object); -}; - -struct WeakCrossThreadPersistentPolicy { - using IsStrongPersistent = std::false_type; - static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( - const void* object); -}; - -// Forward declarations setting up the default policies. -template -class BasicCrossThreadPersistent; -template -class BasicPersistent; -template -class BasicMember; - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/prefinalizer-handler.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/prefinalizer-handler.h deleted file mode 100644 index 64b07ec9112..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/prefinalizer-handler.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_ -#define INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_ - -#include "cppgc/heap.h" -#include "cppgc/liveness-broker.h" - -namespace cppgc { -namespace internal { - -class V8_EXPORT PreFinalizerRegistrationDispatcher final { - public: - using PreFinalizerCallback = bool (*)(const LivenessBroker&, void*); - struct PreFinalizer { - void* object; - PreFinalizerCallback callback; - - bool operator==(const PreFinalizer& other) const; - }; - - static void RegisterPrefinalizer(PreFinalizer pre_finalizer); -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_PREFINALIZER_HANDLER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/write-barrier.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/write-barrier.h deleted file mode 100644 index 28184dc9c83..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/internal/write-barrier.h +++ /dev/null @@ -1,433 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ -#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ - -#include -#include - -#include "cppgc/heap-state.h" -#include "cppgc/internal/api-constants.h" -#include "cppgc/internal/atomic-entry-flag.h" -#include "cppgc/platform.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -#if defined(CPPGC_CAGED_HEAP) -#include "cppgc/internal/caged-heap-local-data.h" -#endif - -namespace cppgc { - -class HeapHandle; - -namespace internal { - -#if defined(CPPGC_CAGED_HEAP) -class WriteBarrierTypeForCagedHeapPolicy; -#else // !CPPGC_CAGED_HEAP -class WriteBarrierTypeForNonCagedHeapPolicy; -#endif // !CPPGC_CAGED_HEAP - -class V8_EXPORT WriteBarrier final { - public: - enum class Type : uint8_t { - kNone, - kMarking, - kGenerational, - }; - - struct Params { - HeapHandle* heap = nullptr; -#if V8_ENABLE_CHECKS - Type type = Type::kNone; -#endif // !V8_ENABLE_CHECKS -#if defined(CPPGC_CAGED_HEAP) - uintptr_t start = 0; - CagedHeapLocalData& caged_heap() const { - return *reinterpret_cast(start); - } - uintptr_t slot_offset = 0; - uintptr_t value_offset = 0; -#endif // CPPGC_CAGED_HEAP - }; - - enum class ValueMode { - kValuePresent, - kNoValuePresent, - }; - - // Returns the required write barrier for a given `slot` and `value`. - static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value, - Params& params); - // Returns the required write barrier for a given `slot`. - template - static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params, - HeapHandleCallback callback); - // Returns the required write barrier for a given `value`. - static V8_INLINE Type GetWriteBarrierType(const void* value, Params& params); - - template - static V8_INLINE Type GetWriteBarrierTypeForExternallyReferencedObject( - const void* value, Params& params, HeapHandleCallback callback); - - static V8_INLINE void DijkstraMarkingBarrier(const Params& params, - const void* object); - static V8_INLINE void DijkstraMarkingBarrierRange( - const Params& params, const void* first_element, size_t element_size, - size_t number_of_elements, TraceCallback trace_callback); - static V8_INLINE void SteeleMarkingBarrier(const Params& params, - const void* object); -#if defined(CPPGC_YOUNG_GENERATION) - static V8_INLINE void GenerationalBarrier(const Params& params, - const void* slot); -#else // !CPPGC_YOUNG_GENERATION - static V8_INLINE void GenerationalBarrier(const Params& params, - const void* slot) {} -#endif // CPPGC_YOUNG_GENERATION - -#if V8_ENABLE_CHECKS - static void CheckParams(Type expected_type, const Params& params); -#else // !V8_ENABLE_CHECKS - static void CheckParams(Type expected_type, const Params& params) {} -#endif // !V8_ENABLE_CHECKS - - // The IncrementalOrConcurrentUpdater class allows cppgc internal to update - // |incremental_or_concurrent_marking_flag_|. - class IncrementalOrConcurrentMarkingFlagUpdater; - static bool IsAnyIncrementalOrConcurrentMarking() { - return incremental_or_concurrent_marking_flag_.MightBeEntered(); - } - - private: - WriteBarrier() = delete; - -#if defined(CPPGC_CAGED_HEAP) - using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy; -#else // !CPPGC_CAGED_HEAP - using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy; -#endif // !CPPGC_CAGED_HEAP - - static void DijkstraMarkingBarrierSlow(const void* value); - static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value); - static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle, - const void* first_element, - size_t element_size, - size_t number_of_elements, - TraceCallback trace_callback); - static void SteeleMarkingBarrierSlow(const void* value); - static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value); - -#if defined(CPPGC_YOUNG_GENERATION) - static CagedHeapLocalData& GetLocalData(HeapHandle&); - static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data, - const AgeTable& ageTable, - const void* slot, uintptr_t value_offset); -#endif // CPPGC_YOUNG_GENERATION - - static AtomicEntryFlag incremental_or_concurrent_marking_flag_; -}; - -template -V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) { - if (type == WriteBarrier::Type::kNone) return WriteBarrier::Type::kNone; -#if V8_ENABLE_CHECKS - params.type = type; -#endif // !V8_ENABLE_CHECKS - return type; -} - -#if defined(CPPGC_CAGED_HEAP) -class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final { - public: - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - return ValueModeDispatch::Get(slot, value, params, callback); - } - - template - static V8_INLINE WriteBarrier::Type Get(const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - return GetNoSlot(value, params, callback); - } - - template - static V8_INLINE WriteBarrier::Type GetForExternallyReferenced( - const void* value, WriteBarrier::Params& params, - HeapHandleCallback callback) { - return GetNoSlot(value, params, callback); - } - - private: - WriteBarrierTypeForCagedHeapPolicy() = delete; - - template - static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value, - WriteBarrier::Params& params, - HeapHandleCallback) { - if (!TryGetCagedHeap(value, value, params)) { - return WriteBarrier::Type::kNone; - } - if (V8_UNLIKELY(params.caged_heap().is_incremental_marking_in_progress)) { - return SetAndReturnType(params); - } - return SetAndReturnType(params); - } - - template - struct ValueModeDispatch; - - static V8_INLINE bool TryGetCagedHeap(const void* slot, const void* value, - WriteBarrier::Params& params) { - // TODO(chromium:1056170): Check if the null check can be folded in with - // the rest of the write barrier. - if (!value) return false; - params.start = reinterpret_cast(value) & - ~(api_constants::kCagedHeapReservationAlignment - 1); - const uintptr_t slot_offset = - reinterpret_cast(slot) - params.start; - if (slot_offset > api_constants::kCagedHeapReservationSize) { - // Check if slot is on stack or value is sentinel or nullptr. This relies - // on the fact that kSentinelPointer is encoded as 0x1. - return false; - } - return true; - } - - // Returns whether marking is in progress. If marking is not in progress - // sets the start of the cage accordingly. - // - // TODO(chromium:1056170): Create fast path on API. - static bool IsMarking(const HeapHandle&, WriteBarrier::Params&); -}; - -template <> -struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, - WriteBarrier::Params& params, - HeapHandleCallback) { - bool within_cage = TryGetCagedHeap(slot, value, params); - if (!within_cage) { - return WriteBarrier::Type::kNone; - } - if (V8_LIKELY(!params.caged_heap().is_incremental_marking_in_progress)) { -#if defined(CPPGC_YOUNG_GENERATION) - params.heap = reinterpret_cast(params.start); - params.slot_offset = reinterpret_cast(slot) - params.start; - params.value_offset = reinterpret_cast(value) - params.start; - return SetAndReturnType(params); -#else // !CPPGC_YOUNG_GENERATION - return SetAndReturnType(params); -#endif // !CPPGC_YOUNG_GENERATION - } - params.heap = reinterpret_cast(params.start); - return SetAndReturnType(params); - } -}; - -template <> -struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kNoValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*, - WriteBarrier::Params& params, - HeapHandleCallback callback) { -#if defined(CPPGC_YOUNG_GENERATION) - HeapHandle& handle = callback(); - if (V8_LIKELY(!IsMarking(handle, params))) { - // params.start is populated by IsMarking(). - params.heap = &handle; - params.slot_offset = reinterpret_cast(slot) - params.start; - // params.value_offset stays 0. - if (params.slot_offset > api_constants::kCagedHeapReservationSize) { - // Check if slot is on stack. - return SetAndReturnType(params); - } - return SetAndReturnType(params); - } -#else // !CPPGC_YOUNG_GENERATION - if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { - return SetAndReturnType(params); - } - HeapHandle& handle = callback(); - if (V8_UNLIKELY(!subtle::HeapState::IsMarking(handle))) { - return SetAndReturnType(params); - } -#endif // !CPPGC_YOUNG_GENERATION - params.heap = &handle; - return SetAndReturnType(params); - } -}; - -#endif // CPPGC_CAGED_HEAP - -class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final { - public: - template - static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - return ValueModeDispatch::Get(slot, value, params, callback); - } - - template - static V8_INLINE WriteBarrier::Type Get(const void* value, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - // The slot will never be used in `Get()` below. - return Get(nullptr, value, params, - callback); - } - - template - static V8_INLINE WriteBarrier::Type GetForExternallyReferenced( - const void* value, WriteBarrier::Params& params, - HeapHandleCallback callback) { - // The slot will never be used in `Get()` below. - return Get(nullptr, value, params, - callback); - } - - private: - template - struct ValueModeDispatch; - - // TODO(chromium:1056170): Create fast path on API. - static bool IsMarking(const void*, HeapHandle**); - // TODO(chromium:1056170): Create fast path on API. - static bool IsMarking(HeapHandle&); - - WriteBarrierTypeForNonCagedHeapPolicy() = delete; -}; - -template <> -struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void*, const void* object, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - // The following check covers nullptr as well as sentinel pointer. - if (object <= static_cast(kSentinelPointer)) { - return WriteBarrier::Type::kNone; - } - if (IsMarking(object, ¶ms.heap)) { - return SetAndReturnType(params); - } - return SetAndReturnType(params); - } -}; - -template <> -struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch< - WriteBarrier::ValueMode::kNoValuePresent> { - template - static V8_INLINE WriteBarrier::Type Get(const void*, const void*, - WriteBarrier::Params& params, - HeapHandleCallback callback) { - if (V8_UNLIKELY(WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) { - HeapHandle& handle = callback(); - if (IsMarking(handle)) { - params.heap = &handle; - return SetAndReturnType(params); - } - } - return WriteBarrier::Type::kNone; - } -}; - -// static -WriteBarrier::Type WriteBarrier::GetWriteBarrierType( - const void* slot, const void* value, WriteBarrier::Params& params) { - return WriteBarrierTypePolicy::Get(slot, value, - params, []() {}); -} - -// static -template -WriteBarrier::Type WriteBarrier::GetWriteBarrierType( - const void* slot, WriteBarrier::Params& params, - HeapHandleCallback callback) { - return WriteBarrierTypePolicy::Get( - slot, nullptr, params, callback); -} - -// static -WriteBarrier::Type WriteBarrier::GetWriteBarrierType( - const void* value, WriteBarrier::Params& params) { - return WriteBarrierTypePolicy::Get(value, params, - []() {}); -} - -// static -template -WriteBarrier::Type -WriteBarrier::GetWriteBarrierTypeForExternallyReferencedObject( - const void* value, Params& params, HeapHandleCallback callback) { - return WriteBarrierTypePolicy::GetForExternallyReferenced(value, params, - callback); -} - -// static -void WriteBarrier::DijkstraMarkingBarrier(const Params& params, - const void* object) { - CheckParams(Type::kMarking, params); -#if defined(CPPGC_CAGED_HEAP) - // Caged heap already filters out sentinels. - DijkstraMarkingBarrierSlow(object); -#else // !CPPGC_CAGED_HEAP - DijkstraMarkingBarrierSlowWithSentinelCheck(object); -#endif // !CPPGC_CAGED_HEAP -} - -// static -void WriteBarrier::DijkstraMarkingBarrierRange(const Params& params, - const void* first_element, - size_t element_size, - size_t number_of_elements, - TraceCallback trace_callback) { - CheckParams(Type::kMarking, params); - DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size, - number_of_elements, trace_callback); -} - -// static -void WriteBarrier::SteeleMarkingBarrier(const Params& params, - const void* object) { - CheckParams(Type::kMarking, params); -#if defined(CPPGC_CAGED_HEAP) - // Caged heap already filters out sentinels. - SteeleMarkingBarrierSlow(object); -#else // !CPPGC_CAGED_HEAP - SteeleMarkingBarrierSlowWithSentinelCheck(object); -#endif // !CPPGC_CAGED_HEAP -} - -#if defined(CPPGC_YOUNG_GENERATION) -// static -void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) { - CheckParams(Type::kGenerational, params); - - const CagedHeapLocalData& local_data = params.caged_heap(); - const AgeTable& age_table = local_data.age_table; - - // Bail out if the slot is in young generation. - if (V8_LIKELY(age_table[params.slot_offset] == AgeTable::Age::kYoung)) return; - - GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset); -} - -#endif // !CPPGC_YOUNG_GENERATION - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/liveness-broker.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/liveness-broker.h deleted file mode 100644 index c94eef0d4ac..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/liveness-broker.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_LIVENESS_BROKER_H_ -#define INCLUDE_CPPGC_LIVENESS_BROKER_H_ - -#include "cppgc/heap.h" -#include "cppgc/member.h" -#include "cppgc/trace-trait.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -namespace internal { -class LivenessBrokerFactory; -} // namespace internal - -/** - * The broker is passed to weak callbacks to allow (temporarily) querying - * the liveness state of an object. References to non-live objects must be - * cleared when `IsHeapObjectAlive()` returns false. - * - * \code - * class GCedWithCustomWeakCallback final - * : public GarbageCollected { - * public: - * UntracedMember bar; - * - * void CustomWeakCallbackMethod(const LivenessBroker& broker) { - * if (!broker.IsHeapObjectAlive(bar)) - * bar = nullptr; - * } - * - * void Trace(cppgc::Visitor* visitor) const { - * visitor->RegisterWeakCallbackMethod< - * GCedWithCustomWeakCallback, - * &GCedWithCustomWeakCallback::CustomWeakCallbackMethod>(this); - * } - * }; - * \endcode - */ -class V8_EXPORT LivenessBroker final { - public: - template - bool IsHeapObjectAlive(const T* object) const { - // nullptr objects are considered alive to allow weakness to be used from - // stack while running into a conservative GC. Treating nullptr as dead - // would mean that e.g. custom collectins could not be strongified on stack. - return !object || - IsHeapObjectAliveImpl( - TraceTrait::GetTraceDescriptor(object).base_object_payload); - } - - template - bool IsHeapObjectAlive(const WeakMember& weak_member) const { - return (weak_member != kSentinelPointer) && - IsHeapObjectAlive(weak_member.Get()); - } - - template - bool IsHeapObjectAlive(const UntracedMember& untraced_member) const { - return (untraced_member != kSentinelPointer) && - IsHeapObjectAlive(untraced_member.Get()); - } - - private: - LivenessBroker() = default; - - bool IsHeapObjectAliveImpl(const void*) const; - - friend class internal::LivenessBrokerFactory; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_LIVENESS_BROKER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/macros.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/macros.h deleted file mode 100644 index 030f397e3df..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/macros.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_MACROS_H_ -#define INCLUDE_CPPGC_MACROS_H_ - -#include - -#include "cppgc/internal/compiler-specific.h" - -namespace cppgc { - -// Use if the object is only stack allocated. -#define CPPGC_STACK_ALLOCATED() \ - public: \ - using IsStackAllocatedTypeMarker CPPGC_UNUSED = int; \ - \ - private: \ - void* operator new(size_t) = delete; \ - void* operator new(size_t, void*) = delete; \ - static_assert(true, "Force semicolon.") - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_MACROS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/member.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/member.h deleted file mode 100644 index 38105b8e432..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/member.h +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_MEMBER_H_ -#define INCLUDE_CPPGC_MEMBER_H_ - -#include -#include -#include - -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -// MemberBase always refers to the object as const object and defers to -// BasicMember on casting to the right type as needed. -class MemberBase { - protected: - struct AtomicInitializerTag {}; - - MemberBase() = default; - explicit MemberBase(const void* value) : raw_(value) {} - MemberBase(const void* value, AtomicInitializerTag) { SetRawAtomic(value); } - - const void** GetRawSlot() const { return &raw_; } - const void* GetRaw() const { return raw_; } - void SetRaw(void* value) { raw_ = value; } - - const void* GetRawAtomic() const { - return reinterpret_cast*>(&raw_)->load( - std::memory_order_relaxed); - } - void SetRawAtomic(const void* value) { - reinterpret_cast*>(&raw_)->store( - value, std::memory_order_relaxed); - } - - void ClearFromGC() const { raw_ = nullptr; } - - private: - mutable const void* raw_ = nullptr; -}; - -// The basic class from which all Member classes are 'generated'. -template -class BasicMember final : private MemberBase, private CheckingPolicy { - public: - using PointeeType = T; - - constexpr BasicMember() = default; - constexpr BasicMember(std::nullptr_t) {} // NOLINT - BasicMember(SentinelPointer s) : MemberBase(s) {} // NOLINT - BasicMember(T* raw) : MemberBase(raw) { // NOLINT - InitializingWriteBarrier(); - this->CheckPointer(Get()); - } - BasicMember(T& raw) : BasicMember(&raw) {} // NOLINT - // Atomic ctor. Using the AtomicInitializerTag forces BasicMember to - // initialize using atomic assignments. This is required for preventing - // data races with concurrent marking. - using AtomicInitializerTag = MemberBase::AtomicInitializerTag; - BasicMember(std::nullptr_t, AtomicInitializerTag atomic) - : MemberBase(nullptr, atomic) {} - BasicMember(SentinelPointer s, AtomicInitializerTag atomic) - : MemberBase(s, atomic) {} - BasicMember(T* raw, AtomicInitializerTag atomic) : MemberBase(raw, atomic) { - InitializingWriteBarrier(); - this->CheckPointer(Get()); - } - BasicMember(T& raw, AtomicInitializerTag atomic) - : BasicMember(&raw, atomic) {} - // Copy ctor. - BasicMember(const BasicMember& other) : BasicMember(other.Get()) {} - // Allow heterogeneous construction. - template ::value>> - BasicMember( // NOLINT - const BasicMember& other) - : BasicMember(other.Get()) {} - // Move ctor. - BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) { - other.Clear(); - } - // Allow heterogeneous move construction. - template ::value>> - BasicMember(BasicMember&& other) noexcept - : BasicMember(other.Get()) { - other.Clear(); - } - // Construction from Persistent. - template ::value>> - BasicMember(const BasicPersistent& p) - : BasicMember(p.Get()) {} - - // Copy assignment. - BasicMember& operator=(const BasicMember& other) { - return operator=(other.Get()); - } - // Allow heterogeneous copy assignment. - template ::value>> - BasicMember& operator=( - const BasicMember& other) { - return operator=(other.Get()); - } - // Move assignment. - BasicMember& operator=(BasicMember&& other) noexcept { - operator=(other.Get()); - other.Clear(); - return *this; - } - // Heterogeneous move assignment. - template ::value>> - BasicMember& operator=(BasicMember&& other) noexcept { - operator=(other.Get()); - other.Clear(); - return *this; - } - // Assignment from Persistent. - template ::value>> - BasicMember& operator=( - const BasicPersistent& - other) { - return operator=(other.Get()); - } - BasicMember& operator=(T* other) { - SetRawAtomic(other); - AssigningWriteBarrier(); - this->CheckPointer(Get()); - return *this; - } - BasicMember& operator=(std::nullptr_t) { - Clear(); - return *this; - } - BasicMember& operator=(SentinelPointer s) { - SetRawAtomic(s); - return *this; - } - - template - void Swap(BasicMember& other) { - T* tmp = Get(); - *this = other; - other = tmp; - } - - explicit operator bool() const { return Get(); } - operator T*() const { return Get(); } - T* operator->() const { return Get(); } - T& operator*() const { return *Get(); } - - // CFI cast exemption to allow passing SentinelPointer through T* and support - // heterogeneous assignments between different Member and Persistent handles - // based on their actual types. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { - // Executed by the mutator, hence non atomic load. - // - // The const_cast below removes the constness from MemberBase storage. The - // following static_cast re-adds any constness if specified through the - // user-visible template parameter T. - return static_cast(const_cast(MemberBase::GetRaw())); - } - - void Clear() { SetRawAtomic(nullptr); } - - T* Release() { - T* result = Get(); - Clear(); - return result; - } - - const T** GetSlotForTesting() const { - return reinterpret_cast(GetRawSlot()); - } - - private: - const T* GetRawAtomic() const { - return static_cast(MemberBase::GetRawAtomic()); - } - - void InitializingWriteBarrier() const { - WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw()); - } - void AssigningWriteBarrier() const { - WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw()); - } - - void ClearFromGC() const { MemberBase::ClearFromGC(); } - - T* GetFromGC() const { return Get(); } - - friend class cppgc::Visitor; - template - friend struct cppgc::TraceTrait; -}; - -template -bool operator==(const BasicMember& member1, - const BasicMember& member2) { - return member1.Get() == member2.Get(); -} - -template -bool operator!=(const BasicMember& member1, - const BasicMember& member2) { - return !(member1 == member2); -} - -template -struct IsWeak< - internal::BasicMember> - : std::true_type {}; - -} // namespace internal - -/** - * Members are used in classes to contain strong pointers to other garbage - * collected objects. All Member fields of a class must be traced in the class' - * trace method. - */ -template -using Member = internal::BasicMember; - -/** - * WeakMember is similar to Member in that it is used to point to other garbage - * collected objects. However instead of creating a strong pointer to the - * object, the WeakMember creates a weak pointer, which does not keep the - * pointee alive. Hence if all pointers to to a heap allocated object are weak - * the object will be garbage collected. At the time of GC the weak pointers - * will automatically be set to null. - */ -template -using WeakMember = internal::BasicMember; - -/** - * UntracedMember is a pointer to an on-heap object that is not traced for some - * reason. Do not use this unless you know what you are doing. Keeping raw - * pointers to on-heap objects is prohibited unless used from stack. Pointee - * must be kept alive through other means. - */ -template -using UntracedMember = internal::BasicMember; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_MEMBER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/name-provider.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/name-provider.h deleted file mode 100644 index 224dd4b5d67..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/name-provider.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_NAME_PROVIDER_H_ -#define INCLUDE_CPPGC_NAME_PROVIDER_H_ - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -/** - * NameProvider allows for providing a human-readable name for garbage-collected - * objects. - * - * There's two cases of names to distinguish: - * a. Explicitly specified names via using NameProvider. Such names are always - * preserved in the system. - * b. Internal names that Oilpan infers from a C++ type on the class hierarchy - * of the object. This is not necessarily the type of the actually - * instantiated object. - * - * Depending on the build configuration, Oilpan may hide names, i.e., represent - * them with kHiddenName, of case b. to avoid exposing internal details. - */ -class V8_EXPORT NameProvider { - public: - /** - * Name that is used when hiding internals. - */ - static constexpr const char kHiddenName[] = "InternalNode"; - - /** - * Name that is used in case compiler support is missing for composing a name - * from C++ types. - */ - static constexpr const char kNoNameDeducible[] = ""; - - /** - * Indicating whether internal names are hidden or not. - * - * @returns true if C++ names should be hidden and represented by kHiddenName. - */ - static constexpr bool HideInternalNames() { -#if CPPGC_SUPPORTS_OBJECT_NAMES - return false; -#else // !CPPGC_SUPPORTS_OBJECT_NAMES - return true; -#endif // !CPPGC_SUPPORTS_OBJECT_NAMES - } - - virtual ~NameProvider() = default; - - /** - * Specifies a name for the garbage-collected object. Such names will never - * be hidden, as they are explicitly specified by the user of this API. - * - * @returns a human readable name for the object. - */ - virtual const char* GetHumanReadableName() const = 0; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_NAME_PROVIDER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/object-size-trait.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/object-size-trait.h deleted file mode 100644 index 35795596d36..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/object-size-trait.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ -#define INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ - -#include - -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -namespace internal { - -struct V8_EXPORT BaseObjectSizeTrait { - protected: - static size_t GetObjectSizeForGarbageCollected(const void*); - static size_t GetObjectSizeForGarbageCollectedMixin(const void*); -}; - -} // namespace internal - -namespace subtle { - -/** - * Trait specifying how to get the size of an object that was allocated using - * `MakeGarbageCollected()`. Also supports querying the size with an inner - * pointer to a mixin. - */ -template > -struct ObjectSizeTrait; - -template -struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait { - static_assert(sizeof(T), "T must be fully defined"); - static_assert(IsGarbageCollectedTypeV, - "T must be of type GarbageCollected or GarbageCollectedMixin"); - - static size_t GetSize(const T& object) { - return GetObjectSizeForGarbageCollected(&object); - } -}; - -template -struct ObjectSizeTrait : cppgc::internal::BaseObjectSizeTrait { - static_assert(sizeof(T), "T must be fully defined"); - - static size_t GetSize(const T& object) { - return GetObjectSizeForGarbageCollectedMixin(&object); - } -}; - -} // namespace subtle -} // namespace cppgc - -#endif // INCLUDE_CPPGC_OBJECT_SIZE_TRAIT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/persistent.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/persistent.h deleted file mode 100644 index b83a464576e..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/persistent.h +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PERSISTENT_H_ -#define INCLUDE_CPPGC_PERSISTENT_H_ - -#include - -#include "cppgc/internal/persistent-node.h" -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/source-location.h" -#include "cppgc/type-traits.h" -#include "cppgc/visitor.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -// PersistentBase always refers to the object as const object and defers to -// BasicPersistent on casting to the right type as needed. -class PersistentBase { - protected: - PersistentBase() = default; - explicit PersistentBase(const void* raw) : raw_(raw) {} - - const void* GetValue() const { return raw_; } - void SetValue(const void* value) { raw_ = value; } - - PersistentNode* GetNode() const { return node_; } - void SetNode(PersistentNode* node) { node_ = node; } - - // Performs a shallow clear which assumes that internal persistent nodes are - // destroyed elsewhere. - void ClearFromGC() const { - raw_ = nullptr; - node_ = nullptr; - } - - protected: - mutable const void* raw_ = nullptr; - mutable PersistentNode* node_ = nullptr; - - friend class PersistentRegion; -}; - -// The basic class from which all Persistent classes are generated. -template -class BasicPersistent final : public PersistentBase, - public LocationPolicy, - private WeaknessPolicy, - private CheckingPolicy { - public: - using typename WeaknessPolicy::IsStrongPersistent; - using PointeeType = T; - - // Null-state/sentinel constructors. - BasicPersistent( // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicPersistent(std::nullptr_t, // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : LocationPolicy(loc) {} - - BasicPersistent( // NOLINT - SentinelPointer s, const SourceLocation& loc = SourceLocation::Current()) - : PersistentBase(s), LocationPolicy(loc) {} - - // Raw value constructors. - BasicPersistent(T* raw, // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : PersistentBase(raw), LocationPolicy(loc) { - if (!IsValid()) return; - SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) - .AllocateNode(this, &BasicPersistent::Trace)); - this->CheckPointer(Get()); - } - - BasicPersistent(T& raw, // NOLINT - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(&raw, loc) {} - - // Copy ctor. - BasicPersistent(const BasicPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(other.Get(), loc) {} - - // Heterogeneous ctor. - template ::value>> - BasicPersistent( - const BasicPersistent& other, - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(other.Get(), loc) {} - - // Move ctor. The heterogeneous move ctor is not supported since e.g. - // persistent can't reuse persistent node from weak persistent. - BasicPersistent( - BasicPersistent&& other, - const SourceLocation& loc = SourceLocation::Current()) noexcept - : PersistentBase(std::move(other)), LocationPolicy(std::move(other)) { - if (!IsValid()) return; - GetNode()->UpdateOwner(this); - other.SetValue(nullptr); - other.SetNode(nullptr); - this->CheckPointer(Get()); - } - - // Constructor from member. - template ::value>> - BasicPersistent(internal::BasicMember - member, - const SourceLocation& loc = SourceLocation::Current()) - : BasicPersistent(member.Get(), loc) {} - - ~BasicPersistent() { Clear(); } - - // Copy assignment. - BasicPersistent& operator=(const BasicPersistent& other) { - return operator=(other.Get()); - } - - template ::value>> - BasicPersistent& operator=( - const BasicPersistent& other) { - return operator=(other.Get()); - } - - // Move assignment. - BasicPersistent& operator=(BasicPersistent&& other) noexcept { - if (this == &other) return *this; - Clear(); - PersistentBase::operator=(std::move(other)); - LocationPolicy::operator=(std::move(other)); - if (!IsValid()) return *this; - GetNode()->UpdateOwner(this); - other.SetValue(nullptr); - other.SetNode(nullptr); - this->CheckPointer(Get()); - return *this; - } - - // Assignment from member. - template ::value>> - BasicPersistent& operator=( - internal::BasicMember - member) { - return operator=(member.Get()); - } - - BasicPersistent& operator=(T* other) { - Assign(other); - return *this; - } - - BasicPersistent& operator=(std::nullptr_t) { - Clear(); - return *this; - } - - BasicPersistent& operator=(SentinelPointer s) { - Assign(s); - return *this; - } - - explicit operator bool() const { return Get(); } - operator T*() const { return Get(); } - T* operator->() const { return Get(); } - T& operator*() const { return *Get(); } - - // CFI cast exemption to allow passing SentinelPointer through T* and support - // heterogeneous assignments between different Member and Persistent handles - // based on their actual types. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const { - // The const_cast below removes the constness from PersistentBase storage. - // The following static_cast re-adds any constness if specified through the - // user-visible template parameter T. - return static_cast(const_cast(GetValue())); - } - - void Clear() { - // Simplified version of `Assign()` to allow calling without a complete type - // `T`. - if (IsValid()) { - WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); - SetNode(nullptr); - } - SetValue(nullptr); - } - - T* Release() { - T* result = Get(); - Clear(); - return result; - } - - template - BasicPersistent - To() const { - return BasicPersistent(static_cast(Get())); - } - - private: - static void Trace(Visitor* v, const void* ptr) { - const auto* persistent = static_cast(ptr); - v->TraceRoot(*persistent, persistent->Location()); - } - - bool IsValid() const { - // Ideally, handling kSentinelPointer would be done by the embedder. On the - // other hand, having Persistent aware of it is beneficial since no node - // gets wasted. - return GetValue() != nullptr && GetValue() != kSentinelPointer; - } - - void Assign(T* ptr) { - if (IsValid()) { - if (ptr && ptr != kSentinelPointer) { - // Simply assign the pointer reusing the existing node. - SetValue(ptr); - this->CheckPointer(ptr); - return; - } - WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); - SetNode(nullptr); - } - SetValue(ptr); - if (!IsValid()) return; - SetNode(WeaknessPolicy::GetPersistentRegion(GetValue()) - .AllocateNode(this, &BasicPersistent::Trace)); - this->CheckPointer(Get()); - } - - void ClearFromGC() const { - if (IsValid()) { - WeaknessPolicy::GetPersistentRegion(GetValue()).FreeNode(GetNode()); - PersistentBase::ClearFromGC(); - } - } - - // Set Get() for details. - V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") - T* GetFromGC() const { - return static_cast(const_cast(GetValue())); - } - - friend class cppgc::Visitor; -}; - -template -bool operator==(const BasicPersistent& p1, - const BasicPersistent& p2) { - return p1.Get() == p2.Get(); -} - -template -bool operator!=(const BasicPersistent& p1, - const BasicPersistent& p2) { - return !(p1 == p2); -} - -template -bool operator==(const BasicPersistent& p, - BasicMember - m) { - return p.Get() == m.Get(); -} - -template -bool operator!=(const BasicPersistent& p, - BasicMember - m) { - return !(p == m); -} - -template -bool operator==(BasicMember - m, - const BasicPersistent& p) { - return m.Get() == p.Get(); -} - -template -bool operator!=(BasicMember - m, - const BasicPersistent& p) { - return !(m == p); -} - -template -struct IsWeak> : std::true_type {}; -} // namespace internal - -/** - * Persistent is a way to create a strong pointer from an off-heap object to - * another on-heap object. As long as the Persistent handle is alive the GC will - * keep the object pointed to alive. The Persistent handle is always a GC root - * from the point of view of the GC. Persistent must be constructed and - * destructed in the same thread. - */ -template -using Persistent = - internal::BasicPersistent; - -/** - * WeakPersistent is a way to create a weak pointer from an off-heap object to - * an on-heap object. The pointer is automatically cleared when the pointee gets - * collected. WeakPersistent must be constructed and destructed in the same - * thread. - */ -template -using WeakPersistent = - internal::BasicPersistent; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PERSISTENT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/platform.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/platform.h deleted file mode 100644 index 3276a26b652..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/platform.h +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PLATFORM_H_ -#define INCLUDE_CPPGC_PLATFORM_H_ - -#include - -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -// TODO(v8:10346): Create separate includes for concepts that are not -// V8-specific. -using IdleTask = v8::IdleTask; -using JobHandle = v8::JobHandle; -using JobDelegate = v8::JobDelegate; -using JobTask = v8::JobTask; -using PageAllocator = v8::PageAllocator; -using Task = v8::Task; -using TaskPriority = v8::TaskPriority; -using TaskRunner = v8::TaskRunner; -using TracingController = v8::TracingController; - -/** - * Platform interface used by Heap. Contains allocators and executors. - */ -class V8_EXPORT Platform { - public: - virtual ~Platform() = default; - - /** - * Returns the allocator used by cppgc to allocate its heap and various - * support structures. - */ - virtual PageAllocator* GetPageAllocator() = 0; - - /** - * Monotonically increasing time in seconds from an arbitrary fixed point in - * the past. This function is expected to return at least - * millisecond-precision values. For this reason, - * it is recommended that the fixed point be no further in the past than - * the epoch. - **/ - virtual double MonotonicallyIncreasingTime() = 0; - - /** - * Foreground task runner that should be used by a Heap. - */ - virtual std::shared_ptr GetForegroundTaskRunner() { - return nullptr; - } - - /** - * Posts `job_task` to run in parallel. Returns a `JobHandle` associated with - * the `Job`, which can be joined or canceled. - * This avoids degenerate cases: - * - Calling `CallOnWorkerThread()` for each work item, causing significant - * overhead. - * - Fixed number of `CallOnWorkerThread()` calls that split the work and - * might run for a long time. This is problematic when many components post - * "num cores" tasks and all expect to use all the cores. In these cases, - * the scheduler lacks context to be fair to multiple same-priority requests - * and/or ability to request lower priority work to yield when high priority - * work comes in. - * A canonical implementation of `job_task` looks like: - * \code - * class MyJobTask : public JobTask { - * public: - * MyJobTask(...) : worker_queue_(...) {} - * // JobTask implementation. - * void Run(JobDelegate* delegate) override { - * while (!delegate->ShouldYield()) { - * // Smallest unit of work. - * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. - * if (!work_item) return; - * ProcessWork(work_item); - * } - * } - * - * size_t GetMaxConcurrency() const override { - * return worker_queue_.GetSize(); // Thread safe. - * } - * }; - * - * // ... - * auto handle = PostJob(TaskPriority::kUserVisible, - * std::make_unique(...)); - * handle->Join(); - * \endcode - * - * `PostJob()` and methods of the returned JobHandle/JobDelegate, must never - * be called while holding a lock that could be acquired by `JobTask::Run()` - * or `JobTask::GetMaxConcurrency()` -- that could result in a deadlock. This - * is because (1) `JobTask::GetMaxConcurrency()` may be invoked while holding - * internal lock (A), hence `JobTask::GetMaxConcurrency()` can only use a lock - * (B) if that lock is *never* held while calling back into `JobHandle` from - * any thread (A=>B/B=>A deadlock) and (2) `JobTask::Run()` or - * `JobTask::GetMaxConcurrency()` may be invoked synchronously from - * `JobHandle` (B=>JobHandle::foo=>B deadlock). - * - * A sufficient `PostJob()` implementation that uses the default Job provided - * in libplatform looks like: - * \code - * std::unique_ptr PostJob( - * TaskPriority priority, std::unique_ptr job_task) override { - * return std::make_unique( - * std::make_shared( - * this, std::move(job_task), kNumThreads)); - * } - * \endcode - */ - virtual std::unique_ptr PostJob( - TaskPriority priority, std::unique_ptr job_task) { - return nullptr; - } - - /** - * Returns an instance of a `TracingController`. This must be non-nullptr. The - * default implementation returns an empty `TracingController` that consumes - * trace data without effect. - */ - virtual TracingController* GetTracingController(); -}; - -/** - * Process-global initialization of the garbage collector. Must be called before - * creating a Heap. - * - * Can be called multiple times when paired with `ShutdownProcess()`. - * - * \param page_allocator The allocator used for maintaining meta data. Must not - * change between multiple calls to InitializeProcess. - */ -V8_EXPORT void InitializeProcess(PageAllocator* page_allocator); - -/** - * Must be called after destroying the last used heap. Some process-global - * metadata may not be returned and reused upon a subsequent - * `InitializeProcess()` call. - */ -V8_EXPORT void ShutdownProcess(); - -namespace internal { - -V8_EXPORT void Abort(); - -} // namespace internal - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PLATFORM_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/prefinalizer.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/prefinalizer.h deleted file mode 100644 index 6153b37ff5d..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/prefinalizer.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PREFINALIZER_H_ -#define INCLUDE_CPPGC_PREFINALIZER_H_ - -#include "cppgc/internal/compiler-specific.h" -#include "cppgc/internal/prefinalizer-handler.h" -#include "cppgc/liveness-broker.h" - -namespace cppgc { - -namespace internal { - -template -class PrefinalizerRegistration final { - public: - explicit PrefinalizerRegistration(T* self) { - static_assert(sizeof(&T::InvokePreFinalizer) > 0, - "USING_PRE_FINALIZER(T) must be defined."); - - cppgc::internal::PreFinalizerRegistrationDispatcher::RegisterPrefinalizer( - {self, T::InvokePreFinalizer}); - } - - void* operator new(size_t, void* location) = delete; - void* operator new(size_t) = delete; -}; - -} // namespace internal - -#define CPPGC_USING_PRE_FINALIZER(Class, PreFinalizer) \ - public: \ - static bool InvokePreFinalizer(const cppgc::LivenessBroker& liveness_broker, \ - void* object) { \ - static_assert(cppgc::IsGarbageCollectedOrMixinTypeV, \ - "Only garbage collected objects can have prefinalizers"); \ - Class* self = static_cast(object); \ - if (liveness_broker.IsHeapObjectAlive(self)) return false; \ - self->PreFinalizer(); \ - return true; \ - } \ - \ - private: \ - CPPGC_NO_UNIQUE_ADDRESS cppgc::internal::PrefinalizerRegistration \ - prefinalizer_dummy_{this}; \ - static_assert(true, "Force semicolon.") - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PREFINALIZER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/process-heap-statistics.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/process-heap-statistics.h deleted file mode 100644 index 774cc92f46c..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/process-heap-statistics.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ -#define INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ - -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { -namespace internal { -class ProcessHeapStatisticsUpdater; -} // namespace internal - -class V8_EXPORT ProcessHeapStatistics final { - public: - static size_t TotalAllocatedObjectSize() { - return total_allocated_object_size_.load(std::memory_order_relaxed); - } - static size_t TotalAllocatedSpace() { - return total_allocated_space_.load(std::memory_order_relaxed); - } - - private: - static std::atomic_size_t total_allocated_space_; - static std::atomic_size_t total_allocated_object_size_; - - friend class internal::ProcessHeapStatisticsUpdater; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_PROCESS_HEAP_STATISTICS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/sentinel-pointer.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/sentinel-pointer.h deleted file mode 100644 index b049d1a2b34..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/sentinel-pointer.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_SENTINEL_POINTER_H_ -#define INCLUDE_CPPGC_SENTINEL_POINTER_H_ - -#include - -namespace cppgc { -namespace internal { - -// Special tag type used to denote some sentinel member. The semantics of the -// sentinel is defined by the embedder. -struct SentinelPointer { - template - operator T*() const { - static constexpr intptr_t kSentinelValue = 1; - return reinterpret_cast(kSentinelValue); - } - // Hidden friends. - friend bool operator==(SentinelPointer, SentinelPointer) { return true; } - friend bool operator!=(SentinelPointer, SentinelPointer) { return false; } -}; - -} // namespace internal - -constexpr internal::SentinelPointer kSentinelPointer; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_SENTINEL_POINTER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/source-location.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/source-location.h deleted file mode 100644 index da5a5ede520..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/source-location.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_SOURCE_LOCATION_H_ -#define INCLUDE_CPPGC_SOURCE_LOCATION_H_ - -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -#if defined(__has_builtin) -#define CPPGC_SUPPORTS_SOURCE_LOCATION \ - (__has_builtin(__builtin_FUNCTION) && __has_builtin(__builtin_FILE) && \ - __has_builtin(__builtin_LINE)) // NOLINT -#elif defined(V8_CC_GNU) && __GNUC__ >= 7 -#define CPPGC_SUPPORTS_SOURCE_LOCATION 1 -#elif defined(V8_CC_INTEL) && __ICC >= 1800 -#define CPPGC_SUPPORTS_SOURCE_LOCATION 1 -#else -#define CPPGC_SUPPORTS_SOURCE_LOCATION 0 -#endif - -namespace cppgc { - -/** - * Encapsulates source location information. Mimics C++20's - * `std::source_location`. - */ -class V8_EXPORT SourceLocation final { - public: - /** - * Construct source location information corresponding to the location of the - * call site. - */ -#if CPPGC_SUPPORTS_SOURCE_LOCATION - static constexpr SourceLocation Current( - const char* function = __builtin_FUNCTION(), - const char* file = __builtin_FILE(), size_t line = __builtin_LINE()) { - return SourceLocation(function, file, line); - } -#else - static constexpr SourceLocation Current() { return SourceLocation(); } -#endif // CPPGC_SUPPORTS_SOURCE_LOCATION - - /** - * Constructs unspecified source location information. - */ - constexpr SourceLocation() = default; - - /** - * Returns the name of the function associated with the position represented - * by this object, if any. - * - * \returns the function name as cstring. - */ - constexpr const char* Function() const { return function_; } - - /** - * Returns the name of the current source file represented by this object. - * - * \returns the file name as cstring. - */ - constexpr const char* FileName() const { return file_; } - - /** - * Returns the line number represented by this object. - * - * \returns the line number. - */ - constexpr size_t Line() const { return line_; } - - /** - * Returns a human-readable string representing this object. - * - * \returns a human-readable string representing source location information. - */ - std::string ToString() const; - - private: - constexpr SourceLocation(const char* function, const char* file, size_t line) - : function_(function), file_(file), line_(line) {} - - const char* function_ = nullptr; - const char* file_ = nullptr; - size_t line_ = 0u; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_SOURCE_LOCATION_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/testing.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/testing.h deleted file mode 100644 index 229ce140f94..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/testing.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_TESTING_H_ -#define INCLUDE_CPPGC_TESTING_H_ - -#include "cppgc/common.h" -#include "cppgc/macros.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class HeapHandle; - -/** - * Namespace contains testing helpers. - */ -namespace testing { - -/** - * Overrides the state of the stack with the provided value. Takes precedence - * over other parameters that set the stack state. Must no be nested. - */ -class V8_EXPORT V8_NODISCARD OverrideEmbedderStackStateScope final { - CPPGC_STACK_ALLOCATED(); - - public: - /** - * Constructs a scoped object that automatically enters and leaves the scope. - * - * \param heap_handle The corresponding heap. - */ - explicit OverrideEmbedderStackStateScope(HeapHandle& heap_handle, - EmbedderStackState state); - ~OverrideEmbedderStackStateScope(); - - OverrideEmbedderStackStateScope(const OverrideEmbedderStackStateScope&) = - delete; - OverrideEmbedderStackStateScope& operator=( - const OverrideEmbedderStackStateScope&) = delete; - - private: - HeapHandle& heap_handle_; -}; - -/** - * Testing interface for managed heaps that allows for controlling garbage - * collection timings. Embedders should use this class when testing the - * interaction of their code with incremental/concurrent garbage collection. - */ -class V8_EXPORT StandaloneTestingHeap final { - public: - explicit StandaloneTestingHeap(HeapHandle&); - - /** - * Start an incremental garbage collection. - */ - void StartGarbageCollection(); - - /** - * Perform an incremental step. This will also schedule concurrent steps if - * needed. - * - * \param stack_state The state of the stack during the step. - */ - bool PerformMarkingStep(EmbedderStackState stack_state); - - /** - * Finalize the current garbage collection cycle atomically. - * Assumes that garbage collection is in progress. - * - * \param stack_state The state of the stack for finalizing the garbage - * collection cycle. - */ - void FinalizeGarbageCollection(EmbedderStackState stack_state); - - /** - * Toggle main thread marking on/off. Allows to stress concurrent marking - * (e.g. to better detect data races). - * - * \param should_mark Denotes whether the main thread should contribute to - * marking. Defaults to true. - */ - void ToggleMainThreadMarking(bool should_mark); - - /** - * Force enable compaction for the next garbage collection cycle. - */ - void ForceCompactionForNextGarbageCollection(); - - private: - HeapHandle& heap_handle_; -}; - -} // namespace testing -} // namespace cppgc - -#endif // INCLUDE_CPPGC_TESTING_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/trace-trait.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/trace-trait.h deleted file mode 100644 index 83619b1d518..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/trace-trait.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_TRACE_TRAIT_H_ -#define INCLUDE_CPPGC_TRACE_TRAIT_H_ - -#include - -#include "cppgc/type-traits.h" -#include "v8config.h" // NOLINT(build/include_directory) - -namespace cppgc { - -class Visitor; - -namespace internal { - -// Implementation of the default TraceTrait handling GarbageCollected and -// GarbageCollectedMixin. -template ::type>> -struct TraceTraitImpl; - -} // namespace internal - -/** - * Callback for invoking tracing on a given object. - * - * \param visitor The visitor to dispatch to. - * \param object The object to invoke tracing on. - */ -using TraceCallback = void (*)(Visitor* visitor, const void* object); - -/** - * Describes how to trace an object, i.e., how to visit all Oilpan-relevant - * fields of an object. - */ -struct TraceDescriptor { - /** - * Adjusted base pointer, i.e., the pointer to the class inheriting directly - * from GarbageCollected, of the object that is being traced. - */ - const void* base_object_payload; - /** - * Callback for tracing the object. - */ - TraceCallback callback; -}; - -namespace internal { - -struct V8_EXPORT TraceTraitFromInnerAddressImpl { - static TraceDescriptor GetTraceDescriptor(const void* address); -}; - -/** - * Trait specifying how the garbage collector processes an object of type T. - * - * Advanced users may override handling by creating a specialization for their - * type. - */ -template -struct TraceTraitBase { - static_assert(internal::IsTraceableV, "T must have a Trace() method"); - - /** - * Accessor for retrieving a TraceDescriptor to process an object of type T. - * - * \param self The object to be processed. - * \returns a TraceDescriptor to process the object. - */ - static TraceDescriptor GetTraceDescriptor(const void* self) { - return internal::TraceTraitImpl::GetTraceDescriptor( - static_cast(self)); - } - - /** - * Function invoking the tracing for an object of type T. - * - * \param visitor The visitor to dispatch to. - * \param self The object to invoke tracing on. - */ - static void Trace(Visitor* visitor, const void* self) { - static_cast(self)->Trace(visitor); - } -}; - -} // namespace internal - -template -struct TraceTrait : public internal::TraceTraitBase {}; - -namespace internal { - -template -struct TraceTraitImpl { - static_assert(IsGarbageCollectedTypeV, - "T must be of type GarbageCollected or GarbageCollectedMixin"); - static TraceDescriptor GetTraceDescriptor(const void* self) { - return {self, TraceTrait::Trace}; - } -}; - -template -struct TraceTraitImpl { - static TraceDescriptor GetTraceDescriptor(const void* self) { - return internal::TraceTraitFromInnerAddressImpl::GetTraceDescriptor(self); - } -}; - -} // namespace internal -} // namespace cppgc - -#endif // INCLUDE_CPPGC_TRACE_TRAIT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/type-traits.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/type-traits.h deleted file mode 100644 index 56cd55d61e2..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/type-traits.h +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_TYPE_TRAITS_H_ -#define INCLUDE_CPPGC_TYPE_TRAITS_H_ - -// This file should stay with minimal dependencies to allow embedder to check -// against Oilpan types without including any other parts. -#include -#include - -namespace cppgc { - -class Visitor; - -namespace internal { -template -class BasicMember; -struct DijkstraWriteBarrierPolicy; -struct NoWriteBarrierPolicy; -class StrongMemberTag; -class UntracedMemberTag; -class WeakMemberTag; - -// Pre-C++17 custom implementation of std::void_t. -template -struct make_void { - typedef void type; -}; -template -using void_t = typename make_void::type; - -// Not supposed to be specialized by the user. -template -struct IsWeak : std::false_type {}; - -// IsTraceMethodConst is used to verify that all Trace methods are marked as -// const. It is equivalent to IsTraceable but for a non-const object. -template -struct IsTraceMethodConst : std::false_type {}; - -template -struct IsTraceMethodConst().Trace( - std::declval()))>> : std::true_type { -}; - -template -struct IsTraceable : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsTraceable< - T, void_t().Trace(std::declval()))>> - : std::true_type { - // All Trace methods should be marked as const. If an object of type - // 'T' is traceable then any object of type 'const T' should also - // be traceable. - static_assert(IsTraceMethodConst(), - "Trace methods should be marked as const."); -}; - -template -constexpr bool IsTraceableV = IsTraceable::value; - -template -struct HasGarbageCollectedMixinTypeMarker : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct HasGarbageCollectedMixinTypeMarker< - T, - void_t::IsGarbageCollectedMixinTypeMarker>> - : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct HasGarbageCollectedTypeMarker : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct HasGarbageCollectedTypeMarker< - T, void_t::IsGarbageCollectedTypeMarker>> - : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template ::value, - bool = HasGarbageCollectedMixinTypeMarker::value> -struct IsGarbageCollectedMixinType : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedMixinType : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template ::value> -struct IsGarbageCollectedType : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedType : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedOrMixinType - : std::integral_constant::value || - IsGarbageCollectedMixinType::value> { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template ::value && - HasGarbageCollectedMixinTypeMarker::value)> -struct IsGarbageCollectedWithMixinType : std::false_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsGarbageCollectedWithMixinType : std::true_type { - static_assert(sizeof(T), "T must be fully defined"); -}; - -template -struct IsSubclassOfBasicMemberTemplate { - private: - template - static std::true_type SubclassCheck( - BasicMember*); - static std::false_type SubclassCheck(...); - - public: - static constexpr bool value = - decltype(SubclassCheck(std::declval()))::value; -}; - -template ::value> -struct IsMemberType : std::false_type {}; - -template -struct IsMemberType : std::true_type {}; - -template ::value> -struct IsWeakMemberType : std::false_type {}; - -template -struct IsWeakMemberType : std::true_type {}; - -template ::value> -struct IsUntracedMemberType : std::false_type {}; - -template -struct IsUntracedMemberType : std::true_type {}; - -template -struct IsComplete { - private: - template - static std::true_type IsSizeOfKnown(U*); - static std::false_type IsSizeOfKnown(...); - - public: - static constexpr bool value = - decltype(IsSizeOfKnown(std::declval()))::value; -}; - -} // namespace internal - -/** - * Value is true for types that inherit from `GarbageCollectedMixin` but not - * `GarbageCollected` (i.e., they are free mixins), and false otherwise. - */ -template -constexpr bool IsGarbageCollectedMixinTypeV = - internal::IsGarbageCollectedMixinType::value; - -/** - * Value is true for types that inherit from `GarbageCollected`, and false - * otherwise. - */ -template -constexpr bool IsGarbageCollectedTypeV = - internal::IsGarbageCollectedType::value; - -/** - * Value is true for types that inherit from either `GarbageCollected` or - * `GarbageCollectedMixin`, and false otherwise. - */ -template -constexpr bool IsGarbageCollectedOrMixinTypeV = - internal::IsGarbageCollectedOrMixinType::value; - -/** - * Value is true for types that inherit from `GarbageCollected` and - * `GarbageCollectedMixin`, and false otherwise. - */ -template -constexpr bool IsGarbageCollectedWithMixinTypeV = - internal::IsGarbageCollectedWithMixinType::value; - -/** - * Value is true for types of type `Member`, and false otherwise. - */ -template -constexpr bool IsMemberTypeV = internal::IsMemberType::value; - -/** - * Value is true for types of type `UntracedMember`, and false otherwise. - */ -template -constexpr bool IsUntracedMemberTypeV = internal::IsUntracedMemberType::value; - -/** - * Value is true for types of type `WeakMember`, and false otherwise. - */ -template -constexpr bool IsWeakMemberTypeV = internal::IsWeakMemberType::value; - -/** - * Value is true for types that are considered weak references, and false - * otherwise. - */ -template -constexpr bool IsWeakV = internal::IsWeak::value; - -/** - * Value is true for types that are complete, and false otherwise. - */ -template -constexpr bool IsCompleteV = internal::IsComplete::value; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_TYPE_TRAITS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/visitor.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/visitor.h deleted file mode 100644 index 57e2ce3963a..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/cppgc/visitor.h +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_CPPGC_VISITOR_H_ -#define INCLUDE_CPPGC_VISITOR_H_ - -#include "cppgc/custom-space.h" -#include "cppgc/ephemeron-pair.h" -#include "cppgc/garbage-collected.h" -#include "cppgc/internal/logging.h" -#include "cppgc/internal/pointer-policies.h" -#include "cppgc/liveness-broker.h" -#include "cppgc/member.h" -#include "cppgc/sentinel-pointer.h" -#include "cppgc/source-location.h" -#include "cppgc/trace-trait.h" -#include "cppgc/type-traits.h" - -namespace cppgc { - -namespace internal { -template -class BasicCrossThreadPersistent; -template -class BasicPersistent; -class ConservativeTracingVisitor; -class VisitorBase; -class VisitorFactory; -} // namespace internal - -using WeakCallback = void (*)(const LivenessBroker&, const void*); - -/** - * Visitor passed to trace methods. All managed pointers must have called the - * Visitor's trace method on them. - * - * \code - * class Foo final : public GarbageCollected { - * public: - * void Trace(Visitor* visitor) const { - * visitor->Trace(foo_); - * visitor->Trace(weak_foo_); - * } - * private: - * Member foo_; - * WeakMember weak_foo_; - * }; - * \endcode - */ -class V8_EXPORT Visitor { - public: - class Key { - private: - Key() = default; - friend class internal::VisitorFactory; - }; - - explicit Visitor(Key) {} - - virtual ~Visitor() = default; - - /** - * Trace method for raw pointers. Prefer the versions for managed pointers. - * - * \param member Reference retaining an object. - */ - template - void Trace(const T* t) { - static_assert(sizeof(T), "Pointee type must be fully defined."); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "T must be GarbageCollected or GarbageCollectedMixin type"); - if (!t) { - return; - } - Visit(t, TraceTrait::GetTraceDescriptor(t)); - } - - /** - * Trace method for Member. - * - * \param member Member reference retaining an object. - */ - template - void Trace(const Member& member) { - const T* value = member.GetRawAtomic(); - CPPGC_DCHECK(value != kSentinelPointer); - Trace(value); - } - - /** - * Trace method for WeakMember. - * - * \param weak_member WeakMember reference weakly retaining an object. - */ - template - void Trace(const WeakMember& weak_member) { - static_assert(sizeof(T), "Pointee type must be fully defined."); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "T must be GarbageCollected or GarbageCollectedMixin type"); - static_assert(!internal::IsAllocatedOnCompactableSpace::value, - "Weak references to compactable objects are not allowed"); - - const T* value = weak_member.GetRawAtomic(); - - // Bailout assumes that WeakMember emits write barrier. - if (!value) { - return; - } - - CPPGC_DCHECK(value != kSentinelPointer); - VisitWeak(value, TraceTrait::GetTraceDescriptor(value), - &HandleWeak>, &weak_member); - } - - /** - * Trace method for inlined objects that are not allocated themselves but - * otherwise follow managed heap layout and have a Trace() method. - * - * \param object reference of the inlined object. - */ - template - void Trace(const T& object) { -#if V8_ENABLE_CHECKS - // This object is embedded in potentially multiple nested objects. The - // outermost object must not be in construction as such objects are (a) not - // processed immediately, and (b) only processed conservatively if not - // otherwise possible. - CheckObjectNotInConstruction(&object); -#endif // V8_ENABLE_CHECKS - TraceTrait::Trace(this, &object); - } - - /** - * Registers a weak callback method on the object of type T. See - * LivenessBroker for an usage example. - * - * \param object of type T specifying a weak callback method. - */ - template - void RegisterWeakCallbackMethod(const T* object) { - RegisterWeakCallback(&WeakCallbackMethodDelegate, object); - } - - /** - * Trace method for EphemeronPair. - * - * \param ephemeron_pair EphemeronPair reference weakly retaining a key object - * and strongly retaining a value object in case the key object is alive. - */ - template - void Trace(const EphemeronPair& ephemeron_pair) { - TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value); - RegisterWeakCallbackMethod, - &EphemeronPair::ClearValueIfKeyIsDead>( - &ephemeron_pair); - } - - /** - * Trace method for a single ephemeron. Used for tracing a raw ephemeron in - * which the `key` and `value` are kept separately. - * - * \param weak_member_key WeakMember reference weakly retaining a key object. - * \param member_value Member reference with ephemeron semantics. - */ - template - void TraceEphemeron(const WeakMember& weak_member_key, - const Member* member_value) { - const KeyType* key = weak_member_key.GetRawAtomic(); - if (!key) return; - - // `value` must always be non-null. - CPPGC_DCHECK(member_value); - const ValueType* value = member_value->GetRawAtomic(); - if (!value) return; - - // KeyType and ValueType may refer to GarbageCollectedMixin. - TraceDescriptor value_desc = - TraceTrait::GetTraceDescriptor(value); - CPPGC_DCHECK(value_desc.base_object_payload); - const void* key_base_object_payload = - TraceTrait::GetTraceDescriptor(key).base_object_payload; - CPPGC_DCHECK(key_base_object_payload); - - VisitEphemeron(key_base_object_payload, value, value_desc); - } - - /** - * Trace method for a single ephemeron. Used for tracing a raw ephemeron in - * which the `key` and `value` are kept separately. Note that this overload - * is for non-GarbageCollected `value`s that can be traced though. - * - * \param key `WeakMember` reference weakly retaining a key object. - * \param value Reference weakly retaining a value object. Note that - * `ValueType` here should not be `Member`. It is expected that - * `TraceTrait::GetTraceDescriptor(value)` returns a - * `TraceDescriptor` with a null base pointer but a valid trace method. - */ - template - void TraceEphemeron(const WeakMember& weak_member_key, - const ValueType* value) { - static_assert(!IsGarbageCollectedOrMixinTypeV, - "garbage-collected types must use WeakMember and Member"); - const KeyType* key = weak_member_key.GetRawAtomic(); - if (!key) return; - - // `value` must always be non-null. - CPPGC_DCHECK(value); - TraceDescriptor value_desc = - TraceTrait::GetTraceDescriptor(value); - // `value_desc.base_object_payload` must be null as this override is only - // taken for non-garbage-collected values. - CPPGC_DCHECK(!value_desc.base_object_payload); - - // KeyType might be a GarbageCollectedMixin. - const void* key_base_object_payload = - TraceTrait::GetTraceDescriptor(key).base_object_payload; - CPPGC_DCHECK(key_base_object_payload); - - VisitEphemeron(key_base_object_payload, value, value_desc); - } - - /** - * Trace method that strongifies a WeakMember. - * - * \param weak_member WeakMember reference retaining an object. - */ - template - void TraceStrongly(const WeakMember& weak_member) { - const T* value = weak_member.GetRawAtomic(); - CPPGC_DCHECK(value != kSentinelPointer); - Trace(value); - } - - /** - * Trace method for weak containers. - * - * \param object reference of the weak container. - * \param callback to be invoked. - * \param data custom data that is passed to the callback. - */ - template - void TraceWeakContainer(const T* object, WeakCallback callback, - const void* data) { - if (!object) return; - VisitWeakContainer(object, TraceTrait::GetTraceDescriptor(object), - TraceTrait::GetWeakTraceDescriptor(object), callback, - data); - } - - /** - * Registers a slot containing a reference to an object allocated on a - * compactable space. Such references maybe be arbitrarily moved by the GC. - * - * \param slot location of reference to object that might be moved by the GC. - */ - template - void RegisterMovableReference(const T** slot) { - static_assert(internal::IsAllocatedOnCompactableSpace::value, - "Only references to objects allocated on compactable spaces " - "should be registered as movable slots."); - static_assert(!IsGarbageCollectedMixinTypeV, - "Mixin types do not support compaction."); - HandleMovableReference(reinterpret_cast(slot)); - } - - /** - * Registers a weak callback that is invoked during garbage collection. - * - * \param callback to be invoked. - * \param data custom data that is passed to the callback. - */ - virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {} - - /** - * Defers tracing an object from a concurrent thread to the mutator thread. - * Should be called by Trace methods of types that are not safe to trace - * concurrently. - * - * \param parameter tells the trace callback which object was deferred. - * \param callback to be invoked for tracing on the mutator thread. - * \param deferred_size size of deferred object. - * - * \returns false if the object does not need to be deferred (i.e. currently - * traced on the mutator thread) and true otherwise (i.e. currently traced on - * a concurrent thread). - */ - virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent( - const void* parameter, TraceCallback callback, size_t deferred_size) { - // By default tracing is not deferred. - return false; - } - - protected: - virtual void Visit(const void* self, TraceDescriptor) {} - virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback, - const void* weak_member) {} - virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {} - virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback, - const void* weak_root, const SourceLocation&) {} - virtual void VisitEphemeron(const void* key, const void* value, - TraceDescriptor value_desc) {} - virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc, - TraceDescriptor weak_desc, - WeakCallback callback, const void* data) {} - virtual void HandleMovableReference(const void**) {} - - private: - template - static void WeakCallbackMethodDelegate(const LivenessBroker& info, - const void* self) { - // Callback is registered through a potential const Trace method but needs - // to be able to modify fields. See HandleWeak. - (const_cast(static_cast(self))->*method)(info); - } - - template - static void HandleWeak(const LivenessBroker& info, const void* object) { - const PointerType* weak = static_cast(object); - auto* raw_ptr = weak->GetFromGC(); - // Sentinel values are preserved for weak pointers. - if (raw_ptr == kSentinelPointer) return; - if (!info.IsHeapObjectAlive(raw_ptr)) { - weak->ClearFromGC(); - } - } - - template * = nullptr> - void TraceRoot(const Persistent& p, const SourceLocation& loc) { - using PointeeType = typename Persistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "Persistent's pointee type must be GarbageCollected or " - "GarbageCollectedMixin"); - auto* ptr = p.GetFromGC(); - if (!ptr) { - return; - } - VisitRoot(ptr, TraceTrait::GetTraceDescriptor(ptr), loc); - } - - template < - typename WeakPersistent, - std::enable_if_t* = nullptr> - void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) { - using PointeeType = typename WeakPersistent::PointeeType; - static_assert(sizeof(PointeeType), - "Persistent's pointee type must be fully defined"); - static_assert(internal::IsGarbageCollectedOrMixinType::value, - "Persistent's pointee type must be GarbageCollected or " - "GarbageCollectedMixin"); - static_assert(!internal::IsAllocatedOnCompactableSpace::value, - "Weak references to compactable objects are not allowed"); - auto* ptr = p.GetFromGC(); - VisitWeakRoot(ptr, TraceTrait::GetTraceDescriptor(ptr), - &HandleWeak, &p, loc); - } - -#if V8_ENABLE_CHECKS - void CheckObjectNotInConstruction(const void* address); -#endif // V8_ENABLE_CHECKS - - template - friend class internal::BasicCrossThreadPersistent; - template - friend class internal::BasicPersistent; - friend class internal::ConservativeTracingVisitor; - friend class internal::VisitorBase; -}; - -} // namespace cppgc - -#endif // INCLUDE_CPPGC_VISITOR_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Debugger.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Debugger.h deleted file mode 100644 index d984c6a4ad0..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Debugger.h +++ /dev/null @@ -1,59 +0,0 @@ -// This file is generated by Exported_h.template. - -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef v8_inspector_protocol_Debugger_api_h -#define v8_inspector_protocol_Debugger_api_h - -#include "v8-inspector.h" - -namespace v8_inspector { -namespace protocol { - -#ifndef v8_inspector_protocol_exported_api_h -#define v8_inspector_protocol_exported_api_h -class V8_EXPORT Exported { -public: - virtual void AppendSerialized(std::vector* out) const = 0; - - virtual ~Exported() { } -}; -#endif // !defined(v8_inspector_protocol_exported_api_h) - -namespace Debugger { -namespace API { - -// ------------- Enums. - -namespace Paused { -namespace ReasonEnum { -V8_EXPORT extern const char* Ambiguous; -V8_EXPORT extern const char* Assert; -V8_EXPORT extern const char* CSPViolation; -V8_EXPORT extern const char* DebugCommand; -V8_EXPORT extern const char* DOM; -V8_EXPORT extern const char* EventListener; -V8_EXPORT extern const char* Exception; -V8_EXPORT extern const char* Instrumentation; -V8_EXPORT extern const char* OOM; -V8_EXPORT extern const char* Other; -V8_EXPORT extern const char* PromiseRejection; -V8_EXPORT extern const char* XHR; -} // ReasonEnum -} // Paused - -// ------------- Types. - -class V8_EXPORT SearchMatch : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -} // namespace API -} // namespace Debugger -} // namespace v8_inspector -} // namespace protocol - -#endif // !defined(v8_inspector_protocol_Debugger_api_h) diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Runtime.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Runtime.h deleted file mode 100644 index f9d515ba74e..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Runtime.h +++ /dev/null @@ -1,52 +0,0 @@ -// This file is generated by Exported_h.template. - -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef v8_inspector_protocol_Runtime_api_h -#define v8_inspector_protocol_Runtime_api_h - -#include "v8-inspector.h" - -namespace v8_inspector { -namespace protocol { - -#ifndef v8_inspector_protocol_exported_api_h -#define v8_inspector_protocol_exported_api_h -class V8_EXPORT Exported { -public: - virtual void AppendSerialized(std::vector* out) const = 0; - - virtual ~Exported() { } -}; -#endif // !defined(v8_inspector_protocol_exported_api_h) - -namespace Runtime { -namespace API { - -// ------------- Enums. - -// ------------- Types. - -class V8_EXPORT RemoteObject : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -class V8_EXPORT StackTrace : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -class V8_EXPORT StackTraceId : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -} // namespace API -} // namespace Runtime -} // namespace v8_inspector -} // namespace protocol - -#endif // !defined(v8_inspector_protocol_Runtime_api_h) diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Schema.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Schema.h deleted file mode 100644 index 03a76fa9c56..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/inspector/Schema.h +++ /dev/null @@ -1,42 +0,0 @@ -// This file is generated by Exported_h.template. - -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef v8_inspector_protocol_Schema_api_h -#define v8_inspector_protocol_Schema_api_h - -#include "v8-inspector.h" - -namespace v8_inspector { -namespace protocol { - -#ifndef v8_inspector_protocol_exported_api_h -#define v8_inspector_protocol_exported_api_h -class V8_EXPORT Exported { -public: - virtual void AppendSerialized(std::vector* out) const = 0; - - virtual ~Exported() { } -}; -#endif // !defined(v8_inspector_protocol_exported_api_h) - -namespace Schema { -namespace API { - -// ------------- Enums. - -// ------------- Types. - -class V8_EXPORT Domain : public Exported { -public: - static std::unique_ptr fromBinary(const uint8_t* data, size_t length); -}; - -} // namespace API -} // namespace Schema -} // namespace v8_inspector -} // namespace protocol - -#endif // !defined(v8_inspector_protocol_Schema_api_h) diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/libplatform-export.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/libplatform-export.h deleted file mode 100644 index 15618434977..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/libplatform-export.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ -#define V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ - -#if defined(_WIN32) - -#ifdef BUILDING_V8_PLATFORM_SHARED -#define V8_PLATFORM_EXPORT __declspec(dllexport) -#elif USING_V8_PLATFORM_SHARED -#define V8_PLATFORM_EXPORT __declspec(dllimport) -#else -#define V8_PLATFORM_EXPORT -#endif // BUILDING_V8_PLATFORM_SHARED - -#else // defined(_WIN32) - -// Setup for Linux shared library export. -#ifdef BUILDING_V8_PLATFORM_SHARED -#define V8_PLATFORM_EXPORT __attribute__((visibility("default"))) -#else -#define V8_PLATFORM_EXPORT -#endif - -#endif // defined(_WIN32) - -#endif // V8_LIBPLATFORM_LIBPLATFORM_EXPORT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/libplatform.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/libplatform.h deleted file mode 100644 index 00de81df887..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/libplatform.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_LIBPLATFORM_LIBPLATFORM_H_ -#define V8_LIBPLATFORM_LIBPLATFORM_H_ - -#include - -#include "libplatform/libplatform-export.h" -#include "libplatform/v8-tracing.h" -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { -namespace platform { - -enum class IdleTaskSupport { kDisabled, kEnabled }; -enum class InProcessStackDumping { kDisabled, kEnabled }; - -enum class MessageLoopBehavior : bool { - kDoNotWait = false, - kWaitForWork = true -}; - -/** - * Returns a new instance of the default v8::Platform implementation. - * - * The caller will take ownership of the returned pointer. |thread_pool_size| - * is the number of worker threads to allocate for background jobs. If a value - * of zero is passed, a suitable default based on the current number of - * processors online will be chosen. - * If |idle_task_support| is enabled then the platform will accept idle - * tasks (IdleTasksEnabled will return true) and will rely on the embedder - * calling v8::platform::RunIdleTasks to process the idle tasks. - * If |tracing_controller| is nullptr, the default platform will create a - * v8::platform::TracingController instance and use it. - */ -V8_PLATFORM_EXPORT std::unique_ptr NewDefaultPlatform( - int thread_pool_size = 0, - IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, - InProcessStackDumping in_process_stack_dumping = - InProcessStackDumping::kDisabled, - std::unique_ptr tracing_controller = {}); - -/** - * The same as NewDefaultPlatform but disables the worker thread pool. - * It must be used with the --single-threaded V8 flag. - */ -V8_PLATFORM_EXPORT std::unique_ptr -NewSingleThreadedDefaultPlatform( - IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, - InProcessStackDumping in_process_stack_dumping = - InProcessStackDumping::kDisabled, - std::unique_ptr tracing_controller = {}); - -/** - * Returns a new instance of the default v8::JobHandle implementation. - * - * The job will be executed by spawning up to |num_worker_threads| many worker - * threads on the provided |platform| with the given |priority|. - */ -V8_PLATFORM_EXPORT std::unique_ptr NewDefaultJobHandle( - v8::Platform* platform, v8::TaskPriority priority, - std::unique_ptr job_task, size_t num_worker_threads); - -/** - * Pumps the message loop for the given isolate. - * - * The caller has to make sure that this is called from the right thread. - * Returns true if a task was executed, and false otherwise. If the call to - * PumpMessageLoop is nested within another call to PumpMessageLoop, only - * nestable tasks may run. Otherwise, any task may run. Unless requested through - * the |behavior| parameter, this call does not block if no task is pending. The - * |platform| has to be created using |NewDefaultPlatform|. - */ -V8_PLATFORM_EXPORT bool PumpMessageLoop( - v8::Platform* platform, v8::Isolate* isolate, - MessageLoopBehavior behavior = MessageLoopBehavior::kDoNotWait); - -/** - * Runs pending idle tasks for at most |idle_time_in_seconds| seconds. - * - * The caller has to make sure that this is called from the right thread. - * This call does not block if no task is pending. The |platform| has to be - * created using |NewDefaultPlatform|. - */ -V8_PLATFORM_EXPORT void RunIdleTasks(v8::Platform* platform, - v8::Isolate* isolate, - double idle_time_in_seconds); - -/** - * Attempts to set the tracing controller for the given platform. - * - * The |platform| has to be created using |NewDefaultPlatform|. - * - */ -V8_DEPRECATE_SOON("Access the DefaultPlatform directly") -V8_PLATFORM_EXPORT void SetTracingController( - v8::Platform* platform, - v8::platform::tracing::TracingController* tracing_controller); - -/** - * Notifies the given platform about the Isolate getting deleted soon. Has to be - * called for all Isolates which are deleted - unless we're shutting down the - * platform. - * - * The |platform| has to be created using |NewDefaultPlatform|. - * - */ -V8_PLATFORM_EXPORT void NotifyIsolateShutdown(v8::Platform* platform, - Isolate* isolate); - -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_LIBPLATFORM_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/v8-tracing.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/v8-tracing.h deleted file mode 100644 index c7a5c4f9f5f..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/libplatform/v8-tracing.h +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_LIBPLATFORM_V8_TRACING_H_ -#define V8_LIBPLATFORM_V8_TRACING_H_ - -#include -#include -#include -#include -#include - -#include "libplatform/libplatform-export.h" -#include "v8-platform.h" // NOLINT(build/include_directory) - -namespace perfetto { -namespace trace_processor { -class TraceProcessorStorage; -} -class TracingSession; -} - -namespace v8 { - -namespace base { -class Mutex; -} // namespace base - -namespace platform { -namespace tracing { - -class TraceEventListener; - -const int kTraceMaxNumArgs = 2; - -class V8_PLATFORM_EXPORT TraceObject { - public: - union ArgValue { - V8_DEPRECATED("use as_uint ? true : false") bool as_bool; - uint64_t as_uint; - int64_t as_int; - double as_double; - const void* as_pointer; - const char* as_string; - }; - - TraceObject() = default; - ~TraceObject(); - void Initialize( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int64_t timestamp, int64_t cpu_timestamp); - void UpdateDuration(int64_t timestamp, int64_t cpu_timestamp); - void InitializeForTesting( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int pid, int tid, int64_t ts, int64_t tts, - uint64_t duration, uint64_t cpu_duration); - - int pid() const { return pid_; } - int tid() const { return tid_; } - char phase() const { return phase_; } - const uint8_t* category_enabled_flag() const { - return category_enabled_flag_; - } - const char* name() const { return name_; } - const char* scope() const { return scope_; } - uint64_t id() const { return id_; } - uint64_t bind_id() const { return bind_id_; } - int num_args() const { return num_args_; } - const char** arg_names() { return arg_names_; } - uint8_t* arg_types() { return arg_types_; } - ArgValue* arg_values() { return arg_values_; } - std::unique_ptr* arg_convertables() { - return arg_convertables_; - } - unsigned int flags() const { return flags_; } - int64_t ts() { return ts_; } - int64_t tts() { return tts_; } - uint64_t duration() { return duration_; } - uint64_t cpu_duration() { return cpu_duration_; } - - private: - int pid_; - int tid_; - char phase_; - const char* name_; - const char* scope_; - const uint8_t* category_enabled_flag_; - uint64_t id_; - uint64_t bind_id_; - int num_args_ = 0; - const char* arg_names_[kTraceMaxNumArgs]; - uint8_t arg_types_[kTraceMaxNumArgs]; - ArgValue arg_values_[kTraceMaxNumArgs]; - std::unique_ptr - arg_convertables_[kTraceMaxNumArgs]; - char* parameter_copy_storage_ = nullptr; - unsigned int flags_; - int64_t ts_; - int64_t tts_; - uint64_t duration_; - uint64_t cpu_duration_; - - // Disallow copy and assign - TraceObject(const TraceObject&) = delete; - void operator=(const TraceObject&) = delete; -}; - -class V8_PLATFORM_EXPORT TraceWriter { - public: - TraceWriter() = default; - virtual ~TraceWriter() = default; - virtual void AppendTraceEvent(TraceObject* trace_event) = 0; - virtual void Flush() = 0; - - static TraceWriter* CreateJSONTraceWriter(std::ostream& stream); - static TraceWriter* CreateJSONTraceWriter(std::ostream& stream, - const std::string& tag); - - static TraceWriter* CreateSystemInstrumentationTraceWriter(); - - private: - // Disallow copy and assign - TraceWriter(const TraceWriter&) = delete; - void operator=(const TraceWriter&) = delete; -}; - -class V8_PLATFORM_EXPORT TraceBufferChunk { - public: - explicit TraceBufferChunk(uint32_t seq); - - void Reset(uint32_t new_seq); - bool IsFull() const { return next_free_ == kChunkSize; } - TraceObject* AddTraceEvent(size_t* event_index); - TraceObject* GetEventAt(size_t index) { return &chunk_[index]; } - - uint32_t seq() const { return seq_; } - size_t size() const { return next_free_; } - - static const size_t kChunkSize = 64; - - private: - size_t next_free_ = 0; - TraceObject chunk_[kChunkSize]; - uint32_t seq_; - - // Disallow copy and assign - TraceBufferChunk(const TraceBufferChunk&) = delete; - void operator=(const TraceBufferChunk&) = delete; -}; - -class V8_PLATFORM_EXPORT TraceBuffer { - public: - TraceBuffer() = default; - virtual ~TraceBuffer() = default; - - virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0; - virtual TraceObject* GetEventByHandle(uint64_t handle) = 0; - virtual bool Flush() = 0; - - static const size_t kRingBufferChunks = 1024; - - static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks, - TraceWriter* trace_writer); - - private: - // Disallow copy and assign - TraceBuffer(const TraceBuffer&) = delete; - void operator=(const TraceBuffer&) = delete; -}; - -// Options determines how the trace buffer stores data. -enum TraceRecordMode { - // Record until the trace buffer is full. - RECORD_UNTIL_FULL, - - // Record until the user ends the trace. The trace buffer is a fixed size - // and we use it as a ring buffer during recording. - RECORD_CONTINUOUSLY, - - // Record until the trace buffer is full, but with a huge buffer size. - RECORD_AS_MUCH_AS_POSSIBLE, - - // Echo to console. Events are discarded. - ECHO_TO_CONSOLE, -}; - -class V8_PLATFORM_EXPORT TraceConfig { - public: - typedef std::vector StringList; - - static TraceConfig* CreateDefaultTraceConfig(); - - TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {} - TraceRecordMode GetTraceRecordMode() const { return record_mode_; } - const StringList& GetEnabledCategories() const { - return included_categories_; - } - bool IsSystraceEnabled() const { return enable_systrace_; } - bool IsArgumentFilterEnabled() const { return enable_argument_filter_; } - - void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; } - void EnableSystrace() { enable_systrace_ = true; } - void EnableArgumentFilter() { enable_argument_filter_ = true; } - - void AddIncludedCategory(const char* included_category); - - bool IsCategoryGroupEnabled(const char* category_group) const; - - private: - TraceRecordMode record_mode_; - bool enable_systrace_ : 1; - bool enable_argument_filter_ : 1; - StringList included_categories_; - - // Disallow copy and assign - TraceConfig(const TraceConfig&) = delete; - void operator=(const TraceConfig&) = delete; -}; - -#if defined(_MSC_VER) -#define V8_PLATFORM_NON_EXPORTED_BASE(code) \ - __pragma(warning(suppress : 4275)) code -#else -#define V8_PLATFORM_NON_EXPORTED_BASE(code) code -#endif // defined(_MSC_VER) - -class V8_PLATFORM_EXPORT TracingController - : public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) { - public: - TracingController(); - ~TracingController() override; - -#if defined(V8_USE_PERFETTO) - // Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides - // the output stream for the JSON trace data. - void InitializeForPerfetto(std::ostream* output_stream); - // Provide an optional listener for testing that will receive trace events. - // Must be called before StartTracing(). - void SetTraceEventListenerForTesting(TraceEventListener* listener); -#else // defined(V8_USE_PERFETTO) - // The pointer returned from GetCategoryGroupEnabled() points to a value with - // zero or more of the following bits. Used in this class only. The - // TRACE_EVENT macros should only use the value as a bool. These values must - // be in sync with macro values in TraceEvent.h in Blink. - enum CategoryGroupEnabledFlags { - // Category group enabled for the recording mode. - ENABLED_FOR_RECORDING = 1 << 0, - // Category group enabled by SetEventCallbackEnabled(). - ENABLED_FOR_EVENT_CALLBACK = 1 << 2, - // Category group enabled to export events to ETW. - ENABLED_FOR_ETW_EXPORT = 1 << 3 - }; - - // Takes ownership of |trace_buffer|. - void Initialize(TraceBuffer* trace_buffer); - - // v8::TracingController implementation. - const uint8_t* GetCategoryGroupEnabled(const char* category_group) override; - uint64_t AddTraceEvent( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags) override; - uint64_t AddTraceEventWithTimestamp( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int64_t timestamp) override; - void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, - const char* name, uint64_t handle) override; - - static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); -#endif // !defined(V8_USE_PERFETTO) - - void AddTraceStateObserver( - v8::TracingController::TraceStateObserver* observer) override; - void RemoveTraceStateObserver( - v8::TracingController::TraceStateObserver* observer) override; - - void StartTracing(TraceConfig* trace_config); - void StopTracing(); - - protected: -#if !defined(V8_USE_PERFETTO) - virtual int64_t CurrentTimestampMicroseconds(); - virtual int64_t CurrentCpuTimestampMicroseconds(); -#endif // !defined(V8_USE_PERFETTO) - - private: -#if !defined(V8_USE_PERFETTO) - void UpdateCategoryGroupEnabledFlag(size_t category_index); - void UpdateCategoryGroupEnabledFlags(); -#endif // !defined(V8_USE_PERFETTO) - - std::unique_ptr mutex_; - std::unique_ptr trace_config_; - std::atomic_bool recording_{false}; - std::unordered_set observers_; - -#if defined(V8_USE_PERFETTO) - std::ostream* output_stream_ = nullptr; - std::unique_ptr - trace_processor_; - TraceEventListener* listener_for_testing_ = nullptr; - std::unique_ptr tracing_session_; -#else // !defined(V8_USE_PERFETTO) - std::unique_ptr trace_buffer_; -#endif // !defined(V8_USE_PERFETTO) - - // Disallow copy and assign - TracingController(const TracingController&) = delete; - void operator=(const TracingController&) = delete; -}; - -#undef V8_PLATFORM_NON_EXPORTED_BASE - -} // namespace tracing -} // namespace platform -} // namespace v8 - -#endif // V8_LIBPLATFORM_V8_TRACING_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-array-buffer.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-array-buffer.h deleted file mode 100644 index 0ce2b653684..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-array-buffer.h +++ /dev/null @@ -1,433 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_ARRAY_BUFFER_H_ -#define INCLUDE_V8_ARRAY_BUFFER_H_ - -#include - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class SharedArrayBuffer; - -#ifndef V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT -// The number of required internal fields can be defined by embedder. -#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2 -#endif - -enum class ArrayBufferCreationMode { kInternalized, kExternalized }; - -/** - * A wrapper around the backing store (i.e. the raw memory) of an array buffer. - * See a document linked in http://crbug.com/v8/9908 for more information. - * - * The allocation and destruction of backing stores is generally managed by - * V8. Clients should always use standard C++ memory ownership types (i.e. - * std::unique_ptr and std::shared_ptr) to manage lifetimes of backing stores - * properly, since V8 internal objects may alias backing stores. - * - * This object does not keep the underlying |ArrayBuffer::Allocator| alive by - * default. Use Isolate::CreateParams::array_buffer_allocator_shared when - * creating the Isolate to make it hold a reference to the allocator itself. - */ -class V8_EXPORT BackingStore : public v8::internal::BackingStoreBase { - public: - ~BackingStore(); - - /** - * Return a pointer to the beginning of the memory block for this backing - * store. The pointer is only valid as long as this backing store object - * lives. - */ - void* Data() const; - - /** - * The length (in bytes) of this backing store. - */ - size_t ByteLength() const; - - /** - * Indicates whether the backing store was created for an ArrayBuffer or - * a SharedArrayBuffer. - */ - bool IsShared() const; - - /** - * Prevent implicit instantiation of operator delete with size_t argument. - * The size_t argument would be incorrect because ptr points to the - * internal BackingStore object. - */ - void operator delete(void* ptr) { ::operator delete(ptr); } - - /** - * Wrapper around ArrayBuffer::Allocator::Reallocate that preserves IsShared. - * Assumes that the backing_store was allocated by the ArrayBuffer allocator - * of the given isolate. - */ - static std::unique_ptr Reallocate( - v8::Isolate* isolate, std::unique_ptr backing_store, - size_t byte_length); - - /** - * This callback is used only if the memory block for a BackingStore cannot be - * allocated with an ArrayBuffer::Allocator. In such cases the destructor of - * the BackingStore invokes the callback to free the memory block. - */ - using DeleterCallback = void (*)(void* data, size_t length, - void* deleter_data); - - /** - * If the memory block of a BackingStore is static or is managed manually, - * then this empty deleter along with nullptr deleter_data can be passed to - * ArrayBuffer::NewBackingStore to indicate that. - * - * The manually managed case should be used with caution and only when it - * is guaranteed that the memory block freeing happens after detaching its - * ArrayBuffer. - */ - static void EmptyDeleter(void* data, size_t length, void* deleter_data); - - private: - /** - * See [Shared]ArrayBuffer::GetBackingStore and - * [Shared]ArrayBuffer::NewBackingStore. - */ - BackingStore(); -}; - -#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS) -// Use v8::BackingStore::DeleterCallback instead. -using BackingStoreDeleterCallback = void (*)(void* data, size_t length, - void* deleter_data); - -#endif - -/** - * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). - */ -class V8_EXPORT ArrayBuffer : public Object { - public: - /** - * A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory. - * The allocator is a global V8 setting. It has to be set via - * Isolate::CreateParams. - * - * Memory allocated through this allocator by V8 is accounted for as external - * memory by V8. Note that V8 keeps track of the memory for all internalized - * |ArrayBuffer|s. Responsibility for tracking external memory (using - * Isolate::AdjustAmountOfExternalAllocatedMemory) is handed over to the - * embedder upon externalization and taken over upon internalization (creating - * an internalized buffer from an existing buffer). - * - * Note that it is unsafe to call back into V8 from any of the allocator - * functions. - */ - class V8_EXPORT Allocator { - public: - virtual ~Allocator() = default; - - /** - * Allocate |length| bytes. Return nullptr if allocation is not successful. - * Memory should be initialized to zeroes. - */ - virtual void* Allocate(size_t length) = 0; - - /** - * Allocate |length| bytes. Return nullptr if allocation is not successful. - * Memory does not have to be initialized. - */ - virtual void* AllocateUninitialized(size_t length) = 0; - - /** - * Free the memory block of size |length|, pointed to by |data|. - * That memory is guaranteed to be previously allocated by |Allocate|. - */ - virtual void Free(void* data, size_t length) = 0; - - /** - * Reallocate the memory block of size |old_length| to a memory block of - * size |new_length| by expanding, contracting, or copying the existing - * memory block. If |new_length| > |old_length|, then the new part of - * the memory must be initialized to zeros. Return nullptr if reallocation - * is not successful. - * - * The caller guarantees that the memory block was previously allocated - * using Allocate or AllocateUninitialized. - * - * The default implementation allocates a new block and copies data. - */ - virtual void* Reallocate(void* data, size_t old_length, size_t new_length); - - /** - * ArrayBuffer allocation mode. kNormal is a malloc/free style allocation, - * while kReservation is for larger allocations with the ability to set - * access permissions. - */ - enum class AllocationMode { kNormal, kReservation }; - - /** - * Convenience allocator. - * - * When the virtual memory cage is enabled, this allocator will allocate its - * backing memory inside the cage. Otherwise, it will rely on malloc/free. - * - * Caller takes ownership, i.e. the returned object needs to be freed using - * |delete allocator| once it is no longer in use. - */ - static Allocator* NewDefaultAllocator(); - }; - - /** - * Data length in bytes. - */ - size_t ByteLength() const; - - /** - * Create a new ArrayBuffer. Allocate |byte_length| bytes. - * Allocated memory will be owned by a created ArrayBuffer and - * will be deallocated when it is garbage-collected, - * unless the object is externalized. - */ - static Local New(Isolate* isolate, size_t byte_length); - - /** - * Create a new ArrayBuffer with an existing backing store. - * The created array keeps a reference to the backing store until the array - * is garbage collected. Note that the IsExternal bit does not affect this - * reference from the array to the backing store. - * - * In future IsExternal bit will be removed. Until then the bit is set as - * follows. If the backing store does not own the underlying buffer, then - * the array is created in externalized state. Otherwise, the array is created - * in internalized state. In the latter case the array can be transitioned - * to the externalized state using Externalize(backing_store). - */ - static Local New(Isolate* isolate, - std::shared_ptr backing_store); - - /** - * Returns a new standalone BackingStore that is allocated using the array - * buffer allocator of the isolate. The result can be later passed to - * ArrayBuffer::New. - * - * If the allocator returns nullptr, then the function may cause GCs in the - * given isolate and re-try the allocation. If GCs do not help, then the - * function will crash with an out-of-memory error. - */ - static std::unique_ptr NewBackingStore(Isolate* isolate, - size_t byte_length); - /** - * Returns a new standalone BackingStore that takes over the ownership of - * the given buffer. The destructor of the BackingStore invokes the given - * deleter callback. - * - * The result can be later passed to ArrayBuffer::New. The raw pointer - * to the buffer must not be passed again to any V8 API function. - */ - static std::unique_ptr NewBackingStore( - void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, - void* deleter_data); - - /** - * Returns true if this ArrayBuffer may be detached. - */ - bool IsDetachable() const; - - /** - * Detaches this ArrayBuffer and all its views (typed arrays). - * Detaching sets the byte length of the buffer and all typed arrays to zero, - * preventing JavaScript from ever accessing underlying backing store. - * ArrayBuffer should have been externalized and must be detachable. - */ - void Detach(); - - /** - * Get a shared pointer to the backing store of this array buffer. This - * pointer coordinates the lifetime management of the internal storage - * with any live ArrayBuffers on the heap, even across isolates. The embedder - * should not attempt to manage lifetime of the storage through other means. - */ - std::shared_ptr GetBackingStore(); - - V8_INLINE static ArrayBuffer* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - static const int kEmbedderFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - - private: - ArrayBuffer(); - static void CheckCast(Value* obj); -}; - -#ifndef V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT -// The number of required internal fields can be defined by embedder. -#define V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT 2 -#endif - -/** - * A base class for an instance of one of "views" over ArrayBuffer, - * including TypedArrays and DataView (ES6 draft 15.13). - */ -class V8_EXPORT ArrayBufferView : public Object { - public: - /** - * Returns underlying ArrayBuffer. - */ - Local Buffer(); - /** - * Byte offset in |Buffer|. - */ - size_t ByteOffset(); - /** - * Size of a view in bytes. - */ - size_t ByteLength(); - - /** - * Copy the contents of the ArrayBufferView's buffer to an embedder defined - * memory without additional overhead that calling ArrayBufferView::Buffer - * might incur. - * - * Will write at most min(|byte_length|, ByteLength) bytes starting at - * ByteOffset of the underlying buffer to the memory starting at |dest|. - * Returns the number of bytes actually written. - */ - size_t CopyContents(void* dest, size_t byte_length); - - /** - * Returns true if ArrayBufferView's backing ArrayBuffer has already been - * allocated. - */ - bool HasBuffer() const; - - V8_INLINE static ArrayBufferView* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kInternalFieldCount = - V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; - static const int kEmbedderFieldCount = - V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT; - - private: - ArrayBufferView(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of DataView constructor (ES6 draft 15.13.7). - */ -class V8_EXPORT DataView : public ArrayBufferView { - public: - static Local New(Local array_buffer, - size_t byte_offset, size_t length); - static Local New(Local shared_array_buffer, - size_t byte_offset, size_t length); - V8_INLINE static DataView* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - DataView(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of the built-in SharedArrayBuffer constructor. - */ -class V8_EXPORT SharedArrayBuffer : public Object { - public: - /** - * Data length in bytes. - */ - size_t ByteLength() const; - - /** - * Create a new SharedArrayBuffer. Allocate |byte_length| bytes. - * Allocated memory will be owned by a created SharedArrayBuffer and - * will be deallocated when it is garbage-collected, - * unless the object is externalized. - */ - static Local New(Isolate* isolate, size_t byte_length); - - /** - * Create a new SharedArrayBuffer with an existing backing store. - * The created array keeps a reference to the backing store until the array - * is garbage collected. Note that the IsExternal bit does not affect this - * reference from the array to the backing store. - * - * In future IsExternal bit will be removed. Until then the bit is set as - * follows. If the backing store does not own the underlying buffer, then - * the array is created in externalized state. Otherwise, the array is created - * in internalized state. In the latter case the array can be transitioned - * to the externalized state using Externalize(backing_store). - */ - static Local New( - Isolate* isolate, std::shared_ptr backing_store); - - /** - * Returns a new standalone BackingStore that is allocated using the array - * buffer allocator of the isolate. The result can be later passed to - * SharedArrayBuffer::New. - * - * If the allocator returns nullptr, then the function may cause GCs in the - * given isolate and re-try the allocation. If GCs do not help, then the - * function will crash with an out-of-memory error. - */ - static std::unique_ptr NewBackingStore(Isolate* isolate, - size_t byte_length); - /** - * Returns a new standalone BackingStore that takes over the ownership of - * the given buffer. The destructor of the BackingStore invokes the given - * deleter callback. - * - * The result can be later passed to SharedArrayBuffer::New. The raw pointer - * to the buffer must not be passed again to any V8 functions. - */ - static std::unique_ptr NewBackingStore( - void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, - void* deleter_data); - - /** - * Get a shared pointer to the backing store of this array buffer. This - * pointer coordinates the lifetime management of the internal storage - * with any live ArrayBuffers on the heap, even across isolates. The embedder - * should not attempt to manage lifetime of the storage through other means. - */ - std::shared_ptr GetBackingStore(); - - V8_INLINE static SharedArrayBuffer* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - - private: - SharedArrayBuffer(); - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_ARRAY_BUFFER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-callbacks.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-callbacks.h deleted file mode 100644 index ff894161f42..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-callbacks.h +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_ISOLATE_CALLBACKS_H_ -#define INCLUDE_V8_ISOLATE_CALLBACKS_H_ - -#include - -#include - -#include "cppgc/common.h" -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -#if defined(V8_OS_WIN) -struct _EXCEPTION_POINTERS; -#endif - -namespace v8 { - -template -class FunctionCallbackInfo; -class Isolate; -class Message; -class Module; -class Object; -class Promise; -class ScriptOrModule; -class String; -class UnboundScript; -class Value; - -/** - * A JIT code event is issued each time code is added, moved or removed. - * - * \note removal events are not currently issued. - */ -struct JitCodeEvent { - enum EventType { - CODE_ADDED, - CODE_MOVED, - CODE_REMOVED, - CODE_ADD_LINE_POS_INFO, - CODE_START_LINE_INFO_RECORDING, - CODE_END_LINE_INFO_RECORDING - }; - // Definition of the code position type. The "POSITION" type means the place - // in the source code which are of interest when making stack traces to - // pin-point the source location of a stack frame as close as possible. - // The "STATEMENT_POSITION" means the place at the beginning of each - // statement, and is used to indicate possible break locations. - enum PositionType { POSITION, STATEMENT_POSITION }; - - // There are three different kinds of CodeType, one for JIT code generated - // by the optimizing compiler, one for byte code generated for the - // interpreter, and one for code generated from Wasm. For JIT_CODE and - // WASM_CODE, |code_start| points to the beginning of jitted assembly code, - // while for BYTE_CODE events, |code_start| points to the first bytecode of - // the interpreted function. - enum CodeType { BYTE_CODE, JIT_CODE, WASM_CODE }; - - // Type of event. - EventType type; - CodeType code_type; - // Start of the instructions. - void* code_start; - // Size of the instructions. - size_t code_len; - // Script info for CODE_ADDED event. - Local script; - // User-defined data for *_LINE_INFO_* event. It's used to hold the source - // code line information which is returned from the - // CODE_START_LINE_INFO_RECORDING event. And it's passed to subsequent - // CODE_ADD_LINE_POS_INFO and CODE_END_LINE_INFO_RECORDING events. - void* user_data; - - struct name_t { - // Name of the object associated with the code, note that the string is not - // zero-terminated. - const char* str; - // Number of chars in str. - size_t len; - }; - - struct line_info_t { - // PC offset - size_t offset; - // Code position - size_t pos; - // The position type. - PositionType position_type; - }; - - struct wasm_source_info_t { - // Source file name. - const char* filename; - // Length of filename. - size_t filename_size; - // Line number table, which maps offsets of JITted code to line numbers of - // source file. - const line_info_t* line_number_table; - // Number of entries in the line number table. - size_t line_number_table_size; - }; - - wasm_source_info_t* wasm_source_info; - - union { - // Only valid for CODE_ADDED. - struct name_t name; - - // Only valid for CODE_ADD_LINE_POS_INFO - struct line_info_t line_info; - - // New location of instructions. Only valid for CODE_MOVED. - void* new_code_start; - }; - - Isolate* isolate; -}; - -/** - * Option flags passed to the SetJitCodeEventHandler function. - */ -enum JitCodeEventOptions { - kJitCodeEventDefault = 0, - // Generate callbacks for already existent code. - kJitCodeEventEnumExisting = 1 -}; - -/** - * Callback function passed to SetJitCodeEventHandler. - * - * \param event code add, move or removal event. - */ -using JitCodeEventHandler = void (*)(const JitCodeEvent* event); - -// --- Garbage Collection Callbacks --- - -/** - * Applications can register callback functions which will be called before and - * after certain garbage collection operations. Allocations are not allowed in - * the callback functions, you therefore cannot manipulate objects (set or - * delete properties for example) since it is possible such operations will - * result in the allocation of objects. - */ -enum GCType { - kGCTypeScavenge = 1 << 0, - kGCTypeMarkSweepCompact = 1 << 1, - kGCTypeIncrementalMarking = 1 << 2, - kGCTypeProcessWeakCallbacks = 1 << 3, - kGCTypeAll = kGCTypeScavenge | kGCTypeMarkSweepCompact | - kGCTypeIncrementalMarking | kGCTypeProcessWeakCallbacks -}; - -/** - * GCCallbackFlags is used to notify additional information about the GC - * callback. - * - kGCCallbackFlagConstructRetainedObjectInfos: The GC callback is for - * constructing retained object infos. - * - kGCCallbackFlagForced: The GC callback is for a forced GC for testing. - * - kGCCallbackFlagSynchronousPhantomCallbackProcessing: The GC callback - * is called synchronously without getting posted to an idle task. - * - kGCCallbackFlagCollectAllAvailableGarbage: The GC callback is called - * in a phase where V8 is trying to collect all available garbage - * (e.g., handling a low memory notification). - * - kGCCallbackScheduleIdleGarbageCollection: The GC callback is called to - * trigger an idle garbage collection. - */ -enum GCCallbackFlags { - kNoGCCallbackFlags = 0, - kGCCallbackFlagConstructRetainedObjectInfos = 1 << 1, - kGCCallbackFlagForced = 1 << 2, - kGCCallbackFlagSynchronousPhantomCallbackProcessing = 1 << 3, - kGCCallbackFlagCollectAllAvailableGarbage = 1 << 4, - kGCCallbackFlagCollectAllExternalMemory = 1 << 5, - kGCCallbackScheduleIdleGarbageCollection = 1 << 6, -}; - -using GCCallback = void (*)(GCType type, GCCallbackFlags flags); - -using InterruptCallback = void (*)(Isolate* isolate, void* data); - -/** - * This callback is invoked when the heap size is close to the heap limit and - * V8 is likely to abort with out-of-memory error. - * The callback can extend the heap limit by returning a value that is greater - * than the current_heap_limit. The initial heap limit is the limit that was - * set after heap setup. - */ -using NearHeapLimitCallback = size_t (*)(void* data, size_t current_heap_limit, - size_t initial_heap_limit); - -/** - * Callback function passed to SetUnhandledExceptionCallback. - */ -#if defined(V8_OS_WIN) -using UnhandledExceptionCallback = - int (*)(_EXCEPTION_POINTERS* exception_pointers); -#endif - -// --- Counters Callbacks --- - -using CounterLookupCallback = int* (*)(const char* name); - -using CreateHistogramCallback = void* (*)(const char* name, int min, int max, - size_t buckets); - -using AddHistogramSampleCallback = void (*)(void* histogram, int sample); - -/** - * HostImportModuleDynamicallyCallback is called when we require the - * embedder to load a module. This is used as part of the dynamic - * import syntax. - * - * The referrer contains metadata about the script/module that calls - * import. - * - * The specifier is the name of the module that should be imported. - * - * The embedder must compile, instantiate, evaluate the Module, and - * obtain its namespace object. - * - * The Promise returned from this function is forwarded to userland - * JavaScript. The embedder must resolve this promise with the module - * namespace object. In case of an exception, the embedder must reject - * this promise with the exception. If the promise creation itself - * fails (e.g. due to stack overflow), the embedder must propagate - * that exception by returning an empty MaybeLocal. - */ -using HostImportModuleDynamicallyCallback V8_DEPRECATED( - "Use HostImportModuleDynamicallyWithImportAssertionsCallback instead") = - MaybeLocal (*)(Local context, - Local referrer, - Local specifier); - -// --- Exceptions --- - -using FatalErrorCallback = void (*)(const char* location, const char* message); - -using OOMErrorCallback = void (*)(const char* location, bool is_heap_oom); - -using MessageCallback = void (*)(Local message, Local data); - -// --- Tracing --- - -enum LogEventStatus : int { kStart = 0, kEnd = 1, kStamp = 2 }; -using LogEventCallback = void (*)(const char* name, - int /* LogEventStatus */ status); - -// --- Crashkeys Callback --- -enum class CrashKeyId { - kIsolateAddress, - kReadonlySpaceFirstPageAddress, - kMapSpaceFirstPageAddress, - kCodeSpaceFirstPageAddress, - kDumpType, -}; - -using AddCrashKeyCallback = void (*)(CrashKeyId id, const std::string& value); - -// --- Enter/Leave Script Callback --- -using BeforeCallEnteredCallback = void (*)(Isolate*); -using CallCompletedCallback = void (*)(Isolate*); - -// --- AllowCodeGenerationFromStrings callbacks --- - -/** - * Callback to check if code generation from strings is allowed. See - * Context::AllowCodeGenerationFromStrings. - */ -using AllowCodeGenerationFromStringsCallback = bool (*)(Local context, - Local source); - -struct ModifyCodeGenerationFromStringsResult { - // If true, proceed with the codegen algorithm. Otherwise, block it. - bool codegen_allowed = false; - // Overwrite the original source with this string, if present. - // Use the original source if empty. - // This field is considered only if codegen_allowed is true. - MaybeLocal modified_source; -}; - -/** - * Access type specification. - */ -enum AccessType { - ACCESS_GET, - ACCESS_SET, - ACCESS_HAS, - ACCESS_DELETE, - ACCESS_KEYS -}; - -// --- Failed Access Check Callback --- - -using FailedAccessCheckCallback = void (*)(Local target, - AccessType type, Local data); - -/** - * Callback to check if codegen is allowed from a source object, and convert - * the source to string if necessary. See: ModifyCodeGenerationFromStrings. - */ -using ModifyCodeGenerationFromStringsCallback = - ModifyCodeGenerationFromStringsResult (*)(Local context, - Local source); -using ModifyCodeGenerationFromStringsCallback2 = - ModifyCodeGenerationFromStringsResult (*)(Local context, - Local source, - bool is_code_like); - -// --- WebAssembly compilation callbacks --- -using ExtensionCallback = bool (*)(const FunctionCallbackInfo&); - -using AllowWasmCodeGenerationCallback = bool (*)(Local context, - Local source); - -// --- Callback for APIs defined on v8-supported objects, but implemented -// by the embedder. Example: WebAssembly.{compile|instantiate}Streaming --- -using ApiImplementationCallback = void (*)(const FunctionCallbackInfo&); - -// --- Callback for WebAssembly.compileStreaming --- -using WasmStreamingCallback = void (*)(const FunctionCallbackInfo&); - -// --- Callback for loading source map file for Wasm profiling support -using WasmLoadSourceMapCallback = Local (*)(Isolate* isolate, - const char* name); - -// --- Callback for checking if WebAssembly Simd is enabled --- -using WasmSimdEnabledCallback = bool (*)(Local context); - -// --- Callback for checking if WebAssembly exceptions are enabled --- -using WasmExceptionsEnabledCallback = bool (*)(Local context); - -// --- Callback for checking if the SharedArrayBuffer constructor is enabled --- -using SharedArrayBufferConstructorEnabledCallback = - bool (*)(Local context); - -/** - * HostImportModuleDynamicallyWithImportAssertionsCallback is called when we - * require the embedder to load a module. This is used as part of the dynamic - * import syntax. - * - * The referrer contains metadata about the script/module that calls - * import. - * - * The specifier is the name of the module that should be imported. - * - * The import_assertions are import assertions for this request in the form: - * [key1, value1, key2, value2, ...] where the keys and values are of type - * v8::String. Note, unlike the FixedArray passed to ResolveModuleCallback and - * returned from ModuleRequest::GetImportAssertions(), this array does not - * contain the source Locations of the assertions. - * - * The embedder must compile, instantiate, evaluate the Module, and - * obtain its namespace object. - * - * The Promise returned from this function is forwarded to userland - * JavaScript. The embedder must resolve this promise with the module - * namespace object. In case of an exception, the embedder must reject - * this promise with the exception. If the promise creation itself - * fails (e.g. due to stack overflow), the embedder must propagate - * that exception by returning an empty MaybeLocal. - */ -using HostImportModuleDynamicallyWithImportAssertionsCallback = - MaybeLocal (*)(Local context, - Local referrer, - Local specifier, - Local import_assertions); - -/** - * HostInitializeImportMetaObjectCallback is called the first time import.meta - * is accessed for a module. Subsequent access will reuse the same value. - * - * The method combines two implementation-defined abstract operations into one: - * HostGetImportMetaProperties and HostFinalizeImportMeta. - * - * The embedder should use v8::Object::CreateDataProperty to add properties on - * the meta object. - */ -using HostInitializeImportMetaObjectCallback = void (*)(Local context, - Local module, - Local meta); - -/** - * PrepareStackTraceCallback is called when the stack property of an error is - * first accessed. The return value will be used as the stack value. If this - * callback is registed, the |Error.prepareStackTrace| API will be disabled. - * |sites| is an array of call sites, specified in - * https://v8.dev/docs/stack-trace-api - */ -using PrepareStackTraceCallback = MaybeLocal (*)(Local context, - Local error, - Local sites); - -} // namespace v8 - -#endif // INCLUDE_V8_ISOLATE_CALLBACKS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-container.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-container.h deleted file mode 100644 index ce068603649..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-container.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_CONTAINER_H_ -#define INCLUDE_V8_CONTAINER_H_ - -#include -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; - -/** - * An instance of the built-in array constructor (ECMA-262, 15.4.2). - */ -class V8_EXPORT Array : public Object { - public: - uint32_t Length() const; - - /** - * Creates a JavaScript array with the given length. If the length - * is negative the returned array will have length 0. - */ - static Local New(Isolate* isolate, int length = 0); - - /** - * Creates a JavaScript array out of a Local array in C++ - * with a known length. - */ - static Local New(Isolate* isolate, Local* elements, - size_t length); - V8_INLINE static Array* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Array(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of the built-in Map constructor (ECMA-262, 6th Edition, 23.1.1). - */ -class V8_EXPORT Map : public Object { - public: - size_t Size() const; - void Clear(); - V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, - Local key); - V8_WARN_UNUSED_RESULT MaybeLocal Set(Local context, - Local key, - Local value); - V8_WARN_UNUSED_RESULT Maybe Has(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - Local key); - - /** - * Returns an array of length Size() * 2, where index N is the Nth key and - * index N + 1 is the Nth value. - */ - Local AsArray() const; - - /** - * Creates a new empty Map. - */ - static Local New(Isolate* isolate); - - V8_INLINE static Map* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Map(); - static void CheckCast(Value* obj); -}; - -/** - * An instance of the built-in Set constructor (ECMA-262, 6th Edition, 23.2.1). - */ -class V8_EXPORT Set : public Object { - public: - size_t Size() const; - void Clear(); - V8_WARN_UNUSED_RESULT MaybeLocal Add(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe Has(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - Local key); - - /** - * Returns an array of the keys in this Set. - */ - Local AsArray() const; - - /** - * Creates a new empty Set. - */ - static Local New(Isolate* isolate); - - V8_INLINE static Set* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Set(); - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_CONTAINER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-context.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-context.h deleted file mode 100644 index bd28c6c9c93..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-context.h +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_CONTEXT_H_ -#define INCLUDE_V8_CONTEXT_H_ - -#include - -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-snapshot.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Function; -class MicrotaskQueue; -class Object; -class ObjectTemplate; -class Value; -class String; - -/** - * A container for extension names. - */ -class V8_EXPORT ExtensionConfiguration { - public: - ExtensionConfiguration() : name_count_(0), names_(nullptr) {} - ExtensionConfiguration(int name_count, const char* names[]) - : name_count_(name_count), names_(names) {} - - const char** begin() const { return &names_[0]; } - const char** end() const { return &names_[name_count_]; } - - private: - const int name_count_; - const char** names_; -}; - -/** - * A sandboxed execution context with its own set of built-in objects - * and functions. - */ -class V8_EXPORT Context : public Data { - public: - /** - * Returns the global proxy object. - * - * Global proxy object is a thin wrapper whose prototype points to actual - * context's global object with the properties like Object, etc. This is done - * that way for security reasons (for more details see - * https://wiki.mozilla.org/Gecko:SplitWindow). - * - * Please note that changes to global proxy object prototype most probably - * would break VM---v8 expects only global object as a prototype of global - * proxy object. - */ - Local Global(); - - /** - * Detaches the global object from its context before - * the global object can be reused to create a new context. - */ - void DetachGlobal(); - - /** - * Creates a new context and returns a handle to the newly allocated - * context. - * - * \param isolate The isolate in which to create the context. - * - * \param extensions An optional extension configuration containing - * the extensions to be installed in the newly created context. - * - * \param global_template An optional object template from which the - * global object for the newly created context will be created. - * - * \param global_object An optional global object to be reused for - * the newly created context. This global object must have been - * created by a previous call to Context::New with the same global - * template. The state of the global object will be completely reset - * and only object identify will remain. - */ - static Local New( - Isolate* isolate, ExtensionConfiguration* extensions = nullptr, - MaybeLocal global_template = MaybeLocal(), - MaybeLocal global_object = MaybeLocal(), - DeserializeInternalFieldsCallback internal_fields_deserializer = - DeserializeInternalFieldsCallback(), - MicrotaskQueue* microtask_queue = nullptr); - - /** - * Create a new context from a (non-default) context snapshot. There - * is no way to provide a global object template since we do not create - * a new global object from template, but we can reuse a global object. - * - * \param isolate See v8::Context::New. - * - * \param context_snapshot_index The index of the context snapshot to - * deserialize from. Use v8::Context::New for the default snapshot. - * - * \param embedder_fields_deserializer Optional callback to deserialize - * internal fields. It should match the SerializeInternalFieldCallback used - * to serialize. - * - * \param extensions See v8::Context::New. - * - * \param global_object See v8::Context::New. - */ - static MaybeLocal FromSnapshot( - Isolate* isolate, size_t context_snapshot_index, - DeserializeInternalFieldsCallback embedder_fields_deserializer = - DeserializeInternalFieldsCallback(), - ExtensionConfiguration* extensions = nullptr, - MaybeLocal global_object = MaybeLocal(), - MicrotaskQueue* microtask_queue = nullptr); - - /** - * Returns an global object that isn't backed by an actual context. - * - * The global template needs to have access checks with handlers installed. - * If an existing global object is passed in, the global object is detached - * from its context. - * - * Note that this is different from a detached context where all accesses to - * the global proxy will fail. Instead, the access check handlers are invoked. - * - * It is also not possible to detach an object returned by this method. - * Instead, the access check handlers need to return nothing to achieve the - * same effect. - * - * It is possible, however, to create a new context from the global object - * returned by this method. - */ - static MaybeLocal NewRemoteContext( - Isolate* isolate, Local global_template, - MaybeLocal global_object = MaybeLocal()); - - /** - * Sets the security token for the context. To access an object in - * another context, the security tokens must match. - */ - void SetSecurityToken(Local token); - - /** Restores the security token to the default value. */ - void UseDefaultSecurityToken(); - - /** Returns the security token of this context.*/ - Local GetSecurityToken(); - - /** - * Enter this context. After entering a context, all code compiled - * and run is compiled and run in this context. If another context - * is already entered, this old context is saved so it can be - * restored when the new context is exited. - */ - void Enter(); - - /** - * Exit this context. Exiting the current context restores the - * context that was in place when entering the current context. - */ - void Exit(); - - /** Returns the isolate associated with a current context. */ - Isolate* GetIsolate(); - - /** Returns the microtask queue associated with a current context. */ - MicrotaskQueue* GetMicrotaskQueue(); - - /** - * The field at kDebugIdIndex used to be reserved for the inspector. - * It now serves no purpose. - */ - enum EmbedderDataFields { kDebugIdIndex = 0 }; - - /** - * Return the number of fields allocated for embedder data. - */ - uint32_t GetNumberOfEmbedderDataFields(); - - /** - * Gets the embedder data with the given index, which must have been set by a - * previous call to SetEmbedderData with the same index. - */ - V8_INLINE Local GetEmbedderData(int index); - - /** - * Gets the binding object used by V8 extras. Extra natives get a reference - * to this object and can use it to "export" functionality by adding - * properties. Extra natives can also "import" functionality by accessing - * properties added by the embedder using the V8 API. - */ - Local GetExtrasBindingObject(); - - /** - * Sets the embedder data with the given index, growing the data as - * needed. Note that index 0 currently has a special meaning for Chrome's - * debugger. - */ - void SetEmbedderData(int index, Local value); - - /** - * Gets a 2-byte-aligned native pointer from the embedder data with the given - * index, which must have been set by a previous call to - * SetAlignedPointerInEmbedderData with the same index. Note that index 0 - * currently has a special meaning for Chrome's debugger. - */ - V8_INLINE void* GetAlignedPointerFromEmbedderData(int index); - - /** - * Sets a 2-byte-aligned native pointer in the embedder data with the given - * index, growing the data as needed. Note that index 0 currently has a - * special meaning for Chrome's debugger. - */ - void SetAlignedPointerInEmbedderData(int index, void* value); - - /** - * Control whether code generation from strings is allowed. Calling - * this method with false will disable 'eval' and the 'Function' - * constructor for code running in this context. If 'eval' or the - * 'Function' constructor are used an exception will be thrown. - * - * If code generation from strings is not allowed the - * V8::AllowCodeGenerationFromStrings callback will be invoked if - * set before blocking the call to 'eval' or the 'Function' - * constructor. If that callback returns true, the call will be - * allowed, otherwise an exception will be thrown. If no callback is - * set an exception will be thrown. - */ - void AllowCodeGenerationFromStrings(bool allow); - - /** - * Returns true if code generation from strings is allowed for the context. - * For more details see AllowCodeGenerationFromStrings(bool) documentation. - */ - bool IsCodeGenerationFromStringsAllowed() const; - - /** - * Sets the error description for the exception that is thrown when - * code generation from strings is not allowed and 'eval' or the 'Function' - * constructor are called. - */ - void SetErrorMessageForCodeGenerationFromStrings(Local message); - - /** - * Return data that was previously attached to the context snapshot via - * SnapshotCreator, and removes the reference to it. - * Repeated call with the same index returns an empty MaybeLocal. - */ - template - V8_INLINE MaybeLocal GetDataFromSnapshotOnce(size_t index); - - /** - * If callback is set, abort any attempt to execute JavaScript in this - * context, call the specified callback, and throw an exception. - * To unset abort, pass nullptr as callback. - */ - using AbortScriptExecutionCallback = void (*)(Isolate* isolate, - Local context); - void SetAbortScriptExecution(AbortScriptExecutionCallback callback); - - /** - * Returns the value that was set or restored by - * SetContinuationPreservedEmbedderData(), if any. - */ - Local GetContinuationPreservedEmbedderData() const; - - /** - * Sets a value that will be stored on continuations and reset while the - * continuation runs. - */ - void SetContinuationPreservedEmbedderData(Local context); - - /** - * Set or clear hooks to be invoked for promise lifecycle operations. - * To clear a hook, set it to an empty v8::Function. Each function will - * receive the observed promise as the first argument. If a chaining - * operation is used on a promise, the init will additionally receive - * the parent promise as the second argument. - */ - void SetPromiseHooks(Local init_hook, Local before_hook, - Local after_hook, - Local resolve_hook); - - /** - * Stack-allocated class which sets the execution context for all - * operations executed within a local scope. - */ - class V8_NODISCARD Scope { - public: - explicit V8_INLINE Scope(Local context) : context_(context) { - context_->Enter(); - } - V8_INLINE ~Scope() { context_->Exit(); } - - private: - Local context_; - }; - - /** - * Stack-allocated class to support the backup incumbent settings object - * stack. - * https://html.spec.whatwg.org/multipage/webappapis.html#backup-incumbent-settings-object-stack - */ - class V8_EXPORT V8_NODISCARD BackupIncumbentScope final { - public: - /** - * |backup_incumbent_context| is pushed onto the backup incumbent settings - * object stack. - */ - explicit BackupIncumbentScope(Local backup_incumbent_context); - ~BackupIncumbentScope(); - - /** - * Returns address that is comparable with JS stack address. Note that JS - * stack may be allocated separately from the native stack. See also - * |TryCatch::JSStackComparableAddressPrivate| for details. - */ - V8_DEPRECATE_SOON( - "This is private V8 information that should not be exposed in the API.") - uintptr_t JSStackComparableAddress() const { - return JSStackComparableAddressPrivate(); - } - - private: - friend class internal::Isolate; - - uintptr_t JSStackComparableAddressPrivate() const { - return js_stack_comparable_address_; - } - - Local backup_incumbent_context_; - uintptr_t js_stack_comparable_address_ = 0; - const BackupIncumbentScope* prev_ = nullptr; - }; - - V8_INLINE static Context* Cast(Data* data); - - private: - friend class Value; - friend class Script; - friend class Object; - friend class Function; - - static void CheckCast(Data* obj); - - internal::Address* GetDataFromSnapshotOnce(size_t index); - Local SlowGetEmbedderData(int index); - void* SlowGetAlignedPointerFromEmbedderData(int index); -}; - -// --- Implementation --- - -Local Context::GetEmbedderData(int index) { -#ifndef V8_ENABLE_CHECKS - using A = internal::Address; - using I = internal::Internals; - A ctx = *reinterpret_cast(this); - A embedder_data = - I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); - int value_offset = - I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); - A value = I::ReadRawField(embedder_data, value_offset); -#ifdef V8_COMPRESS_POINTERS - // We read the full pointer value and then decompress it in order to avoid - // dealing with potential endiannes issues. - value = - I::DecompressTaggedAnyField(embedder_data, static_cast(value)); -#endif - internal::Isolate* isolate = internal::IsolateFromNeverReadOnlySpaceObject( - *reinterpret_cast(this)); - A* result = HandleScope::CreateHandle(isolate, value); - return Local(reinterpret_cast(result)); -#else - return SlowGetEmbedderData(index); -#endif -} - -void* Context::GetAlignedPointerFromEmbedderData(int index) { -#ifndef V8_ENABLE_CHECKS - using A = internal::Address; - using I = internal::Internals; - A ctx = *reinterpret_cast(this); - A embedder_data = - I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); - int value_offset = - I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); -#ifdef V8_HEAP_SANDBOX - value_offset += I::kEmbedderDataSlotRawPayloadOffset; -#endif - internal::Isolate* isolate = I::GetIsolateForHeapSandbox(ctx); - return reinterpret_cast( - I::ReadExternalPointerField(isolate, embedder_data, value_offset, - internal::kEmbedderDataSlotPayloadTag)); -#else - return SlowGetAlignedPointerFromEmbedderData(index); -#endif -} - -template -MaybeLocal Context::GetDataFromSnapshotOnce(size_t index) { - T* data = reinterpret_cast(GetDataFromSnapshotOnce(index)); - if (data) internal::PerformCastCheck(data); - return Local(data); -} - -Context* Context::Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); -} - -} // namespace v8 - -#endif // INCLUDE_V8_CONTEXT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-cppgc.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-cppgc.h deleted file mode 100644 index 813e0842fa7..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-cppgc.h +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_CPPGC_H_ -#define INCLUDE_V8_CPPGC_H_ - -#include -#include -#include - -#include "cppgc/common.h" -#include "cppgc/custom-space.h" -#include "cppgc/heap-statistics.h" -#include "cppgc/internal/write-barrier.h" -#include "cppgc/visitor.h" -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8-traced-handle.h" // NOLINT(build/include_directory) - -namespace cppgc { -class AllocationHandle; -class HeapHandle; -} // namespace cppgc - -namespace v8 { - -class Object; - -namespace internal { -class CppHeap; -} // namespace internal - -class CustomSpaceStatisticsReceiver; - -/** - * Describes how V8 wrapper objects maintain references to garbage-collected C++ - * objects. - */ -struct WrapperDescriptor final { - /** - * The index used on `v8::Ojbect::SetAlignedPointerFromInternalField()` and - * related APIs to add additional data to an object which is used to identify - * JS->C++ references. - */ - using InternalFieldIndex = int; - - /** - * Unknown embedder id. The value is reserved for internal usages and must not - * be used with `CppHeap`. - */ - static constexpr uint16_t kUnknownEmbedderId = UINT16_MAX; - - constexpr WrapperDescriptor(InternalFieldIndex wrappable_type_index, - InternalFieldIndex wrappable_instance_index, - uint16_t embedder_id_for_garbage_collected) - : wrappable_type_index(wrappable_type_index), - wrappable_instance_index(wrappable_instance_index), - embedder_id_for_garbage_collected(embedder_id_for_garbage_collected) {} - - /** - * Index of the wrappable type. - */ - InternalFieldIndex wrappable_type_index; - - /** - * Index of the wrappable instance. - */ - InternalFieldIndex wrappable_instance_index; - - /** - * Embedder id identifying instances of garbage-collected objects. It is - * expected that the first field of the wrappable type is a uint16_t holding - * the id. Only references to instances of wrappables types with an id of - * `embedder_id_for_garbage_collected` will be considered by CppHeap. - */ - uint16_t embedder_id_for_garbage_collected; -}; - -struct V8_EXPORT CppHeapCreateParams { - CppHeapCreateParams(const CppHeapCreateParams&) = delete; - CppHeapCreateParams& operator=(const CppHeapCreateParams&) = delete; - - std::vector> custom_spaces; - WrapperDescriptor wrapper_descriptor; -}; - -/** - * A heap for allocating managed C++ objects. - */ -class V8_EXPORT CppHeap { - public: - static std::unique_ptr Create(v8::Platform* platform, - const CppHeapCreateParams& params); - - virtual ~CppHeap() = default; - - /** - * \returns the opaque handle for allocating objects using - * `MakeGarbageCollected()`. - */ - cppgc::AllocationHandle& GetAllocationHandle(); - - /** - * \returns the opaque heap handle which may be used to refer to this heap in - * other APIs. Valid as long as the underlying `CppHeap` is alive. - */ - cppgc::HeapHandle& GetHeapHandle(); - - /** - * Terminate clears all roots and performs multiple garbage collections to - * reclaim potentially newly created objects in destructors. - * - * After this call, object allocation is prohibited. - */ - void Terminate(); - - /** - * \param detail_level specifies whether should return detailed - * statistics or only brief summary statistics. - * \returns current CppHeap statistics regarding memory consumption - * and utilization. - */ - cppgc::HeapStatistics CollectStatistics( - cppgc::HeapStatistics::DetailLevel detail_level); - - /** - * Collects statistics for the given spaces and reports them to the receiver. - * - * \param custom_spaces a collection of custom space indicies. - * \param receiver an object that gets the results. - */ - void CollectCustomSpaceStatisticsAtLastGC( - std::vector custom_spaces, - std::unique_ptr receiver); - - /** - * Enables a detached mode that allows testing garbage collection using - * `cppgc::testing` APIs. Once used, the heap cannot be attached to an - * `Isolate` anymore. - */ - void EnableDetachedGarbageCollectionsForTesting(); - - /** - * Performs a stop-the-world garbage collection for testing purposes. - * - * \param stack_state The stack state to assume for the garbage collection. - */ - void CollectGarbageForTesting(cppgc::EmbedderStackState stack_state); - - private: - CppHeap() = default; - - friend class internal::CppHeap; -}; - -class JSVisitor : public cppgc::Visitor { - public: - explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {} - - void Trace(const TracedReferenceBase& ref) { - if (ref.IsEmptyThreadSafe()) return; - Visit(ref); - } - - protected: - using cppgc::Visitor::Visit; - - virtual void Visit(const TracedReferenceBase& ref) {} -}; - -/** - * **DO NOT USE: Use the appropriate managed types.** - * - * Consistency helpers that aid in maintaining a consistent internal state of - * the garbage collector. - */ -class V8_EXPORT JSHeapConsistency final { - public: - using WriteBarrierParams = cppgc::internal::WriteBarrier::Params; - using WriteBarrierType = cppgc::internal::WriteBarrier::Type; - - /** - * Gets the required write barrier type for a specific write. - * - * Note: Handling for C++ to JS references. - * - * \param ref The reference being written to. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \param callback Callback returning the corresponding heap handle. The - * callback is only invoked if the heap cannot otherwise be figured out. The - * callback must not allocate. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - template - static V8_INLINE WriteBarrierType - GetWriteBarrierType(const TracedReferenceBase& ref, - WriteBarrierParams& params, HeapHandleCallback callback) { - if (ref.IsEmpty()) return WriteBarrierType::kNone; - - if (V8_LIKELY(!cppgc::internal::WriteBarrier:: - IsAnyIncrementalOrConcurrentMarking())) { - return cppgc::internal::WriteBarrier::Type::kNone; - } - cppgc::HeapHandle& handle = callback(); - if (!cppgc::subtle::HeapState::IsMarking(handle)) { - return cppgc::internal::WriteBarrier::Type::kNone; - } - params.heap = &handle; -#if V8_ENABLE_CHECKS - params.type = cppgc::internal::WriteBarrier::Type::kMarking; -#endif // !V8_ENABLE_CHECKS - return cppgc::internal::WriteBarrier::Type::kMarking; - } - - /** - * Gets the required write barrier type for a specific write. - * - * Note: Handling for JS to C++ references. - * - * \param wrapper The wrapper that has been written into. - * \param wrapper_index The wrapper index in `wrapper` that has been written - * into. - * \param wrappable The value that was written. - * \param params Parameters that may be used for actual write barrier calls. - * Only filled if return value indicates that a write barrier is needed. The - * contents of the `params` are an implementation detail. - * \param callback Callback returning the corresponding heap handle. The - * callback is only invoked if the heap cannot otherwise be figured out. The - * callback must not allocate. - * \returns whether a write barrier is needed and which barrier to invoke. - */ - template - static V8_INLINE WriteBarrierType GetWriteBarrierType( - v8::Local& wrapper, int wrapper_index, const void* wrappable, - WriteBarrierParams& params, HeapHandleCallback callback) { -#if V8_ENABLE_CHECKS - CheckWrapper(wrapper, wrapper_index, wrappable); -#endif // V8_ENABLE_CHECKS - return cppgc::internal::WriteBarrier:: - GetWriteBarrierTypeForExternallyReferencedObject(wrappable, params, - callback); - } - - /** - * Conservative Dijkstra-style write barrier that processes an object if it - * has not yet been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param ref The reference being written to. - */ - static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params, - cppgc::HeapHandle& heap_handle, - const TracedReferenceBase& ref) { - cppgc::internal::WriteBarrier::CheckParams(WriteBarrierType::kMarking, - params); - DijkstraMarkingBarrierSlow(heap_handle, ref); - } - - /** - * Conservative Dijkstra-style write barrier that processes an object if it - * has not yet been processed. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param object The pointer to the object. May be an interior pointer to a - * an interface of the actual object. - */ - static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params, - cppgc::HeapHandle& heap_handle, - const void* object) { - cppgc::internal::WriteBarrier::DijkstraMarkingBarrier(params, object); - } - - /** - * Generational barrier for maintaining consistency when running with multiple - * generations. - * - * \param params The parameters retrieved from `GetWriteBarrierType()`. - * \param ref The reference being written to. - */ - static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params, - const TracedReferenceBase& ref) {} - - private: - JSHeapConsistency() = delete; - - static void CheckWrapper(v8::Local&, int, const void*); - - static void DijkstraMarkingBarrierSlow(cppgc::HeapHandle&, - const TracedReferenceBase& ref); -}; - -/** - * Provided as input to `CppHeap::CollectCustomSpaceStatisticsAtLastGC()`. - * - * Its method is invoked with the results of the statistic collection. - */ -class CustomSpaceStatisticsReceiver { - public: - virtual ~CustomSpaceStatisticsReceiver() = default; - /** - * Reports the size of a space at the last GC. It is called for each space - * that was requested in `CollectCustomSpaceStatisticsAtLastGC()`. - * - * \param space_index The index of the space. - * \param bytes The total size of live objects in the space at the last GC. - * It is zero if there was no GC yet. - */ - virtual void AllocatedBytes(cppgc::CustomSpaceIndex space_index, - size_t bytes) = 0; -}; - -} // namespace v8 - -namespace cppgc { - -template -struct TraceTrait> { - static void Trace(Visitor* visitor, const v8::TracedReference* self) { - static_cast(visitor)->Trace(*self); - } -}; - -} // namespace cppgc - -#endif // INCLUDE_V8_CPPGC_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-data.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-data.h deleted file mode 100644 index dbd36c9a035..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-data.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_DATA_H_ -#define INCLUDE_V8_DATA_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * The superclass of objects that can reside on V8's heap. - */ -class V8_EXPORT Data { - public: - /** - * Returns true if this data is a |v8::Value|. - */ - bool IsValue() const; - - /** - * Returns true if this data is a |v8::Module|. - */ - bool IsModule() const; - - /** - * Returns true if this data is a |v8::Private|. - */ - bool IsPrivate() const; - - /** - * Returns true if this data is a |v8::ObjectTemplate|. - */ - bool IsObjectTemplate() const; - - /** - * Returns true if this data is a |v8::FunctionTemplate|. - */ - bool IsFunctionTemplate() const; - - /** - * Returns true if this data is a |v8::Context|. - */ - bool IsContext() const; - - private: - Data(); -}; - -/** - * A fixed-sized array with elements of type Data. - */ -class V8_EXPORT FixedArray : public Data { - public: - int Length() const; - Local Get(Local context, int i) const; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_DATA_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-date.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-date.h deleted file mode 100644 index e7a01f29b2d..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-date.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_DATE_H_ -#define INCLUDE_V8_DATE_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * An instance of the built-in Date constructor (ECMA-262, 15.9). - */ -class V8_EXPORT Date : public Object { - public: - static V8_WARN_UNUSED_RESULT MaybeLocal New(Local context, - double time); - - /** - * A specialization of Value::NumberValue that is more efficient - * because we know the structure of this object. - */ - double ValueOf() const; - - V8_INLINE static Date* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_DATE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-debug.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-debug.h deleted file mode 100644 index a13ae3f6d6c..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-debug.h +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_DEBUG_H_ -#define INCLUDE_V8_DEBUG_H_ - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; -class String; - -/** - * A single JavaScript stack frame. - */ -class V8_EXPORT StackFrame { - public: - /** - * Returns the number, 1-based, of the line for the associate function call. - * This method will return Message::kNoLineNumberInfo if it is unable to - * retrieve the line number, or if kLineNumber was not passed as an option - * when capturing the StackTrace. - */ - int GetLineNumber() const; - - /** - * Returns the 1-based column offset on the line for the associated function - * call. - * This method will return Message::kNoColumnInfo if it is unable to retrieve - * the column number, or if kColumnOffset was not passed as an option when - * capturing the StackTrace. - */ - int GetColumn() const; - - /** - * Returns the id of the script for the function for this StackFrame. - * This method will return Message::kNoScriptIdInfo if it is unable to - * retrieve the script id, or if kScriptId was not passed as an option when - * capturing the StackTrace. - */ - int GetScriptId() const; - - /** - * Returns the name of the resource that contains the script for the - * function for this StackFrame. - */ - Local GetScriptName() const; - - /** - * Returns the name of the resource that contains the script for the - * function for this StackFrame or sourceURL value if the script name - * is undefined and its source ends with //# sourceURL=... string or - * deprecated //@ sourceURL=... string. - */ - Local GetScriptNameOrSourceURL() const; - - /** - * Returns the source of the script for the function for this StackFrame. - */ - Local GetScriptSource() const; - - /** - * Returns the source mapping URL (if one is present) of the script for - * the function for this StackFrame. - */ - Local GetScriptSourceMappingURL() const; - - /** - * Returns the name of the function associated with this stack frame. - */ - Local GetFunctionName() const; - - /** - * Returns whether or not the associated function is compiled via a call to - * eval(). - */ - bool IsEval() const; - - /** - * Returns whether or not the associated function is called as a - * constructor via "new". - */ - bool IsConstructor() const; - - /** - * Returns whether or not the associated functions is defined in wasm. - */ - bool IsWasm() const; - - /** - * Returns whether or not the associated function is defined by the user. - */ - bool IsUserJavaScript() const; -}; - -/** - * Representation of a JavaScript stack trace. The information collected is a - * snapshot of the execution stack and the information remains valid after - * execution continues. - */ -class V8_EXPORT StackTrace { - public: - /** - * Flags that determine what information is placed captured for each - * StackFrame when grabbing the current stack trace. - * Note: these options are deprecated and we always collect all available - * information (kDetailed). - */ - enum StackTraceOptions { - kLineNumber = 1, - kColumnOffset = 1 << 1 | kLineNumber, - kScriptName = 1 << 2, - kFunctionName = 1 << 3, - kIsEval = 1 << 4, - kIsConstructor = 1 << 5, - kScriptNameOrSourceURL = 1 << 6, - kScriptId = 1 << 7, - kExposeFramesAcrossSecurityOrigins = 1 << 8, - kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName, - kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL - }; - - /** - * Returns a StackFrame at a particular index. - */ - Local GetFrame(Isolate* isolate, uint32_t index) const; - - /** - * Returns the number of StackFrames. - */ - int GetFrameCount() const; - - /** - * Grab a snapshot of the current JavaScript execution stack. - * - * \param frame_limit The maximum number of stack frames we want to capture. - * \param options Enumerates the set of things we will capture for each - * StackFrame. - */ - static Local CurrentStackTrace( - Isolate* isolate, int frame_limit, StackTraceOptions options = kDetailed); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_DEBUG_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-embedder-heap.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-embedder-heap.h deleted file mode 100644 index 501a4fc523b..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-embedder-heap.h +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EMBEDDER_HEAP_H_ -#define INCLUDE_V8_EMBEDDER_HEAP_H_ - -#include -#include - -#include -#include - -#include "cppgc/common.h" -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-traced-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Data; -class Isolate; -class Value; - -namespace internal { -class LocalEmbedderHeapTracer; -} // namespace internal - -/** - * Handler for embedder roots on non-unified heap garbage collections. - */ -class V8_EXPORT EmbedderRootsHandler { - public: - virtual ~EmbedderRootsHandler() = default; - - /** - * Returns true if the TracedGlobal handle should be considered as root for - * the currently running non-tracing garbage collection and false otherwise. - * The default implementation will keep all TracedGlobal references as roots. - * - * If this returns false, then V8 may decide that the object referred to by - * such a handle is reclaimed. In that case: - * - No action is required if handles are used with destructors, i.e., by just - * using |TracedGlobal|. - * - When run without destructors, i.e., by using |TracedReference|, V8 calls - * |ResetRoot|. - * - * Note that the |handle| is different from the handle that the embedder holds - * for retaining the object. The embedder may use |WrapperClassId()| to - * distinguish cases where it wants handles to be treated as roots from not - * being treated as roots. - */ - virtual bool IsRoot(const v8::TracedReference& handle) = 0; - virtual bool IsRoot(const v8::TracedGlobal& handle) = 0; - - /** - * Used in combination with |IsRoot|. Called by V8 when an - * object that is backed by a handle is reclaimed by a non-tracing garbage - * collection. It is up to the embedder to reset the original handle. - * - * Note that the |handle| is different from the handle that the embedder holds - * for retaining the object. It is up to the embedder to find the original - * handle via the object or class id. - */ - virtual void ResetRoot(const v8::TracedReference& handle) = 0; -}; - -/** - * Interface for tracing through the embedder heap. During a V8 garbage - * collection, V8 collects hidden fields of all potential wrappers, and at the - * end of its marking phase iterates the collection and asks the embedder to - * trace through its heap and use reporter to report each JavaScript object - * reachable from any of the given wrappers. - */ -class V8_EXPORT EmbedderHeapTracer { - public: - using EmbedderStackState = cppgc::EmbedderStackState; - - enum TraceFlags : uint64_t { - kNoFlags = 0, - kReduceMemory = 1 << 0, - kForced = 1 << 2, - }; - - /** - * Interface for iterating through TracedGlobal handles. - */ - class V8_EXPORT TracedGlobalHandleVisitor { - public: - virtual ~TracedGlobalHandleVisitor() = default; - virtual void VisitTracedGlobalHandle(const TracedGlobal& handle) {} - virtual void VisitTracedReference(const TracedReference& handle) {} - }; - - /** - * Summary of a garbage collection cycle. See |TraceEpilogue| on how the - * summary is reported. - */ - struct TraceSummary { - /** - * Time spent managing the retained memory in milliseconds. This can e.g. - * include the time tracing through objects in the embedder. - */ - double time = 0.0; - - /** - * Memory retained by the embedder through the |EmbedderHeapTracer| - * mechanism in bytes. - */ - size_t allocated_size = 0; - }; - - virtual ~EmbedderHeapTracer() = default; - - /** - * Iterates all TracedGlobal handles created for the v8::Isolate the tracer is - * attached to. - */ - void IterateTracedGlobalHandles(TracedGlobalHandleVisitor* visitor); - - /** - * Called by the embedder to set the start of the stack which is e.g. used by - * V8 to determine whether handles are used from stack or heap. - */ - void SetStackStart(void* stack_start); - - /** - * Called by the embedder to notify V8 of an empty execution stack. - */ - V8_DEPRECATE_SOON( - "This call only optimized internal caches which V8 is able to figure out " - "on its own now.") - void NotifyEmptyEmbedderStack(); - - /** - * Called by v8 to register internal fields of found wrappers. - * - * The embedder is expected to store them somewhere and trace reachable - * wrappers from them when called through |AdvanceTracing|. - */ - virtual void RegisterV8References( - const std::vector>& embedder_fields) = 0; - - void RegisterEmbedderReference(const BasicTracedReference& ref); - - /** - * Called at the beginning of a GC cycle. - */ - virtual void TracePrologue(TraceFlags flags) {} - - /** - * Called to advance tracing in the embedder. - * - * The embedder is expected to trace its heap starting from wrappers reported - * by RegisterV8References method, and report back all reachable wrappers. - * Furthermore, the embedder is expected to stop tracing by the given - * deadline. A deadline of infinity means that tracing should be finished. - * - * Returns |true| if tracing is done, and false otherwise. - */ - virtual bool AdvanceTracing(double deadline_in_ms) = 0; - - /* - * Returns true if there no more tracing work to be done (see AdvanceTracing) - * and false otherwise. - */ - virtual bool IsTracingDone() = 0; - - /** - * Called at the end of a GC cycle. - * - * Note that allocation is *not* allowed within |TraceEpilogue|. Can be - * overriden to fill a |TraceSummary| that is used by V8 to schedule future - * garbage collections. - */ - virtual void TraceEpilogue(TraceSummary* trace_summary) {} - - /** - * Called upon entering the final marking pause. No more incremental marking - * steps will follow this call. - */ - virtual void EnterFinalPause(EmbedderStackState stack_state) = 0; - - /* - * Called by the embedder to request immediate finalization of the currently - * running tracing phase that has been started with TracePrologue and not - * yet finished with TraceEpilogue. - * - * Will be a noop when currently not in tracing. - * - * This is an experimental feature. - */ - void FinalizeTracing(); - - /** - * See documentation on EmbedderRootsHandler. - */ - virtual bool IsRootForNonTracingGC( - const v8::TracedReference& handle); - virtual bool IsRootForNonTracingGC(const v8::TracedGlobal& handle); - - /** - * See documentation on EmbedderRootsHandler. - */ - virtual void ResetHandleInNonTracingGC( - const v8::TracedReference& handle); - - /* - * Called by the embedder to immediately perform a full garbage collection. - * - * Should only be used in testing code. - */ - void GarbageCollectionForTesting(EmbedderStackState stack_state); - - /* - * Called by the embedder to signal newly allocated or freed memory. Not bound - * to tracing phases. Embedders should trade off when increments are reported - * as V8 may consult global heuristics on whether to trigger garbage - * collection on this change. - */ - void IncreaseAllocatedSize(size_t bytes); - void DecreaseAllocatedSize(size_t bytes); - - /* - * Returns the v8::Isolate this tracer is attached too and |nullptr| if it - * is not attached to any v8::Isolate. - */ - v8::Isolate* isolate() const { return isolate_; } - - protected: - v8::Isolate* isolate_ = nullptr; - - friend class internal::LocalEmbedderHeapTracer; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_EMBEDDER_HEAP_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-exception.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-exception.h deleted file mode 100644 index add882da4c4..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-exception.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EXCEPTION_H_ -#define INCLUDE_V8_EXCEPTION_H_ - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; -class Message; -class StackTrace; -class String; -class Value; - -namespace internal { -class Isolate; -class ThreadLocalTop; -} // namespace internal - -/** - * Create new error objects by calling the corresponding error object - * constructor with the message. - */ -class V8_EXPORT Exception { - public: - static Local RangeError(Local message); - static Local ReferenceError(Local message); - static Local SyntaxError(Local message); - static Local TypeError(Local message); - static Local WasmCompileError(Local message); - static Local WasmLinkError(Local message); - static Local WasmRuntimeError(Local message); - static Local Error(Local message); - - /** - * Creates an error message for the given exception. - * Will try to reconstruct the original stack trace from the exception value, - * or capture the current stack trace if not available. - */ - static Local CreateMessage(Isolate* isolate, Local exception); - - /** - * Returns the original stack trace that was captured at the creation time - * of a given exception, or an empty handle if not available. - */ - static Local GetStackTrace(Local exception); -}; - -/** - * An external exception handler. - */ -class V8_EXPORT TryCatch { - public: - /** - * Creates a new try/catch block and registers it with v8. Note that - * all TryCatch blocks should be stack allocated because the memory - * location itself is compared against JavaScript try/catch blocks. - */ - explicit TryCatch(Isolate* isolate); - - /** - * Unregisters and deletes this try/catch block. - */ - ~TryCatch(); - - /** - * Returns true if an exception has been caught by this try/catch block. - */ - bool HasCaught() const; - - /** - * For certain types of exceptions, it makes no sense to continue execution. - * - * If CanContinue returns false, the correct action is to perform any C++ - * cleanup needed and then return. If CanContinue returns false and - * HasTerminated returns true, it is possible to call - * CancelTerminateExecution in order to continue calling into the engine. - */ - bool CanContinue() const; - - /** - * Returns true if an exception has been caught due to script execution - * being terminated. - * - * There is no JavaScript representation of an execution termination - * exception. Such exceptions are thrown when the TerminateExecution - * methods are called to terminate a long-running script. - * - * If such an exception has been thrown, HasTerminated will return true, - * indicating that it is possible to call CancelTerminateExecution in order - * to continue calling into the engine. - */ - bool HasTerminated() const; - - /** - * Throws the exception caught by this TryCatch in a way that avoids - * it being caught again by this same TryCatch. As with ThrowException - * it is illegal to execute any JavaScript operations after calling - * ReThrow; the caller must return immediately to where the exception - * is caught. - */ - Local ReThrow(); - - /** - * Returns the exception caught by this try/catch block. If no exception has - * been caught an empty handle is returned. - */ - Local Exception() const; - - /** - * Returns the .stack property of an object. If no .stack - * property is present an empty handle is returned. - */ - V8_WARN_UNUSED_RESULT static MaybeLocal StackTrace( - Local context, Local exception); - - /** - * Returns the .stack property of the thrown object. If no .stack property is - * present or if this try/catch block has not caught an exception, an empty - * handle is returned. - */ - V8_WARN_UNUSED_RESULT MaybeLocal StackTrace( - Local context) const; - - /** - * Returns the message associated with this exception. If there is - * no message associated an empty handle is returned. - */ - Local Message() const; - - /** - * Clears any exceptions that may have been caught by this try/catch block. - * After this method has been called, HasCaught() will return false. Cancels - * the scheduled exception if it is caught and ReThrow() is not called before. - * - * It is not necessary to clear a try/catch block before using it again; if - * another exception is thrown the previously caught exception will just be - * overwritten. However, it is often a good idea since it makes it easier - * to determine which operation threw a given exception. - */ - void Reset(); - - /** - * Set verbosity of the external exception handler. - * - * By default, exceptions that are caught by an external exception - * handler are not reported. Call SetVerbose with true on an - * external exception handler to have exceptions caught by the - * handler reported as if they were not caught. - */ - void SetVerbose(bool value); - - /** - * Returns true if verbosity is enabled. - */ - bool IsVerbose() const; - - /** - * Set whether or not this TryCatch should capture a Message object - * which holds source information about where the exception - * occurred. True by default. - */ - void SetCaptureMessage(bool value); - - V8_DEPRECATE_SOON( - "This is private information that should not be exposed by the API") - static void* JSStackComparableAddress(TryCatch* handler) { - if (handler == nullptr) return nullptr; - return reinterpret_cast(handler->JSStackComparableAddressPrivate()); - } - - TryCatch(const TryCatch&) = delete; - void operator=(const TryCatch&) = delete; - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - /** - * There are cases when the raw address of C++ TryCatch object cannot be - * used for comparisons with addresses into the JS stack. The cases are: - * 1) ARM, ARM64 and MIPS simulators which have separate JS stack. - * 2) Address sanitizer allocates local C++ object in the heap when - * UseAfterReturn mode is enabled. - * This method returns address that can be used for comparisons with - * addresses into the JS stack. When neither simulator nor ASAN's - * UseAfterReturn is enabled, then the address returned will be the address - * of the C++ try catch handler itself. - */ - internal::Address JSStackComparableAddressPrivate() { - return js_stack_comparable_address_; - } - - void ResetInternal(); - - internal::Isolate* isolate_; - TryCatch* next_; - void* exception_; - void* message_obj_; - internal::Address js_stack_comparable_address_; - bool is_verbose_ : 1; - bool can_continue_ : 1; - bool capture_message_ : 1; - bool rethrow_ : 1; - bool has_terminated_ : 1; - - friend class internal::Isolate; - friend class internal::ThreadLocalTop; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_EXCEPTION_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-extension.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-extension.h deleted file mode 100644 index 0705e2afbb8..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-extension.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EXTENSION_H_ -#define INCLUDE_V8_EXTENSION_H_ - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class FunctionTemplate; - -// --- Extensions --- - -/** - * Ignore - */ -class V8_EXPORT Extension { - public: - // Note that the strings passed into this constructor must live as long - // as the Extension itself. - Extension(const char* name, const char* source = nullptr, int dep_count = 0, - const char** deps = nullptr, int source_length = -1); - virtual ~Extension() { delete source_; } - virtual Local GetNativeFunctionTemplate( - Isolate* isolate, Local name) { - return Local(); - } - - const char* name() const { return name_; } - size_t source_length() const { return source_length_; } - const String::ExternalOneByteStringResource* source() const { - return source_; - } - int dependency_count() const { return dep_count_; } - const char** dependencies() const { return deps_; } - void set_auto_enable(bool value) { auto_enable_ = value; } - bool auto_enable() { return auto_enable_; } - - // Disallow copying and assigning. - Extension(const Extension&) = delete; - void operator=(const Extension&) = delete; - - private: - const char* name_; - size_t source_length_; // expected to initialize before source_ - String::ExternalOneByteStringResource* source_; - int dep_count_; - const char** deps_; - bool auto_enable_; -}; - -void V8_EXPORT RegisterExtension(std::unique_ptr); - -} // namespace v8 - -#endif // INCLUDE_V8_EXTENSION_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-external.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-external.h deleted file mode 100644 index 2e245036f42..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-external.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_EXTERNAL_H_ -#define INCLUDE_V8_EXTERNAL_H_ - -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -/** - * A JavaScript value that wraps a C++ void*. This type of value is mainly used - * to associate C++ data structures with JavaScript objects. - */ -class V8_EXPORT External : public Value { - public: - static Local New(Isolate* isolate, void* value); - V8_INLINE static External* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - void* Value() const; - - private: - static void CheckCast(v8::Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_EXTERNAL_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-fast-api-calls.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-fast-api-calls.h deleted file mode 100644 index ca13b1e6266..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-fast-api-calls.h +++ /dev/null @@ -1,838 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * This file provides additional API on top of the default one for making - * API calls, which come from embedder C++ functions. The functions are being - * called directly from optimized code, doing all the necessary typechecks - * in the compiler itself, instead of on the embedder side. Hence the "fast" - * in the name. Example usage might look like: - * - * \code - * void FastMethod(int param, bool another_param); - * - * v8::FunctionTemplate::New(isolate, SlowCallback, data, - * signature, length, constructor_behavior - * side_effect_type, - * &v8::CFunction::Make(FastMethod)); - * \endcode - * - * By design, fast calls are limited by the following requirements, which - * the embedder should enforce themselves: - * - they should not allocate on the JS heap; - * - they should not trigger JS execution. - * To enforce them, the embedder could use the existing - * v8::Isolate::DisallowJavascriptExecutionScope and a utility similar to - * Blink's NoAllocationScope: - * https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/heap/thread_state_scopes.h;l=16 - * - * Due to these limitations, it's not directly possible to report errors by - * throwing a JS exception or to otherwise do an allocation. There is an - * alternative way of creating fast calls that supports falling back to the - * slow call and then performing the necessary allocation. When one creates - * the fast method by using CFunction::MakeWithFallbackSupport instead of - * CFunction::Make, the fast callback gets as last parameter an output variable, - * through which it can request falling back to the slow call. So one might - * declare their method like: - * - * \code - * void FastMethodWithFallback(int param, FastApiCallbackOptions& options); - * \endcode - * - * If the callback wants to signal an error condition or to perform an - * allocation, it must set options.fallback to true and do an early return from - * the fast method. Then V8 checks the value of options.fallback and if it's - * true, falls back to executing the SlowCallback, which is capable of reporting - * the error (either by throwing a JS exception or logging to the console) or - * doing the allocation. It's the embedder's responsibility to ensure that the - * fast callback is idempotent up to the point where error and fallback - * conditions are checked, because otherwise executing the slow callback might - * produce visible side-effects twice. - * - * An example for custom embedder type support might employ a way to wrap/ - * unwrap various C++ types in JSObject instances, e.g: - * - * \code - * - * // Helper method with a check for field count. - * template - * inline T* GetInternalField(v8::Local wrapper) { - * assert(offset < wrapper->InternalFieldCount()); - * return reinterpret_cast( - * wrapper->GetAlignedPointerFromInternalField(offset)); - * } - * - * class CustomEmbedderType { - * public: - * // Returns the raw C object from a wrapper JS object. - * static CustomEmbedderType* Unwrap(v8::Local wrapper) { - * return GetInternalField(wrapper); - * } - * static void FastMethod(v8::Local receiver_obj, int param) { - * CustomEmbedderType* receiver = static_cast( - * receiver_obj->GetAlignedPointerFromInternalField( - * kV8EmbedderWrapperObjectIndex)); - * - * // Type checks are already done by the optimized code. - * // Then call some performance-critical method like: - * // receiver->Method(param); - * } - * - * static void SlowMethod( - * const v8::FunctionCallbackInfo& info) { - * v8::Local instance = - * v8::Local::Cast(info.Holder()); - * CustomEmbedderType* receiver = Unwrap(instance); - * // TODO: Do type checks and extract {param}. - * receiver->Method(param); - * } - * }; - * - * // TODO(mslekova): Clean-up these constants - * // The constants kV8EmbedderWrapperTypeIndex and - * // kV8EmbedderWrapperObjectIndex describe the offsets for the type info - * // struct and the native object, when expressed as internal field indices - * // within a JSObject. The existance of this helper function assumes that - * // all embedder objects have their JSObject-side type info at the same - * // offset, but this is not a limitation of the API itself. For a detailed - * // use case, see the third example. - * static constexpr int kV8EmbedderWrapperTypeIndex = 0; - * static constexpr int kV8EmbedderWrapperObjectIndex = 1; - * - * // The following setup function can be templatized based on - * // the {embedder_object} argument. - * void SetupCustomEmbedderObject(v8::Isolate* isolate, - * v8::Local context, - * CustomEmbedderType* embedder_object) { - * isolate->set_embedder_wrapper_type_index( - * kV8EmbedderWrapperTypeIndex); - * isolate->set_embedder_wrapper_object_index( - * kV8EmbedderWrapperObjectIndex); - * - * v8::CFunction c_func = - * MakeV8CFunction(CustomEmbedderType::FastMethod); - * - * Local method_template = - * v8::FunctionTemplate::New( - * isolate, CustomEmbedderType::SlowMethod, v8::Local(), - * v8::Local(), 1, v8::ConstructorBehavior::kAllow, - * v8::SideEffectType::kHasSideEffect, &c_func); - * - * v8::Local object_template = - * v8::ObjectTemplate::New(isolate); - * object_template->SetInternalFieldCount( - * kV8EmbedderWrapperObjectIndex + 1); - * object_template->Set(isolate, "method", method_template); - * - * // Instantiate the wrapper JS object. - * v8::Local object = - * object_template->NewInstance(context).ToLocalChecked(); - * object->SetAlignedPointerInInternalField( - * kV8EmbedderWrapperObjectIndex, - * reinterpret_cast(embedder_object)); - * - * // TODO: Expose {object} where it's necessary. - * } - * \endcode - * - * For instance if {object} is exposed via a global "obj" variable, - * one could write in JS: - * function hot_func() { - * obj.method(42); - * } - * and once {hot_func} gets optimized, CustomEmbedderType::FastMethod - * will be called instead of the slow version, with the following arguments: - * receiver := the {embedder_object} from above - * param := 42 - * - * Currently supported return types: - * - void - * - bool - * - int32_t - * - uint32_t - * - float32_t - * - float64_t - * Currently supported argument types: - * - pointer to an embedder type - * - JavaScript array of primitive types - * - bool - * - int32_t - * - uint32_t - * - int64_t - * - uint64_t - * - float32_t - * - float64_t - * - * The 64-bit integer types currently have the IDL (unsigned) long long - * semantics: https://heycam.github.io/webidl/#abstract-opdef-converttoint - * In the future we'll extend the API to also provide conversions from/to - * BigInt to preserve full precision. - * The floating point types currently have the IDL (unrestricted) semantics, - * which is the only one used by WebGL. We plan to add support also for - * restricted floats/doubles, similarly to the BigInt conversion policies. - * We also differ from the specific NaN bit pattern that WebIDL prescribes - * (https://heycam.github.io/webidl/#es-unrestricted-float) in that Blink - * passes NaN values as-is, i.e. doesn't normalize them. - * - * To be supported types: - * - TypedArrays and ArrayBuffers - * - arrays of embedder types - * - * - * The API offers a limited support for function overloads: - * - * \code - * void FastMethod_2Args(int param, bool another_param); - * void FastMethod_3Args(int param, bool another_param, int third_param); - * - * v8::CFunction fast_method_2args_c_func = - * MakeV8CFunction(FastMethod_2Args); - * v8::CFunction fast_method_3args_c_func = - * MakeV8CFunction(FastMethod_3Args); - * const v8::CFunction fast_method_overloads[] = {fast_method_2args_c_func, - * fast_method_3args_c_func}; - * Local method_template = - * v8::FunctionTemplate::NewWithCFunctionOverloads( - * isolate, SlowCallback, data, signature, length, - * constructor_behavior, side_effect_type, - * {fast_method_overloads, 2}); - * \endcode - * - * In this example a single FunctionTemplate is associated to multiple C++ - * functions. The overload resolution is currently only based on the number of - * arguments passed in a call. For example, if this method_template is - * registered with a wrapper JS object as described above, a call with two - * arguments: - * obj.method(42, true); - * will result in a fast call to FastMethod_2Args, while a call with three or - * more arguments: - * obj.method(42, true, 11); - * will result in a fast call to FastMethod_3Args. Instead a call with less than - * two arguments, like: - * obj.method(42); - * would not result in a fast call but would fall back to executing the - * associated SlowCallback. - */ - -#ifndef INCLUDE_V8_FAST_API_CALLS_H_ -#define INCLUDE_V8_FAST_API_CALLS_H_ - -#include -#include - -#include -#include - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-typed-array.h" // NOLINT(build/include_directory) -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -class CTypeInfo { - public: - enum class Type : uint8_t { - kVoid, - kBool, - kInt32, - kUint32, - kInt64, - kUint64, - kFloat32, - kFloat64, - kV8Value, - kApiObject, // This will be deprecated once all users have - // migrated from v8::ApiObject to v8::Local. - }; - - // kCallbackOptionsType is not part of the Type enum - // because it is only used internally. Use value 255 that is larger - // than any valid Type enum. - static constexpr Type kCallbackOptionsType = Type(255); - - enum class SequenceType : uint8_t { - kScalar, - kIsSequence, // sequence - kIsTypedArray, // TypedArray of T or any ArrayBufferView if T - // is void - kIsArrayBuffer // ArrayBuffer - }; - - enum class Flags : uint8_t { - kNone = 0, - kAllowSharedBit = 1 << 0, // Must be an ArrayBuffer or TypedArray - kEnforceRangeBit = 1 << 1, // T must be integral - kClampBit = 1 << 2, // T must be integral - kIsRestrictedBit = 1 << 3, // T must be float or double - }; - - explicit constexpr CTypeInfo( - Type type, SequenceType sequence_type = SequenceType::kScalar, - Flags flags = Flags::kNone) - : type_(type), sequence_type_(sequence_type), flags_(flags) {} - - constexpr Type GetType() const { return type_; } - constexpr SequenceType GetSequenceType() const { return sequence_type_; } - constexpr Flags GetFlags() const { return flags_; } - - static constexpr bool IsIntegralType(Type type) { - return type == Type::kInt32 || type == Type::kUint32 || - type == Type::kInt64 || type == Type::kUint64; - } - - static constexpr bool IsFloatingPointType(Type type) { - return type == Type::kFloat32 || type == Type::kFloat64; - } - - static constexpr bool IsPrimitive(Type type) { - return IsIntegralType(type) || IsFloatingPointType(type) || - type == Type::kBool; - } - - private: - Type type_; - SequenceType sequence_type_; - Flags flags_; -}; - -struct FastApiTypedArrayBase { - public: - // Returns the length in number of elements. - size_t V8_EXPORT length() const { return length_; } - // Checks whether the given index is within the bounds of the collection. - void V8_EXPORT ValidateIndex(size_t index) const; - - protected: - size_t length_ = 0; -}; - -template -struct FastApiTypedArray : public FastApiTypedArrayBase { - public: - V8_INLINE T get(size_t index) const { -#ifdef DEBUG - ValidateIndex(index); -#endif // DEBUG - T tmp; - memcpy(&tmp, reinterpret_cast(data_) + index, sizeof(T)); - return tmp; - } - - private: - // This pointer should include the typed array offset applied. - // It's not guaranteed that it's aligned to sizeof(T), it's only - // guaranteed that it's 4-byte aligned, so for 8-byte types we need to - // provide a special implementation for reading from it, which hides - // the possibly unaligned read in the `get` method. - void* data_; -}; - -// Any TypedArray. It uses kTypedArrayBit with base type void -// Overloaded args of ArrayBufferView and TypedArray are not supported -// (for now) because the generic “any” ArrayBufferView doesn’t have its -// own instance type. It could be supported if we specify that -// TypedArray always has precedence over the generic ArrayBufferView, -// but this complicates overload resolution. -struct FastApiArrayBufferView { - void* data; - size_t byte_length; -}; - -struct FastApiArrayBuffer { - void* data; - size_t byte_length; -}; - -class V8_EXPORT CFunctionInfo { - public: - // Construct a struct to hold a CFunction's type information. - // |return_info| describes the function's return type. - // |arg_info| is an array of |arg_count| CTypeInfos describing the - // arguments. Only the last argument may be of the special type - // CTypeInfo::kCallbackOptionsType. - CFunctionInfo(const CTypeInfo& return_info, unsigned int arg_count, - const CTypeInfo* arg_info); - - const CTypeInfo& ReturnInfo() const { return return_info_; } - - // The argument count, not including the v8::FastApiCallbackOptions - // if present. - unsigned int ArgumentCount() const { - return HasOptions() ? arg_count_ - 1 : arg_count_; - } - - // |index| must be less than ArgumentCount(). - // Note: if the last argument passed on construction of CFunctionInfo - // has type CTypeInfo::kCallbackOptionsType, it is not included in - // ArgumentCount(). - const CTypeInfo& ArgumentInfo(unsigned int index) const; - - bool HasOptions() const { - // The options arg is always the last one. - return arg_count_ > 0 && arg_info_[arg_count_ - 1].GetType() == - CTypeInfo::kCallbackOptionsType; - } - - private: - const CTypeInfo return_info_; - const unsigned int arg_count_; - const CTypeInfo* arg_info_; -}; - -class V8_EXPORT CFunction { - public: - constexpr CFunction() : address_(nullptr), type_info_(nullptr) {} - - const CTypeInfo& ReturnInfo() const { return type_info_->ReturnInfo(); } - - const CTypeInfo& ArgumentInfo(unsigned int index) const { - return type_info_->ArgumentInfo(index); - } - - unsigned int ArgumentCount() const { return type_info_->ArgumentCount(); } - - const void* GetAddress() const { return address_; } - const CFunctionInfo* GetTypeInfo() const { return type_info_; } - - enum class OverloadResolution { kImpossible, kAtRuntime, kAtCompileTime }; - - // Returns whether an overload between this and the given CFunction can - // be resolved at runtime by the RTTI available for the arguments or at - // compile time for functions with different number of arguments. - OverloadResolution GetOverloadResolution(const CFunction* other) { - // Runtime overload resolution can only deal with functions with the - // same number of arguments. Functions with different arity are handled - // by compile time overload resolution though. - if (ArgumentCount() != other->ArgumentCount()) { - return OverloadResolution::kAtCompileTime; - } - - // The functions can only differ by a single argument position. - int diff_index = -1; - for (unsigned int i = 0; i < ArgumentCount(); ++i) { - if (ArgumentInfo(i).GetSequenceType() != - other->ArgumentInfo(i).GetSequenceType()) { - if (diff_index >= 0) { - return OverloadResolution::kImpossible; - } - diff_index = i; - - // We only support overload resolution between sequence types. - if (ArgumentInfo(i).GetSequenceType() == - CTypeInfo::SequenceType::kScalar || - other->ArgumentInfo(i).GetSequenceType() == - CTypeInfo::SequenceType::kScalar) { - return OverloadResolution::kImpossible; - } - } - } - - return OverloadResolution::kAtRuntime; - } - - template - static CFunction Make(F* func) { - return ArgUnwrap::Make(func); - } - - template - V8_DEPRECATED("Use CFunctionBuilder instead.") - static CFunction MakeWithFallbackSupport(F* func) { - return ArgUnwrap::Make(func); - } - - CFunction(const void* address, const CFunctionInfo* type_info); - - private: - const void* address_; - const CFunctionInfo* type_info_; - - template - class ArgUnwrap { - static_assert(sizeof(F) != sizeof(F), - "CFunction must be created from a function pointer."); - }; - - template - class ArgUnwrap { - public: - static CFunction Make(R (*func)(Args...)); - }; -}; - -struct V8_DEPRECATE_SOON("Use v8::Local instead.") ApiObject { - uintptr_t address; -}; - -/** - * A struct which may be passed to a fast call callback, like so: - * \code - * void FastMethodWithOptions(int param, FastApiCallbackOptions& options); - * \endcode - */ -struct FastApiCallbackOptions { - /** - * Creates a new instance of FastApiCallbackOptions for testing purpose. The - * returned instance may be filled with mock data. - */ - static FastApiCallbackOptions CreateForTesting(Isolate* isolate) { - return {false, {0}}; - } - - /** - * If the callback wants to signal an error condition or to perform an - * allocation, it must set options.fallback to true and do an early return - * from the fast method. Then V8 checks the value of options.fallback and if - * it's true, falls back to executing the SlowCallback, which is capable of - * reporting the error (either by throwing a JS exception or logging to the - * console) or doing the allocation. It's the embedder's responsibility to - * ensure that the fast callback is idempotent up to the point where error and - * fallback conditions are checked, because otherwise executing the slow - * callback might produce visible side-effects twice. - */ - bool fallback; - - /** - * The `data` passed to the FunctionTemplate constructor, or `undefined`. - * `data_ptr` allows for default constructing FastApiCallbackOptions. - */ - union { - uintptr_t data_ptr; - v8::Value data; - }; -}; - -namespace internal { - -// Helper to count the number of occurances of `T` in `List` -template -struct count : std::integral_constant {}; -template -struct count - : std::integral_constant::value> {}; -template -struct count : count {}; - -template -class CFunctionInfoImpl : public CFunctionInfo { - static constexpr int kOptionsArgCount = - count(); - static constexpr int kReceiverCount = 1; - - static_assert(kOptionsArgCount == 0 || kOptionsArgCount == 1, - "Only one options parameter is supported."); - - static_assert(sizeof...(ArgBuilders) >= kOptionsArgCount + kReceiverCount, - "The receiver or the options argument is missing."); - - public: - constexpr CFunctionInfoImpl() - : CFunctionInfo(RetBuilder::Build(), sizeof...(ArgBuilders), - arg_info_storage_), - arg_info_storage_{ArgBuilders::Build()...} { - constexpr CTypeInfo::Type kReturnType = RetBuilder::Build().GetType(); - static_assert(kReturnType == CTypeInfo::Type::kVoid || - kReturnType == CTypeInfo::Type::kBool || - kReturnType == CTypeInfo::Type::kInt32 || - kReturnType == CTypeInfo::Type::kUint32 || - kReturnType == CTypeInfo::Type::kFloat32 || - kReturnType == CTypeInfo::Type::kFloat64, - "64-bit int and api object values are not currently " - "supported return types."); - } - - private: - const CTypeInfo arg_info_storage_[sizeof...(ArgBuilders)]; -}; - -template -struct TypeInfoHelper { - static_assert(sizeof(T) != sizeof(T), "This type is not supported"); -}; - -#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR(T, Enum) \ - template <> \ - struct TypeInfoHelper { \ - static constexpr CTypeInfo::Flags Flags() { \ - return CTypeInfo::Flags::kNone; \ - } \ - \ - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \ - static constexpr CTypeInfo::SequenceType SequenceType() { \ - return CTypeInfo::SequenceType::kScalar; \ - } \ - }; - -template -struct CTypeInfoTraits {}; - -#define DEFINE_TYPE_INFO_TRAITS(CType, Enum) \ - template <> \ - struct CTypeInfoTraits { \ - using ctype = CType; \ - }; - -#define PRIMITIVE_C_TYPES(V) \ - V(bool, kBool) \ - V(int32_t, kInt32) \ - V(uint32_t, kUint32) \ - V(int64_t, kInt64) \ - V(uint64_t, kUint64) \ - V(float, kFloat32) \ - V(double, kFloat64) - -// Same as above, but includes deprecated types for compatibility. -#define ALL_C_TYPES(V) \ - PRIMITIVE_C_TYPES(V) \ - V(void, kVoid) \ - V(v8::Local, kV8Value) \ - V(v8::Local, kV8Value) \ - V(ApiObject, kApiObject) - -// ApiObject was a temporary solution to wrap the pointer to the v8::Value. -// Please use v8::Local in new code for the arguments and -// v8::Local for the receiver, as ApiObject will be deprecated. - -ALL_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR) -PRIMITIVE_C_TYPES(DEFINE_TYPE_INFO_TRAITS) - -#undef PRIMITIVE_C_TYPES -#undef ALL_C_TYPES - -#define SPECIALIZE_GET_TYPE_INFO_HELPER_FOR_TA(T, Enum) \ - template <> \ - struct TypeInfoHelper&> { \ - static constexpr CTypeInfo::Flags Flags() { \ - return CTypeInfo::Flags::kNone; \ - } \ - \ - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::Enum; } \ - static constexpr CTypeInfo::SequenceType SequenceType() { \ - return CTypeInfo::SequenceType::kIsTypedArray; \ - } \ - }; - -#define TYPED_ARRAY_C_TYPES(V) \ - V(int32_t, kInt32) \ - V(uint32_t, kUint32) \ - V(int64_t, kInt64) \ - V(uint64_t, kUint64) \ - V(float, kFloat32) \ - V(double, kFloat64) - -TYPED_ARRAY_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR_TA) - -#undef TYPED_ARRAY_C_TYPES - -template <> -struct TypeInfoHelper> { - static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } - - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::kVoid; } - static constexpr CTypeInfo::SequenceType SequenceType() { - return CTypeInfo::SequenceType::kIsSequence; - } -}; - -template <> -struct TypeInfoHelper> { - static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } - - static constexpr CTypeInfo::Type Type() { return CTypeInfo::Type::kUint32; } - static constexpr CTypeInfo::SequenceType SequenceType() { - return CTypeInfo::SequenceType::kIsTypedArray; - } -}; - -template <> -struct TypeInfoHelper { - static constexpr CTypeInfo::Flags Flags() { return CTypeInfo::Flags::kNone; } - - static constexpr CTypeInfo::Type Type() { - return CTypeInfo::kCallbackOptionsType; - } - static constexpr CTypeInfo::SequenceType SequenceType() { - return CTypeInfo::SequenceType::kScalar; - } -}; - -#define STATIC_ASSERT_IMPLIES(COND, ASSERTION, MSG) \ - static_assert(((COND) == 0) || (ASSERTION), MSG) - -template -class CTypeInfoBuilder { - public: - using BaseType = T; - - static constexpr CTypeInfo Build() { - constexpr CTypeInfo::Flags kFlags = - MergeFlags(TypeInfoHelper::Flags(), Flags...); - constexpr CTypeInfo::Type kType = TypeInfoHelper::Type(); - constexpr CTypeInfo::SequenceType kSequenceType = - TypeInfoHelper::SequenceType(); - - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kAllowSharedBit), - (kSequenceType == CTypeInfo::SequenceType::kIsTypedArray || - kSequenceType == CTypeInfo::SequenceType::kIsArrayBuffer), - "kAllowSharedBit is only allowed for TypedArrays and ArrayBuffers."); - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kEnforceRangeBit), - CTypeInfo::IsIntegralType(kType), - "kEnforceRangeBit is only allowed for integral types."); - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kClampBit), - CTypeInfo::IsIntegralType(kType), - "kClampBit is only allowed for integral types."); - STATIC_ASSERT_IMPLIES( - uint8_t(kFlags) & uint8_t(CTypeInfo::Flags::kIsRestrictedBit), - CTypeInfo::IsFloatingPointType(kType), - "kIsRestrictedBit is only allowed for floating point types."); - STATIC_ASSERT_IMPLIES(kSequenceType == CTypeInfo::SequenceType::kIsSequence, - kType == CTypeInfo::Type::kVoid, - "Sequences are only supported from void type."); - STATIC_ASSERT_IMPLIES( - kSequenceType == CTypeInfo::SequenceType::kIsTypedArray, - CTypeInfo::IsPrimitive(kType) || kType == CTypeInfo::Type::kVoid, - "TypedArrays are only supported from primitive types or void."); - - // Return the same type with the merged flags. - return CTypeInfo(TypeInfoHelper::Type(), - TypeInfoHelper::SequenceType(), kFlags); - } - - private: - template - static constexpr CTypeInfo::Flags MergeFlags(CTypeInfo::Flags flags, - Rest... rest) { - return CTypeInfo::Flags(uint8_t(flags) | uint8_t(MergeFlags(rest...))); - } - static constexpr CTypeInfo::Flags MergeFlags() { return CTypeInfo::Flags(0); } -}; - -template -class CFunctionBuilderWithFunction { - public: - explicit constexpr CFunctionBuilderWithFunction(const void* fn) : fn_(fn) {} - - template - constexpr auto Ret() { - return CFunctionBuilderWithFunction< - CTypeInfoBuilder, - ArgBuilders...>(fn_); - } - - template - constexpr auto Arg() { - // Return a copy of the builder with the Nth arg builder merged with - // template parameter pack Flags. - return ArgImpl( - std::make_index_sequence()); - } - - auto Build() { - static CFunctionInfoImpl instance; - return CFunction(fn_, &instance); - } - - private: - template - struct GetArgBuilder; - - // Returns the same ArgBuilder as the one at index N, including its flags. - // Flags in the template parameter pack are ignored. - template - struct GetArgBuilder { - using type = - typename std::tuple_element>::type; - }; - - // Returns an ArgBuilder with the same base type as the one at index N, - // but merges the flags with the flags in the template parameter pack. - template - struct GetArgBuilder { - using type = CTypeInfoBuilder< - typename std::tuple_element>::type::BaseType, - std::tuple_element>::type::Build() - .GetFlags(), - Flags...>; - }; - - // Return a copy of the CFunctionBuilder, but merges the Flags on - // ArgBuilder index N with the new Flags passed in the template parameter - // pack. - template - constexpr auto ArgImpl(std::index_sequence) { - return CFunctionBuilderWithFunction< - RetBuilder, typename GetArgBuilder::type...>(fn_); - } - - const void* fn_; -}; - -class CFunctionBuilder { - public: - constexpr CFunctionBuilder() {} - - template - constexpr auto Fn(R (*fn)(Args...)) { - return CFunctionBuilderWithFunction, - CTypeInfoBuilder...>( - reinterpret_cast(fn)); - } -}; - -} // namespace internal - -// static -template -CFunction CFunction::ArgUnwrap::Make(R (*func)(Args...)) { - return internal::CFunctionBuilder().Fn(func).Build(); -} - -using CFunctionBuilder = internal::CFunctionBuilder; - -static constexpr CTypeInfo kTypeInfoInt32 = CTypeInfo(CTypeInfo::Type::kInt32); -static constexpr CTypeInfo kTypeInfoFloat64 = - CTypeInfo(CTypeInfo::Type::kFloat64); - -/** - * Copies the contents of this JavaScript array to a C++ buffer with - * a given max_length. A CTypeInfo is passed as an argument, - * instructing different rules for conversion (e.g. restricted float/double). - * The element type T of the destination array must match the C type - * corresponding to the CTypeInfo (specified by CTypeInfoTraits). - * If the array length is larger than max_length or the array is of - * unsupported type, the operation will fail, returning false. Generally, an - * array which contains objects, undefined, null or anything not convertible - * to the requested destination type, is considered unsupported. The operation - * returns true on success. `type_info` will be used for conversions. - */ -template -bool V8_EXPORT V8_WARN_UNUSED_RESULT TryCopyAndConvertArrayToCppBuffer( - Local src, T* dst, uint32_t max_length); - -template <> -inline bool V8_WARN_UNUSED_RESULT -TryCopyAndConvertArrayToCppBuffer<&kTypeInfoInt32, int32_t>( - Local src, int32_t* dst, uint32_t max_length) { - return CopyAndConvertArrayToCppBufferInt32(src, dst, max_length); -} - -template <> -inline bool V8_WARN_UNUSED_RESULT -TryCopyAndConvertArrayToCppBuffer<&kTypeInfoFloat64, double>( - Local src, double* dst, uint32_t max_length) { - return CopyAndConvertArrayToCppBufferFloat64(src, dst, max_length); -} - -} // namespace v8 - -#endif // INCLUDE_V8_FAST_API_CALLS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-forward.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-forward.h deleted file mode 100644 index ae16fe64b21..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-forward.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_LOCAL_HANDLES_H_ -#define INCLUDE_V8_LOCAL_HANDLES_H_ - -// This header is intended to be used by headers that pass around V8 types, -// either by pointer or using Local. The full definitions can be included -// either via v8.h or the more fine-grained headers. - -#include "v8-local-handle.h" // NOLINT(build/include_directory) - -namespace v8 { - -class AccessorSignature; -class Array; -class ArrayBuffer; -class ArrayBufferView; -class BigInt; -class BigInt64Array; -class BigIntObject; -class BigUint64Array; -class Boolean; -class BooleanObject; -class Context; -class DataView; -class Data; -class Date; -class External; -class FixedArray; -class Float32Array; -class Float64Array; -class Function; -template -class FunctionCallbackInfo; -class FunctionTemplate; -class Int16Array; -class Int32; -class Int32Array; -class Int8Array; -class Integer; -class Isolate; -class Map; -class Module; -class Name; -class Number; -class NumberObject; -class Object; -class ObjectTemplate; -class Platform; -class Primitive; -class Private; -class Promise; -class Proxy; -class RegExp; -class Script; -class Set; -class SharedArrayBuffer; -class Signature; -class String; -class StringObject; -class Symbol; -class SymbolObject; -class Template; -class TypedArray; -class Uint16Array; -class Uint32; -class Uint32Array; -class Uint8Array; -class Uint8ClampedArray; -class UnboundModuleScript; -class Value; -class WasmMemoryObject; -class WasmModuleObject; - -} // namespace v8 - -#endif // INCLUDE_V8_LOCAL_HANDLES_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-function-callback.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-function-callback.h deleted file mode 100644 index 2adff99b1cb..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-function-callback.h +++ /dev/null @@ -1,475 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_FUNCTION_CALLBACK_H_ -#define INCLUDE_V8_FUNCTION_CALLBACK_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -template -class BasicTracedReference; -template -class Global; -class Object; -class Value; - -namespace internal { -class FunctionCallbackArguments; -class PropertyCallbackArguments; -} // namespace internal - -namespace debug { -class ConsoleCallArguments; -} // namespace debug - -template -class ReturnValue { - public: - template - V8_INLINE ReturnValue(const ReturnValue& that) : value_(that.value_) { - static_assert(std::is_base_of::value, "type check"); - } - // Local setters - template - V8_INLINE void Set(const Global& handle); - template - V8_INLINE void Set(const BasicTracedReference& handle); - template - V8_INLINE void Set(const Local handle); - // Fast primitive setters - V8_INLINE void Set(bool value); - V8_INLINE void Set(double i); - V8_INLINE void Set(int32_t i); - V8_INLINE void Set(uint32_t i); - // Fast JS primitive setters - V8_INLINE void SetNull(); - V8_INLINE void SetUndefined(); - V8_INLINE void SetEmptyString(); - // Convenience getter for Isolate - V8_INLINE Isolate* GetIsolate() const; - - // Pointer setter: Uncompilable to prevent inadvertent misuse. - template - V8_INLINE void Set(S* whatever); - - // Getter. Creates a new Local<> so it comes with a certain performance - // hit. If the ReturnValue was not yet set, this will return the undefined - // value. - V8_INLINE Local Get() const; - - private: - template - friend class ReturnValue; - template - friend class FunctionCallbackInfo; - template - friend class PropertyCallbackInfo; - template - friend class PersistentValueMapBase; - V8_INLINE void SetInternal(internal::Address value) { *value_ = value; } - V8_INLINE internal::Address GetDefaultValue(); - V8_INLINE explicit ReturnValue(internal::Address* slot); - internal::Address* value_; -}; - -/** - * The argument information given to function call callbacks. This - * class provides access to information about the context of the call, - * including the receiver, the number and values of arguments, and - * the holder of the function. - */ -template -class FunctionCallbackInfo { - public: - /** The number of available arguments. */ - V8_INLINE int Length() const; - /** - * Accessor for the available arguments. Returns `undefined` if the index - * is out of bounds. - */ - V8_INLINE Local operator[](int i) const; - /** Returns the receiver. This corresponds to the "this" value. */ - V8_INLINE Local This() const; - /** - * If the callback was created without a Signature, this is the same - * value as This(). If there is a signature, and the signature didn't match - * This() but one of its hidden prototypes, this will be the respective - * hidden prototype. - * - * Note that this is not the prototype of This() on which the accessor - * referencing this callback was found (which in V8 internally is often - * referred to as holder [sic]). - */ - V8_INLINE Local Holder() const; - /** For construct calls, this returns the "new.target" value. */ - V8_INLINE Local NewTarget() const; - /** Indicates whether this is a regular call or a construct call. */ - V8_INLINE bool IsConstructCall() const; - /** The data argument specified when creating the callback. */ - V8_INLINE Local Data() const; - /** The current Isolate. */ - V8_INLINE Isolate* GetIsolate() const; - /** The ReturnValue for the call. */ - V8_INLINE ReturnValue GetReturnValue() const; - // This shouldn't be public, but the arm compiler needs it. - static const int kArgsLength = 6; - - protected: - friend class internal::FunctionCallbackArguments; - friend class internal::CustomArguments; - friend class debug::ConsoleCallArguments; - static const int kHolderIndex = 0; - static const int kIsolateIndex = 1; - static const int kReturnValueDefaultValueIndex = 2; - static const int kReturnValueIndex = 3; - static const int kDataIndex = 4; - static const int kNewTargetIndex = 5; - - V8_INLINE FunctionCallbackInfo(internal::Address* implicit_args, - internal::Address* values, int length); - internal::Address* implicit_args_; - internal::Address* values_; - int length_; -}; - -/** - * The information passed to a property callback about the context - * of the property access. - */ -template -class PropertyCallbackInfo { - public: - /** - * \return The isolate of the property access. - */ - V8_INLINE Isolate* GetIsolate() const; - - /** - * \return The data set in the configuration, i.e., in - * `NamedPropertyHandlerConfiguration` or - * `IndexedPropertyHandlerConfiguration.` - */ - V8_INLINE Local Data() const; - - /** - * \return The receiver. In many cases, this is the object on which the - * property access was intercepted. When using - * `Reflect.get`, `Function.prototype.call`, or similar functions, it is the - * object passed in as receiver or thisArg. - * - * \code - * void GetterCallback(Local name, - * const v8::PropertyCallbackInfo& info) { - * auto context = info.GetIsolate()->GetCurrentContext(); - * - * v8::Local a_this = - * info.This() - * ->GetRealNamedProperty(context, v8_str("a")) - * .ToLocalChecked(); - * v8::Local a_holder = - * info.Holder() - * ->GetRealNamedProperty(context, v8_str("a")) - * .ToLocalChecked(); - * - * CHECK(v8_str("r")->Equals(context, a_this).FromJust()); - * CHECK(v8_str("obj")->Equals(context, a_holder).FromJust()); - * - * info.GetReturnValue().Set(name); - * } - * - * v8::Local templ = - * v8::FunctionTemplate::New(isolate); - * templ->InstanceTemplate()->SetHandler( - * v8::NamedPropertyHandlerConfiguration(GetterCallback)); - * LocalContext env; - * env->Global() - * ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local()) - * .ToLocalChecked() - * ->NewInstance(env.local()) - * .ToLocalChecked()) - * .FromJust(); - * - * CompileRun("obj.a = 'obj'; var r = {a: 'r'}; Reflect.get(obj, 'x', r)"); - * \endcode - */ - V8_INLINE Local This() const; - - /** - * \return The object in the prototype chain of the receiver that has the - * interceptor. Suppose you have `x` and its prototype is `y`, and `y` - * has an interceptor. Then `info.This()` is `x` and `info.Holder()` is `y`. - * The Holder() could be a hidden object (the global object, rather - * than the global proxy). - * - * \note For security reasons, do not pass the object back into the runtime. - */ - V8_INLINE Local Holder() const; - - /** - * \return The return value of the callback. - * Can be changed by calling Set(). - * \code - * info.GetReturnValue().Set(...) - * \endcode - * - */ - V8_INLINE ReturnValue GetReturnValue() const; - - /** - * \return True if the intercepted function should throw if an error occurs. - * Usually, `true` corresponds to `'use strict'`. - * - * \note Always `false` when intercepting `Reflect.set()` - * independent of the language mode. - */ - V8_INLINE bool ShouldThrowOnError() const; - - // This shouldn't be public, but the arm compiler needs it. - static const int kArgsLength = 7; - - protected: - friend class MacroAssembler; - friend class internal::PropertyCallbackArguments; - friend class internal::CustomArguments; - static const int kShouldThrowOnErrorIndex = 0; - static const int kHolderIndex = 1; - static const int kIsolateIndex = 2; - static const int kReturnValueDefaultValueIndex = 3; - static const int kReturnValueIndex = 4; - static const int kDataIndex = 5; - static const int kThisIndex = 6; - - V8_INLINE PropertyCallbackInfo(internal::Address* args) : args_(args) {} - internal::Address* args_; -}; - -using FunctionCallback = void (*)(const FunctionCallbackInfo& info); - -// --- Implementation --- - -template -ReturnValue::ReturnValue(internal::Address* slot) : value_(slot) {} - -template -template -void ReturnValue::Set(const Global& handle) { - static_assert(std::is_base_of::value, "type check"); - if (V8_UNLIKELY(handle.IsEmpty())) { - *value_ = GetDefaultValue(); - } else { - *value_ = *reinterpret_cast(*handle); - } -} - -template -template -void ReturnValue::Set(const BasicTracedReference& handle) { - static_assert(std::is_base_of::value, "type check"); - if (V8_UNLIKELY(handle.IsEmpty())) { - *value_ = GetDefaultValue(); - } else { - *value_ = *reinterpret_cast(handle.val_); - } -} - -template -template -void ReturnValue::Set(const Local handle) { - static_assert(std::is_void::value || std::is_base_of::value, - "type check"); - if (V8_UNLIKELY(handle.IsEmpty())) { - *value_ = GetDefaultValue(); - } else { - *value_ = *reinterpret_cast(*handle); - } -} - -template -void ReturnValue::Set(double i) { - static_assert(std::is_base_of::value, "type check"); - Set(Number::New(GetIsolate(), i)); -} - -template -void ReturnValue::Set(int32_t i) { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - if (V8_LIKELY(I::IsValidSmi(i))) { - *value_ = I::IntToSmi(i); - return; - } - Set(Integer::New(GetIsolate(), i)); -} - -template -void ReturnValue::Set(uint32_t i) { - static_assert(std::is_base_of::value, "type check"); - // Can't simply use INT32_MAX here for whatever reason. - bool fits_into_int32_t = (i & (1U << 31)) == 0; - if (V8_LIKELY(fits_into_int32_t)) { - Set(static_cast(i)); - return; - } - Set(Integer::NewFromUnsigned(GetIsolate(), i)); -} - -template -void ReturnValue::Set(bool value) { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - int root_index; - if (value) { - root_index = I::kTrueValueRootIndex; - } else { - root_index = I::kFalseValueRootIndex; - } - *value_ = *I::GetRoot(GetIsolate(), root_index); -} - -template -void ReturnValue::SetNull() { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - *value_ = *I::GetRoot(GetIsolate(), I::kNullValueRootIndex); -} - -template -void ReturnValue::SetUndefined() { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - *value_ = *I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex); -} - -template -void ReturnValue::SetEmptyString() { - static_assert(std::is_base_of::value, "type check"); - using I = internal::Internals; - *value_ = *I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex); -} - -template -Isolate* ReturnValue::GetIsolate() const { - // Isolate is always the pointer below the default value on the stack. - return *reinterpret_cast(&value_[-2]); -} - -template -Local ReturnValue::Get() const { - using I = internal::Internals; - if (*value_ == *I::GetRoot(GetIsolate(), I::kTheHoleValueRootIndex)) - return Local(*Undefined(GetIsolate())); - return Local::New(GetIsolate(), reinterpret_cast(value_)); -} - -template -template -void ReturnValue::Set(S* whatever) { - static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse"); -} - -template -internal::Address ReturnValue::GetDefaultValue() { - // Default value is always the pointer below value_ on the stack. - return value_[-1]; -} - -template -FunctionCallbackInfo::FunctionCallbackInfo(internal::Address* implicit_args, - internal::Address* values, - int length) - : implicit_args_(implicit_args), values_(values), length_(length) {} - -template -Local FunctionCallbackInfo::operator[](int i) const { - // values_ points to the first argument (not the receiver). - if (i < 0 || length_ <= i) return Local(*Undefined(GetIsolate())); - return Local(reinterpret_cast(values_ + i)); -} - -template -Local FunctionCallbackInfo::This() const { - // values_ points to the first argument (not the receiver). - return Local(reinterpret_cast(values_ - 1)); -} - -template -Local FunctionCallbackInfo::Holder() const { - return Local( - reinterpret_cast(&implicit_args_[kHolderIndex])); -} - -template -Local FunctionCallbackInfo::NewTarget() const { - return Local( - reinterpret_cast(&implicit_args_[kNewTargetIndex])); -} - -template -Local FunctionCallbackInfo::Data() const { - return Local(reinterpret_cast(&implicit_args_[kDataIndex])); -} - -template -Isolate* FunctionCallbackInfo::GetIsolate() const { - return *reinterpret_cast(&implicit_args_[kIsolateIndex]); -} - -template -ReturnValue FunctionCallbackInfo::GetReturnValue() const { - return ReturnValue(&implicit_args_[kReturnValueIndex]); -} - -template -bool FunctionCallbackInfo::IsConstructCall() const { - return !NewTarget()->IsUndefined(); -} - -template -int FunctionCallbackInfo::Length() const { - return length_; -} - -template -Isolate* PropertyCallbackInfo::GetIsolate() const { - return *reinterpret_cast(&args_[kIsolateIndex]); -} - -template -Local PropertyCallbackInfo::Data() const { - return Local(reinterpret_cast(&args_[kDataIndex])); -} - -template -Local PropertyCallbackInfo::This() const { - return Local(reinterpret_cast(&args_[kThisIndex])); -} - -template -Local PropertyCallbackInfo::Holder() const { - return Local(reinterpret_cast(&args_[kHolderIndex])); -} - -template -ReturnValue PropertyCallbackInfo::GetReturnValue() const { - return ReturnValue(&args_[kReturnValueIndex]); -} - -template -bool PropertyCallbackInfo::ShouldThrowOnError() const { - using I = internal::Internals; - if (args_[kShouldThrowOnErrorIndex] != - I::IntToSmi(I::kInferShouldThrowMode)) { - return args_[kShouldThrowOnErrorIndex] != I::IntToSmi(I::kDontThrow); - } - return v8::internal::ShouldThrowOnError( - reinterpret_cast(GetIsolate())); -} - -} // namespace v8 - -#endif // INCLUDE_V8_FUNCTION_CALLBACK_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-function.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-function.h deleted file mode 100644 index 9424a86fdaf..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-function.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_FUNCTION_H_ -#define INCLUDE_V8_FUNCTION_H_ - -#include -#include - -#include "v8-function-callback.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-message.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8-template.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * A JavaScript function object (ECMA-262, 15.3). - */ -class V8_EXPORT Function : public Object { - public: - /** - * Create a function in the current execution context - * for a given FunctionCallback. - */ - static MaybeLocal New( - Local context, FunctionCallback callback, - Local data = Local(), int length = 0, - ConstructorBehavior behavior = ConstructorBehavior::kAllow, - SideEffectType side_effect_type = SideEffectType::kHasSideEffect); - - V8_WARN_UNUSED_RESULT MaybeLocal NewInstance( - Local context, int argc, Local argv[]) const; - - V8_WARN_UNUSED_RESULT MaybeLocal NewInstance( - Local context) const { - return NewInstance(context, 0, nullptr); - } - - /** - * When side effect checks are enabled, passing kHasNoSideEffect allows the - * constructor to be invoked without throwing. Calls made within the - * constructor are still checked. - */ - V8_WARN_UNUSED_RESULT MaybeLocal NewInstanceWithSideEffectType( - Local context, int argc, Local argv[], - SideEffectType side_effect_type = SideEffectType::kHasSideEffect) const; - - V8_WARN_UNUSED_RESULT MaybeLocal Call(Local context, - Local recv, int argc, - Local argv[]); - - void SetName(Local name); - Local GetName() const; - - /** - * Name inferred from variable or property assignment of this function. - * Used to facilitate debugging and profiling of JavaScript code written - * in an OO style, where many functions are anonymous but are assigned - * to object properties. - */ - Local GetInferredName() const; - - /** - * displayName if it is set, otherwise name if it is configured, otherwise - * function name, otherwise inferred name. - */ - Local GetDebugName() const; - - /** - * Returns zero based line number of function body and - * kLineOffsetNotFound if no information available. - */ - int GetScriptLineNumber() const; - /** - * Returns zero based column number of function body and - * kLineOffsetNotFound if no information available. - */ - int GetScriptColumnNumber() const; - - /** - * Returns scriptId. - */ - int ScriptId() const; - - /** - * Returns the original function if this function is bound, else returns - * v8::Undefined. - */ - Local GetBoundFunction() const; - - /** - * Calls builtin Function.prototype.toString on this function. - * This is different from Value::ToString() that may call a user-defined - * toString() function, and different than Object::ObjectProtoToString() which - * always serializes "[object Function]". - */ - V8_WARN_UNUSED_RESULT MaybeLocal FunctionProtoToString( - Local context); - - ScriptOrigin GetScriptOrigin() const; - V8_INLINE static Function* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kLineOffsetNotFound; - - private: - Function(); - static void CheckCast(Value* obj); -}; -} // namespace v8 - -#endif // INCLUDE_V8_FUNCTION_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-initialization.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-initialization.h deleted file mode 100644 index 3b609292f62..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-initialization.h +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_INITIALIZATION_H_ -#define INCLUDE_V8_INITIALIZATION_H_ - -#include -#include - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-isolate.h" // NOLINT(build/include_directory) -#include "v8-platform.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -// We reserve the V8_* prefix for macros defined in V8 public API and -// assume there are no name conflicts with the embedder's code. - -/** - * The v8 JavaScript engine. - */ -namespace v8 { - -class PageAllocator; -class Platform; -template -class PersistentValueMapBase; - -/** - * EntropySource is used as a callback function when v8 needs a source - * of entropy. - */ -using EntropySource = bool (*)(unsigned char* buffer, size_t length); - -/** - * ReturnAddressLocationResolver is used as a callback function when v8 is - * resolving the location of a return address on the stack. Profilers that - * change the return address on the stack can use this to resolve the stack - * location to wherever the profiler stashed the original return address. - * - * \param return_addr_location A location on stack where a machine - * return address resides. - * \returns Either return_addr_location, or else a pointer to the profiler's - * copy of the original return address. - * - * \note The resolver function must not cause garbage collection. - */ -using ReturnAddressLocationResolver = - uintptr_t (*)(uintptr_t return_addr_location); - -using DcheckErrorCallback = void (*)(const char* file, int line, - const char* message); - -/** - * Container class for static utility functions. - */ -class V8_EXPORT V8 { - public: - /** - * Hand startup data to V8, in case the embedder has chosen to build - * V8 with external startup data. - * - * Note: - * - By default the startup data is linked into the V8 library, in which - * case this function is not meaningful. - * - If this needs to be called, it needs to be called before V8 - * tries to make use of its built-ins. - * - To avoid unnecessary copies of data, V8 will point directly into the - * given data blob, so pretty please keep it around until V8 exit. - * - Compression of the startup blob might be useful, but needs to - * handled entirely on the embedders' side. - * - The call will abort if the data is invalid. - */ - static void SetSnapshotDataBlob(StartupData* startup_blob); - - /** Set the callback to invoke in case of Dcheck failures. */ - static void SetDcheckErrorHandler(DcheckErrorCallback that); - - /** - * Sets V8 flags from a string. - */ - static void SetFlagsFromString(const char* str); - static void SetFlagsFromString(const char* str, size_t length); - - /** - * Sets V8 flags from the command line. - */ - static void SetFlagsFromCommandLine(int* argc, char** argv, - bool remove_flags); - - /** Get the version string. */ - static const char* GetVersion(); - - /** - * Initializes V8. This function needs to be called before the first Isolate - * is created. It always returns true. - */ - V8_INLINE static bool Initialize() { - const int kBuildConfiguration = - (internal::PointerCompressionIsEnabled() ? kPointerCompression : 0) | - (internal::SmiValuesAre31Bits() ? k31BitSmis : 0) | - (internal::HeapSandboxIsEnabled() ? kHeapSandbox : 0) | - (internal::VirtualMemoryCageIsEnabled() ? kVirtualMemoryCage : 0); - return Initialize(kBuildConfiguration); - } - - /** - * Allows the host application to provide a callback which can be used - * as a source of entropy for random number generators. - */ - static void SetEntropySource(EntropySource source); - - /** - * Allows the host application to provide a callback that allows v8 to - * cooperate with a profiler that rewrites return addresses on stack. - */ - static void SetReturnAddressLocationResolver( - ReturnAddressLocationResolver return_address_resolver); - - /** - * Releases any resources used by v8 and stops any utility threads - * that may be running. Note that disposing v8 is permanent, it - * cannot be reinitialized. - * - * It should generally not be necessary to dispose v8 before exiting - * a process, this should happen automatically. It is only necessary - * to use if the process needs the resources taken up by v8. - */ - static bool Dispose(); - - /** - * Initialize the ICU library bundled with V8. The embedder should only - * invoke this method when using the bundled ICU. Returns true on success. - * - * If V8 was compiled with the ICU data in an external file, the location - * of the data file has to be provided. - */ - static bool InitializeICU(const char* icu_data_file = nullptr); - - /** - * Initialize the ICU library bundled with V8. The embedder should only - * invoke this method when using the bundled ICU. If V8 was compiled with - * the ICU data in an external file and when the default location of that - * file should be used, a path to the executable must be provided. - * Returns true on success. - * - * The default is a file called icudtl.dat side-by-side with the executable. - * - * Optionally, the location of the data file can be provided to override the - * default. - */ - static bool InitializeICUDefaultLocation(const char* exec_path, - const char* icu_data_file = nullptr); - - /** - * Initialize the external startup data. The embedder only needs to - * invoke this method when external startup data was enabled in a build. - * - * If V8 was compiled with the startup data in an external file, then - * V8 needs to be given those external files during startup. There are - * three ways to do this: - * - InitializeExternalStartupData(const char*) - * This will look in the given directory for the file "snapshot_blob.bin". - * - InitializeExternalStartupDataFromFile(const char*) - * As above, but will directly use the given file name. - * - Call SetSnapshotDataBlob. - * This will read the blobs from the given data structure and will - * not perform any file IO. - */ - static void InitializeExternalStartupData(const char* directory_path); - static void InitializeExternalStartupDataFromFile(const char* snapshot_blob); - - /** - * Sets the v8::Platform to use. This should be invoked before V8 is - * initialized. - */ - static void InitializePlatform(Platform* platform); - - /** - * Clears all references to the v8::Platform. This should be invoked after - * V8 was disposed. - */ - static void ShutdownPlatform(); - -#ifdef V8_VIRTUAL_MEMORY_CAGE - // - // Virtual Memory Cage related API. - // - // This API is not yet stable and subject to changes in the future. - // - - /** - * Initializes the virtual memory cage for V8. - * - * This must be invoked after the platform was initialized but before V8 is - * initialized. The virtual memory cage is torn down during platform shutdown. - * Returns true on success, false otherwise. - */ - static bool InitializeVirtualMemoryCage(); - - /** - * Provides access to the data page allocator for the virtual memory cage. - * - * This allocator allocates pages inside the data cage part of the virtual - * memory cage in which data buffers such as ArrayBuffer backing stores must - * be allocated. Objects in this region should generally consists purely of - * data and not contain any pointers. It should be assumed that an attacker - * can corrupt data inside the cage, and so in particular the contents of - * pages returned by this allocator, arbitrarily and concurrently. - * - * The virtual memory cage must have been initialized before. - */ - static PageAllocator* GetVirtualMemoryCageDataPageAllocator(); -#endif - - /** - * Activate trap-based bounds checking for WebAssembly. - * - * \param use_v8_signal_handler Whether V8 should install its own signal - * handler or rely on the embedder's. - */ - static bool EnableWebAssemblyTrapHandler(bool use_v8_signal_handler); - -#if defined(V8_OS_WIN) - /** - * On Win64, by default V8 does not emit unwinding data for jitted code, - * which means the OS cannot walk the stack frames and the system Structured - * Exception Handling (SEH) cannot unwind through V8-generated code: - * https://code.google.com/p/v8/issues/detail?id=3598. - * - * This function allows embedders to register a custom exception handler for - * exceptions in V8-generated code. - */ - static void SetUnhandledExceptionCallback( - UnhandledExceptionCallback unhandled_exception_callback); -#endif - - /** - * Get statistics about the shared memory usage. - */ - static void GetSharedMemoryStatistics(SharedMemoryStatistics* statistics); - - private: - V8(); - - enum BuildConfigurationFeatures { - kPointerCompression = 1 << 0, - k31BitSmis = 1 << 1, - kHeapSandbox = 1 << 2, - kVirtualMemoryCage = 1 << 3, - }; - - /** - * Checks that the embedder build configuration is compatible with - * the V8 binary and if so initializes V8. - */ - static bool Initialize(int build_config); - - friend class Context; - template - friend class PersistentValueMapBase; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_INITIALIZATION_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-inspector-protocol.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-inspector-protocol.h deleted file mode 100644 index a5ffb7d6954..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-inspector-protocol.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_INSPECTOR_PROTOCOL_H_ -#define V8_V8_INSPECTOR_PROTOCOL_H_ - -#include "inspector/Debugger.h" // NOLINT(build/include_directory) -#include "inspector/Runtime.h" // NOLINT(build/include_directory) -#include "inspector/Schema.h" // NOLINT(build/include_directory) -#include "v8-inspector.h" // NOLINT(build/include_directory) - -#endif // V8_V8_INSPECTOR_PROTOCOL_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-inspector.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-inspector.h deleted file mode 100644 index 74592fdf573..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-inspector.h +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_INSPECTOR_H_ -#define V8_V8_INSPECTOR_H_ - -#include - -#include -#include - -#include "v8-isolate.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) - -namespace v8 { -class Context; -class Name; -class Object; -class StackTrace; -class Value; -} // namespace v8 - -namespace v8_inspector { - -namespace protocol { -namespace Debugger { -namespace API { -class SearchMatch; -} -} -namespace Runtime { -namespace API { -class RemoteObject; -class StackTrace; -class StackTraceId; -} -} -namespace Schema { -namespace API { -class Domain; -} -} -} // namespace protocol - -class V8_EXPORT StringView { - public: - StringView() : m_is8Bit(true), m_length(0), m_characters8(nullptr) {} - - StringView(const uint8_t* characters, size_t length) - : m_is8Bit(true), m_length(length), m_characters8(characters) {} - - StringView(const uint16_t* characters, size_t length) - : m_is8Bit(false), m_length(length), m_characters16(characters) {} - - bool is8Bit() const { return m_is8Bit; } - size_t length() const { return m_length; } - - // TODO(dgozman): add DCHECK(m_is8Bit) to accessors once platform can be used - // here. - const uint8_t* characters8() const { return m_characters8; } - const uint16_t* characters16() const { return m_characters16; } - - private: - bool m_is8Bit; - size_t m_length; - union { - const uint8_t* m_characters8; - const uint16_t* m_characters16; - }; -}; - -class V8_EXPORT StringBuffer { - public: - virtual ~StringBuffer() = default; - virtual StringView string() const = 0; - // This method copies contents. - static std::unique_ptr create(StringView); -}; - -class V8_EXPORT V8ContextInfo { - public: - V8ContextInfo(v8::Local context, int contextGroupId, - StringView humanReadableName) - : context(context), - contextGroupId(contextGroupId), - humanReadableName(humanReadableName), - hasMemoryOnConsole(false) {} - - v8::Local context; - // Each v8::Context is a part of a group. The group id must be non-zero. - int contextGroupId; - StringView humanReadableName; - StringView origin; - StringView auxData; - bool hasMemoryOnConsole; - - static int executionContextId(v8::Local context); - - // Disallow copying and allocating this one. - enum NotNullTagEnum { NotNullLiteral }; - void* operator new(size_t) = delete; - void* operator new(size_t, NotNullTagEnum, void*) = delete; - void* operator new(size_t, void*) = delete; - V8ContextInfo(const V8ContextInfo&) = delete; - V8ContextInfo& operator=(const V8ContextInfo&) = delete; -}; - -class V8_EXPORT V8StackTrace { - public: - virtual StringView firstNonEmptySourceURL() const = 0; - virtual bool isEmpty() const = 0; - virtual StringView topSourceURL() const = 0; - virtual int topLineNumber() const = 0; - virtual int topColumnNumber() const = 0; - virtual int topScriptId() const = 0; - V8_DEPRECATE_SOON("Use V8::StackTrace::topScriptId() instead.") - int topScriptIdAsInteger() const { return topScriptId(); } - virtual StringView topFunctionName() const = 0; - - virtual ~V8StackTrace() = default; - virtual std::unique_ptr - buildInspectorObject() const = 0; - virtual std::unique_ptr - buildInspectorObject(int maxAsyncDepth) const = 0; - virtual std::unique_ptr toString() const = 0; - - // Safe to pass between threads, drops async chain. - virtual std::unique_ptr clone() = 0; -}; - -class V8_EXPORT V8InspectorSession { - public: - virtual ~V8InspectorSession() = default; - - // Cross-context inspectable values (DOM nodes in different worlds, etc.). - class V8_EXPORT Inspectable { - public: - virtual v8::Local get(v8::Local) = 0; - virtual ~Inspectable() = default; - }; - class V8_EXPORT CommandLineAPIScope { - public: - virtual ~CommandLineAPIScope() = default; - }; - virtual void addInspectedObject(std::unique_ptr) = 0; - - // Dispatching protocol messages. - static bool canDispatchMethod(StringView method); - virtual void dispatchProtocolMessage(StringView message) = 0; - virtual std::vector state() = 0; - virtual std::vector> - supportedDomains() = 0; - - virtual std::unique_ptr - initializeCommandLineAPIScope(int executionContextId) = 0; - - // Debugger actions. - virtual void schedulePauseOnNextStatement(StringView breakReason, - StringView breakDetails) = 0; - virtual void cancelPauseOnNextStatement() = 0; - virtual void breakProgram(StringView breakReason, - StringView breakDetails) = 0; - virtual void setSkipAllPauses(bool) = 0; - virtual void resume(bool setTerminateOnResume = false) = 0; - virtual void stepOver() = 0; - virtual std::vector> - searchInTextByLines(StringView text, StringView query, bool caseSensitive, - bool isRegex) = 0; - - // Remote objects. - virtual std::unique_ptr wrapObject( - v8::Local, v8::Local, StringView groupName, - bool generatePreview) = 0; - - virtual bool unwrapObject(std::unique_ptr* error, - StringView objectId, v8::Local*, - v8::Local*, - std::unique_ptr* objectGroup) = 0; - virtual void releaseObjectGroup(StringView) = 0; - virtual void triggerPreciseCoverageDeltaUpdate(StringView occasion) = 0; -}; - -class V8_EXPORT V8InspectorClient { - public: - virtual ~V8InspectorClient() = default; - - virtual void runMessageLoopOnPause(int contextGroupId) {} - virtual void quitMessageLoopOnPause() {} - virtual void runIfWaitingForDebugger(int contextGroupId) {} - - virtual void muteMetrics(int contextGroupId) {} - virtual void unmuteMetrics(int contextGroupId) {} - - virtual void beginUserGesture() {} - virtual void endUserGesture() {} - - virtual std::unique_ptr valueSubtype(v8::Local) { - return nullptr; - } - virtual std::unique_ptr descriptionForValueSubtype( - v8::Local, v8::Local) { - return nullptr; - } - virtual bool isInspectableHeapObject(v8::Local) { return true; } - - virtual v8::Local ensureDefaultContextInGroup( - int contextGroupId) { - return v8::Local(); - } - virtual void beginEnsureAllContextsInGroup(int contextGroupId) {} - virtual void endEnsureAllContextsInGroup(int contextGroupId) {} - - virtual void installAdditionalCommandLineAPI(v8::Local, - v8::Local) {} - virtual void consoleAPIMessage(int contextGroupId, - v8::Isolate::MessageErrorLevel level, - const StringView& message, - const StringView& url, unsigned lineNumber, - unsigned columnNumber, V8StackTrace*) {} - virtual v8::MaybeLocal memoryInfo(v8::Isolate*, - v8::Local) { - return v8::MaybeLocal(); - } - - virtual void consoleTime(const StringView& title) {} - virtual void consoleTimeEnd(const StringView& title) {} - virtual void consoleTimeStamp(const StringView& title) {} - virtual void consoleClear(int contextGroupId) {} - virtual double currentTimeMS() { return 0; } - typedef void (*TimerCallback)(void*); - virtual void startRepeatingTimer(double, TimerCallback, void* data) {} - virtual void cancelTimer(void* data) {} - - // TODO(dgozman): this was added to support service worker shadow page. We - // should not connect at all. - virtual bool canExecuteScripts(int contextGroupId) { return true; } - - virtual void maxAsyncCallStackDepthChanged(int depth) {} - - virtual std::unique_ptr resourceNameToUrl( - const StringView& resourceName) { - return nullptr; - } - - // The caller would defer to generating a random 64 bit integer if - // this method returns 0. - virtual int64_t generateUniqueId() { return 0; } -}; - -// These stack trace ids are intended to be passed between debuggers and be -// resolved later. This allows to track cross-debugger calls and step between -// them if a single client connects to multiple debuggers. -struct V8_EXPORT V8StackTraceId { - uintptr_t id; - std::pair debugger_id; - bool should_pause = false; - - V8StackTraceId(); - V8StackTraceId(const V8StackTraceId&) = default; - V8StackTraceId(uintptr_t id, const std::pair debugger_id); - V8StackTraceId(uintptr_t id, const std::pair debugger_id, - bool should_pause); - explicit V8StackTraceId(StringView); - V8StackTraceId& operator=(const V8StackTraceId&) = default; - V8StackTraceId& operator=(V8StackTraceId&&) noexcept = default; - ~V8StackTraceId() = default; - - bool IsInvalid() const; - std::unique_ptr ToString(); -}; - -class V8_EXPORT V8Inspector { - public: - static std::unique_ptr create(v8::Isolate*, V8InspectorClient*); - virtual ~V8Inspector() = default; - - // Contexts instrumentation. - virtual void contextCreated(const V8ContextInfo&) = 0; - virtual void contextDestroyed(v8::Local) = 0; - virtual void resetContextGroup(int contextGroupId) = 0; - virtual v8::MaybeLocal contextById(int contextId) = 0; - - // Various instrumentation. - virtual void idleStarted() = 0; - virtual void idleFinished() = 0; - - // Async stack traces instrumentation. - virtual void asyncTaskScheduled(StringView taskName, void* task, - bool recurring) = 0; - virtual void asyncTaskCanceled(void* task) = 0; - virtual void asyncTaskStarted(void* task) = 0; - virtual void asyncTaskFinished(void* task) = 0; - virtual void allAsyncTasksCanceled() = 0; - - virtual V8StackTraceId storeCurrentStackTrace(StringView description) = 0; - virtual void externalAsyncTaskStarted(const V8StackTraceId& parent) = 0; - virtual void externalAsyncTaskFinished(const V8StackTraceId& parent) = 0; - - // Exceptions instrumentation. - virtual unsigned exceptionThrown(v8::Local, StringView message, - v8::Local exception, - StringView detailedMessage, StringView url, - unsigned lineNumber, unsigned columnNumber, - std::unique_ptr, - int scriptId) = 0; - virtual void exceptionRevoked(v8::Local, unsigned exceptionId, - StringView message) = 0; - virtual bool associateExceptionData(v8::Local, - v8::Local exception, - v8::Local key, - v8::Local value) = 0; - - // Connection. - class V8_EXPORT Channel { - public: - virtual ~Channel() = default; - virtual void sendResponse(int callId, - std::unique_ptr message) = 0; - virtual void sendNotification(std::unique_ptr message) = 0; - virtual void flushProtocolNotifications() = 0; - }; - virtual std::unique_ptr connect(int contextGroupId, - Channel*, - StringView state) = 0; - - // API methods. - virtual std::unique_ptr createStackTrace( - v8::Local) = 0; - virtual std::unique_ptr captureStackTrace(bool fullStack) = 0; -}; - -} // namespace v8_inspector - -#endif // V8_V8_INSPECTOR_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-internal.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-internal.h deleted file mode 100644 index 6516a16219f..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-internal.h +++ /dev/null @@ -1,578 +0,0 @@ -// Copyright 2018 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_INTERNAL_H_ -#define INCLUDE_V8_INTERNAL_H_ - -#include -#include -#include -#include - -#include "v8-version.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Array; -class Context; -class Data; -class Isolate; -template -class Local; - -namespace internal { - -class Isolate; - -typedef uintptr_t Address; -static const Address kNullAddress = 0; - -/** - * Configuration of tagging scheme. - */ -const int kApiSystemPointerSize = sizeof(void*); -const int kApiDoubleSize = sizeof(double); -const int kApiInt32Size = sizeof(int32_t); -const int kApiInt64Size = sizeof(int64_t); -const int kApiSizetSize = sizeof(size_t); - -// Tag information for HeapObject. -const int kHeapObjectTag = 1; -const int kWeakHeapObjectTag = 3; -const int kHeapObjectTagSize = 2; -const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; - -// Tag information for fowarding pointers stored in object headers. -// 0b00 at the lowest 2 bits in the header indicates that the map word is a -// forwarding pointer. -const int kForwardingTag = 0; -const int kForwardingTagSize = 2; -const intptr_t kForwardingTagMask = (1 << kForwardingTagSize) - 1; - -// Tag information for Smi. -const int kSmiTag = 0; -const int kSmiTagSize = 1; -const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1; - -template -struct SmiTagging; - -constexpr intptr_t kIntptrAllBitsSet = intptr_t{-1}; -constexpr uintptr_t kUintptrAllBitsSet = - static_cast(kIntptrAllBitsSet); - -// Smi constants for systems where tagged pointer is a 32-bit value. -template <> -struct SmiTagging<4> { - enum { kSmiShiftSize = 0, kSmiValueSize = 31 }; - - static constexpr intptr_t kSmiMinValue = - static_cast(kUintptrAllBitsSet << (kSmiValueSize - 1)); - static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1); - - V8_INLINE static int SmiToInt(const internal::Address value) { - int shift_bits = kSmiTagSize + kSmiShiftSize; - // Truncate and shift down (requires >> to be sign extending). - return static_cast(static_cast(value)) >> shift_bits; - } - V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { - // Is value in range [kSmiMinValue, kSmiMaxValue]. - // Use unsigned operations in order to avoid undefined behaviour in case of - // signed integer overflow. - return (static_cast(value) - - static_cast(kSmiMinValue)) <= - (static_cast(kSmiMaxValue) - - static_cast(kSmiMinValue)); - } -}; - -// Smi constants for systems where tagged pointer is a 64-bit value. -template <> -struct SmiTagging<8> { - enum { kSmiShiftSize = 31, kSmiValueSize = 32 }; - - static constexpr intptr_t kSmiMinValue = - static_cast(kUintptrAllBitsSet << (kSmiValueSize - 1)); - static constexpr intptr_t kSmiMaxValue = -(kSmiMinValue + 1); - - V8_INLINE static int SmiToInt(const internal::Address value) { - int shift_bits = kSmiTagSize + kSmiShiftSize; - // Shift down and throw away top 32 bits. - return static_cast(static_cast(value) >> shift_bits); - } - V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { - // To be representable as a long smi, the value must be a 32-bit integer. - return (value == static_cast(value)); - } -}; - -#ifdef V8_COMPRESS_POINTERS -static_assert( - kApiSystemPointerSize == kApiInt64Size, - "Pointer compression can be enabled only for 64-bit architectures"); -const int kApiTaggedSize = kApiInt32Size; -#else -const int kApiTaggedSize = kApiSystemPointerSize; -#endif - -constexpr bool PointerCompressionIsEnabled() { - return kApiTaggedSize != kApiSystemPointerSize; -} - -constexpr bool HeapSandboxIsEnabled() { -#ifdef V8_HEAP_SANDBOX - return true; -#else - return false; -#endif -} - -using ExternalPointer_t = Address; - -// If the heap sandbox is enabled, these tag values will be ORed with the -// external pointers in the external pointer table to prevent use of pointers of -// the wrong type. When a pointer is loaded, it is ANDed with the inverse of the -// expected type's tag. The tags are constructed in a way that guarantees that a -// failed type check will result in one or more of the top bits of the pointer -// to be set, rendering the pointer inacessible. This construction allows -// performing the type check and removing GC marking bits from the pointer at -// the same time. -enum ExternalPointerTag : uint64_t { - kExternalPointerNullTag = 0x0000000000000000, - kExternalStringResourceTag = 0x00ff000000000000, // 0b000000011111111 - kExternalStringResourceDataTag = 0x017f000000000000, // 0b000000101111111 - kForeignForeignAddressTag = 0x01bf000000000000, // 0b000000110111111 - kNativeContextMicrotaskQueueTag = 0x01df000000000000, // 0b000000111011111 - kEmbedderDataSlotPayloadTag = 0x01ef000000000000, // 0b000000111101111 - kCodeEntryPointTag = 0x01f7000000000000, // 0b000000111110111 -}; - -constexpr uint64_t kExternalPointerTagMask = 0xffff000000000000; - -#ifdef V8_31BIT_SMIS_ON_64BIT_ARCH -using PlatformSmiTagging = SmiTagging; -#else -using PlatformSmiTagging = SmiTagging; -#endif - -// TODO(ishell): Consinder adding kSmiShiftBits = kSmiShiftSize + kSmiTagSize -// since it's used much more often than the inividual constants. -const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize; -const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize; -const int kSmiMinValue = static_cast(PlatformSmiTagging::kSmiMinValue); -const int kSmiMaxValue = static_cast(PlatformSmiTagging::kSmiMaxValue); -constexpr bool SmiValuesAre31Bits() { return kSmiValueSize == 31; } -constexpr bool SmiValuesAre32Bits() { return kSmiValueSize == 32; } - -V8_INLINE static constexpr internal::Address IntToSmi(int value) { - return (static_cast
(value) << (kSmiTagSize + kSmiShiftSize)) | - kSmiTag; -} - -// Converts encoded external pointer to address. -V8_EXPORT Address DecodeExternalPointerImpl(const Isolate* isolate, - ExternalPointer_t pointer, - ExternalPointerTag tag); - -// {obj} must be the raw tagged pointer representation of a HeapObject -// that's guaranteed to never be in ReadOnlySpace. -V8_EXPORT internal::Isolate* IsolateFromNeverReadOnlySpaceObject(Address obj); - -// Returns if we need to throw when an error occurs. This infers the language -// mode based on the current context and the closure. This returns true if the -// language mode is strict. -V8_EXPORT bool ShouldThrowOnError(v8::internal::Isolate* isolate); - -V8_EXPORT bool CanHaveInternalField(int instance_type); - -/** - * This class exports constants and functionality from within v8 that - * is necessary to implement inline functions in the v8 api. Don't - * depend on functions and constants defined here. - */ -class Internals { -#ifdef V8_MAP_PACKING - V8_INLINE static constexpr internal::Address UnpackMapWord( - internal::Address mapword) { - // TODO(wenyuzhao): Clear header metadata. - return mapword ^ kMapWordXorMask; - } -#endif - - public: - // These values match non-compiler-dependent values defined within - // the implementation of v8. - static const int kHeapObjectMapOffset = 0; - static const int kMapInstanceTypeOffset = 1 * kApiTaggedSize + kApiInt32Size; - static const int kStringResourceOffset = - 1 * kApiTaggedSize + 2 * kApiInt32Size; - - static const int kOddballKindOffset = 4 * kApiTaggedSize + kApiDoubleSize; - static const int kJSObjectHeaderSize = 3 * kApiTaggedSize; - static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize; - static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize; - static const int kEmbedderDataSlotSize = kApiSystemPointerSize; -#ifdef V8_HEAP_SANDBOX - static const int kEmbedderDataSlotRawPayloadOffset = kApiTaggedSize; -#endif - static const int kNativeContextEmbedderDataOffset = 6 * kApiTaggedSize; - static const int kFullStringRepresentationMask = 0x0f; - static const int kStringEncodingMask = 0x8; - static const int kExternalTwoByteRepresentationTag = 0x02; - static const int kExternalOneByteRepresentationTag = 0x0a; - - static const uint32_t kNumIsolateDataSlots = 4; - - // IsolateData layout guarantees. - static const int kIsolateEmbedderDataOffset = 0; - static const int kIsolateFastCCallCallerFpOffset = - kNumIsolateDataSlots * kApiSystemPointerSize; - static const int kIsolateFastCCallCallerPcOffset = - kIsolateFastCCallCallerFpOffset + kApiSystemPointerSize; - static const int kIsolateFastApiCallTargetOffset = - kIsolateFastCCallCallerPcOffset + kApiSystemPointerSize; - static const int kIsolateCageBaseOffset = - kIsolateFastApiCallTargetOffset + kApiSystemPointerSize; - static const int kIsolateLongTaskStatsCounterOffset = - kIsolateCageBaseOffset + kApiSystemPointerSize; - static const int kIsolateStackGuardOffset = - kIsolateLongTaskStatsCounterOffset + kApiSizetSize; - static const int kIsolateRootsOffset = - kIsolateStackGuardOffset + 7 * kApiSystemPointerSize; - - static const int kExternalPointerTableBufferOffset = 0; - static const int kExternalPointerTableLengthOffset = - kExternalPointerTableBufferOffset + kApiSystemPointerSize; - static const int kExternalPointerTableCapacityOffset = - kExternalPointerTableLengthOffset + kApiInt32Size; - - static const int kUndefinedValueRootIndex = 4; - static const int kTheHoleValueRootIndex = 5; - static const int kNullValueRootIndex = 6; - static const int kTrueValueRootIndex = 7; - static const int kFalseValueRootIndex = 8; - static const int kEmptyStringRootIndex = 9; - - static const int kNodeClassIdOffset = 1 * kApiSystemPointerSize; - static const int kNodeFlagsOffset = 1 * kApiSystemPointerSize + 3; - static const int kNodeStateMask = 0x7; - static const int kNodeStateIsWeakValue = 2; - static const int kNodeStateIsPendingValue = 3; - - static const int kFirstNonstringType = 0x40; - static const int kOddballType = 0x43; - static const int kForeignType = 0x46; - static const int kJSSpecialApiObjectType = 0x410; - static const int kJSObjectType = 0x421; - static const int kFirstJSApiObjectType = 0x422; - static const int kLastJSApiObjectType = 0x80A; - - static const int kUndefinedOddballKind = 5; - static const int kNullOddballKind = 3; - - // Constants used by PropertyCallbackInfo to check if we should throw when an - // error occurs. - static const int kThrowOnError = 0; - static const int kDontThrow = 1; - static const int kInferShouldThrowMode = 2; - - // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an - // incremental GC once the external memory reaches this limit. - static constexpr int kExternalAllocationSoftLimit = 64 * 1024 * 1024; - -#ifdef V8_MAP_PACKING - static const uintptr_t kMapWordMetadataMask = 0xffffULL << 48; - // The lowest two bits of mapwords are always `0b10` - static const uintptr_t kMapWordSignature = 0b10; - // XORing a (non-compressed) map with this mask ensures that the two - // low-order bits are 0b10. The 0 at the end makes this look like a Smi, - // although real Smis have all lower 32 bits unset. We only rely on these - // values passing as Smis in very few places. - static const int kMapWordXorMask = 0b11; -#endif - - V8_EXPORT static void CheckInitializedImpl(v8::Isolate* isolate); - V8_INLINE static void CheckInitialized(v8::Isolate* isolate) { -#ifdef V8_ENABLE_CHECKS - CheckInitializedImpl(isolate); -#endif - } - - V8_INLINE static bool HasHeapObjectTag(const internal::Address value) { - return (value & kHeapObjectTagMask) == static_cast
(kHeapObjectTag); - } - - V8_INLINE static int SmiValue(const internal::Address value) { - return PlatformSmiTagging::SmiToInt(value); - } - - V8_INLINE static constexpr internal::Address IntToSmi(int value) { - return internal::IntToSmi(value); - } - - V8_INLINE static constexpr bool IsValidSmi(intptr_t value) { - return PlatformSmiTagging::IsValidSmi(value); - } - - V8_INLINE static int GetInstanceType(const internal::Address obj) { - typedef internal::Address A; - A map = ReadTaggedPointerField(obj, kHeapObjectMapOffset); -#ifdef V8_MAP_PACKING - map = UnpackMapWord(map); -#endif - return ReadRawField(map, kMapInstanceTypeOffset); - } - - V8_INLINE static int GetOddballKind(const internal::Address obj) { - return SmiValue(ReadTaggedSignedField(obj, kOddballKindOffset)); - } - - V8_INLINE static bool IsExternalTwoByteString(int instance_type) { - int representation = (instance_type & kFullStringRepresentationMask); - return representation == kExternalTwoByteRepresentationTag; - } - - V8_INLINE static uint8_t GetNodeFlag(internal::Address* obj, int shift) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - return *addr & static_cast(1U << shift); - } - - V8_INLINE static void UpdateNodeFlag(internal::Address* obj, bool value, - int shift) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - uint8_t mask = static_cast(1U << shift); - *addr = static_cast((*addr & ~mask) | (value << shift)); - } - - V8_INLINE static uint8_t GetNodeState(internal::Address* obj) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - return *addr & kNodeStateMask; - } - - V8_INLINE static void UpdateNodeState(internal::Address* obj, uint8_t value) { - uint8_t* addr = reinterpret_cast(obj) + kNodeFlagsOffset; - *addr = static_cast((*addr & ~kNodeStateMask) | value); - } - - V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, uint32_t slot, - void* data) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateEmbedderDataOffset + - slot * kApiSystemPointerSize; - *reinterpret_cast(addr) = data; - } - - V8_INLINE static void* GetEmbedderData(const v8::Isolate* isolate, - uint32_t slot) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateEmbedderDataOffset + - slot * kApiSystemPointerSize; - return *reinterpret_cast(addr); - } - - V8_INLINE static void IncrementLongTasksStatsCounter(v8::Isolate* isolate) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateLongTaskStatsCounterOffset; - ++(*reinterpret_cast(addr)); - } - - V8_INLINE static internal::Address* GetRoot(v8::Isolate* isolate, int index) { - internal::Address addr = reinterpret_cast(isolate) + - kIsolateRootsOffset + - index * kApiSystemPointerSize; - return reinterpret_cast(addr); - } - - template - V8_INLINE static T ReadRawField(internal::Address heap_object_ptr, - int offset) { - internal::Address addr = heap_object_ptr + offset - kHeapObjectTag; -#ifdef V8_COMPRESS_POINTERS - if (sizeof(T) > kApiTaggedSize) { - // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size - // fields (external pointers, doubles and BigInt data) are only - // kTaggedSize aligned so we have to use unaligned pointer friendly way of - // accessing them in order to avoid undefined behavior in C++ code. - T r; - memcpy(&r, reinterpret_cast(addr), sizeof(T)); - return r; - } -#endif - return *reinterpret_cast(addr); - } - - V8_INLINE static internal::Address ReadTaggedPointerField( - internal::Address heap_object_ptr, int offset) { -#ifdef V8_COMPRESS_POINTERS - uint32_t value = ReadRawField(heap_object_ptr, offset); - internal::Address base = - GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr); - return base + static_cast(static_cast(value)); -#else - return ReadRawField(heap_object_ptr, offset); -#endif - } - - V8_INLINE static internal::Address ReadTaggedSignedField( - internal::Address heap_object_ptr, int offset) { -#ifdef V8_COMPRESS_POINTERS - uint32_t value = ReadRawField(heap_object_ptr, offset); - return static_cast(static_cast(value)); -#else - return ReadRawField(heap_object_ptr, offset); -#endif - } - - V8_INLINE static internal::Isolate* GetIsolateForHeapSandbox( - internal::Address obj) { -#ifdef V8_HEAP_SANDBOX - return internal::IsolateFromNeverReadOnlySpaceObject(obj); -#else - // Not used in non-sandbox mode. - return nullptr; -#endif - } - - V8_INLINE static Address DecodeExternalPointer( - const Isolate* isolate, ExternalPointer_t encoded_pointer, - ExternalPointerTag tag) { -#ifdef V8_HEAP_SANDBOX - return internal::DecodeExternalPointerImpl(isolate, encoded_pointer, tag); -#else - return encoded_pointer; -#endif - } - - V8_INLINE static internal::Address ReadExternalPointerField( - internal::Isolate* isolate, internal::Address heap_object_ptr, int offset, - ExternalPointerTag tag) { -#ifdef V8_HEAP_SANDBOX - internal::ExternalPointer_t encoded_value = - ReadRawField(heap_object_ptr, offset); - // We currently have to treat zero as nullptr in embedder slots. - return encoded_value ? DecodeExternalPointer(isolate, encoded_value, tag) - : 0; -#else - return ReadRawField
(heap_object_ptr, offset); -#endif - } - -#ifdef V8_COMPRESS_POINTERS - // See v8:7703 or src/ptr-compr.* for details about pointer compression. - static constexpr size_t kPtrComprCageReservationSize = size_t{1} << 32; - static constexpr size_t kPtrComprCageBaseAlignment = size_t{1} << 32; - - V8_INLINE static internal::Address GetPtrComprCageBaseFromOnHeapAddress( - internal::Address addr) { - return addr & -static_cast(kPtrComprCageBaseAlignment); - } - - V8_INLINE static internal::Address DecompressTaggedAnyField( - internal::Address heap_object_ptr, uint32_t value) { - internal::Address base = - GetPtrComprCageBaseFromOnHeapAddress(heap_object_ptr); - return base + static_cast(static_cast(value)); - } - -#endif // V8_COMPRESS_POINTERS -}; - -constexpr bool VirtualMemoryCageIsEnabled() { -#ifdef V8_VIRTUAL_MEMORY_CAGE - return true; -#else - return false; -#endif -} - -#ifdef V8_VIRTUAL_MEMORY_CAGE -// Size of the pointer compression cage located at the start of the virtual -// memory cage. -constexpr size_t kVirtualMemoryCagePointerCageSize = - Internals::kPtrComprCageReservationSize; - -// Size of the virtual memory cage, excluding the guard regions surrounding it. -constexpr size_t kVirtualMemoryCageSize = size_t{1} << 40; // 1 TB - -static_assert(kVirtualMemoryCageSize > kVirtualMemoryCagePointerCageSize, - "The virtual memory cage must be larger than the pointer " - "compression cage contained within it."); - -// Required alignment of the virtual memory cage. For simplicity, we require the -// size of the guard regions to be a multiple of this, so that this specifies -// the alignment of the cage including and excluding surrounding guard regions. -// The alignment requirement is due to the pointer compression cage being -// located at the start of the virtual memory cage. -constexpr size_t kVirtualMemoryCageAlignment = - Internals::kPtrComprCageBaseAlignment; - -// Size of the guard regions surrounding the virtual memory cage. This assumes a -// worst-case scenario of a 32-bit unsigned index being used to access an array -// of 64-bit values. -constexpr size_t kVirtualMemoryCageGuardRegionSize = size_t{32} << 30; // 32 GB - -static_assert((kVirtualMemoryCageGuardRegionSize % - kVirtualMemoryCageAlignment) == 0, - "The size of the virtual memory cage guard region must be a " - "multiple of its required alignment."); - -// Minimum possible size of the virtual memory cage, excluding the guard regions -// surrounding it. Used by unit tests. -constexpr size_t kVirtualMemoryCageMinimumSize = - 2 * kVirtualMemoryCagePointerCageSize; - -// For now, even if the virtual memory cage is enabled, we still allow backing -// stores to be allocated outside of it as fallback. This will simplify the -// initial rollout. However, if the heap sandbox is also enabled, we already use -// the "enforcing mode" of the virtual memory cage. This is useful for testing. -#ifdef V8_HEAP_SANDBOX -constexpr bool kAllowBackingStoresOutsideDataCage = false; -#else -constexpr bool kAllowBackingStoresOutsideDataCage = true; -#endif // V8_HEAP_SANDBOX - -#endif // V8_VIRTUAL_MEMORY_CAGE - -// Only perform cast check for types derived from v8::Data since -// other types do not implement the Cast method. -template -struct CastCheck { - template - static void Perform(T* data); -}; - -template <> -template -void CastCheck::Perform(T* data) { - T::Cast(data); -} - -template <> -template -void CastCheck::Perform(T* data) {} - -template -V8_INLINE void PerformCastCheck(T* data) { - CastCheck::value && - !std::is_same>::value>::Perform(data); -} - -// A base class for backing stores, which is needed due to vagaries of -// how static casts work with std::shared_ptr. -class BackingStoreBase {}; - -} // namespace internal - -V8_EXPORT bool CopyAndConvertArrayToCppBufferInt32(Local src, - int32_t* dst, - uint32_t max_length); - -V8_EXPORT bool CopyAndConvertArrayToCppBufferFloat64(Local src, - double* dst, - uint32_t max_length); - -} // namespace v8 - -#endif // INCLUDE_V8_INTERNAL_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-isolate.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-isolate.h deleted file mode 100644 index c018859c020..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-isolate.h +++ /dev/null @@ -1,1669 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_ISOLATE_H_ -#define INCLUDE_V8_ISOLATE_H_ - -#include -#include - -#include -#include -#include - -#include "cppgc/common.h" -#include "v8-array-buffer.h" // NOLINT(build/include_directory) -#include "v8-callbacks.h" // NOLINT(build/include_directory) -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-debug.h" // NOLINT(build/include_directory) -#include "v8-embedder-heap.h" // NOLINT(build/include_directory) -#include "v8-function-callback.h" // NOLINT(build/include_directory) -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-microtask.h" // NOLINT(build/include_directory) -#include "v8-persistent-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8-statistics.h" // NOLINT(build/include_directory) -#include "v8-unwinder.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class CppHeap; -class HeapProfiler; -class MicrotaskQueue; -class StartupData; -class ScriptOrModule; -class SharedArrayBuffer; - -namespace internal { -class MicrotaskQueue; -class ThreadLocalTop; -} // namespace internal - -namespace metrics { -class Recorder; -} // namespace metrics - -/** - * A set of constraints that specifies the limits of the runtime's memory use. - * You must set the heap size before initializing the VM - the size cannot be - * adjusted after the VM is initialized. - * - * If you are using threads then you should hold the V8::Locker lock while - * setting the stack limit and you must set a non-default stack limit separately - * for each thread. - * - * The arguments for set_max_semi_space_size, set_max_old_space_size, - * set_max_executable_size, set_code_range_size specify limits in MB. - * - * The argument for set_max_semi_space_size_in_kb is in KB. - */ -class V8_EXPORT ResourceConstraints { - public: - /** - * Configures the constraints with reasonable default values based on the - * provided heap size limit. The heap size includes both the young and - * the old generation. - * - * \param initial_heap_size_in_bytes The initial heap size or zero. - * By default V8 starts with a small heap and dynamically grows it to - * match the set of live objects. This may lead to ineffective - * garbage collections at startup if the live set is large. - * Setting the initial heap size avoids such garbage collections. - * Note that this does not affect young generation garbage collections. - * - * \param maximum_heap_size_in_bytes The hard limit for the heap size. - * When the heap size approaches this limit, V8 will perform series of - * garbage collections and invoke the NearHeapLimitCallback. If the garbage - * collections do not help and the callback does not increase the limit, - * then V8 will crash with V8::FatalProcessOutOfMemory. - */ - void ConfigureDefaultsFromHeapSize(size_t initial_heap_size_in_bytes, - size_t maximum_heap_size_in_bytes); - - /** - * Configures the constraints with reasonable default values based on the - * capabilities of the current device the VM is running on. - * - * \param physical_memory The total amount of physical memory on the current - * device, in bytes. - * \param virtual_memory_limit The amount of virtual memory on the current - * device, in bytes, or zero, if there is no limit. - */ - void ConfigureDefaults(uint64_t physical_memory, - uint64_t virtual_memory_limit); - - /** - * The address beyond which the VM's stack may not grow. - */ - uint32_t* stack_limit() const { return stack_limit_; } - void set_stack_limit(uint32_t* value) { stack_limit_ = value; } - - /** - * The amount of virtual memory reserved for generated code. This is relevant - * for 64-bit architectures that rely on code range for calls in code. - * - * When V8_COMPRESS_POINTERS_IN_SHARED_CAGE is defined, there is a shared - * process-wide code range that is lazily initialized. This value is used to - * configure that shared code range when the first Isolate is - * created. Subsequent Isolates ignore this value. - */ - size_t code_range_size_in_bytes() const { return code_range_size_; } - void set_code_range_size_in_bytes(size_t limit) { code_range_size_ = limit; } - - /** - * The maximum size of the old generation. - * When the old generation approaches this limit, V8 will perform series of - * garbage collections and invoke the NearHeapLimitCallback. - * If the garbage collections do not help and the callback does not - * increase the limit, then V8 will crash with V8::FatalProcessOutOfMemory. - */ - size_t max_old_generation_size_in_bytes() const { - return max_old_generation_size_; - } - void set_max_old_generation_size_in_bytes(size_t limit) { - max_old_generation_size_ = limit; - } - - /** - * The maximum size of the young generation, which consists of two semi-spaces - * and a large object space. This affects frequency of Scavenge garbage - * collections and should be typically much smaller that the old generation. - */ - size_t max_young_generation_size_in_bytes() const { - return max_young_generation_size_; - } - void set_max_young_generation_size_in_bytes(size_t limit) { - max_young_generation_size_ = limit; - } - - size_t initial_old_generation_size_in_bytes() const { - return initial_old_generation_size_; - } - void set_initial_old_generation_size_in_bytes(size_t initial_size) { - initial_old_generation_size_ = initial_size; - } - - size_t initial_young_generation_size_in_bytes() const { - return initial_young_generation_size_; - } - void set_initial_young_generation_size_in_bytes(size_t initial_size) { - initial_young_generation_size_ = initial_size; - } - - private: - static constexpr size_t kMB = 1048576u; - size_t code_range_size_ = 0; - size_t max_old_generation_size_ = 0; - size_t max_young_generation_size_ = 0; - size_t initial_old_generation_size_ = 0; - size_t initial_young_generation_size_ = 0; - uint32_t* stack_limit_ = nullptr; -}; - -/** - * Option flags passed to the SetRAILMode function. - * See documentation https://developers.google.com/web/tools/chrome-devtools/ - * profile/evaluate-performance/rail - */ -enum RAILMode : unsigned { - // Response performance mode: In this mode very low virtual machine latency - // is provided. V8 will try to avoid JavaScript execution interruptions. - // Throughput may be throttled. - PERFORMANCE_RESPONSE, - // Animation performance mode: In this mode low virtual machine latency is - // provided. V8 will try to avoid as many JavaScript execution interruptions - // as possible. Throughput may be throttled. This is the default mode. - PERFORMANCE_ANIMATION, - // Idle performance mode: The embedder is idle. V8 can complete deferred work - // in this mode. - PERFORMANCE_IDLE, - // Load performance mode: In this mode high throughput is provided. V8 may - // turn off latency optimizations. - PERFORMANCE_LOAD -}; - -/** - * Memory pressure level for the MemoryPressureNotification. - * kNone hints V8 that there is no memory pressure. - * kModerate hints V8 to speed up incremental garbage collection at the cost of - * of higher latency due to garbage collection pauses. - * kCritical hints V8 to free memory as soon as possible. Garbage collection - * pauses at this level will be large. - */ -enum class MemoryPressureLevel { kNone, kModerate, kCritical }; - -/** - * Isolate represents an isolated instance of the V8 engine. V8 isolates have - * completely separate states. Objects from one isolate must not be used in - * other isolates. The embedder can create multiple isolates and use them in - * parallel in multiple threads. An isolate can be entered by at most one - * thread at any given time. The Locker/Unlocker API must be used to - * synchronize. - */ -class V8_EXPORT Isolate { - public: - /** - * Initial configuration parameters for a new Isolate. - */ - struct V8_EXPORT CreateParams { - CreateParams(); - ~CreateParams(); - - /** - * Allows the host application to provide the address of a function that is - * notified each time code is added, moved or removed. - */ - JitCodeEventHandler code_event_handler = nullptr; - - /** - * ResourceConstraints to use for the new Isolate. - */ - ResourceConstraints constraints; - - /** - * Explicitly specify a startup snapshot blob. The embedder owns the blob. - */ - StartupData* snapshot_blob = nullptr; - - /** - * Enables the host application to provide a mechanism for recording - * statistics counters. - */ - CounterLookupCallback counter_lookup_callback = nullptr; - - /** - * Enables the host application to provide a mechanism for recording - * histograms. The CreateHistogram function returns a - * histogram which will later be passed to the AddHistogramSample - * function. - */ - CreateHistogramCallback create_histogram_callback = nullptr; - AddHistogramSampleCallback add_histogram_sample_callback = nullptr; - - /** - * The ArrayBuffer::Allocator to use for allocating and freeing the backing - * store of ArrayBuffers. - * - * If the shared_ptr version is used, the Isolate instance and every - * |BackingStore| allocated using this allocator hold a std::shared_ptr - * to the allocator, in order to facilitate lifetime - * management for the allocator instance. - */ - ArrayBuffer::Allocator* array_buffer_allocator = nullptr; - std::shared_ptr array_buffer_allocator_shared; - - /** - * Specifies an optional nullptr-terminated array of raw addresses in the - * embedder that V8 can match against during serialization and use for - * deserialization. This array and its content must stay valid for the - * entire lifetime of the isolate. - */ - const intptr_t* external_references = nullptr; - - /** - * Whether calling Atomics.wait (a function that may block) is allowed in - * this isolate. This can also be configured via SetAllowAtomicsWait. - */ - bool allow_atomics_wait = true; - - /** - * Termination is postponed when there is no active SafeForTerminationScope. - */ - bool only_terminate_in_safe_scope = false; - - /** - * The following parameters describe the offsets for addressing type info - * for wrapped API objects and are used by the fast C API - * (for details see v8-fast-api-calls.h). - */ - int embedder_wrapper_type_index = -1; - int embedder_wrapper_object_index = -1; - }; - - /** - * Stack-allocated class which sets the isolate for all operations - * executed within a local scope. - */ - class V8_EXPORT V8_NODISCARD Scope { - public: - explicit Scope(Isolate* isolate) : isolate_(isolate) { isolate->Enter(); } - - ~Scope() { isolate_->Exit(); } - - // Prevent copying of Scope objects. - Scope(const Scope&) = delete; - Scope& operator=(const Scope&) = delete; - - private: - Isolate* const isolate_; - }; - - /** - * Assert that no Javascript code is invoked. - */ - class V8_EXPORT V8_NODISCARD DisallowJavascriptExecutionScope { - public: - enum OnFailure { CRASH_ON_FAILURE, THROW_ON_FAILURE, DUMP_ON_FAILURE }; - - DisallowJavascriptExecutionScope(Isolate* isolate, OnFailure on_failure); - ~DisallowJavascriptExecutionScope(); - - // Prevent copying of Scope objects. - DisallowJavascriptExecutionScope(const DisallowJavascriptExecutionScope&) = - delete; - DisallowJavascriptExecutionScope& operator=( - const DisallowJavascriptExecutionScope&) = delete; - - private: - OnFailure on_failure_; - Isolate* isolate_; - - bool was_execution_allowed_assert_; - bool was_execution_allowed_throws_; - bool was_execution_allowed_dump_; - }; - - /** - * Introduce exception to DisallowJavascriptExecutionScope. - */ - class V8_EXPORT V8_NODISCARD AllowJavascriptExecutionScope { - public: - explicit AllowJavascriptExecutionScope(Isolate* isolate); - ~AllowJavascriptExecutionScope(); - - // Prevent copying of Scope objects. - AllowJavascriptExecutionScope(const AllowJavascriptExecutionScope&) = - delete; - AllowJavascriptExecutionScope& operator=( - const AllowJavascriptExecutionScope&) = delete; - - private: - Isolate* isolate_; - bool was_execution_allowed_assert_; - bool was_execution_allowed_throws_; - bool was_execution_allowed_dump_; - }; - - /** - * Do not run microtasks while this scope is active, even if microtasks are - * automatically executed otherwise. - */ - class V8_EXPORT V8_NODISCARD SuppressMicrotaskExecutionScope { - public: - explicit SuppressMicrotaskExecutionScope( - Isolate* isolate, MicrotaskQueue* microtask_queue = nullptr); - ~SuppressMicrotaskExecutionScope(); - - // Prevent copying of Scope objects. - SuppressMicrotaskExecutionScope(const SuppressMicrotaskExecutionScope&) = - delete; - SuppressMicrotaskExecutionScope& operator=( - const SuppressMicrotaskExecutionScope&) = delete; - - private: - internal::Isolate* const isolate_; - internal::MicrotaskQueue* const microtask_queue_; - internal::Address previous_stack_height_; - - friend class internal::ThreadLocalTop; - }; - - /** - * This scope allows terminations inside direct V8 API calls and forbid them - * inside any recursive API calls without explicit SafeForTerminationScope. - */ - class V8_EXPORT V8_NODISCARD SafeForTerminationScope { - public: - explicit SafeForTerminationScope(v8::Isolate* isolate); - ~SafeForTerminationScope(); - - // Prevent copying of Scope objects. - SafeForTerminationScope(const SafeForTerminationScope&) = delete; - SafeForTerminationScope& operator=(const SafeForTerminationScope&) = delete; - - private: - internal::Isolate* isolate_; - bool prev_value_; - }; - - /** - * Types of garbage collections that can be requested via - * RequestGarbageCollectionForTesting. - */ - enum GarbageCollectionType { - kFullGarbageCollection, - kMinorGarbageCollection - }; - - /** - * Features reported via the SetUseCounterCallback callback. Do not change - * assigned numbers of existing items; add new features to the end of this - * list. - */ - enum UseCounterFeature { - kUseAsm = 0, - kBreakIterator = 1, - kLegacyConst = 2, - kMarkDequeOverflow = 3, - kStoreBufferOverflow = 4, - kSlotsBufferOverflow = 5, - kObjectObserve = 6, - kForcedGC = 7, - kSloppyMode = 8, - kStrictMode = 9, - kStrongMode = 10, - kRegExpPrototypeStickyGetter = 11, - kRegExpPrototypeToString = 12, - kRegExpPrototypeUnicodeGetter = 13, - kIntlV8Parse = 14, - kIntlPattern = 15, - kIntlResolved = 16, - kPromiseChain = 17, - kPromiseAccept = 18, - kPromiseDefer = 19, - kHtmlCommentInExternalScript = 20, - kHtmlComment = 21, - kSloppyModeBlockScopedFunctionRedefinition = 22, - kForInInitializer = 23, - kArrayProtectorDirtied = 24, - kArraySpeciesModified = 25, - kArrayPrototypeConstructorModified = 26, - kArrayInstanceProtoModified = 27, - kArrayInstanceConstructorModified = 28, - kLegacyFunctionDeclaration = 29, - kRegExpPrototypeSourceGetter = 30, // Unused. - kRegExpPrototypeOldFlagGetter = 31, // Unused. - kDecimalWithLeadingZeroInStrictMode = 32, - kLegacyDateParser = 33, - kDefineGetterOrSetterWouldThrow = 34, - kFunctionConstructorReturnedUndefined = 35, - kAssigmentExpressionLHSIsCallInSloppy = 36, - kAssigmentExpressionLHSIsCallInStrict = 37, - kPromiseConstructorReturnedUndefined = 38, - kConstructorNonUndefinedPrimitiveReturn = 39, - kLabeledExpressionStatement = 40, - kLineOrParagraphSeparatorAsLineTerminator = 41, - kIndexAccessor = 42, - kErrorCaptureStackTrace = 43, - kErrorPrepareStackTrace = 44, - kErrorStackTraceLimit = 45, - kWebAssemblyInstantiation = 46, - kDeoptimizerDisableSpeculation = 47, - kArrayPrototypeSortJSArrayModifiedPrototype = 48, - kFunctionTokenOffsetTooLongForToString = 49, - kWasmSharedMemory = 50, - kWasmThreadOpcodes = 51, - kAtomicsNotify = 52, // Unused. - kAtomicsWake = 53, // Unused. - kCollator = 54, - kNumberFormat = 55, - kDateTimeFormat = 56, - kPluralRules = 57, - kRelativeTimeFormat = 58, - kLocale = 59, - kListFormat = 60, - kSegmenter = 61, - kStringLocaleCompare = 62, - kStringToLocaleUpperCase = 63, - kStringToLocaleLowerCase = 64, - kNumberToLocaleString = 65, - kDateToLocaleString = 66, - kDateToLocaleDateString = 67, - kDateToLocaleTimeString = 68, - kAttemptOverrideReadOnlyOnPrototypeSloppy = 69, - kAttemptOverrideReadOnlyOnPrototypeStrict = 70, - kOptimizedFunctionWithOneShotBytecode = 71, // Unused. - kRegExpMatchIsTrueishOnNonJSRegExp = 72, - kRegExpMatchIsFalseishOnJSRegExp = 73, - kDateGetTimezoneOffset = 74, // Unused. - kStringNormalize = 75, - kCallSiteAPIGetFunctionSloppyCall = 76, - kCallSiteAPIGetThisSloppyCall = 77, - kRegExpMatchAllWithNonGlobalRegExp = 78, - kRegExpExecCalledOnSlowRegExp = 79, - kRegExpReplaceCalledOnSlowRegExp = 80, - kDisplayNames = 81, - kSharedArrayBufferConstructed = 82, - kArrayPrototypeHasElements = 83, - kObjectPrototypeHasElements = 84, - kNumberFormatStyleUnit = 85, - kDateTimeFormatRange = 86, - kDateTimeFormatDateTimeStyle = 87, - kBreakIteratorTypeWord = 88, - kBreakIteratorTypeLine = 89, - kInvalidatedArrayBufferDetachingProtector = 90, - kInvalidatedArrayConstructorProtector = 91, - kInvalidatedArrayIteratorLookupChainProtector = 92, - kInvalidatedArraySpeciesLookupChainProtector = 93, - kInvalidatedIsConcatSpreadableLookupChainProtector = 94, - kInvalidatedMapIteratorLookupChainProtector = 95, - kInvalidatedNoElementsProtector = 96, - kInvalidatedPromiseHookProtector = 97, - kInvalidatedPromiseResolveLookupChainProtector = 98, - kInvalidatedPromiseSpeciesLookupChainProtector = 99, - kInvalidatedPromiseThenLookupChainProtector = 100, - kInvalidatedRegExpSpeciesLookupChainProtector = 101, - kInvalidatedSetIteratorLookupChainProtector = 102, - kInvalidatedStringIteratorLookupChainProtector = 103, - kInvalidatedStringLengthOverflowLookupChainProtector = 104, - kInvalidatedTypedArraySpeciesLookupChainProtector = 105, - kWasmSimdOpcodes = 106, - kVarRedeclaredCatchBinding = 107, - kWasmRefTypes = 108, - kWasmBulkMemory = 109, // Unused. - kWasmMultiValue = 110, - kWasmExceptionHandling = 111, - kInvalidatedMegaDOMProtector = 112, - - // If you add new values here, you'll also need to update Chromium's: - // web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to - // this list need to be landed first, then changes on the Chromium side. - kUseCounterFeatureCount // This enum value must be last. - }; - - enum MessageErrorLevel { - kMessageLog = (1 << 0), - kMessageDebug = (1 << 1), - kMessageInfo = (1 << 2), - kMessageError = (1 << 3), - kMessageWarning = (1 << 4), - kMessageAll = kMessageLog | kMessageDebug | kMessageInfo | kMessageError | - kMessageWarning, - }; - - using UseCounterCallback = void (*)(Isolate* isolate, - UseCounterFeature feature); - - /** - * Allocates a new isolate but does not initialize it. Does not change the - * currently entered isolate. - * - * Only Isolate::GetData() and Isolate::SetData(), which access the - * embedder-controlled parts of the isolate, are allowed to be called on the - * uninitialized isolate. To initialize the isolate, call - * Isolate::Initialize(). - * - * When an isolate is no longer used its resources should be freed - * by calling Dispose(). Using the delete operator is not allowed. - * - * V8::Initialize() must have run prior to this. - */ - static Isolate* Allocate(); - - /** - * Initialize an Isolate previously allocated by Isolate::Allocate(). - */ - static void Initialize(Isolate* isolate, const CreateParams& params); - - /** - * Creates a new isolate. Does not change the currently entered - * isolate. - * - * When an isolate is no longer used its resources should be freed - * by calling Dispose(). Using the delete operator is not allowed. - * - * V8::Initialize() must have run prior to this. - */ - static Isolate* New(const CreateParams& params); - - /** - * Returns the entered isolate for the current thread or NULL in - * case there is no current isolate. - * - * This method must not be invoked before V8::Initialize() was invoked. - */ - static Isolate* GetCurrent(); - - /** - * Returns the entered isolate for the current thread or NULL in - * case there is no current isolate. - * - * No checks are performed by this method. - */ - static Isolate* TryGetCurrent(); - - /** - * Clears the set of objects held strongly by the heap. This set of - * objects are originally built when a WeakRef is created or - * successfully dereferenced. - * - * This is invoked automatically after microtasks are run. See - * MicrotasksPolicy for when microtasks are run. - * - * This needs to be manually invoked only if the embedder is manually running - * microtasks via a custom MicrotaskQueue class's PerformCheckpoint. In that - * case, it is the embedder's responsibility to make this call at a time which - * does not interrupt synchronous ECMAScript code execution. - */ - void ClearKeptObjects(); - - /** - * Custom callback used by embedders to help V8 determine if it should abort - * when it throws and no internal handler is predicted to catch the - * exception. If --abort-on-uncaught-exception is used on the command line, - * then V8 will abort if either: - * - no custom callback is set. - * - the custom callback set returns true. - * Otherwise, the custom callback will not be called and V8 will not abort. - */ - using AbortOnUncaughtExceptionCallback = bool (*)(Isolate*); - void SetAbortOnUncaughtExceptionCallback( - AbortOnUncaughtExceptionCallback callback); - - /** - * This specifies the callback called by the upcoming dynamic - * import() language feature to load modules. - */ - V8_DEPRECATED( - "Use the version of SetHostImportModuleDynamicallyCallback that takes a " - "HostImportModuleDynamicallyWithImportAssertionsCallback instead") - void SetHostImportModuleDynamicallyCallback( - HostImportModuleDynamicallyCallback callback); - - /** - * This specifies the callback called by the upcoming dynamic - * import() language feature to load modules. - */ - void SetHostImportModuleDynamicallyCallback( - HostImportModuleDynamicallyWithImportAssertionsCallback callback); - - /** - * This specifies the callback called by the upcoming import.meta - * language feature to retrieve host-defined meta data for a module. - */ - void SetHostInitializeImportMetaObjectCallback( - HostInitializeImportMetaObjectCallback callback); - - /** - * This specifies the callback called when the stack property of Error - * is accessed. - */ - void SetPrepareStackTraceCallback(PrepareStackTraceCallback callback); - - /** - * Optional notification that the system is running low on memory. - * V8 uses these notifications to guide heuristics. - * It is allowed to call this function from another thread while - * the isolate is executing long running JavaScript code. - */ - void MemoryPressureNotification(MemoryPressureLevel level); - - /** - * Drop non-essential caches. Should only be called from testing code. - * The method can potentially block for a long time and does not necessarily - * trigger GC. - */ - void ClearCachesForTesting(); - - /** - * Methods below this point require holding a lock (using Locker) in - * a multi-threaded environment. - */ - - /** - * Sets this isolate as the entered one for the current thread. - * Saves the previously entered one (if any), so that it can be - * restored when exiting. Re-entering an isolate is allowed. - */ - void Enter(); - - /** - * Exits this isolate by restoring the previously entered one in the - * current thread. The isolate may still stay the same, if it was - * entered more than once. - * - * Requires: this == Isolate::GetCurrent(). - */ - void Exit(); - - /** - * Disposes the isolate. The isolate must not be entered by any - * thread to be disposable. - */ - void Dispose(); - - /** - * Dumps activated low-level V8 internal stats. This can be used instead - * of performing a full isolate disposal. - */ - void DumpAndResetStats(); - - /** - * Discards all V8 thread-specific data for the Isolate. Should be used - * if a thread is terminating and it has used an Isolate that will outlive - * the thread -- all thread-specific data for an Isolate is discarded when - * an Isolate is disposed so this call is pointless if an Isolate is about - * to be Disposed. - */ - void DiscardThreadSpecificMetadata(); - - /** - * Associate embedder-specific data with the isolate. |slot| has to be - * between 0 and GetNumberOfDataSlots() - 1. - */ - V8_INLINE void SetData(uint32_t slot, void* data); - - /** - * Retrieve embedder-specific data from the isolate. - * Returns NULL if SetData has never been called for the given |slot|. - */ - V8_INLINE void* GetData(uint32_t slot); - - /** - * Returns the maximum number of available embedder data slots. Valid slots - * are in the range of 0 - GetNumberOfDataSlots() - 1. - */ - V8_INLINE static uint32_t GetNumberOfDataSlots(); - - /** - * Return data that was previously attached to the isolate snapshot via - * SnapshotCreator, and removes the reference to it. - * Repeated call with the same index returns an empty MaybeLocal. - */ - template - V8_INLINE MaybeLocal GetDataFromSnapshotOnce(size_t index); - - /** - * Get statistics about the heap memory usage. - */ - void GetHeapStatistics(HeapStatistics* heap_statistics); - - /** - * Returns the number of spaces in the heap. - */ - size_t NumberOfHeapSpaces(); - - /** - * Get the memory usage of a space in the heap. - * - * \param space_statistics The HeapSpaceStatistics object to fill in - * statistics. - * \param index The index of the space to get statistics from, which ranges - * from 0 to NumberOfHeapSpaces() - 1. - * \returns true on success. - */ - bool GetHeapSpaceStatistics(HeapSpaceStatistics* space_statistics, - size_t index); - - /** - * Returns the number of types of objects tracked in the heap at GC. - */ - size_t NumberOfTrackedHeapObjectTypes(); - - /** - * Get statistics about objects in the heap. - * - * \param object_statistics The HeapObjectStatistics object to fill in - * statistics of objects of given type, which were live in the previous GC. - * \param type_index The index of the type of object to fill details about, - * which ranges from 0 to NumberOfTrackedHeapObjectTypes() - 1. - * \returns true on success. - */ - bool GetHeapObjectStatisticsAtLastGC(HeapObjectStatistics* object_statistics, - size_t type_index); - - /** - * Get statistics about code and its metadata in the heap. - * - * \param object_statistics The HeapCodeStatistics object to fill in - * statistics of code, bytecode and their metadata. - * \returns true on success. - */ - bool GetHeapCodeAndMetadataStatistics(HeapCodeStatistics* object_statistics); - - /** - * This API is experimental and may change significantly. - * - * Enqueues a memory measurement request and invokes the delegate with the - * results. - * - * \param delegate the delegate that defines which contexts to measure and - * reports the results. - * - * \param execution promptness executing the memory measurement. - * The kEager value is expected to be used only in tests. - */ - bool MeasureMemory( - std::unique_ptr delegate, - MeasureMemoryExecution execution = MeasureMemoryExecution::kDefault); - - /** - * Get a call stack sample from the isolate. - * \param state Execution state. - * \param frames Caller allocated buffer to store stack frames. - * \param frames_limit Maximum number of frames to capture. The buffer must - * be large enough to hold the number of frames. - * \param sample_info The sample info is filled up by the function - * provides number of actual captured stack frames and - * the current VM state. - * \note GetStackSample should only be called when the JS thread is paused or - * interrupted. Otherwise the behavior is undefined. - */ - void GetStackSample(const RegisterState& state, void** frames, - size_t frames_limit, SampleInfo* sample_info); - - /** - * Adjusts the amount of registered external memory. Used to give V8 an - * indication of the amount of externally allocated memory that is kept alive - * by JavaScript objects. V8 uses this to decide when to perform global - * garbage collections. Registering externally allocated memory will trigger - * global garbage collections more often than it would otherwise in an attempt - * to garbage collect the JavaScript objects that keep the externally - * allocated memory alive. - * - * \param change_in_bytes the change in externally allocated memory that is - * kept alive by JavaScript objects. - * \returns the adjusted value. - */ - int64_t AdjustAmountOfExternalAllocatedMemory(int64_t change_in_bytes); - - /** - * Returns the number of phantom handles without callbacks that were reset - * by the garbage collector since the last call to this function. - */ - size_t NumberOfPhantomHandleResetsSinceLastCall(); - - /** - * Returns heap profiler for this isolate. Will return NULL until the isolate - * is initialized. - */ - HeapProfiler* GetHeapProfiler(); - - /** - * Tells the VM whether the embedder is idle or not. - */ - void SetIdle(bool is_idle); - - /** Returns the ArrayBuffer::Allocator used in this isolate. */ - ArrayBuffer::Allocator* GetArrayBufferAllocator(); - - /** Returns true if this isolate has a current context. */ - bool InContext(); - - /** - * Returns the context of the currently running JavaScript, or the context - * on the top of the stack if no JavaScript is running. - */ - Local GetCurrentContext(); - - /** - * Returns either the last context entered through V8's C++ API, or the - * context of the currently running microtask while processing microtasks. - * If a context is entered while executing a microtask, that context is - * returned. - */ - Local GetEnteredOrMicrotaskContext(); - - /** - * Returns the Context that corresponds to the Incumbent realm in HTML spec. - * https://html.spec.whatwg.org/multipage/webappapis.html#incumbent - */ - Local GetIncumbentContext(); - - /** - * Schedules a v8::Exception::Error with the given message. - * See ThrowException for more details. Templatized to provide compile-time - * errors in case of too long strings (see v8::String::NewFromUtf8Literal). - */ - template - Local ThrowError(const char (&message)[N]) { - return ThrowError(String::NewFromUtf8Literal(this, message)); - } - Local ThrowError(Local message); - - /** - * Schedules an exception to be thrown when returning to JavaScript. When an - * exception has been scheduled it is illegal to invoke any JavaScript - * operation; the caller must return immediately and only after the exception - * has been handled does it become legal to invoke JavaScript operations. - */ - Local ThrowException(Local exception); - - using GCCallback = void (*)(Isolate* isolate, GCType type, - GCCallbackFlags flags); - using GCCallbackWithData = void (*)(Isolate* isolate, GCType type, - GCCallbackFlags flags, void* data); - - /** - * Enables the host application to receive a notification before a - * garbage collection. Allocations are allowed in the callback function, - * but the callback is not re-entrant: if the allocation inside it will - * trigger the garbage collection, the callback won't be called again. - * It is possible to specify the GCType filter for your callback. But it is - * not possible to register the same callback function two times with - * different GCType filters. - */ - void AddGCPrologueCallback(GCCallbackWithData callback, void* data = nullptr, - GCType gc_type_filter = kGCTypeAll); - void AddGCPrologueCallback(GCCallback callback, - GCType gc_type_filter = kGCTypeAll); - - /** - * This function removes callback which was installed by - * AddGCPrologueCallback function. - */ - void RemoveGCPrologueCallback(GCCallbackWithData, void* data = nullptr); - void RemoveGCPrologueCallback(GCCallback callback); - - /** - * Sets the embedder heap tracer for the isolate. - */ - void SetEmbedderHeapTracer(EmbedderHeapTracer* tracer); - - /* - * Gets the currently active heap tracer for the isolate. - */ - EmbedderHeapTracer* GetEmbedderHeapTracer(); - - /** - * Sets an embedder roots handle that V8 should consider when performing - * non-unified heap garbage collections. - * - * Using only EmbedderHeapTracer automatically sets up a default handler. - * The intended use case is for setting a custom handler after invoking - * `AttachCppHeap()`. - * - * V8 does not take ownership of the handler. - */ - void SetEmbedderRootsHandler(EmbedderRootsHandler* handler); - - /** - * Attaches a managed C++ heap as an extension to the JavaScript heap. The - * embedder maintains ownership of the CppHeap. At most one C++ heap can be - * attached to V8. - * - * This is an experimental feature and may still change significantly. - */ - void AttachCppHeap(CppHeap*); - - /** - * Detaches a managed C++ heap if one was attached using `AttachCppHeap()`. - * - * This is an experimental feature and may still change significantly. - */ - void DetachCppHeap(); - - /** - * This is an experimental feature and may still change significantly. - - * \returns the C++ heap managed by V8. Only available if such a heap has been - * attached using `AttachCppHeap()`. - */ - CppHeap* GetCppHeap() const; - - /** - * Use for |AtomicsWaitCallback| to indicate the type of event it receives. - */ - enum class AtomicsWaitEvent { - /** Indicates that this call is happening before waiting. */ - kStartWait, - /** `Atomics.wait()` finished because of an `Atomics.wake()` call. */ - kWokenUp, - /** `Atomics.wait()` finished because it timed out. */ - kTimedOut, - /** `Atomics.wait()` was interrupted through |TerminateExecution()|. */ - kTerminatedExecution, - /** `Atomics.wait()` was stopped through |AtomicsWaitWakeHandle|. */ - kAPIStopped, - /** `Atomics.wait()` did not wait, as the initial condition was not met. */ - kNotEqual - }; - - /** - * Passed to |AtomicsWaitCallback| as a means of stopping an ongoing - * `Atomics.wait` call. - */ - class V8_EXPORT AtomicsWaitWakeHandle { - public: - /** - * Stop this `Atomics.wait()` call and call the |AtomicsWaitCallback| - * with |kAPIStopped|. - * - * This function may be called from another thread. The caller has to ensure - * through proper synchronization that it is not called after - * the finishing |AtomicsWaitCallback|. - * - * Note that the ECMAScript specification does not plan for the possibility - * of wakeups that are neither coming from a timeout or an `Atomics.wake()` - * call, so this may invalidate assumptions made by existing code. - * The embedder may accordingly wish to schedule an exception in the - * finishing |AtomicsWaitCallback|. - */ - void Wake(); - }; - - /** - * Embedder callback for `Atomics.wait()` that can be added through - * |SetAtomicsWaitCallback|. - * - * This will be called just before starting to wait with the |event| value - * |kStartWait| and after finishing waiting with one of the other - * values of |AtomicsWaitEvent| inside of an `Atomics.wait()` call. - * - * |array_buffer| will refer to the underlying SharedArrayBuffer, - * |offset_in_bytes| to the location of the waited-on memory address inside - * the SharedArrayBuffer. - * - * |value| and |timeout_in_ms| will be the values passed to - * the `Atomics.wait()` call. If no timeout was used, |timeout_in_ms| - * will be `INFINITY`. - * - * In the |kStartWait| callback, |stop_handle| will be an object that - * is only valid until the corresponding finishing callback and that - * can be used to stop the wait process while it is happening. - * - * This callback may schedule exceptions, *unless* |event| is equal to - * |kTerminatedExecution|. - */ - using AtomicsWaitCallback = void (*)(AtomicsWaitEvent event, - Local array_buffer, - size_t offset_in_bytes, int64_t value, - double timeout_in_ms, - AtomicsWaitWakeHandle* stop_handle, - void* data); - - /** - * Set a new |AtomicsWaitCallback|. This overrides an earlier - * |AtomicsWaitCallback|, if there was any. If |callback| is nullptr, - * this unsets the callback. |data| will be passed to the callback - * as its last parameter. - */ - void SetAtomicsWaitCallback(AtomicsWaitCallback callback, void* data); - - /** - * Enables the host application to receive a notification after a - * garbage collection. Allocations are allowed in the callback function, - * but the callback is not re-entrant: if the allocation inside it will - * trigger the garbage collection, the callback won't be called again. - * It is possible to specify the GCType filter for your callback. But it is - * not possible to register the same callback function two times with - * different GCType filters. - */ - void AddGCEpilogueCallback(GCCallbackWithData callback, void* data = nullptr, - GCType gc_type_filter = kGCTypeAll); - void AddGCEpilogueCallback(GCCallback callback, - GCType gc_type_filter = kGCTypeAll); - - /** - * This function removes callback which was installed by - * AddGCEpilogueCallback function. - */ - void RemoveGCEpilogueCallback(GCCallbackWithData callback, - void* data = nullptr); - void RemoveGCEpilogueCallback(GCCallback callback); - - using GetExternallyAllocatedMemoryInBytesCallback = size_t (*)(); - - /** - * Set the callback that tells V8 how much memory is currently allocated - * externally of the V8 heap. Ideally this memory is somehow connected to V8 - * objects and may get freed-up when the corresponding V8 objects get - * collected by a V8 garbage collection. - */ - void SetGetExternallyAllocatedMemoryInBytesCallback( - GetExternallyAllocatedMemoryInBytesCallback callback); - - /** - * Forcefully terminate the current thread of JavaScript execution - * in the given isolate. - * - * This method can be used by any thread even if that thread has not - * acquired the V8 lock with a Locker object. - */ - void TerminateExecution(); - - /** - * Is V8 terminating JavaScript execution. - * - * Returns true if JavaScript execution is currently terminating - * because of a call to TerminateExecution. In that case there are - * still JavaScript frames on the stack and the termination - * exception is still active. - */ - bool IsExecutionTerminating(); - - /** - * Resume execution capability in the given isolate, whose execution - * was previously forcefully terminated using TerminateExecution(). - * - * When execution is forcefully terminated using TerminateExecution(), - * the isolate can not resume execution until all JavaScript frames - * have propagated the uncatchable exception which is generated. This - * method allows the program embedding the engine to handle the - * termination event and resume execution capability, even if - * JavaScript frames remain on the stack. - * - * This method can be used by any thread even if that thread has not - * acquired the V8 lock with a Locker object. - */ - void CancelTerminateExecution(); - - /** - * Request V8 to interrupt long running JavaScript code and invoke - * the given |callback| passing the given |data| to it. After |callback| - * returns control will be returned to the JavaScript code. - * There may be a number of interrupt requests in flight. - * Can be called from another thread without acquiring a |Locker|. - * Registered |callback| must not reenter interrupted Isolate. - */ - void RequestInterrupt(InterruptCallback callback, void* data); - - /** - * Returns true if there is ongoing background work within V8 that will - * eventually post a foreground task, like asynchronous WebAssembly - * compilation. - */ - bool HasPendingBackgroundTasks(); - - /** - * Request garbage collection in this Isolate. It is only valid to call this - * function if --expose_gc was specified. - * - * This should only be used for testing purposes and not to enforce a garbage - * collection schedule. It has strong negative impact on the garbage - * collection performance. Use IdleNotificationDeadline() or - * LowMemoryNotification() instead to influence the garbage collection - * schedule. - */ - void RequestGarbageCollectionForTesting(GarbageCollectionType type); - - /** - * Set the callback to invoke for logging event. - */ - void SetEventLogger(LogEventCallback that); - - /** - * Adds a callback to notify the host application right before a script - * is about to run. If a script re-enters the runtime during executing, the - * BeforeCallEnteredCallback is invoked for each re-entrance. - * Executing scripts inside the callback will re-trigger the callback. - */ - void AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback); - - /** - * Removes callback that was installed by AddBeforeCallEnteredCallback. - */ - void RemoveBeforeCallEnteredCallback(BeforeCallEnteredCallback callback); - - /** - * Adds a callback to notify the host application when a script finished - * running. If a script re-enters the runtime during executing, the - * CallCompletedCallback is only invoked when the outer-most script - * execution ends. Executing scripts inside the callback do not trigger - * further callbacks. - */ - void AddCallCompletedCallback(CallCompletedCallback callback); - - /** - * Removes callback that was installed by AddCallCompletedCallback. - */ - void RemoveCallCompletedCallback(CallCompletedCallback callback); - - /** - * Set the PromiseHook callback for various promise lifecycle - * events. - */ - void SetPromiseHook(PromiseHook hook); - - /** - * Set callback to notify about promise reject with no handler, or - * revocation of such a previous notification once the handler is added. - */ - void SetPromiseRejectCallback(PromiseRejectCallback callback); - - /** - * Runs the default MicrotaskQueue until it gets empty and perform other - * microtask checkpoint steps, such as calling ClearKeptObjects. Asserts that - * the MicrotasksPolicy is not kScoped. Any exceptions thrown by microtask - * callbacks are swallowed. - */ - void PerformMicrotaskCheckpoint(); - - /** - * Enqueues the callback to the default MicrotaskQueue - */ - void EnqueueMicrotask(Local microtask); - - /** - * Enqueues the callback to the default MicrotaskQueue - */ - void EnqueueMicrotask(MicrotaskCallback callback, void* data = nullptr); - - /** - * Controls how Microtasks are invoked. See MicrotasksPolicy for details. - */ - void SetMicrotasksPolicy(MicrotasksPolicy policy); - - /** - * Returns the policy controlling how Microtasks are invoked. - */ - MicrotasksPolicy GetMicrotasksPolicy() const; - - /** - * Adds a callback to notify the host application after - * microtasks were run on the default MicrotaskQueue. The callback is - * triggered by explicit RunMicrotasks call or automatic microtasks execution - * (see SetMicrotaskPolicy). - * - * Callback will trigger even if microtasks were attempted to run, - * but the microtasks queue was empty and no single microtask was actually - * executed. - * - * Executing scripts inside the callback will not re-trigger microtasks and - * the callback. - */ - void AddMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr); - - /** - * Removes callback that was installed by AddMicrotasksCompletedCallback. - */ - void RemoveMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr); - - /** - * Sets a callback for counting the number of times a feature of V8 is used. - */ - void SetUseCounterCallback(UseCounterCallback callback); - - /** - * Enables the host application to provide a mechanism for recording - * statistics counters. - */ - void SetCounterFunction(CounterLookupCallback); - - /** - * Enables the host application to provide a mechanism for recording - * histograms. The CreateHistogram function returns a - * histogram which will later be passed to the AddHistogramSample - * function. - */ - void SetCreateHistogramFunction(CreateHistogramCallback); - void SetAddHistogramSampleFunction(AddHistogramSampleCallback); - - /** - * Enables the host application to provide a mechanism for recording - * event based metrics. In order to use this interface - * include/v8-metrics.h - * needs to be included and the recorder needs to be derived from the - * Recorder base class defined there. - * This method can only be called once per isolate and must happen during - * isolate initialization before background threads are spawned. - */ - void SetMetricsRecorder( - const std::shared_ptr& metrics_recorder); - - /** - * Enables the host application to provide a mechanism for recording a - * predefined set of data as crash keys to be used in postmortem debugging in - * case of a crash. - */ - void SetAddCrashKeyCallback(AddCrashKeyCallback); - - /** - * Optional notification that the embedder is idle. - * V8 uses the notification to perform garbage collection. - * This call can be used repeatedly if the embedder remains idle. - * Returns true if the embedder should stop calling IdleNotificationDeadline - * until real work has been done. This indicates that V8 has done - * as much cleanup as it will be able to do. - * - * The deadline_in_seconds argument specifies the deadline V8 has to finish - * garbage collection work. deadline_in_seconds is compared with - * MonotonicallyIncreasingTime() and should be based on the same timebase as - * that function. There is no guarantee that the actual work will be done - * within the time limit. - */ - bool IdleNotificationDeadline(double deadline_in_seconds); - - /** - * Optional notification that the system is running low on memory. - * V8 uses these notifications to attempt to free memory. - */ - void LowMemoryNotification(); - - /** - * Optional notification that a context has been disposed. V8 uses these - * notifications to guide the GC heuristic and cancel FinalizationRegistry - * cleanup tasks. Returns the number of context disposals - including this one - * - since the last time V8 had a chance to clean up. - * - * The optional parameter |dependant_context| specifies whether the disposed - * context was depending on state from other contexts or not. - */ - int ContextDisposedNotification(bool dependant_context = true); - - /** - * Optional notification that the isolate switched to the foreground. - * V8 uses these notifications to guide heuristics. - */ - void IsolateInForegroundNotification(); - - /** - * Optional notification that the isolate switched to the background. - * V8 uses these notifications to guide heuristics. - */ - void IsolateInBackgroundNotification(); - - /** - * Optional notification which will enable the memory savings mode. - * V8 uses this notification to guide heuristics which may result in a - * smaller memory footprint at the cost of reduced runtime performance. - */ - void EnableMemorySavingsMode(); - - /** - * Optional notification which will disable the memory savings mode. - */ - void DisableMemorySavingsMode(); - - /** - * Optional notification to tell V8 the current performance requirements - * of the embedder based on RAIL. - * V8 uses these notifications to guide heuristics. - * This is an unfinished experimental feature. Semantics and implementation - * may change frequently. - */ - void SetRAILMode(RAILMode rail_mode); - - /** - * Update load start time of the RAIL mode - */ - void UpdateLoadStartTime(); - - /** - * Optional notification to tell V8 the current isolate is used for debugging - * and requires higher heap limit. - */ - void IncreaseHeapLimitForDebugging(); - - /** - * Restores the original heap limit after IncreaseHeapLimitForDebugging(). - */ - void RestoreOriginalHeapLimit(); - - /** - * Returns true if the heap limit was increased for debugging and the - * original heap limit was not restored yet. - */ - bool IsHeapLimitIncreasedForDebugging(); - - /** - * Allows the host application to provide the address of a function that is - * notified each time code is added, moved or removed. - * - * \param options options for the JIT code event handler. - * \param event_handler the JIT code event handler, which will be invoked - * each time code is added, moved or removed. - * \note \p event_handler won't get notified of existent code. - * \note since code removal notifications are not currently issued, the - * \p event_handler may get notifications of code that overlaps earlier - * code notifications. This happens when code areas are reused, and the - * earlier overlapping code areas should therefore be discarded. - * \note the events passed to \p event_handler and the strings they point to - * are not guaranteed to live past each call. The \p event_handler must - * copy strings and other parameters it needs to keep around. - * \note the set of events declared in JitCodeEvent::EventType is expected to - * grow over time, and the JitCodeEvent structure is expected to accrue - * new members. The \p event_handler function must ignore event codes - * it does not recognize to maintain future compatibility. - * \note Use Isolate::CreateParams to get events for code executed during - * Isolate setup. - */ - void SetJitCodeEventHandler(JitCodeEventOptions options, - JitCodeEventHandler event_handler); - - /** - * Modifies the stack limit for this Isolate. - * - * \param stack_limit An address beyond which the Vm's stack may not grow. - * - * \note If you are using threads then you should hold the V8::Locker lock - * while setting the stack limit and you must set a non-default stack - * limit separately for each thread. - */ - void SetStackLimit(uintptr_t stack_limit); - - /** - * Returns a memory range that can potentially contain jitted code. Code for - * V8's 'builtins' will not be in this range if embedded builtins is enabled. - * - * On Win64, embedders are advised to install function table callbacks for - * these ranges, as default SEH won't be able to unwind through jitted code. - * The first page of the code range is reserved for the embedder and is - * committed, writable, and executable, to be used to store unwind data, as - * documented in - * https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64. - * - * Might be empty on other platforms. - * - * https://code.google.com/p/v8/issues/detail?id=3598 - */ - void GetCodeRange(void** start, size_t* length_in_bytes); - - /** - * As GetCodeRange, but for embedded builtins (these live in a distinct - * memory region from other V8 Code objects). - */ - void GetEmbeddedCodeRange(const void** start, size_t* length_in_bytes); - - /** - * Returns the JSEntryStubs necessary for use with the Unwinder API. - */ - JSEntryStubs GetJSEntryStubs(); - - static constexpr size_t kMinCodePagesBufferSize = 32; - - /** - * Copies the code heap pages currently in use by V8 into |code_pages_out|. - * |code_pages_out| must have at least kMinCodePagesBufferSize capacity and - * must be empty. - * - * Signal-safe, does not allocate, does not access the V8 heap. - * No code on the stack can rely on pages that might be missing. - * - * Returns the number of pages available to be copied, which might be greater - * than |capacity|. In this case, only |capacity| pages will be copied into - * |code_pages_out|. The caller should provide a bigger buffer on the next - * call in order to get all available code pages, but this is not required. - */ - size_t CopyCodePages(size_t capacity, MemoryRange* code_pages_out); - - /** Set the callback to invoke in case of fatal errors. */ - void SetFatalErrorHandler(FatalErrorCallback that); - - /** Set the callback to invoke in case of OOM errors. */ - void SetOOMErrorHandler(OOMErrorCallback that); - - /** - * Add a callback to invoke in case the heap size is close to the heap limit. - * If multiple callbacks are added, only the most recently added callback is - * invoked. - */ - void AddNearHeapLimitCallback(NearHeapLimitCallback callback, void* data); - - /** - * Remove the given callback and restore the heap limit to the - * given limit. If the given limit is zero, then it is ignored. - * If the current heap size is greater than the given limit, - * then the heap limit is restored to the minimal limit that - * is possible for the current heap size. - */ - void RemoveNearHeapLimitCallback(NearHeapLimitCallback callback, - size_t heap_limit); - - /** - * If the heap limit was changed by the NearHeapLimitCallback, then the - * initial heap limit will be restored once the heap size falls below the - * given threshold percentage of the initial heap limit. - * The threshold percentage is a number in (0.0, 1.0) range. - */ - void AutomaticallyRestoreInitialHeapLimit(double threshold_percent = 0.5); - - /** - * Set the callback to invoke to check if code generation from - * strings should be allowed. - */ - void SetModifyCodeGenerationFromStringsCallback( - ModifyCodeGenerationFromStringsCallback2 callback); - - /** - * Set the callback to invoke to check if wasm code generation should - * be allowed. - */ - void SetAllowWasmCodeGenerationCallback( - AllowWasmCodeGenerationCallback callback); - - /** - * Embedder over{ride|load} injection points for wasm APIs. The expectation - * is that the embedder sets them at most once. - */ - void SetWasmModuleCallback(ExtensionCallback callback); - void SetWasmInstanceCallback(ExtensionCallback callback); - - void SetWasmStreamingCallback(WasmStreamingCallback callback); - - void SetWasmLoadSourceMapCallback(WasmLoadSourceMapCallback callback); - - void SetWasmSimdEnabledCallback(WasmSimdEnabledCallback callback); - - void SetWasmExceptionsEnabledCallback(WasmExceptionsEnabledCallback callback); - - void SetSharedArrayBufferConstructorEnabledCallback( - SharedArrayBufferConstructorEnabledCallback callback); - - /** - * This function can be called by the embedder to signal V8 that the dynamic - * enabling of features has finished. V8 can now set up dynamically added - * features. - */ - void InstallConditionalFeatures(Local context); - - /** - * Check if V8 is dead and therefore unusable. This is the case after - * fatal errors such as out-of-memory situations. - */ - bool IsDead(); - - /** - * Adds a message listener (errors only). - * - * The same message listener can be added more than once and in that - * case it will be called more than once for each message. - * - * If data is specified, it will be passed to the callback when it is called. - * Otherwise, the exception object will be passed to the callback instead. - */ - bool AddMessageListener(MessageCallback that, - Local data = Local()); - - /** - * Adds a message listener. - * - * The same message listener can be added more than once and in that - * case it will be called more than once for each message. - * - * If data is specified, it will be passed to the callback when it is called. - * Otherwise, the exception object will be passed to the callback instead. - * - * A listener can listen for particular error levels by providing a mask. - */ - bool AddMessageListenerWithErrorLevel(MessageCallback that, - int message_levels, - Local data = Local()); - - /** - * Remove all message listeners from the specified callback function. - */ - void RemoveMessageListeners(MessageCallback that); - - /** Callback function for reporting failed access checks.*/ - void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback); - - /** - * Tells V8 to capture current stack trace when uncaught exception occurs - * and report it to the message listeners. The option is off by default. - */ - void SetCaptureStackTraceForUncaughtExceptions( - bool capture, int frame_limit = 10, - StackTrace::StackTraceOptions options = StackTrace::kOverview); - - /** - * Iterates through all external resources referenced from current isolate - * heap. GC is not invoked prior to iterating, therefore there is no - * guarantee that visited objects are still alive. - */ - void VisitExternalResources(ExternalResourceVisitor* visitor); - - /** - * Iterates through all the persistent handles in the current isolate's heap - * that have class_ids. - */ - void VisitHandlesWithClassIds(PersistentHandleVisitor* visitor); - - /** - * Iterates through all the persistent handles in the current isolate's heap - * that have class_ids and are weak to be marked as inactive if there is no - * pending activity for the handle. - */ - void VisitWeakHandles(PersistentHandleVisitor* visitor); - - /** - * Check if this isolate is in use. - * True if at least one thread Enter'ed this isolate. - */ - bool IsInUse(); - - /** - * Set whether calling Atomics.wait (a function that may block) is allowed in - * this isolate. This can also be configured via - * CreateParams::allow_atomics_wait. - */ - void SetAllowAtomicsWait(bool allow); - - /** - * Time zone redetection indicator for - * DateTimeConfigurationChangeNotification. - * - * kSkip indicates V8 that the notification should not trigger redetecting - * host time zone. kRedetect indicates V8 that host time zone should be - * redetected, and used to set the default time zone. - * - * The host time zone detection may require file system access or similar - * operations unlikely to be available inside a sandbox. If v8 is run inside a - * sandbox, the host time zone has to be detected outside the sandbox before - * calling DateTimeConfigurationChangeNotification function. - */ - enum class TimeZoneDetection { kSkip, kRedetect }; - - /** - * Notification that the embedder has changed the time zone, daylight savings - * time or other date / time configuration parameters. V8 keeps a cache of - * various values used for date / time computation. This notification will - * reset those cached values for the current context so that date / time - * configuration changes would be reflected. - * - * This API should not be called more than needed as it will negatively impact - * the performance of date operations. - */ - void DateTimeConfigurationChangeNotification( - TimeZoneDetection time_zone_detection = TimeZoneDetection::kSkip); - - /** - * Notification that the embedder has changed the locale. V8 keeps a cache of - * various values used for locale computation. This notification will reset - * those cached values for the current context so that locale configuration - * changes would be reflected. - * - * This API should not be called more than needed as it will negatively impact - * the performance of locale operations. - */ - void LocaleConfigurationChangeNotification(); - - Isolate() = delete; - ~Isolate() = delete; - Isolate(const Isolate&) = delete; - Isolate& operator=(const Isolate&) = delete; - // Deleting operator new and delete here is allowed as ctor and dtor is also - // deleted. - void* operator new(size_t size) = delete; - void* operator new[](size_t size) = delete; - void operator delete(void*, size_t) = delete; - void operator delete[](void*, size_t) = delete; - - private: - template - friend class PersistentValueMapBase; - - internal::Address* GetDataFromSnapshotOnce(size_t index); - void ReportExternalAllocationLimitReached(); -}; - -void Isolate::SetData(uint32_t slot, void* data) { - using I = internal::Internals; - I::SetEmbedderData(this, slot, data); -} - -void* Isolate::GetData(uint32_t slot) { - using I = internal::Internals; - return I::GetEmbedderData(this, slot); -} - -uint32_t Isolate::GetNumberOfDataSlots() { - using I = internal::Internals; - return I::kNumIsolateDataSlots; -} - -template -MaybeLocal Isolate::GetDataFromSnapshotOnce(size_t index) { - T* data = reinterpret_cast(GetDataFromSnapshotOnce(index)); - if (data) internal::PerformCastCheck(data); - return Local(data); -} - -} // namespace v8 - -#endif // INCLUDE_V8_ISOLATE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-json.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-json.h deleted file mode 100644 index 23d918fc973..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-json.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_JSON_H_ -#define INCLUDE_V8_JSON_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Value; -class String; - -/** - * A JSON Parser and Stringifier. - */ -class V8_EXPORT JSON { - public: - /** - * Tries to parse the string |json_string| and returns it as value if - * successful. - * - * \param the context in which to parse and create the value. - * \param json_string The string to parse. - * \return The corresponding value if successfully parsed. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal Parse( - Local context, Local json_string); - - /** - * Tries to stringify the JSON-serializable object |json_object| and returns - * it as string if successful. - * - * \param json_object The JSON-serializable object to stringify. - * \return The corresponding string if successfully stringified. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal Stringify( - Local context, Local json_object, - Local gap = Local()); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_JSON_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-local-handle.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-local-handle.h deleted file mode 100644 index 66a8e93af60..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-local-handle.h +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_LOCAL_HANDLE_H_ -#define INCLUDE_V8_LOCAL_HANDLE_H_ - -#include - -#include - -#include "v8-internal.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Boolean; -template -class BasicTracedReference; -class Context; -class EscapableHandleScope; -template -class Eternal; -template -class FunctionCallbackInfo; -class Isolate; -template -class MaybeLocal; -template -class NonCopyablePersistentTraits; -class Object; -template > -class Persistent; -template -class PersistentBase; -template -class PersistentValueMapBase; -template -class PersistentValueVector; -class Primitive; -class Private; -template -class PropertyCallbackInfo; -template -class ReturnValue; -class String; -template -class Traced; -template -class TracedGlobal; -template -class TracedReference; -class TracedReferenceBase; -class Utils; - -namespace internal { -template -class CustomArguments; -} // namespace internal - -namespace api_internal { -// Called when ToLocalChecked is called on an empty Local. -V8_EXPORT void ToLocalEmpty(); -} // namespace api_internal - -/** - * A stack-allocated class that governs a number of local handles. - * After a handle scope has been created, all local handles will be - * allocated within that handle scope until either the handle scope is - * deleted or another handle scope is created. If there is already a - * handle scope and a new one is created, all allocations will take - * place in the new handle scope until it is deleted. After that, - * new handles will again be allocated in the original handle scope. - * - * After the handle scope of a local handle has been deleted the - * garbage collector will no longer track the object stored in the - * handle and may deallocate it. The behavior of accessing a handle - * for which the handle scope has been deleted is undefined. - */ -class V8_EXPORT V8_NODISCARD HandleScope { - public: - explicit HandleScope(Isolate* isolate); - - ~HandleScope(); - - /** - * Counts the number of allocated handles. - */ - static int NumberOfHandles(Isolate* isolate); - - V8_INLINE Isolate* GetIsolate() const { - return reinterpret_cast(isolate_); - } - - HandleScope(const HandleScope&) = delete; - void operator=(const HandleScope&) = delete; - - protected: - V8_INLINE HandleScope() = default; - - void Initialize(Isolate* isolate); - - static internal::Address* CreateHandle(internal::Isolate* isolate, - internal::Address value); - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - internal::Isolate* isolate_; - internal::Address* prev_next_; - internal::Address* prev_limit_; - - // Local::New uses CreateHandle with an Isolate* parameter. - template - friend class Local; - - // Object::GetInternalField and Context::GetEmbedderData use CreateHandle with - // a HeapObject in their shortcuts. - friend class Object; - friend class Context; -}; - -/** - * An object reference managed by the v8 garbage collector. - * - * All objects returned from v8 have to be tracked by the garbage collector so - * that it knows that the objects are still alive. Also, because the garbage - * collector may move objects, it is unsafe to point directly to an object. - * Instead, all objects are stored in handles which are known by the garbage - * collector and updated whenever an object moves. Handles should always be - * passed by value (except in cases like out-parameters) and they should never - * be allocated on the heap. - * - * There are two types of handles: local and persistent handles. - * - * Local handles are light-weight and transient and typically used in local - * operations. They are managed by HandleScopes. That means that a HandleScope - * must exist on the stack when they are created and that they are only valid - * inside of the HandleScope active during their creation. For passing a local - * handle to an outer HandleScope, an EscapableHandleScope and its Escape() - * method must be used. - * - * Persistent handles can be used when storing objects across several - * independent operations and have to be explicitly deallocated when they're no - * longer used. - * - * It is safe to extract the object stored in the handle by dereferencing the - * handle (for instance, to extract the Object* from a Local); the value - * will still be governed by a handle behind the scenes and the same rules apply - * to these values as to their handles. - */ -template -class Local { - public: - V8_INLINE Local() : val_(nullptr) {} - template - V8_INLINE Local(Local that) : val_(reinterpret_cast(*that)) { - /** - * This check fails when trying to convert between incompatible - * handles. For example, converting from a Local to a - * Local. - */ - static_assert(std::is_base_of::value, "type check"); - } - - /** - * Returns true if the handle is empty. - */ - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - - /** - * Sets the handle to be empty. IsEmpty() will then return true. - */ - V8_INLINE void Clear() { val_ = nullptr; } - - V8_INLINE T* operator->() const { return val_; } - - V8_INLINE T* operator*() const { return val_; } - - /** - * Checks whether two handles are the same. - * Returns true if both are empty, or if the objects to which they refer - * are identical. - * - * If both handles refer to JS objects, this is the same as strict equality. - * For primitives, such as numbers or strings, a `false` return value does not - * indicate that the values aren't equal in the JavaScript sense. - * Use `Value::StrictEquals()` to check primitives for equality. - */ - template - V8_INLINE bool operator==(const Local& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - template - V8_INLINE bool operator==(const PersistentBase& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - /** - * Checks whether two handles are different. - * Returns true if only one of the handles is empty, or if - * the objects to which they refer are different. - * - * If both handles refer to JS objects, this is the same as strict - * non-equality. For primitives, such as numbers or strings, a `true` return - * value does not indicate that the values aren't equal in the JavaScript - * sense. Use `Value::StrictEquals()` to check primitives for equality. - */ - template - V8_INLINE bool operator!=(const Local& that) const { - return !operator==(that); - } - - template - V8_INLINE bool operator!=(const Persistent& that) const { - return !operator==(that); - } - - /** - * Cast a handle to a subclass, e.g. Local to Local. - * This is only valid if the handle actually refers to a value of the - * target type. - */ - template - V8_INLINE static Local Cast(Local that) { -#ifdef V8_ENABLE_CHECKS - // If we're going to perform the type check then we have to check - // that the handle isn't empty before doing the checked cast. - if (that.IsEmpty()) return Local(); -#endif - return Local(T::Cast(*that)); - } - - /** - * Calling this is equivalent to Local::Cast(). - * In particular, this is only valid if the handle actually refers to a value - * of the target type. - */ - template - V8_INLINE Local As() const { - return Local::Cast(*this); - } - - /** - * Create a local handle for the content of another handle. - * The referee is kept alive by the local handle even when - * the original handle is destroyed/disposed. - */ - V8_INLINE static Local New(Isolate* isolate, Local that) { - return New(isolate, that.val_); - } - - V8_INLINE static Local New(Isolate* isolate, - const PersistentBase& that) { - return New(isolate, that.val_); - } - - V8_INLINE static Local New(Isolate* isolate, - const BasicTracedReference& that) { - return New(isolate, *that); - } - - private: - friend class TracedReferenceBase; - friend class Utils; - template - friend class Eternal; - template - friend class PersistentBase; - template - friend class Persistent; - template - friend class Local; - template - friend class MaybeLocal; - template - friend class FunctionCallbackInfo; - template - friend class PropertyCallbackInfo; - friend class String; - friend class Object; - friend class Context; - friend class Isolate; - friend class Private; - template - friend class internal::CustomArguments; - friend Local Undefined(Isolate* isolate); - friend Local Null(Isolate* isolate); - friend Local True(Isolate* isolate); - friend Local False(Isolate* isolate); - friend class HandleScope; - friend class EscapableHandleScope; - template - friend class PersistentValueMapBase; - template - friend class PersistentValueVector; - template - friend class ReturnValue; - template - friend class Traced; - template - friend class TracedGlobal; - template - friend class BasicTracedReference; - template - friend class TracedReference; - - explicit V8_INLINE Local(T* that) : val_(that) {} - V8_INLINE static Local New(Isolate* isolate, T* that) { - if (that == nullptr) return Local(); - T* that_ptr = that; - internal::Address* p = reinterpret_cast(that_ptr); - return Local(reinterpret_cast(HandleScope::CreateHandle( - reinterpret_cast(isolate), *p))); - } - T* val_; -}; - -#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS) -// Handle is an alias for Local for historical reasons. -template -using Handle = Local; -#endif - -/** - * A MaybeLocal<> is a wrapper around Local<> that enforces a check whether - * the Local<> is empty before it can be used. - * - * If an API method returns a MaybeLocal<>, the API method can potentially fail - * either because an exception is thrown, or because an exception is pending, - * e.g. because a previous API call threw an exception that hasn't been caught - * yet, or because a TerminateExecution exception was thrown. In that case, an - * empty MaybeLocal is returned. - */ -template -class MaybeLocal { - public: - V8_INLINE MaybeLocal() : val_(nullptr) {} - template - V8_INLINE MaybeLocal(Local that) : val_(reinterpret_cast(*that)) { - static_assert(std::is_base_of::value, "type check"); - } - - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - - /** - * Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty, - * |false| is returned and |out| is left untouched. - */ - template - V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local* out) const { - out->val_ = IsEmpty() ? nullptr : this->val_; - return !IsEmpty(); - } - - /** - * Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty, - * V8 will crash the process. - */ - V8_INLINE Local ToLocalChecked() { - if (V8_UNLIKELY(val_ == nullptr)) api_internal::ToLocalEmpty(); - return Local(val_); - } - - /** - * Converts this MaybeLocal<> to a Local<>, using a default value if this - * MaybeLocal<> is empty. - */ - template - V8_INLINE Local FromMaybe(Local default_value) const { - return IsEmpty() ? default_value : Local(val_); - } - - private: - T* val_; -}; - -/** - * A HandleScope which first allocates a handle in the current scope - * which will be later filled with the escape value. - */ -class V8_EXPORT V8_NODISCARD EscapableHandleScope : public HandleScope { - public: - explicit EscapableHandleScope(Isolate* isolate); - V8_INLINE ~EscapableHandleScope() = default; - - /** - * Pushes the value into the previous scope and returns a handle to it. - * Cannot be called twice. - */ - template - V8_INLINE Local Escape(Local value) { - internal::Address* slot = - Escape(reinterpret_cast(*value)); - return Local(reinterpret_cast(slot)); - } - - template - V8_INLINE MaybeLocal EscapeMaybe(MaybeLocal value) { - return Escape(value.FromMaybe(Local())); - } - - EscapableHandleScope(const EscapableHandleScope&) = delete; - void operator=(const EscapableHandleScope&) = delete; - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - internal::Address* Escape(internal::Address* escape_value); - internal::Address* escape_slot_; -}; - -/** - * A SealHandleScope acts like a handle scope in which no handle allocations - * are allowed. It can be useful for debugging handle leaks. - * Handles can be allocated within inner normal HandleScopes. - */ -class V8_EXPORT V8_NODISCARD SealHandleScope { - public: - explicit SealHandleScope(Isolate* isolate); - ~SealHandleScope(); - - SealHandleScope(const SealHandleScope&) = delete; - void operator=(const SealHandleScope&) = delete; - - private: - // Declaring operator new and delete as deleted is not spec compliant. - // Therefore declare them private instead to disable dynamic alloc - void* operator new(size_t size); - void* operator new[](size_t size); - void operator delete(void*, size_t); - void operator delete[](void*, size_t); - - internal::Isolate* const isolate_; - internal::Address* prev_limit_; - int prev_sealed_level_; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_LOCAL_HANDLE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-locker.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-locker.h deleted file mode 100644 index b90fc5ed917..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-locker.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_LOCKER_H_ -#define INCLUDE_V8_LOCKER_H_ - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -namespace internal { -class Isolate; -} // namespace internal - -class Isolate; - -/** - * Multiple threads in V8 are allowed, but only one thread at a time is allowed - * to use any given V8 isolate, see the comments in the Isolate class. The - * definition of 'using a V8 isolate' includes accessing handles or holding onto - * object pointers obtained from V8 handles while in the particular V8 isolate. - * It is up to the user of V8 to ensure, perhaps with locking, that this - * constraint is not violated. In addition to any other synchronization - * mechanism that may be used, the v8::Locker and v8::Unlocker classes must be - * used to signal thread switches to V8. - * - * v8::Locker is a scoped lock object. While it's active, i.e. between its - * construction and destruction, the current thread is allowed to use the locked - * isolate. V8 guarantees that an isolate can be locked by at most one thread at - * any time. In other words, the scope of a v8::Locker is a critical section. - * - * Sample usage: - * \code - * ... - * { - * v8::Locker locker(isolate); - * v8::Isolate::Scope isolate_scope(isolate); - * ... - * // Code using V8 and isolate goes here. - * ... - * } // Destructor called here - * \endcode - * - * If you wish to stop using V8 in a thread A you can do this either by - * destroying the v8::Locker object as above or by constructing a v8::Unlocker - * object: - * - * \code - * { - * isolate->Exit(); - * v8::Unlocker unlocker(isolate); - * ... - * // Code not using V8 goes here while V8 can run in another thread. - * ... - * } // Destructor called here. - * isolate->Enter(); - * \endcode - * - * The Unlocker object is intended for use in a long-running callback from V8, - * where you want to release the V8 lock for other threads to use. - * - * The v8::Locker is a recursive lock, i.e. you can lock more than once in a - * given thread. This can be useful if you have code that can be called either - * from code that holds the lock or from code that does not. The Unlocker is - * not recursive so you can not have several Unlockers on the stack at once, and - * you can not use an Unlocker in a thread that is not inside a Locker's scope. - * - * An unlocker will unlock several lockers if it has to and reinstate the - * correct depth of locking on its destruction, e.g.: - * - * \code - * // V8 not locked. - * { - * v8::Locker locker(isolate); - * Isolate::Scope isolate_scope(isolate); - * // V8 locked. - * { - * v8::Locker another_locker(isolate); - * // V8 still locked (2 levels). - * { - * isolate->Exit(); - * v8::Unlocker unlocker(isolate); - * // V8 not locked. - * } - * isolate->Enter(); - * // V8 locked again (2 levels). - * } - * // V8 still locked (1 level). - * } - * // V8 Now no longer locked. - * \endcode - */ -class V8_EXPORT Unlocker { - public: - /** - * Initialize Unlocker for a given Isolate. - */ - V8_INLINE explicit Unlocker(Isolate* isolate) { Initialize(isolate); } - - ~Unlocker(); - - private: - void Initialize(Isolate* isolate); - - internal::Isolate* isolate_; -}; - -class V8_EXPORT Locker { - public: - /** - * Initialize Locker for a given Isolate. - */ - V8_INLINE explicit Locker(Isolate* isolate) { Initialize(isolate); } - - ~Locker(); - - /** - * Returns whether or not the locker for a given isolate, is locked by the - * current thread. - */ - static bool IsLocked(Isolate* isolate); - - /** - * Returns whether v8::Locker is being used by this V8 instance. - */ - static bool IsActive(); - - // Disallow copying and assigning. - Locker(const Locker&) = delete; - void operator=(const Locker&) = delete; - - private: - void Initialize(Isolate* isolate); - - bool has_lock_; - bool top_level_; - internal::Isolate* isolate_; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_LOCKER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-maybe.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-maybe.h deleted file mode 100644 index 0532a510059..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-maybe.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MAYBE_H_ -#define INCLUDE_V8_MAYBE_H_ - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -namespace api_internal { -// Called when ToChecked is called on an empty Maybe. -V8_EXPORT void FromJustIsNothing(); -} // namespace api_internal - -/** - * A simple Maybe type, representing an object which may or may not have a - * value, see https://hackage.haskell.org/package/base/docs/Data-Maybe.html. - * - * If an API method returns a Maybe<>, the API method can potentially fail - * either because an exception is thrown, or because an exception is pending, - * e.g. because a previous API call threw an exception that hasn't been caught - * yet, or because a TerminateExecution exception was thrown. In that case, a - * "Nothing" value is returned. - */ -template -class Maybe { - public: - V8_INLINE bool IsNothing() const { return !has_value_; } - V8_INLINE bool IsJust() const { return has_value_; } - - /** - * An alias for |FromJust|. Will crash if the Maybe<> is nothing. - */ - V8_INLINE T ToChecked() const { return FromJust(); } - - /** - * Short-hand for ToChecked(), which doesn't return a value. To be used, where - * the actual value of the Maybe is not needed like Object::Set. - */ - V8_INLINE void Check() const { - if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing(); - } - - /** - * Converts this Maybe<> to a value of type T. If this Maybe<> is - * nothing (empty), |false| is returned and |out| is left untouched. - */ - V8_WARN_UNUSED_RESULT V8_INLINE bool To(T* out) const { - if (V8_LIKELY(IsJust())) *out = value_; - return IsJust(); - } - - /** - * Converts this Maybe<> to a value of type T. If this Maybe<> is - * nothing (empty), V8 will crash the process. - */ - V8_INLINE T FromJust() const { - if (V8_UNLIKELY(!IsJust())) api_internal::FromJustIsNothing(); - return value_; - } - - /** - * Converts this Maybe<> to a value of type T, using a default value if this - * Maybe<> is nothing (empty). - */ - V8_INLINE T FromMaybe(const T& default_value) const { - return has_value_ ? value_ : default_value; - } - - V8_INLINE bool operator==(const Maybe& other) const { - return (IsJust() == other.IsJust()) && - (!IsJust() || FromJust() == other.FromJust()); - } - - V8_INLINE bool operator!=(const Maybe& other) const { - return !operator==(other); - } - - private: - Maybe() : has_value_(false) {} - explicit Maybe(const T& t) : has_value_(true), value_(t) {} - - bool has_value_; - T value_; - - template - friend Maybe Nothing(); - template - friend Maybe Just(const U& u); -}; - -template -inline Maybe Nothing() { - return Maybe(); -} - -template -inline Maybe Just(const T& t) { - return Maybe(t); -} - -// A template specialization of Maybe for the case of T = void. -template <> -class Maybe { - public: - V8_INLINE bool IsNothing() const { return !is_valid_; } - V8_INLINE bool IsJust() const { return is_valid_; } - - V8_INLINE bool operator==(const Maybe& other) const { - return IsJust() == other.IsJust(); - } - - V8_INLINE bool operator!=(const Maybe& other) const { - return !operator==(other); - } - - private: - struct JustTag {}; - - Maybe() : is_valid_(false) {} - explicit Maybe(JustTag) : is_valid_(true) {} - - bool is_valid_; - - template - friend Maybe Nothing(); - friend Maybe JustVoid(); -}; - -inline Maybe JustVoid() { return Maybe(Maybe::JustTag()); } - -} // namespace v8 - -#endif // INCLUDE_V8_MAYBE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-memory-span.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-memory-span.h deleted file mode 100644 index b26af4f705b..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-memory-span.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MEMORY_SPAN_H_ -#define INCLUDE_V8_MEMORY_SPAN_H_ - -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -/** - * Points to an unowned continous buffer holding a known number of elements. - * - * This is similar to std::span (under consideration for C++20), but does not - * require advanced C++ support. In the (far) future, this may be replaced with - * or aliased to std::span. - * - * To facilitate future migration, this class exposes a subset of the interface - * implemented by std::span. - */ -template -class V8_EXPORT MemorySpan { - public: - /** The default constructor creates an empty span. */ - constexpr MemorySpan() = default; - - constexpr MemorySpan(T* data, size_t size) : data_(data), size_(size) {} - - /** Returns a pointer to the beginning of the buffer. */ - constexpr T* data() const { return data_; } - /** Returns the number of elements that the buffer holds. */ - constexpr size_t size() const { return size_; } - - private: - T* data_ = nullptr; - size_t size_ = 0; -}; - -} // namespace v8 -#endif // INCLUDE_V8_MEMORY_SPAN_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-message.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-message.h deleted file mode 100644 index 195ca79bd91..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-message.h +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MESSAGE_H_ -#define INCLUDE_V8_MESSAGE_H_ - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-maybe.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Integer; -class PrimitiveArray; -class StackTrace; -class String; -class Value; - -/** - * The optional attributes of ScriptOrigin. - */ -class ScriptOriginOptions { - public: - V8_INLINE ScriptOriginOptions(bool is_shared_cross_origin = false, - bool is_opaque = false, bool is_wasm = false, - bool is_module = false) - : flags_((is_shared_cross_origin ? kIsSharedCrossOrigin : 0) | - (is_wasm ? kIsWasm : 0) | (is_opaque ? kIsOpaque : 0) | - (is_module ? kIsModule : 0)) {} - V8_INLINE ScriptOriginOptions(int flags) - : flags_(flags & - (kIsSharedCrossOrigin | kIsOpaque | kIsWasm | kIsModule)) {} - - bool IsSharedCrossOrigin() const { - return (flags_ & kIsSharedCrossOrigin) != 0; - } - bool IsOpaque() const { return (flags_ & kIsOpaque) != 0; } - bool IsWasm() const { return (flags_ & kIsWasm) != 0; } - bool IsModule() const { return (flags_ & kIsModule) != 0; } - - int Flags() const { return flags_; } - - private: - enum { - kIsSharedCrossOrigin = 1, - kIsOpaque = 1 << 1, - kIsWasm = 1 << 2, - kIsModule = 1 << 3 - }; - const int flags_; -}; - -/** - * The origin, within a file, of a script. - */ -class V8_EXPORT ScriptOrigin { - public: - V8_DEPRECATE_SOON("Use constructor with primitive C++ types") - ScriptOrigin( - Local resource_name, Local resource_line_offset, - Local resource_column_offset, - Local resource_is_shared_cross_origin = Local(), - Local script_id = Local(), - Local source_map_url = Local(), - Local resource_is_opaque = Local(), - Local is_wasm = Local(), - Local is_module = Local(), - Local host_defined_options = Local()); - V8_DEPRECATE_SOON("Use constructor that takes an isolate") - explicit ScriptOrigin( - Local resource_name, int resource_line_offset = 0, - int resource_column_offset = 0, - bool resource_is_shared_cross_origin = false, int script_id = -1, - Local source_map_url = Local(), - bool resource_is_opaque = false, bool is_wasm = false, - bool is_module = false, - Local host_defined_options = Local()); - V8_INLINE ScriptOrigin( - Isolate* isolate, Local resource_name, - int resource_line_offset = 0, int resource_column_offset = 0, - bool resource_is_shared_cross_origin = false, int script_id = -1, - Local source_map_url = Local(), - bool resource_is_opaque = false, bool is_wasm = false, - bool is_module = false, - Local host_defined_options = Local()) - : isolate_(isolate), - resource_name_(resource_name), - resource_line_offset_(resource_line_offset), - resource_column_offset_(resource_column_offset), - options_(resource_is_shared_cross_origin, resource_is_opaque, is_wasm, - is_module), - script_id_(script_id), - source_map_url_(source_map_url), - host_defined_options_(host_defined_options) {} - - V8_INLINE Local ResourceName() const; - V8_DEPRECATE_SOON("Use getter with primitive C++ types.") - V8_INLINE Local ResourceLineOffset() const; - V8_DEPRECATE_SOON("Use getter with primitive C++ types.") - V8_INLINE Local ResourceColumnOffset() const; - V8_DEPRECATE_SOON("Use getter with primitive C++ types.") - V8_INLINE Local ScriptID() const; - V8_INLINE int LineOffset() const; - V8_INLINE int ColumnOffset() const; - V8_INLINE int ScriptId() const; - V8_INLINE Local SourceMapUrl() const; - V8_INLINE Local HostDefinedOptions() const; - V8_INLINE ScriptOriginOptions Options() const { return options_; } - - private: - Isolate* isolate_; - Local resource_name_; - int resource_line_offset_; - int resource_column_offset_; - ScriptOriginOptions options_; - int script_id_; - Local source_map_url_; - Local host_defined_options_; -}; - -/** - * An error message. - */ -class V8_EXPORT Message { - public: - Local Get() const; - - /** - * Return the isolate to which the Message belongs. - */ - Isolate* GetIsolate() const; - - V8_WARN_UNUSED_RESULT MaybeLocal GetSource( - Local context) const; - V8_WARN_UNUSED_RESULT MaybeLocal GetSourceLine( - Local context) const; - - /** - * Returns the origin for the script from where the function causing the - * error originates. - */ - ScriptOrigin GetScriptOrigin() const; - - /** - * Returns the resource name for the script from where the function causing - * the error originates. - */ - Local GetScriptResourceName() const; - - /** - * Exception stack trace. By default stack traces are not captured for - * uncaught exceptions. SetCaptureStackTraceForUncaughtExceptions allows - * to change this option. - */ - Local GetStackTrace() const; - - /** - * Returns the number, 1-based, of the line where the error occurred. - */ - V8_WARN_UNUSED_RESULT Maybe GetLineNumber(Local context) const; - - /** - * Returns the index within the script of the first character where - * the error occurred. - */ - int GetStartPosition() const; - - /** - * Returns the index within the script of the last character where - * the error occurred. - */ - int GetEndPosition() const; - - /** - * Returns the Wasm function index where the error occurred. Returns -1 if - * message is not from a Wasm script. - */ - int GetWasmFunctionIndex() const; - - /** - * Returns the error level of the message. - */ - int ErrorLevel() const; - - /** - * Returns the index within the line of the first character where - * the error occurred. - */ - int GetStartColumn() const; - V8_WARN_UNUSED_RESULT Maybe GetStartColumn(Local context) const; - - /** - * Returns the index within the line of the last character where - * the error occurred. - */ - int GetEndColumn() const; - V8_WARN_UNUSED_RESULT Maybe GetEndColumn(Local context) const; - - /** - * Passes on the value set by the embedder when it fed the script from which - * this Message was generated to V8. - */ - bool IsSharedCrossOrigin() const; - bool IsOpaque() const; - - // TODO(1245381): Print to a string instead of on a FILE. - static void PrintCurrentStackTrace(Isolate* isolate, FILE* out); - - static const int kNoLineNumberInfo = 0; - static const int kNoColumnInfo = 0; - static const int kNoScriptIdInfo = 0; - static const int kNoWasmFunctionIndexInfo = -1; -}; - -Local ScriptOrigin::ResourceName() const { return resource_name_; } - -Local ScriptOrigin::HostDefinedOptions() const { - return host_defined_options_; -} - -int ScriptOrigin::LineOffset() const { return resource_line_offset_; } - -int ScriptOrigin::ColumnOffset() const { return resource_column_offset_; } - -int ScriptOrigin::ScriptId() const { return script_id_; } - -Local ScriptOrigin::SourceMapUrl() const { return source_map_url_; } - -} // namespace v8 - -#endif // INCLUDE_V8_MESSAGE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-metrics.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-metrics.h deleted file mode 100644 index 29e54401067..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-metrics.h +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2020 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_METRICS_H_ -#define V8_METRICS_H_ - -#include -#include - -#include - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; - -namespace metrics { - -struct GarbageCollectionPhases { - int64_t compact_wall_clock_duration_in_us = -1; - int64_t mark_wall_clock_duration_in_us = -1; - int64_t sweep_wall_clock_duration_in_us = -1; - int64_t weak_wall_clock_duration_in_us = -1; -}; - -struct GarbageCollectionSizes { - int64_t bytes_before = -1; - int64_t bytes_after = -1; - int64_t bytes_freed = -1; -}; - -struct GarbageCollectionFullCycle { - GarbageCollectionPhases total; - GarbageCollectionPhases total_cpp; - GarbageCollectionPhases main_thread; - GarbageCollectionPhases main_thread_cpp; - GarbageCollectionPhases main_thread_atomic; - GarbageCollectionPhases main_thread_atomic_cpp; - GarbageCollectionPhases main_thread_incremental; - GarbageCollectionPhases main_thread_incremental_cpp; - GarbageCollectionSizes objects; - GarbageCollectionSizes objects_cpp; - GarbageCollectionSizes memory; - GarbageCollectionSizes memory_cpp; - double collection_rate_in_percent; - double collection_rate_cpp_in_percent; - double efficiency_in_bytes_per_us; - double efficiency_cpp_in_bytes_per_us; - double main_thread_efficiency_in_bytes_per_us; - double main_thread_efficiency_cpp_in_bytes_per_us; -}; - -struct GarbageCollectionFullMainThreadIncrementalMark { - int64_t wall_clock_duration_in_us = -1; - int64_t cpp_wall_clock_duration_in_us = -1; -}; - -struct GarbageCollectionFullMainThreadBatchedIncrementalMark { - std::vector events; -}; - -struct GarbageCollectionFullMainThreadIncrementalSweep { - int64_t wall_clock_duration_in_us = -1; - int64_t cpp_wall_clock_duration_in_us = -1; -}; - -struct GarbageCollectionFullMainThreadBatchedIncrementalSweep { - std::vector events; -}; - -struct GarbageCollectionYoungCycle { - int64_t total_wall_clock_duration_in_us = -1; - int64_t main_thread_wall_clock_duration_in_us = -1; - double collection_rate_in_percent; - double efficiency_in_bytes_per_us; - double main_thread_efficiency_in_bytes_per_us; -}; - -struct WasmModuleDecoded { - bool async = false; - bool streamed = false; - bool success = false; - size_t module_size_in_bytes = 0; - size_t function_count = 0; - int64_t wall_clock_duration_in_us = -1; - int64_t cpu_duration_in_us = -1; -}; - -struct WasmModuleCompiled { - bool async = false; - bool streamed = false; - bool cached = false; - bool deserialized = false; - bool lazy = false; - bool success = false; - size_t code_size_in_bytes = 0; - size_t liftoff_bailout_count = 0; - int64_t wall_clock_duration_in_us = -1; - int64_t cpu_duration_in_us = -1; -}; - -struct WasmModuleInstantiated { - bool async = false; - bool success = false; - size_t imported_function_count = 0; - int64_t wall_clock_duration_in_us = -1; -}; - -struct WasmModuleTieredUp { - bool lazy = false; - size_t code_size_in_bytes = 0; - int64_t wall_clock_duration_in_us = -1; - int64_t cpu_duration_in_us = -1; -}; - -struct WasmModulesPerIsolate { - size_t count = 0; -}; - -#define V8_MAIN_THREAD_METRICS_EVENTS(V) \ - V(GarbageCollectionFullCycle) \ - V(GarbageCollectionFullMainThreadIncrementalMark) \ - V(GarbageCollectionFullMainThreadBatchedIncrementalMark) \ - V(GarbageCollectionFullMainThreadIncrementalSweep) \ - V(GarbageCollectionFullMainThreadBatchedIncrementalSweep) \ - V(GarbageCollectionYoungCycle) \ - V(WasmModuleDecoded) \ - V(WasmModuleCompiled) \ - V(WasmModuleInstantiated) \ - V(WasmModuleTieredUp) - -#define V8_THREAD_SAFE_METRICS_EVENTS(V) V(WasmModulesPerIsolate) - -/** - * This class serves as a base class for recording event-based metrics in V8. - * There a two kinds of metrics, those which are expected to be thread-safe and - * whose implementation is required to fulfill this requirement and those whose - * implementation does not have that requirement and only needs to be - * executable on the main thread. If such an event is triggered from a - * background thread, it will be delayed and executed by the foreground task - * runner. - * - * The thread-safe events are listed in the V8_THREAD_SAFE_METRICS_EVENTS - * macro above while the main thread event are listed in - * V8_MAIN_THREAD_METRICS_EVENTS above. For the former, a virtual method - * AddMainThreadEvent(const E& event, v8::Context::Token token) will be - * generated and for the latter AddThreadSafeEvent(const E& event). - * - * Thread-safe events are not allowed to access the context and therefore do - * not carry a context ID with them. These IDs can be generated using - * Recorder::GetContextId() and the ID will be valid throughout the lifetime - * of the isolate. It is not guaranteed that the ID will still resolve to - * a valid context using Recorder::GetContext() at the time the metric is - * recorded. In this case, an empty handle will be returned. - * - * The embedder is expected to call v8::Isolate::SetMetricsRecorder() - * providing its implementation and have the virtual methods overwritten - * for the events it cares about. - */ -class V8_EXPORT Recorder { - public: - // A unique identifier for a context in this Isolate. - // It is guaranteed to not be reused throughout the lifetime of the Isolate. - class ContextId { - public: - ContextId() : id_(kEmptyId) {} - - bool IsEmpty() const { return id_ == kEmptyId; } - static const ContextId Empty() { return ContextId{kEmptyId}; } - - bool operator==(const ContextId& other) const { return id_ == other.id_; } - bool operator!=(const ContextId& other) const { return id_ != other.id_; } - - private: - friend class ::v8::Context; - friend class ::v8::internal::Isolate; - - explicit ContextId(uintptr_t id) : id_(id) {} - - static constexpr uintptr_t kEmptyId = 0; - uintptr_t id_; - }; - - virtual ~Recorder() = default; - -#define ADD_MAIN_THREAD_EVENT(E) \ - virtual void AddMainThreadEvent(const E& event, ContextId context_id) {} - V8_MAIN_THREAD_METRICS_EVENTS(ADD_MAIN_THREAD_EVENT) -#undef ADD_MAIN_THREAD_EVENT - -#define ADD_THREAD_SAFE_EVENT(E) \ - virtual void AddThreadSafeEvent(const E& event) {} - V8_THREAD_SAFE_METRICS_EVENTS(ADD_THREAD_SAFE_EVENT) -#undef ADD_THREAD_SAFE_EVENT - - virtual void NotifyIsolateDisposal() {} - - // Return the context with the given id or an empty handle if the context - // was already garbage collected. - static MaybeLocal GetContext(Isolate* isolate, ContextId id); - // Return the unique id corresponding to the given context. - static ContextId GetContextId(Local context); -}; - -/** - * Experimental API intended for the LongTasks UKM (crbug.com/1173527). - * The Reset() method should be called at the start of a potential - * long task. The Get() method returns durations of V8 work that - * happened during the task. - * - * This API is experimental and may be removed/changed in the future. - */ -struct V8_EXPORT LongTaskStats { - /** - * Resets durations of V8 work for the new task. - */ - V8_INLINE static void Reset(Isolate* isolate) { - v8::internal::Internals::IncrementLongTasksStatsCounter(isolate); - } - - /** - * Returns durations of V8 work that happened since the last Reset(). - */ - static LongTaskStats Get(Isolate* isolate); - - int64_t gc_full_atomic_wall_clock_duration_us = 0; - int64_t gc_full_incremental_wall_clock_duration_us = 0; - int64_t gc_young_wall_clock_duration_us = 0; -}; - -} // namespace metrics -} // namespace v8 - -#endif // V8_METRICS_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-microtask-queue.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-microtask-queue.h deleted file mode 100644 index af9caa54a8f..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-microtask-queue.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MICROTASKS_QUEUE_H_ -#define INCLUDE_V8_MICROTASKS_QUEUE_H_ - -#include - -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-microtask.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Function; - -namespace internal { -class Isolate; -class MicrotaskQueue; -} // namespace internal - -/** - * Represents the microtask queue, where microtasks are stored and processed. - * https://html.spec.whatwg.org/multipage/webappapis.html#microtask-queue - * https://html.spec.whatwg.org/multipage/webappapis.html#enqueuejob(queuename,-job,-arguments) - * https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint - * - * A MicrotaskQueue instance may be associated to multiple Contexts by passing - * it to Context::New(), and they can be detached by Context::DetachGlobal(). - * The embedder must keep the MicrotaskQueue instance alive until all associated - * Contexts are gone or detached. - * - * Use the same instance of MicrotaskQueue for all Contexts that may access each - * other synchronously. E.g. for Web embedding, use the same instance for all - * origins that share the same URL scheme and eTLD+1. - */ -class V8_EXPORT MicrotaskQueue { - public: - /** - * Creates an empty MicrotaskQueue instance. - */ - static std::unique_ptr New( - Isolate* isolate, MicrotasksPolicy policy = MicrotasksPolicy::kAuto); - - virtual ~MicrotaskQueue() = default; - - /** - * Enqueues the callback to the queue. - */ - virtual void EnqueueMicrotask(Isolate* isolate, - Local microtask) = 0; - - /** - * Enqueues the callback to the queue. - */ - virtual void EnqueueMicrotask(v8::Isolate* isolate, - MicrotaskCallback callback, - void* data = nullptr) = 0; - - /** - * Adds a callback to notify the embedder after microtasks were run. The - * callback is triggered by explicit RunMicrotasks call or automatic - * microtasks execution (see Isolate::SetMicrotasksPolicy). - * - * Callback will trigger even if microtasks were attempted to run, - * but the microtasks queue was empty and no single microtask was actually - * executed. - * - * Executing scripts inside the callback will not re-trigger microtasks and - * the callback. - */ - virtual void AddMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr) = 0; - - /** - * Removes callback that was installed by AddMicrotasksCompletedCallback. - */ - virtual void RemoveMicrotasksCompletedCallback( - MicrotasksCompletedCallbackWithData callback, void* data = nullptr) = 0; - - /** - * Runs microtasks if no microtask is running on this MicrotaskQueue instance. - */ - virtual void PerformCheckpoint(Isolate* isolate) = 0; - - /** - * Returns true if a microtask is running on this MicrotaskQueue instance. - */ - virtual bool IsRunningMicrotasks() const = 0; - - /** - * Returns the current depth of nested MicrotasksScope that has - * kRunMicrotasks. - */ - virtual int GetMicrotasksScopeDepth() const = 0; - - MicrotaskQueue(const MicrotaskQueue&) = delete; - MicrotaskQueue& operator=(const MicrotaskQueue&) = delete; - - private: - friend class internal::MicrotaskQueue; - MicrotaskQueue() = default; -}; - -/** - * This scope is used to control microtasks when MicrotasksPolicy::kScoped - * is used on Isolate. In this mode every non-primitive call to V8 should be - * done inside some MicrotasksScope. - * Microtasks are executed when topmost MicrotasksScope marked as kRunMicrotasks - * exits. - * kDoNotRunMicrotasks should be used to annotate calls not intended to trigger - * microtasks. - */ -class V8_EXPORT V8_NODISCARD MicrotasksScope { - public: - enum Type { kRunMicrotasks, kDoNotRunMicrotasks }; - - MicrotasksScope(Isolate* isolate, Type type); - MicrotasksScope(Isolate* isolate, MicrotaskQueue* microtask_queue, Type type); - ~MicrotasksScope(); - - /** - * Runs microtasks if no kRunMicrotasks scope is currently active. - */ - static void PerformCheckpoint(Isolate* isolate); - - /** - * Returns current depth of nested kRunMicrotasks scopes. - */ - static int GetCurrentDepth(Isolate* isolate); - - /** - * Returns true while microtasks are being executed. - */ - static bool IsRunningMicrotasks(Isolate* isolate); - - // Prevent copying. - MicrotasksScope(const MicrotasksScope&) = delete; - MicrotasksScope& operator=(const MicrotasksScope&) = delete; - - private: - internal::Isolate* const isolate_; - internal::MicrotaskQueue* const microtask_queue_; - bool run_; -}; - -} // namespace v8 - -#endif // INCLUDE_V8_MICROTASKS_QUEUE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-microtask.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-microtask.h deleted file mode 100644 index c159203608d..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-microtask.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_MICROTASK_H_ -#define INCLUDE_V8_MICROTASK_H_ - -namespace v8 { - -class Isolate; - -// --- Microtasks Callbacks --- -using MicrotasksCompletedCallbackWithData = void (*)(Isolate*, void*); -using MicrotaskCallback = void (*)(void* data); - -/** - * Policy for running microtasks: - * - explicit: microtasks are invoked with the - * Isolate::PerformMicrotaskCheckpoint() method; - * - scoped: microtasks invocation is controlled by MicrotasksScope objects; - * - auto: microtasks are invoked when the script call depth decrements - * to zero. - */ -enum class MicrotasksPolicy { kExplicit, kScoped, kAuto }; - -} // namespace v8 - -#endif // INCLUDE_V8_MICROTASK_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-object.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-object.h deleted file mode 100644 index 114e452a380..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-object.h +++ /dev/null @@ -1,770 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_OBJECT_H_ -#define INCLUDE_V8_OBJECT_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-maybe.h" // NOLINT(build/include_directory) -#include "v8-persistent-handle.h" // NOLINT(build/include_directory) -#include "v8-primitive.h" // NOLINT(build/include_directory) -#include "v8-traced-handle.h" // NOLINT(build/include_directory) -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Array; -class Function; -class FunctionTemplate; -template -class PropertyCallbackInfo; - -/** - * A private symbol - * - * This is an experimental feature. Use at your own risk. - */ -class V8_EXPORT Private : public Data { - public: - /** - * Returns the print name string of the private symbol, or undefined if none. - */ - Local Name() const; - - /** - * Create a private symbol. If name is not empty, it will be the description. - */ - static Local New(Isolate* isolate, - Local name = Local()); - - /** - * Retrieve a global private symbol. If a symbol with this name has not - * been retrieved in the same isolate before, it is created. - * Note that private symbols created this way are never collected, so - * they should only be used for statically fixed properties. - * Also, there is only one global name space for the names used as keys. - * To minimize the potential for clashes, use qualified names as keys, - * e.g., "Class#property". - */ - static Local ForApi(Isolate* isolate, Local name); - - V8_INLINE static Private* Cast(Data* data); - - private: - Private(); - - static void CheckCast(Data* that); -}; - -/** - * An instance of a Property Descriptor, see Ecma-262 6.2.4. - * - * Properties in a descriptor are present or absent. If you do not set - * `enumerable`, `configurable`, and `writable`, they are absent. If `value`, - * `get`, or `set` are absent, but you must specify them in the constructor, use - * empty handles. - * - * Accessors `get` and `set` must be callable or undefined if they are present. - * - * \note Only query properties if they are present, i.e., call `x()` only if - * `has_x()` returns true. - * - * \code - * // var desc = {writable: false} - * v8::PropertyDescriptor d(Local()), false); - * d.value(); // error, value not set - * if (d.has_writable()) { - * d.writable(); // false - * } - * - * // var desc = {value: undefined} - * v8::PropertyDescriptor d(v8::Undefined(isolate)); - * - * // var desc = {get: undefined} - * v8::PropertyDescriptor d(v8::Undefined(isolate), Local())); - * \endcode - */ -class V8_EXPORT PropertyDescriptor { - public: - // GenericDescriptor - PropertyDescriptor(); - - // DataDescriptor - explicit PropertyDescriptor(Local value); - - // DataDescriptor with writable property - PropertyDescriptor(Local value, bool writable); - - // AccessorDescriptor - PropertyDescriptor(Local get, Local set); - - ~PropertyDescriptor(); - - Local value() const; - bool has_value() const; - - Local get() const; - bool has_get() const; - Local set() const; - bool has_set() const; - - void set_enumerable(bool enumerable); - bool enumerable() const; - bool has_enumerable() const; - - void set_configurable(bool configurable); - bool configurable() const; - bool has_configurable() const; - - bool writable() const; - bool has_writable() const; - - struct PrivateData; - PrivateData* get_private() const { return private_; } - - PropertyDescriptor(const PropertyDescriptor&) = delete; - void operator=(const PropertyDescriptor&) = delete; - - private: - PrivateData* private_; -}; - -/** - * PropertyAttribute. - */ -enum PropertyAttribute { - /** None. **/ - None = 0, - /** ReadOnly, i.e., not writable. **/ - ReadOnly = 1 << 0, - /** DontEnum, i.e., not enumerable. **/ - DontEnum = 1 << 1, - /** DontDelete, i.e., not configurable. **/ - DontDelete = 1 << 2 -}; - -/** - * Accessor[Getter|Setter] are used as callback functions when - * setting|getting a particular property. See Object and ObjectTemplate's - * method SetAccessor. - */ -using AccessorGetterCallback = - void (*)(Local property, const PropertyCallbackInfo& info); -using AccessorNameGetterCallback = - void (*)(Local property, const PropertyCallbackInfo& info); - -using AccessorSetterCallback = void (*)(Local property, - Local value, - const PropertyCallbackInfo& info); -using AccessorNameSetterCallback = - void (*)(Local property, Local value, - const PropertyCallbackInfo& info); - -/** - * Access control specifications. - * - * Some accessors should be accessible across contexts. These - * accessors have an explicit access control parameter which specifies - * the kind of cross-context access that should be allowed. - * - * TODO(dcarney): Remove PROHIBITS_OVERWRITING as it is now unused. - */ -enum AccessControl { - DEFAULT = 0, - ALL_CAN_READ = 1, - ALL_CAN_WRITE = 1 << 1, - PROHIBITS_OVERWRITING = 1 << 2 -}; - -/** - * Property filter bits. They can be or'ed to build a composite filter. - */ -enum PropertyFilter { - ALL_PROPERTIES = 0, - ONLY_WRITABLE = 1, - ONLY_ENUMERABLE = 2, - ONLY_CONFIGURABLE = 4, - SKIP_STRINGS = 8, - SKIP_SYMBOLS = 16 -}; - -/** - * Options for marking whether callbacks may trigger JS-observable side effects. - * Side-effect-free callbacks are allowlisted during debug evaluation with - * throwOnSideEffect. It applies when calling a Function, FunctionTemplate, - * or an Accessor callback. For Interceptors, please see - * PropertyHandlerFlags's kHasNoSideEffect. - * Callbacks that only cause side effects to the receiver are allowlisted if - * invoked on receiver objects that are created within the same debug-evaluate - * call, as these objects are temporary and the side effect does not escape. - */ -enum class SideEffectType { - kHasSideEffect, - kHasNoSideEffect, - kHasSideEffectToReceiver -}; - -/** - * Keys/Properties filter enums: - * - * KeyCollectionMode limits the range of collected properties. kOwnOnly limits - * the collected properties to the given Object only. kIncludesPrototypes will - * include all keys of the objects's prototype chain as well. - */ -enum class KeyCollectionMode { kOwnOnly, kIncludePrototypes }; - -/** - * kIncludesIndices allows for integer indices to be collected, while - * kSkipIndices will exclude integer indices from being collected. - */ -enum class IndexFilter { kIncludeIndices, kSkipIndices }; - -/** - * kConvertToString will convert integer indices to strings. - * kKeepNumbers will return numbers for integer indices. - */ -enum class KeyConversionMode { kConvertToString, kKeepNumbers, kNoNumbers }; - -/** - * Integrity level for objects. - */ -enum class IntegrityLevel { kFrozen, kSealed }; - -/** - * A JavaScript object (ECMA-262, 4.3.3) - */ -class V8_EXPORT Object : public Value { - public: - /** - * Set only return Just(true) or Empty(), so if it should never fail, use - * result.Check(). - */ - V8_WARN_UNUSED_RESULT Maybe Set(Local context, - Local key, Local value); - - V8_WARN_UNUSED_RESULT Maybe Set(Local context, uint32_t index, - Local value); - - // Implements CreateDataProperty (ECMA-262, 7.3.4). - // - // Defines a configurable, writable, enumerable property with the given value - // on the object unless the property already exists and is not configurable - // or the object is not extensible. - // - // Returns true on success. - V8_WARN_UNUSED_RESULT Maybe CreateDataProperty(Local context, - Local key, - Local value); - V8_WARN_UNUSED_RESULT Maybe CreateDataProperty(Local context, - uint32_t index, - Local value); - - // Implements DefineOwnProperty. - // - // In general, CreateDataProperty will be faster, however, does not allow - // for specifying attributes. - // - // Returns true on success. - V8_WARN_UNUSED_RESULT Maybe DefineOwnProperty( - Local context, Local key, Local value, - PropertyAttribute attributes = None); - - // Implements Object.DefineProperty(O, P, Attributes), see Ecma-262 19.1.2.4. - // - // The defineProperty function is used to add an own property or - // update the attributes of an existing own property of an object. - // - // Both data and accessor descriptors can be used. - // - // In general, CreateDataProperty is faster, however, does not allow - // for specifying attributes or an accessor descriptor. - // - // The PropertyDescriptor can change when redefining a property. - // - // Returns true on success. - V8_WARN_UNUSED_RESULT Maybe DefineProperty( - Local context, Local key, PropertyDescriptor& descriptor); - - V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, - Local key); - - V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, - uint32_t index); - - /** - * Gets the property attributes of a property which can be None or - * any combination of ReadOnly, DontEnum and DontDelete. Returns - * None when the property doesn't exist. - */ - V8_WARN_UNUSED_RESULT Maybe GetPropertyAttributes( - Local context, Local key); - - /** - * Returns Object.getOwnPropertyDescriptor as per ES2016 section 19.1.2.6. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetOwnPropertyDescriptor( - Local context, Local key); - - /** - * Object::Has() calls the abstract operation HasProperty(O, P) described - * in ECMA-262, 7.3.10. Has() returns - * true, if the object has the property, either own or on the prototype chain. - * Interceptors, i.e., PropertyQueryCallbacks, are called if present. - * - * Has() has the same side effects as JavaScript's `variable in object`. - * For example, calling Has() on a revoked proxy will throw an exception. - * - * \note Has() converts the key to a name, which possibly calls back into - * JavaScript. - * - * See also v8::Object::HasOwnProperty() and - * v8::Object::HasRealNamedProperty(). - */ - V8_WARN_UNUSED_RESULT Maybe Has(Local context, - Local key); - - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - Local key); - - V8_WARN_UNUSED_RESULT Maybe Has(Local context, uint32_t index); - - V8_WARN_UNUSED_RESULT Maybe Delete(Local context, - uint32_t index); - - /** - * Note: SideEffectType affects the getter only, not the setter. - */ - V8_WARN_UNUSED_RESULT Maybe SetAccessor( - Local context, Local name, - AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter = nullptr, - MaybeLocal data = MaybeLocal(), - AccessControl settings = DEFAULT, PropertyAttribute attribute = None, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - - void SetAccessorProperty(Local name, Local getter, - Local setter = Local(), - PropertyAttribute attribute = None, - AccessControl settings = DEFAULT); - - /** - * Sets a native data property like Template::SetNativeDataProperty, but - * this method sets on this object directly. - */ - V8_WARN_UNUSED_RESULT Maybe SetNativeDataProperty( - Local context, Local name, - AccessorNameGetterCallback getter, - AccessorNameSetterCallback setter = nullptr, - Local data = Local(), PropertyAttribute attributes = None, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - - /** - * Attempts to create a property with the given name which behaves like a data - * property, except that the provided getter is invoked (and provided with the - * data value) to supply its value the first time it is read. After the - * property is accessed once, it is replaced with an ordinary data property. - * - * Analogous to Template::SetLazyDataProperty. - */ - V8_WARN_UNUSED_RESULT Maybe SetLazyDataProperty( - Local context, Local name, - AccessorNameGetterCallback getter, Local data = Local(), - PropertyAttribute attributes = None, - SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, - SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); - - /** - * Functionality for private properties. - * This is an experimental feature, use at your own risk. - * Note: Private properties are not inherited. Do not rely on this, since it - * may change. - */ - Maybe HasPrivate(Local context, Local key); - Maybe SetPrivate(Local context, Local key, - Local value); - Maybe DeletePrivate(Local context, Local key); - MaybeLocal GetPrivate(Local context, Local key); - - /** - * Returns an array containing the names of the enumerable properties - * of this object, including properties from prototype objects. The - * array returned by this method contains the same values as would - * be enumerated by a for-in statement over this object. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetPropertyNames( - Local context); - V8_WARN_UNUSED_RESULT MaybeLocal GetPropertyNames( - Local context, KeyCollectionMode mode, - PropertyFilter property_filter, IndexFilter index_filter, - KeyConversionMode key_conversion = KeyConversionMode::kKeepNumbers); - - /** - * This function has the same functionality as GetPropertyNames but - * the returned array doesn't contain the names of properties from - * prototype objects. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetOwnPropertyNames( - Local context); - - /** - * Returns an array containing the names of the filtered properties - * of this object, including properties from prototype objects. The - * array returned by this method contains the same values as would - * be enumerated by a for-in statement over this object. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetOwnPropertyNames( - Local context, PropertyFilter filter, - KeyConversionMode key_conversion = KeyConversionMode::kKeepNumbers); - - /** - * Get the prototype object. This does not skip objects marked to - * be skipped by __proto__ and it does not consult the security - * handler. - */ - Local GetPrototype(); - - /** - * Set the prototype object. This does not skip objects marked to - * be skipped by __proto__ and it does not consult the security - * handler. - */ - V8_WARN_UNUSED_RESULT Maybe SetPrototype(Local context, - Local prototype); - - /** - * Finds an instance of the given function template in the prototype - * chain. - */ - Local FindInstanceInPrototypeChain(Local tmpl); - - /** - * Call builtin Object.prototype.toString on this object. - * This is different from Value::ToString() that may call - * user-defined toString function. This one does not. - */ - V8_WARN_UNUSED_RESULT MaybeLocal ObjectProtoToString( - Local context); - - /** - * Returns the name of the function invoked as a constructor for this object. - */ - Local GetConstructorName(); - - /** - * Sets the integrity level of the object. - */ - Maybe SetIntegrityLevel(Local context, IntegrityLevel level); - - /** Gets the number of internal fields for this Object. */ - int InternalFieldCount() const; - - /** Same as above, but works for PersistentBase. */ - V8_INLINE static int InternalFieldCount( - const PersistentBase& object) { - return object.val_->InternalFieldCount(); - } - - /** Same as above, but works for BasicTracedReference. */ - V8_INLINE static int InternalFieldCount( - const BasicTracedReference& object) { - return object->InternalFieldCount(); - } - - /** Gets the value from an internal field. */ - V8_INLINE Local GetInternalField(int index); - - /** Sets the value in an internal field. */ - void SetInternalField(int index, Local value); - - /** - * Gets a 2-byte-aligned native pointer from an internal field. This field - * must have been set by SetAlignedPointerInInternalField, everything else - * leads to undefined behavior. - */ - V8_INLINE void* GetAlignedPointerFromInternalField(int index); - - /** Same as above, but works for PersistentBase. */ - V8_INLINE static void* GetAlignedPointerFromInternalField( - const PersistentBase& object, int index) { - return object.val_->GetAlignedPointerFromInternalField(index); - } - - /** Same as above, but works for TracedGlobal. */ - V8_INLINE static void* GetAlignedPointerFromInternalField( - const BasicTracedReference& object, int index) { - return object->GetAlignedPointerFromInternalField(index); - } - - /** - * Sets a 2-byte-aligned native pointer in an internal field. To retrieve such - * a field, GetAlignedPointerFromInternalField must be used, everything else - * leads to undefined behavior. - */ - void SetAlignedPointerInInternalField(int index, void* value); - void SetAlignedPointerInInternalFields(int argc, int indices[], - void* values[]); - - /** - * HasOwnProperty() is like JavaScript's Object.prototype.hasOwnProperty(). - * - * See also v8::Object::Has() and v8::Object::HasRealNamedProperty(). - */ - V8_WARN_UNUSED_RESULT Maybe HasOwnProperty(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe HasOwnProperty(Local context, - uint32_t index); - /** - * Use HasRealNamedProperty() if you want to check if an object has an own - * property without causing side effects, i.e., without calling interceptors. - * - * This function is similar to v8::Object::HasOwnProperty(), but it does not - * call interceptors. - * - * \note Consider using non-masking interceptors, i.e., the interceptors are - * not called if the receiver has the real named property. See - * `v8::PropertyHandlerFlags::kNonMasking`. - * - * See also v8::Object::Has(). - */ - V8_WARN_UNUSED_RESULT Maybe HasRealNamedProperty(Local context, - Local key); - V8_WARN_UNUSED_RESULT Maybe HasRealIndexedProperty( - Local context, uint32_t index); - V8_WARN_UNUSED_RESULT Maybe HasRealNamedCallbackProperty( - Local context, Local key); - - /** - * If result.IsEmpty() no real property was located in the prototype chain. - * This means interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetRealNamedPropertyInPrototypeChain( - Local context, Local key); - - /** - * Gets the property attributes of a real property in the prototype chain, - * which can be None or any combination of ReadOnly, DontEnum and DontDelete. - * Interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT Maybe - GetRealNamedPropertyAttributesInPrototypeChain(Local context, - Local key); - - /** - * If result.IsEmpty() no real property was located on the object or - * in the prototype chain. - * This means interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT MaybeLocal GetRealNamedProperty( - Local context, Local key); - - /** - * Gets the property attributes of a real property which can be - * None or any combination of ReadOnly, DontEnum and DontDelete. - * Interceptors in the prototype chain are not called. - */ - V8_WARN_UNUSED_RESULT Maybe GetRealNamedPropertyAttributes( - Local context, Local key); - - /** Tests for a named lookup interceptor.*/ - bool HasNamedLookupInterceptor() const; - - /** Tests for an index lookup interceptor.*/ - bool HasIndexedLookupInterceptor() const; - - /** - * Returns the identity hash for this object. The current implementation - * uses a hidden property on the object to store the identity hash. - * - * The return value will never be 0. Also, it is not guaranteed to be - * unique. - */ - int GetIdentityHash(); - - /** - * Clone this object with a fast but shallow copy. Values will point - * to the same values as the original object. - */ - // TODO(dcarney): take an isolate and optionally bail out? - Local Clone(); - - /** - * Returns the context in which the object was created. - */ - V8_DEPRECATE_SOON("Use MaybeLocal GetCreationContext()") - Local CreationContext(); - MaybeLocal GetCreationContext(); - - /** Same as above, but works for Persistents */ - V8_DEPRECATE_SOON( - "Use MaybeLocal GetCreationContext(const " - "PersistentBase& object)") - static Local CreationContext(const PersistentBase& object); - V8_INLINE static MaybeLocal GetCreationContext( - const PersistentBase& object) { - return object.val_->GetCreationContext(); - } - - /** - * Checks whether a callback is set by the - * ObjectTemplate::SetCallAsFunctionHandler method. - * When an Object is callable this method returns true. - */ - bool IsCallable() const; - - /** - * True if this object is a constructor. - */ - bool IsConstructor() const; - - /** - * True if this object can carry information relevant to the embedder in its - * embedder fields, false otherwise. This is generally true for objects - * constructed through function templates but also holds for other types where - * V8 automatically adds internal fields at compile time, such as e.g. - * v8::ArrayBuffer. - */ - bool IsApiWrapper() const; - - /** - * True if this object was created from an object template which was marked - * as undetectable. See v8::ObjectTemplate::MarkAsUndetectable for more - * information. - */ - bool IsUndetectable() const; - - /** - * Call an Object as a function if a callback is set by the - * ObjectTemplate::SetCallAsFunctionHandler method. - */ - V8_WARN_UNUSED_RESULT MaybeLocal CallAsFunction(Local context, - Local recv, - int argc, - Local argv[]); - - /** - * Call an Object as a constructor if a callback is set by the - * ObjectTemplate::SetCallAsFunctionHandler method. - * Note: This method behaves like the Function::NewInstance method. - */ - V8_WARN_UNUSED_RESULT MaybeLocal CallAsConstructor( - Local context, int argc, Local argv[]); - - /** - * Return the isolate to which the Object belongs to. - */ - Isolate* GetIsolate(); - - /** - * If this object is a Set, Map, WeakSet or WeakMap, this returns a - * representation of the elements of this object as an array. - * If this object is a SetIterator or MapIterator, this returns all - * elements of the underlying collection, starting at the iterator's current - * position. - * For other types, this will return an empty MaybeLocal (without - * scheduling an exception). - */ - MaybeLocal PreviewEntries(bool* is_key_value); - - static Local New(Isolate* isolate); - - /** - * Creates a JavaScript object with the given properties, and - * a the given prototype_or_null (which can be any JavaScript - * value, and if it's null, the newly created object won't have - * a prototype at all). This is similar to Object.create(). - * All properties will be created as enumerable, configurable - * and writable properties. - */ - static Local New(Isolate* isolate, Local prototype_or_null, - Local* names, Local* values, - size_t length); - - V8_INLINE static Object* Cast(Value* obj); - - /** - * Support for TC39 "dynamic code brand checks" proposal. - * - * This API allows to query whether an object was constructed from a - * "code like" ObjectTemplate. - * - * See also: v8::ObjectTemplate::SetCodeLike - */ - bool IsCodeLike(Isolate* isolate) const; - - private: - Object(); - static void CheckCast(Value* obj); - Local SlowGetInternalField(int index); - void* SlowGetAlignedPointerFromInternalField(int index); -}; - -// --- Implementation --- - -Local Object::GetInternalField(int index) { -#ifndef V8_ENABLE_CHECKS - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - // Fast path: If the object is a plain JSObject, which is the common case, we - // know where to find the internal fields and can return the value directly. - int instance_type = I::GetInstanceType(obj); - if (v8::internal::CanHaveInternalField(instance_type)) { - int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); - A value = I::ReadRawField(obj, offset); -#ifdef V8_COMPRESS_POINTERS - // We read the full pointer value and then decompress it in order to avoid - // dealing with potential endiannes issues. - value = I::DecompressTaggedAnyField(obj, static_cast(value)); -#endif - internal::Isolate* isolate = - internal::IsolateFromNeverReadOnlySpaceObject(obj); - A* result = HandleScope::CreateHandle(isolate, value); - return Local(reinterpret_cast(result)); - } -#endif - return SlowGetInternalField(index); -} - -void* Object::GetAlignedPointerFromInternalField(int index) { -#ifndef V8_ENABLE_CHECKS - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - // Fast path: If the object is a plain JSObject, which is the common case, we - // know where to find the internal fields and can return the value directly. - auto instance_type = I::GetInstanceType(obj); - if (v8::internal::CanHaveInternalField(instance_type)) { - int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index); -#ifdef V8_HEAP_SANDBOX - offset += I::kEmbedderDataSlotRawPayloadOffset; -#endif - internal::Isolate* isolate = I::GetIsolateForHeapSandbox(obj); - A value = I::ReadExternalPointerField( - isolate, obj, offset, internal::kEmbedderDataSlotPayloadTag); - return reinterpret_cast(value); - } -#endif - return SlowGetAlignedPointerFromInternalField(index); -} - -Private* Private::Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return reinterpret_cast(data); -} - -Object* Object::Cast(v8::Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); -} - -} // namespace v8 - -#endif // INCLUDE_V8_OBJECT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-persistent-handle.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-persistent-handle.h deleted file mode 100644 index a6c21268d6a..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-persistent-handle.h +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PERSISTENT_HANDLE_H_ -#define INCLUDE_V8_PERSISTENT_HANDLE_H_ - -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-weak-callback-info.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; -template -class PersistentValueMapBase; -template -class PersistentValueVector; -template -class Global; -template -class PersistentBase; -template -class PersistentValueMap; -class Value; - -namespace api_internal { -V8_EXPORT Value* Eternalize(v8::Isolate* isolate, Value* handle); -V8_EXPORT internal::Address* CopyGlobalReference(internal::Address* from); -V8_EXPORT void DisposeGlobal(internal::Address* global_handle); -V8_EXPORT void MakeWeak(internal::Address** location_addr); -V8_EXPORT void* ClearWeak(internal::Address* location); -V8_EXPORT void AnnotateStrongRetainer(internal::Address* location, - const char* label); -V8_EXPORT internal::Address* GlobalizeReference(internal::Isolate* isolate, - internal::Address* handle); -V8_EXPORT void MoveGlobalReference(internal::Address** from, - internal::Address** to); -} // namespace api_internal - -/** - * Eternal handles are set-once handles that live for the lifetime of the - * isolate. - */ -template -class Eternal { - public: - V8_INLINE Eternal() : val_(nullptr) {} - template - V8_INLINE Eternal(Isolate* isolate, Local handle) : val_(nullptr) { - Set(isolate, handle); - } - // Can only be safely called if already set. - V8_INLINE Local Get(Isolate* isolate) const { - // The eternal handle will never go away, so as with the roots, we don't - // even need to open a handle. - return Local(val_); - } - - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - - template - void Set(Isolate* isolate, Local handle) { - static_assert(std::is_base_of::value, "type check"); - val_ = reinterpret_cast( - api_internal::Eternalize(isolate, reinterpret_cast(*handle))); - } - - private: - T* val_; -}; - -namespace api_internal { -V8_EXPORT void MakeWeak(internal::Address* location, void* data, - WeakCallbackInfo::Callback weak_callback, - WeakCallbackType type); -} // namespace api_internal - -/** - * An object reference that is independent of any handle scope. Where - * a Local handle only lives as long as the HandleScope in which it was - * allocated, a PersistentBase handle remains valid until it is explicitly - * disposed using Reset(). - * - * A persistent handle contains a reference to a storage cell within - * the V8 engine which holds an object value and which is updated by - * the garbage collector whenever the object is moved. A new storage - * cell can be created using the constructor or PersistentBase::Reset and - * existing handles can be disposed using PersistentBase::Reset. - * - */ -template -class PersistentBase { - public: - /** - * If non-empty, destroy the underlying storage cell - * IsEmpty() will return true after this call. - */ - V8_INLINE void Reset(); - - /** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ - template - V8_INLINE void Reset(Isolate* isolate, const Local& other); - - /** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ - template - V8_INLINE void Reset(Isolate* isolate, const PersistentBase& other); - - V8_INLINE bool IsEmpty() const { return val_ == nullptr; } - V8_INLINE void Empty() { val_ = 0; } - - V8_INLINE Local Get(Isolate* isolate) const { - return Local::New(isolate, *this); - } - - template - V8_INLINE bool operator==(const PersistentBase& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - template - V8_INLINE bool operator==(const Local& that) const { - internal::Address* a = reinterpret_cast(this->val_); - internal::Address* b = reinterpret_cast(that.val_); - if (a == nullptr) return b == nullptr; - if (b == nullptr) return false; - return *a == *b; - } - - template - V8_INLINE bool operator!=(const PersistentBase& that) const { - return !operator==(that); - } - - template - V8_INLINE bool operator!=(const Local& that) const { - return !operator==(that); - } - - /** - * Install a finalization callback on this object. - * NOTE: There is no guarantee as to *when* or even *if* the callback is - * invoked. The invocation is performed solely on a best effort basis. - * As always, GC-based finalization should *not* be relied upon for any - * critical form of resource management! - * - * The callback is supposed to reset the handle. No further V8 API may be - * called in this callback. In case additional work involving V8 needs to be - * done, a second callback can be scheduled using - * WeakCallbackInfo::SetSecondPassCallback. - */ - template - V8_INLINE void SetWeak(P* parameter, - typename WeakCallbackInfo

::Callback callback, - WeakCallbackType type); - - /** - * Turns this handle into a weak phantom handle without finalization callback. - * The handle will be reset automatically when the garbage collector detects - * that the object is no longer reachable. - * A related function Isolate::NumberOfPhantomHandleResetsSinceLastCall - * returns how many phantom handles were reset by the garbage collector. - */ - V8_INLINE void SetWeak(); - - template - V8_INLINE P* ClearWeak(); - - // TODO(dcarney): remove this. - V8_INLINE void ClearWeak() { ClearWeak(); } - - /** - * Annotates the strong handle with the given label, which is then used by the - * heap snapshot generator as a name of the edge from the root to the handle. - * The function does not take ownership of the label and assumes that the - * label is valid as long as the handle is valid. - */ - V8_INLINE void AnnotateStrongRetainer(const char* label); - - /** Returns true if the handle's reference is weak. */ - V8_INLINE bool IsWeak() const; - - /** - * Assigns a wrapper class ID to the handle. - */ - V8_INLINE void SetWrapperClassId(uint16_t class_id); - - /** - * Returns the class ID previously assigned to this handle or 0 if no class ID - * was previously assigned. - */ - V8_INLINE uint16_t WrapperClassId() const; - - PersistentBase(const PersistentBase& other) = delete; - void operator=(const PersistentBase&) = delete; - - private: - friend class Isolate; - friend class Utils; - template - friend class Local; - template - friend class Persistent; - template - friend class Global; - template - friend class PersistentBase; - template - friend class ReturnValue; - template - friend class PersistentValueMapBase; - template - friend class PersistentValueVector; - friend class Object; - - explicit V8_INLINE PersistentBase(T* val) : val_(val) {} - V8_INLINE static T* New(Isolate* isolate, T* that); - - T* val_; -}; - -/** - * Default traits for Persistent. This class does not allow - * use of the copy constructor or assignment operator. - * At present kResetInDestructor is not set, but that will change in a future - * version. - */ -template -class NonCopyablePersistentTraits { - public: - using NonCopyablePersistent = Persistent>; - static const bool kResetInDestructor = false; - template - V8_INLINE static void Copy(const Persistent& source, - NonCopyablePersistent* dest) { - static_assert(sizeof(S) < 0, - "NonCopyablePersistentTraits::Copy is not instantiable"); - } -}; - -/** - * Helper class traits to allow copying and assignment of Persistent. - * This will clone the contents of storage cell, but not any of the flags, etc. - */ -template -struct CopyablePersistentTraits { - using CopyablePersistent = Persistent>; - static const bool kResetInDestructor = true; - template - static V8_INLINE void Copy(const Persistent& source, - CopyablePersistent* dest) { - // do nothing, just allow copy - } -}; - -/** - * A PersistentBase which allows copy and assignment. - * - * Copy, assignment and destructor behavior is controlled by the traits - * class M. - * - * Note: Persistent class hierarchy is subject to future changes. - */ -template -class Persistent : public PersistentBase { - public: - /** - * A Persistent with no storage cell. - */ - V8_INLINE Persistent() : PersistentBase(nullptr) {} - /** - * Construct a Persistent from a Local. - * When the Local is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Persistent(Isolate* isolate, Local that) - : PersistentBase(PersistentBase::New(isolate, *that)) { - static_assert(std::is_base_of::value, "type check"); - } - /** - * Construct a Persistent from a Persistent. - * When the Persistent is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Persistent(Isolate* isolate, const Persistent& that) - : PersistentBase(PersistentBase::New(isolate, *that)) { - static_assert(std::is_base_of::value, "type check"); - } - /** - * The copy constructors and assignment operator create a Persistent - * exactly as the Persistent constructor, but the Copy function from the - * traits class is called, allowing the setting of flags based on the - * copied Persistent. - */ - V8_INLINE Persistent(const Persistent& that) : PersistentBase(nullptr) { - Copy(that); - } - template - V8_INLINE Persistent(const Persistent& that) : PersistentBase(0) { - Copy(that); - } - V8_INLINE Persistent& operator=(const Persistent& that) { - Copy(that); - return *this; - } - template - V8_INLINE Persistent& operator=(const Persistent& that) { - Copy(that); - return *this; - } - /** - * The destructor will dispose the Persistent based on the - * kResetInDestructor flags in the traits class. Since not calling dispose - * can result in a memory leak, it is recommended to always set this flag. - */ - V8_INLINE ~Persistent() { - if (M::kResetInDestructor) this->Reset(); - } - - // TODO(dcarney): this is pretty useless, fix or remove - template - V8_INLINE static Persistent& Cast(const Persistent& that) { -#ifdef V8_ENABLE_CHECKS - // If we're going to perform the type check then we have to check - // that the handle isn't empty before doing the checked cast. - if (!that.IsEmpty()) T::Cast(*that); -#endif - return reinterpret_cast&>(const_cast&>(that)); - } - - // TODO(dcarney): this is pretty useless, fix or remove - template - V8_INLINE Persistent& As() const { - return Persistent::Cast(*this); - } - - private: - friend class Isolate; - friend class Utils; - template - friend class Local; - template - friend class Persistent; - template - friend class ReturnValue; - - explicit V8_INLINE Persistent(T* that) : PersistentBase(that) {} - V8_INLINE T* operator*() const { return this->val_; } - template - V8_INLINE void Copy(const Persistent& that); -}; - -/** - * A PersistentBase which has move semantics. - * - * Note: Persistent class hierarchy is subject to future changes. - */ -template -class Global : public PersistentBase { - public: - /** - * A Global with no storage cell. - */ - V8_INLINE Global() : PersistentBase(nullptr) {} - - /** - * Construct a Global from a Local. - * When the Local is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Global(Isolate* isolate, Local that) - : PersistentBase(PersistentBase::New(isolate, *that)) { - static_assert(std::is_base_of::value, "type check"); - } - - /** - * Construct a Global from a PersistentBase. - * When the Persistent is non-empty, a new storage cell is created - * pointing to the same object, and no flags are set. - */ - template - V8_INLINE Global(Isolate* isolate, const PersistentBase& that) - : PersistentBase(PersistentBase::New(isolate, that.val_)) { - static_assert(std::is_base_of::value, "type check"); - } - - /** - * Move constructor. - */ - V8_INLINE Global(Global&& other); - - V8_INLINE ~Global() { this->Reset(); } - - /** - * Move via assignment. - */ - template - V8_INLINE Global& operator=(Global&& rhs); - - /** - * Pass allows returning uniques from functions, etc. - */ - Global Pass() { return static_cast(*this); } - - /* - * For compatibility with Chromium's base::Bind (base::Passed). - */ - using MoveOnlyTypeForCPP03 = void; - - Global(const Global&) = delete; - void operator=(const Global&) = delete; - - private: - template - friend class ReturnValue; - V8_INLINE T* operator*() const { return this->val_; } -}; - -// UniquePersistent is an alias for Global for historical reason. -template -using UniquePersistent = Global; - -/** - * Interface for iterating through all the persistent handles in the heap. - */ -class V8_EXPORT PersistentHandleVisitor { - public: - virtual ~PersistentHandleVisitor() = default; - virtual void VisitPersistentHandle(Persistent* value, - uint16_t class_id) {} -}; - -template -T* PersistentBase::New(Isolate* isolate, T* that) { - if (that == nullptr) return nullptr; - internal::Address* p = reinterpret_cast(that); - return reinterpret_cast(api_internal::GlobalizeReference( - reinterpret_cast(isolate), p)); -} - -template -template -void Persistent::Copy(const Persistent& that) { - static_assert(std::is_base_of::value, "type check"); - this->Reset(); - if (that.IsEmpty()) return; - internal::Address* p = reinterpret_cast(that.val_); - this->val_ = reinterpret_cast(api_internal::CopyGlobalReference(p)); - M::Copy(that, this); -} - -template -bool PersistentBase::IsWeak() const { - using I = internal::Internals; - if (this->IsEmpty()) return false; - return I::GetNodeState(reinterpret_cast(this->val_)) == - I::kNodeStateIsWeakValue; -} - -template -void PersistentBase::Reset() { - if (this->IsEmpty()) return; - api_internal::DisposeGlobal(reinterpret_cast(this->val_)); - val_ = nullptr; -} - -/** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ -template -template -void PersistentBase::Reset(Isolate* isolate, const Local& other) { - static_assert(std::is_base_of::value, "type check"); - Reset(); - if (other.IsEmpty()) return; - this->val_ = New(isolate, other.val_); -} - -/** - * If non-empty, destroy the underlying storage cell - * and create a new one with the contents of other if other is non empty - */ -template -template -void PersistentBase::Reset(Isolate* isolate, - const PersistentBase& other) { - static_assert(std::is_base_of::value, "type check"); - Reset(); - if (other.IsEmpty()) return; - this->val_ = New(isolate, other.val_); -} - -template -template -V8_INLINE void PersistentBase::SetWeak( - P* parameter, typename WeakCallbackInfo

::Callback callback, - WeakCallbackType type) { - using Callback = WeakCallbackInfo::Callback; -#if (__GNUC__ >= 8) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - api_internal::MakeWeak(reinterpret_cast(this->val_), - parameter, reinterpret_cast(callback), type); -#if (__GNUC__ >= 8) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif -} - -template -void PersistentBase::SetWeak() { - api_internal::MakeWeak(reinterpret_cast(&this->val_)); -} - -template -template -P* PersistentBase::ClearWeak() { - return reinterpret_cast(api_internal::ClearWeak( - reinterpret_cast(this->val_))); -} - -template -void PersistentBase::AnnotateStrongRetainer(const char* label) { - api_internal::AnnotateStrongRetainer( - reinterpret_cast(this->val_), label); -} - -template -void PersistentBase::SetWrapperClassId(uint16_t class_id) { - using I = internal::Internals; - if (this->IsEmpty()) return; - internal::Address* obj = reinterpret_cast(this->val_); - uint8_t* addr = reinterpret_cast(obj) + I::kNodeClassIdOffset; - *reinterpret_cast(addr) = class_id; -} - -template -uint16_t PersistentBase::WrapperClassId() const { - using I = internal::Internals; - if (this->IsEmpty()) return 0; - internal::Address* obj = reinterpret_cast(this->val_); - uint8_t* addr = reinterpret_cast(obj) + I::kNodeClassIdOffset; - return *reinterpret_cast(addr); -} - -template -Global::Global(Global&& other) : PersistentBase(other.val_) { - if (other.val_ != nullptr) { - api_internal::MoveGlobalReference( - reinterpret_cast(&other.val_), - reinterpret_cast(&this->val_)); - other.val_ = nullptr; - } -} - -template -template -Global& Global::operator=(Global&& rhs) { - static_assert(std::is_base_of::value, "type check"); - if (this != &rhs) { - this->Reset(); - if (rhs.val_ != nullptr) { - this->val_ = rhs.val_; - api_internal::MoveGlobalReference( - reinterpret_cast(&rhs.val_), - reinterpret_cast(&this->val_)); - rhs.val_ = nullptr; - } - } - return *this; -} - -} // namespace v8 - -#endif // INCLUDE_V8_PERSISTENT_HANDLE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-platform.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-platform.h deleted file mode 100644 index dee399fa771..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-platform.h +++ /dev/null @@ -1,713 +0,0 @@ -// Copyright 2013 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_PLATFORM_H_ -#define V8_V8_PLATFORM_H_ - -#include -#include -#include // For abort. -#include -#include - -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -// Valid priorities supported by the task scheduling infrastructure. -enum class TaskPriority : uint8_t { - /** - * Best effort tasks are not critical for performance of the application. The - * platform implementation should preempt such tasks if higher priority tasks - * arrive. - */ - kBestEffort, - /** - * User visible tasks are long running background tasks that will - * improve performance and memory usage of the application upon completion. - * Example: background compilation and garbage collection. - */ - kUserVisible, - /** - * User blocking tasks are highest priority tasks that block the execution - * thread (e.g. major garbage collection). They must be finished as soon as - * possible. - */ - kUserBlocking, -}; - -/** - * A Task represents a unit of work. - */ -class Task { - public: - virtual ~Task() = default; - - virtual void Run() = 0; -}; - -/** - * An IdleTask represents a unit of work to be performed in idle time. - * The Run method is invoked with an argument that specifies the deadline in - * seconds returned by MonotonicallyIncreasingTime(). - * The idle task is expected to complete by this deadline. - */ -class IdleTask { - public: - virtual ~IdleTask() = default; - virtual void Run(double deadline_in_seconds) = 0; -}; - -/** - * A TaskRunner allows scheduling of tasks. The TaskRunner may still be used to - * post tasks after the isolate gets destructed, but these tasks may not get - * executed anymore. All tasks posted to a given TaskRunner will be invoked in - * sequence. Tasks can be posted from any thread. - */ -class TaskRunner { - public: - /** - * Schedules a task to be invoked by this TaskRunner. The TaskRunner - * implementation takes ownership of |task|. - */ - virtual void PostTask(std::unique_ptr task) = 0; - - /** - * Schedules a task to be invoked by this TaskRunner. The TaskRunner - * implementation takes ownership of |task|. The |task| cannot be nested - * within other task executions. - * - * Tasks which shouldn't be interleaved with JS execution must be posted with - * |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the - * embedder may process tasks in a callback which is called during JS - * execution. - * - * In particular, tasks which execute JS must be non-nestable, since JS - * execution is not allowed to nest. - * - * Requires that |TaskRunner::NonNestableTasksEnabled()| is true. - */ - virtual void PostNonNestableTask(std::unique_ptr task) {} - - /** - * Schedules a task to be invoked by this TaskRunner. The task is scheduled - * after the given number of seconds |delay_in_seconds|. The TaskRunner - * implementation takes ownership of |task|. - */ - virtual void PostDelayedTask(std::unique_ptr task, - double delay_in_seconds) = 0; - - /** - * Schedules a task to be invoked by this TaskRunner. The task is scheduled - * after the given number of seconds |delay_in_seconds|. The TaskRunner - * implementation takes ownership of |task|. The |task| cannot be nested - * within other task executions. - * - * Tasks which shouldn't be interleaved with JS execution must be posted with - * |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the - * embedder may process tasks in a callback which is called during JS - * execution. - * - * In particular, tasks which execute JS must be non-nestable, since JS - * execution is not allowed to nest. - * - * Requires that |TaskRunner::NonNestableDelayedTasksEnabled()| is true. - */ - virtual void PostNonNestableDelayedTask(std::unique_ptr task, - double delay_in_seconds) {} - - /** - * Schedules an idle task to be invoked by this TaskRunner. The task is - * scheduled when the embedder is idle. Requires that - * |TaskRunner::IdleTasksEnabled()| is true. Idle tasks may be reordered - * relative to other task types and may be starved for an arbitrarily long - * time if no idle time is available. The TaskRunner implementation takes - * ownership of |task|. - */ - virtual void PostIdleTask(std::unique_ptr task) = 0; - - /** - * Returns true if idle tasks are enabled for this TaskRunner. - */ - virtual bool IdleTasksEnabled() = 0; - - /** - * Returns true if non-nestable tasks are enabled for this TaskRunner. - */ - virtual bool NonNestableTasksEnabled() const { return false; } - - /** - * Returns true if non-nestable delayed tasks are enabled for this TaskRunner. - */ - virtual bool NonNestableDelayedTasksEnabled() const { return false; } - - TaskRunner() = default; - virtual ~TaskRunner() = default; - - TaskRunner(const TaskRunner&) = delete; - TaskRunner& operator=(const TaskRunner&) = delete; -}; - -/** - * Delegate that's passed to Job's worker task, providing an entry point to - * communicate with the scheduler. - */ -class JobDelegate { - public: - /** - * Returns true if this thread should return from the worker task on the - * current thread ASAP. Workers should periodically invoke ShouldYield (or - * YieldIfNeeded()) as often as is reasonable. - */ - virtual bool ShouldYield() = 0; - - /** - * Notifies the scheduler that max concurrency was increased, and the number - * of worker should be adjusted accordingly. See Platform::PostJob() for more - * details. - */ - virtual void NotifyConcurrencyIncrease() = 0; - - /** - * Returns a task_id unique among threads currently running this job, such - * that GetTaskId() < worker count. To achieve this, the same task_id may be - * reused by a different thread after a worker_task returns. - */ - virtual uint8_t GetTaskId() = 0; - - /** - * Returns true if the current task is called from the thread currently - * running JobHandle::Join(). - */ - virtual bool IsJoiningThread() const = 0; -}; - -/** - * Handle returned when posting a Job. Provides methods to control execution of - * the posted Job. - */ -class JobHandle { - public: - virtual ~JobHandle() = default; - - /** - * Notifies the scheduler that max concurrency was increased, and the number - * of worker should be adjusted accordingly. See Platform::PostJob() for more - * details. - */ - virtual void NotifyConcurrencyIncrease() = 0; - - /** - * Contributes to the job on this thread. Doesn't return until all tasks have - * completed and max concurrency becomes 0. When Join() is called and max - * concurrency reaches 0, it should not increase again. This also promotes - * this Job's priority to be at least as high as the calling thread's - * priority. - */ - virtual void Join() = 0; - - /** - * Forces all existing workers to yield ASAP. Waits until they have all - * returned from the Job's callback before returning. - */ - virtual void Cancel() = 0; - - /* - * Forces all existing workers to yield ASAP but doesn’t wait for them. - * Warning, this is dangerous if the Job's callback is bound to or has access - * to state which may be deleted after this call. - */ - virtual void CancelAndDetach() = 0; - - /** - * Returns true if there's any work pending or any worker running. - */ - virtual bool IsActive() = 0; - - /** - * Returns true if associated with a Job and other methods may be called. - * Returns false after Join() or Cancel() was called. This may return true - * even if no workers are running and IsCompleted() returns true - */ - virtual bool IsValid() = 0; - - /** - * Returns true if job priority can be changed. - */ - virtual bool UpdatePriorityEnabled() const { return false; } - - /** - * Update this Job's priority. - */ - virtual void UpdatePriority(TaskPriority new_priority) {} -}; - -/** - * A JobTask represents work to run in parallel from Platform::PostJob(). - */ -class JobTask { - public: - virtual ~JobTask() = default; - - virtual void Run(JobDelegate* delegate) = 0; - - /** - * Controls the maximum number of threads calling Run() concurrently, given - * the number of threads currently assigned to this job and executing Run(). - * Run() is only invoked if the number of threads previously running Run() was - * less than the value returned. Since GetMaxConcurrency() is a leaf function, - * it must not call back any JobHandle methods. - */ - virtual size_t GetMaxConcurrency(size_t worker_count) const = 0; -}; - -/** - * The interface represents complex arguments to trace events. - */ -class ConvertableToTraceFormat { - public: - virtual ~ConvertableToTraceFormat() = default; - - /** - * Append the class info to the provided |out| string. The appended - * data must be a valid JSON object. Strings must be properly quoted, and - * escaped. There is no processing applied to the content after it is - * appended. - */ - virtual void AppendAsTraceFormat(std::string* out) const = 0; -}; - -/** - * V8 Tracing controller. - * - * Can be implemented by an embedder to record trace events from V8. - */ -class TracingController { - public: - virtual ~TracingController() = default; - - // In Perfetto mode, trace events are written using Perfetto's Track Event - // API directly without going through the embedder. However, it is still - // possible to observe tracing being enabled and disabled. -#if !defined(V8_USE_PERFETTO) - /** - * Called by TRACE_EVENT* macros, don't call this directly. - * The name parameter is a category group for example: - * TRACE_EVENT0("v8,parse", "V8.Parse") - * The pointer returned points to a value with zero or more of the bits - * defined in CategoryGroupEnabledFlags. - **/ - virtual const uint8_t* GetCategoryGroupEnabled(const char* name) { - static uint8_t no = 0; - return &no; - } - - /** - * Adds a trace event to the platform tracing system. These function calls are - * usually the result of a TRACE_* macro from trace_event_common.h when - * tracing and the category of the particular trace are enabled. It is not - * advisable to call these functions on their own; they are really only meant - * to be used by the trace macros. The returned handle can be used by - * UpdateTraceEventDuration to update the duration of COMPLETE events. - */ - virtual uint64_t AddTraceEvent( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags) { - return 0; - } - virtual uint64_t AddTraceEventWithTimestamp( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, - std::unique_ptr* arg_convertables, - unsigned int flags, int64_t timestamp) { - return 0; - } - - /** - * Sets the duration field of a COMPLETE trace event. It must be called with - * the handle returned from AddTraceEvent(). - **/ - virtual void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, - const char* name, uint64_t handle) {} -#endif // !defined(V8_USE_PERFETTO) - - class TraceStateObserver { - public: - virtual ~TraceStateObserver() = default; - virtual void OnTraceEnabled() = 0; - virtual void OnTraceDisabled() = 0; - }; - - /** Adds tracing state change observer. */ - virtual void AddTraceStateObserver(TraceStateObserver*) {} - - /** Removes tracing state change observer. */ - virtual void RemoveTraceStateObserver(TraceStateObserver*) {} -}; - -/** - * A V8 memory page allocator. - * - * Can be implemented by an embedder to manage large host OS allocations. - */ -class PageAllocator { - public: - virtual ~PageAllocator() = default; - - /** - * Gets the page granularity for AllocatePages and FreePages. Addresses and - * lengths for those calls should be multiples of AllocatePageSize(). - */ - virtual size_t AllocatePageSize() = 0; - - /** - * Gets the page granularity for SetPermissions and ReleasePages. Addresses - * and lengths for those calls should be multiples of CommitPageSize(). - */ - virtual size_t CommitPageSize() = 0; - - /** - * Sets the random seed so that GetRandomMmapAddr() will generate repeatable - * sequences of random mmap addresses. - */ - virtual void SetRandomMmapSeed(int64_t seed) = 0; - - /** - * Returns a randomized address, suitable for memory allocation under ASLR. - * The address will be aligned to AllocatePageSize. - */ - virtual void* GetRandomMmapAddr() = 0; - - /** - * Memory permissions. - */ - enum Permission { - kNoAccess, - kRead, - kReadWrite, - kReadWriteExecute, - kReadExecute, - // Set this when reserving memory that will later require kReadWriteExecute - // permissions. The resulting behavior is platform-specific, currently - // this is used to set the MAP_JIT flag on Apple Silicon. - // TODO(jkummerow): Remove this when Wasm has a platform-independent - // w^x implementation. - kNoAccessWillJitLater - }; - - /** - * Allocates memory in range with the given alignment and permission. - */ - virtual void* AllocatePages(void* address, size_t length, size_t alignment, - Permission permissions) = 0; - - /** - * Frees memory in a range that was allocated by a call to AllocatePages. - */ - virtual bool FreePages(void* address, size_t length) = 0; - - /** - * Releases memory in a range that was allocated by a call to AllocatePages. - */ - virtual bool ReleasePages(void* address, size_t length, - size_t new_length) = 0; - - /** - * Sets permissions on pages in an allocated range. - */ - virtual bool SetPermissions(void* address, size_t length, - Permission permissions) = 0; - - /** - * Frees memory in the given [address, address + size) range. address and size - * should be operating system page-aligned. The next write to this - * memory area brings the memory transparently back. This should be treated as - * a hint to the OS that the pages are no longer needed. It does not guarantee - * that the pages will be discarded immediately or at all. - */ - virtual bool DiscardSystemPages(void* address, size_t size) { return true; } - - /** - * Decommits any wired memory pages in the given range, allowing the OS to - * reclaim them, and marks the region as inacessible (kNoAccess). The address - * range stays reserved and can be accessed again later by changing its - * permissions. However, in that case the memory content is guaranteed to be - * zero-initialized again. The memory must have been previously allocated by a - * call to AllocatePages. Returns true on success, false otherwise. - */ -#ifdef V8_VIRTUAL_MEMORY_CAGE - // Implementing this API is required when the virtual memory cage is enabled. - virtual bool DecommitPages(void* address, size_t size) = 0; -#else - // Otherwise, it is optional for now. - virtual bool DecommitPages(void* address, size_t size) { return false; } -#endif - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - */ - class SharedMemoryMapping { - public: - // Implementations are expected to free the shared memory mapping in the - // destructor. - virtual ~SharedMemoryMapping() = default; - virtual void* GetMemory() const = 0; - }; - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - */ - class SharedMemory { - public: - // Implementations are expected to free the shared memory in the destructor. - virtual ~SharedMemory() = default; - virtual std::unique_ptr RemapTo( - void* new_address) const = 0; - virtual void* GetMemory() const = 0; - virtual size_t GetSize() const = 0; - }; - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - * - * Reserve pages at a fixed address returning whether the reservation is - * possible. The reserved memory is detached from the PageAllocator and so - * should not be freed by it. It's intended for use with - * SharedMemory::RemapTo, where ~SharedMemoryMapping would free the memory. - */ - virtual bool ReserveForSharedMemoryMapping(void* address, size_t size) { - return false; - } - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - * - * Allocates shared memory pages. Not all PageAllocators need support this and - * so this method need not be overridden. - * Allocates a new read-only shared memory region of size |length| and copies - * the memory at |original_address| into it. - */ - virtual std::unique_ptr AllocateSharedPages( - size_t length, const void* original_address) { - return {}; - } - - /** - * INTERNAL ONLY: This interface has not been stabilised and may change - * without notice from one release to another without being deprecated first. - * - * If not overridden and changed to return true, V8 will not attempt to call - * AllocateSharedPages or RemapSharedPages. If overridden, AllocateSharedPages - * and RemapSharedPages must also be overridden. - */ - virtual bool CanAllocateSharedPages() { return false; } -}; - -/** - * V8 Platform abstraction layer. - * - * The embedder has to provide an implementation of this interface before - * initializing the rest of V8. - */ -class Platform { - public: - virtual ~Platform() = default; - - /** - * Allows the embedder to manage memory page allocations. - */ - virtual PageAllocator* GetPageAllocator() { - // TODO(bbudge) Make this abstract after all embedders implement this. - return nullptr; - } - - /** - * Enables the embedder to respond in cases where V8 can't allocate large - * blocks of memory. V8 retries the failed allocation once after calling this - * method. On success, execution continues; otherwise V8 exits with a fatal - * error. - * Embedder overrides of this function must NOT call back into V8. - */ - virtual void OnCriticalMemoryPressure() { - // TODO(bbudge) Remove this when embedders override the following method. - // See crbug.com/634547. - } - - /** - * Enables the embedder to respond in cases where V8 can't allocate large - * memory regions. The |length| parameter is the amount of memory needed. - * Returns true if memory is now available. Returns false if no memory could - * be made available. V8 will retry allocations until this method returns - * false. - * - * Embedder overrides of this function must NOT call back into V8. - */ - virtual bool OnCriticalMemoryPressure(size_t length) { return false; } - - /** - * Gets the number of worker threads used by - * Call(BlockingTask)OnWorkerThread(). This can be used to estimate the number - * of tasks a work package should be split into. A return value of 0 means - * that there are no worker threads available. Note that a value of 0 won't - * prohibit V8 from posting tasks using |CallOnWorkerThread|. - */ - virtual int NumberOfWorkerThreads() = 0; - - /** - * Returns a TaskRunner which can be used to post a task on the foreground. - * The TaskRunner's NonNestableTasksEnabled() must be true. This function - * should only be called from a foreground thread. - */ - virtual std::shared_ptr GetForegroundTaskRunner( - Isolate* isolate) = 0; - - /** - * Schedules a task to be invoked on a worker thread. - */ - virtual void CallOnWorkerThread(std::unique_ptr task) = 0; - - /** - * Schedules a task that blocks the main thread to be invoked with - * high-priority on a worker thread. - */ - virtual void CallBlockingTaskOnWorkerThread(std::unique_ptr task) { - // Embedders may optionally override this to process these tasks in a high - // priority pool. - CallOnWorkerThread(std::move(task)); - } - - /** - * Schedules a task to be invoked with low-priority on a worker thread. - */ - virtual void CallLowPriorityTaskOnWorkerThread(std::unique_ptr task) { - // Embedders may optionally override this to process these tasks in a low - // priority pool. - CallOnWorkerThread(std::move(task)); - } - - /** - * Schedules a task to be invoked on a worker thread after |delay_in_seconds| - * expires. - */ - virtual void CallDelayedOnWorkerThread(std::unique_ptr task, - double delay_in_seconds) = 0; - - /** - * Returns true if idle tasks are enabled for the given |isolate|. - */ - virtual bool IdleTasksEnabled(Isolate* isolate) { return false; } - - /** - * Posts |job_task| to run in parallel. Returns a JobHandle associated with - * the Job, which can be joined or canceled. - * This avoids degenerate cases: - * - Calling CallOnWorkerThread() for each work item, causing significant - * overhead. - * - Fixed number of CallOnWorkerThread() calls that split the work and might - * run for a long time. This is problematic when many components post - * "num cores" tasks and all expect to use all the cores. In these cases, - * the scheduler lacks context to be fair to multiple same-priority requests - * and/or ability to request lower priority work to yield when high priority - * work comes in. - * A canonical implementation of |job_task| looks like: - * class MyJobTask : public JobTask { - * public: - * MyJobTask(...) : worker_queue_(...) {} - * // JobTask: - * void Run(JobDelegate* delegate) override { - * while (!delegate->ShouldYield()) { - * // Smallest unit of work. - * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. - * if (!work_item) return; - * ProcessWork(work_item); - * } - * } - * - * size_t GetMaxConcurrency() const override { - * return worker_queue_.GetSize(); // Thread safe. - * } - * }; - * auto handle = PostJob(TaskPriority::kUserVisible, - * std::make_unique(...)); - * handle->Join(); - * - * PostJob() and methods of the returned JobHandle/JobDelegate, must never be - * called while holding a lock that could be acquired by JobTask::Run or - * JobTask::GetMaxConcurrency -- that could result in a deadlock. This is - * because [1] JobTask::GetMaxConcurrency may be invoked while holding - * internal lock (A), hence JobTask::GetMaxConcurrency can only use a lock (B) - * if that lock is *never* held while calling back into JobHandle from any - * thread (A=>B/B=>A deadlock) and [2] JobTask::Run or - * JobTask::GetMaxConcurrency may be invoked synchronously from JobHandle - * (B=>JobHandle::foo=>B deadlock). - * - * A sufficient PostJob() implementation that uses the default Job provided in - * libplatform looks like: - * std::unique_ptr PostJob( - * TaskPriority priority, std::unique_ptr job_task) override { - * return v8::platform::NewDefaultJobHandle( - * this, priority, std::move(job_task), NumberOfWorkerThreads()); - * } - */ - virtual std::unique_ptr PostJob( - TaskPriority priority, std::unique_ptr job_task) = 0; - - /** - * Monotonically increasing time in seconds from an arbitrary fixed point in - * the past. This function is expected to return at least - * millisecond-precision values. For this reason, - * it is recommended that the fixed point be no further in the past than - * the epoch. - **/ - virtual double MonotonicallyIncreasingTime() = 0; - - /** - * Current wall-clock time in milliseconds since epoch. - * This function is expected to return at least millisecond-precision values. - */ - virtual double CurrentClockTimeMillis() = 0; - - typedef void (*StackTracePrinter)(); - - /** - * Returns a function pointer that print a stack trace of the current stack - * on invocation. Disables printing of the stack trace if nullptr. - */ - virtual StackTracePrinter GetStackTracePrinter() { return nullptr; } - - /** - * Returns an instance of a v8::TracingController. This must be non-nullptr. - */ - virtual TracingController* GetTracingController() = 0; - - /** - * Tells the embedder to generate and upload a crashdump during an unexpected - * but non-critical scenario. - */ - virtual void DumpWithoutCrashing() {} - - protected: - /** - * Default implementation of current wall-clock time in milliseconds - * since epoch. Useful for implementing |CurrentClockTimeMillis| if - * nothing special needed. - */ - V8_EXPORT static double SystemClockTimeMillis(); -}; - -} // namespace v8 - -#endif // V8_V8_PLATFORM_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-primitive-object.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-primitive-object.h deleted file mode 100644 index 573932d0789..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-primitive-object.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PRIMITIVE_OBJECT_H_ -#define INCLUDE_V8_PRIMITIVE_OBJECT_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Isolate; - -/** - * A Number object (ECMA-262, 4.3.21). - */ -class V8_EXPORT NumberObject : public Object { - public: - static Local New(Isolate* isolate, double value); - - double ValueOf() const; - - V8_INLINE static NumberObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A BigInt object (https://tc39.github.io/proposal-bigint) - */ -class V8_EXPORT BigIntObject : public Object { - public: - static Local New(Isolate* isolate, int64_t value); - - Local ValueOf() const; - - V8_INLINE static BigIntObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A Boolean object (ECMA-262, 4.3.15). - */ -class V8_EXPORT BooleanObject : public Object { - public: - static Local New(Isolate* isolate, bool value); - - bool ValueOf() const; - - V8_INLINE static BooleanObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A String object (ECMA-262, 4.3.18). - */ -class V8_EXPORT StringObject : public Object { - public: - static Local New(Isolate* isolate, Local value); - - Local ValueOf() const; - - V8_INLINE static StringObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -/** - * A Symbol object (ECMA-262 edition 6). - */ -class V8_EXPORT SymbolObject : public Object { - public: - static Local New(Isolate* isolate, Local value); - - Local ValueOf() const; - - V8_INLINE static SymbolObject* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_PRIMITIVE_OBJECT_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-primitive.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-primitive.h deleted file mode 100644 index 59d959da057..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-primitive.h +++ /dev/null @@ -1,858 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PRIMITIVE_H_ -#define INCLUDE_V8_PRIMITIVE_H_ - -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-internal.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-value.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; -class Isolate; -class String; - -namespace internal { -class ExternalString; -class ScopedExternalStringLock; -} // namespace internal - -/** - * The superclass of primitive values. See ECMA-262 4.3.2. - */ -class V8_EXPORT Primitive : public Value {}; - -/** - * A primitive boolean value (ECMA-262, 4.3.14). Either the true - * or false value. - */ -class V8_EXPORT Boolean : public Primitive { - public: - bool Value() const; - V8_INLINE static Boolean* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - V8_INLINE static Local New(Isolate* isolate, bool value); - - private: - static void CheckCast(v8::Data* that); -}; - -/** - * An array to hold Primitive values. This is used by the embedder to - * pass host defined options to the ScriptOptions during compilation. - * - * This is passed back to the embedder as part of - * HostImportModuleDynamicallyCallback for module loading. - */ -class V8_EXPORT PrimitiveArray { - public: - static Local New(Isolate* isolate, int length); - int Length() const; - void Set(Isolate* isolate, int index, Local item); - Local Get(Isolate* isolate, int index); -}; - -/** - * A superclass for symbols and strings. - */ -class V8_EXPORT Name : public Primitive { - public: - /** - * Returns the identity hash for this object. The current implementation - * uses an inline property on the object to store the identity hash. - * - * The return value will never be 0. Also, it is not guaranteed to be - * unique. - */ - int GetIdentityHash(); - - V8_INLINE static Name* Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - static void CheckCast(Data* that); -}; - -/** - * A flag describing different modes of string creation. - * - * Aside from performance implications there are no differences between the two - * creation modes. - */ -enum class NewStringType { - /** - * Create a new string, always allocating new storage memory. - */ - kNormal, - - /** - * Acts as a hint that the string should be created in the - * old generation heap space and be deduplicated if an identical string - * already exists. - */ - kInternalized -}; - -/** - * A JavaScript string value (ECMA-262, 4.3.17). - */ -class V8_EXPORT String : public Name { - public: - static constexpr int kMaxLength = - internal::kApiSystemPointerSize == 4 ? (1 << 28) - 16 : (1 << 29) - 24; - - enum Encoding { - UNKNOWN_ENCODING = 0x1, - TWO_BYTE_ENCODING = 0x0, - ONE_BYTE_ENCODING = 0x8 - }; - /** - * Returns the number of characters (UTF-16 code units) in this string. - */ - int Length() const; - - /** - * Returns the number of bytes in the UTF-8 encoded - * representation of this string. - */ - int Utf8Length(Isolate* isolate) const; - - /** - * Returns whether this string is known to contain only one byte data, - * i.e. ISO-8859-1 code points. - * Does not read the string. - * False negatives are possible. - */ - bool IsOneByte() const; - - /** - * Returns whether this string contain only one byte data, - * i.e. ISO-8859-1 code points. - * Will read the entire string in some cases. - */ - bool ContainsOnlyOneByte() const; - - /** - * Write the contents of the string to an external buffer. - * If no arguments are given, expects the buffer to be large - * enough to hold the entire string and NULL terminator. Copies - * the contents of the string and the NULL terminator into the - * buffer. - * - * WriteUtf8 will not write partial UTF-8 sequences, preferring to stop - * before the end of the buffer. - * - * Copies up to length characters into the output buffer. - * Only null-terminates if there is enough space in the buffer. - * - * \param buffer The buffer into which the string will be copied. - * \param start The starting position within the string at which - * copying begins. - * \param length The number of characters to copy from the string. For - * WriteUtf8 the number of bytes in the buffer. - * \param nchars_ref The number of characters written, can be NULL. - * \param options Various options that might affect performance of this or - * subsequent operations. - * \return The number of characters copied to the buffer excluding the null - * terminator. For WriteUtf8: The number of bytes copied to the buffer - * including the null terminator (if written). - */ - enum WriteOptions { - NO_OPTIONS = 0, - HINT_MANY_WRITES_EXPECTED = 1, - NO_NULL_TERMINATION = 2, - PRESERVE_ONE_BYTE_NULL = 4, - // Used by WriteUtf8 to replace orphan surrogate code units with the - // unicode replacement character. Needs to be set to guarantee valid UTF-8 - // output. - REPLACE_INVALID_UTF8 = 8 - }; - - // 16-bit character codes. - int Write(Isolate* isolate, uint16_t* buffer, int start = 0, int length = -1, - int options = NO_OPTIONS) const; - // One byte characters. - int WriteOneByte(Isolate* isolate, uint8_t* buffer, int start = 0, - int length = -1, int options = NO_OPTIONS) const; - // UTF-8 encoded characters. - int WriteUtf8(Isolate* isolate, char* buffer, int length = -1, - int* nchars_ref = nullptr, int options = NO_OPTIONS) const; - - /** - * A zero length string. - */ - V8_INLINE static Local Empty(Isolate* isolate); - - /** - * Returns true if the string is external. - */ - bool IsExternal() const; - - /** - * Returns true if the string is both external and two-byte. - */ - bool IsExternalTwoByte() const; - - /** - * Returns true if the string is both external and one-byte. - */ - bool IsExternalOneByte() const; - - class V8_EXPORT ExternalStringResourceBase { - public: - virtual ~ExternalStringResourceBase() = default; - - /** - * If a string is cacheable, the value returned by - * ExternalStringResource::data() may be cached, otherwise it is not - * expected to be stable beyond the current top-level task. - */ - virtual bool IsCacheable() const { return true; } - - // Disallow copying and assigning. - ExternalStringResourceBase(const ExternalStringResourceBase&) = delete; - void operator=(const ExternalStringResourceBase&) = delete; - - protected: - ExternalStringResourceBase() = default; - - /** - * Internally V8 will call this Dispose method when the external string - * resource is no longer needed. The default implementation will use the - * delete operator. This method can be overridden in subclasses to - * control how allocated external string resources are disposed. - */ - virtual void Dispose() { delete this; } - - /** - * For a non-cacheable string, the value returned by - * |ExternalStringResource::data()| has to be stable between |Lock()| and - * |Unlock()|, that is the string must behave as is |IsCacheable()| returned - * true. - * - * These two functions must be thread-safe, and can be called from anywhere. - * They also must handle lock depth, in the sense that each can be called - * several times, from different threads, and unlocking should only happen - * when the balance of Lock() and Unlock() calls is 0. - */ - virtual void Lock() const {} - - /** - * Unlocks the string. - */ - virtual void Unlock() const {} - - private: - friend class internal::ExternalString; - friend class v8::String; - friend class internal::ScopedExternalStringLock; - }; - - /** - * An ExternalStringResource is a wrapper around a two-byte string - * buffer that resides outside V8's heap. Implement an - * ExternalStringResource to manage the life cycle of the underlying - * buffer. Note that the string data must be immutable. - */ - class V8_EXPORT ExternalStringResource : public ExternalStringResourceBase { - public: - /** - * Override the destructor to manage the life cycle of the underlying - * buffer. - */ - ~ExternalStringResource() override = default; - - /** - * The string data from the underlying buffer. If the resource is cacheable - * then data() must return the same value for all invocations. - */ - virtual const uint16_t* data() const = 0; - - /** - * The length of the string. That is, the number of two-byte characters. - */ - virtual size_t length() const = 0; - - /** - * Returns the cached data from the underlying buffer. This method can be - * called only for cacheable resources (i.e. IsCacheable() == true) and only - * after UpdateDataCache() was called. - */ - const uint16_t* cached_data() const { - CheckCachedDataInvariants(); - return cached_data_; - } - - /** - * Update {cached_data_} with the data from the underlying buffer. This can - * be called only for cacheable resources. - */ - void UpdateDataCache(); - - protected: - ExternalStringResource() = default; - - private: - void CheckCachedDataInvariants() const; - - const uint16_t* cached_data_ = nullptr; - }; - - /** - * An ExternalOneByteStringResource is a wrapper around an one-byte - * string buffer that resides outside V8's heap. Implement an - * ExternalOneByteStringResource to manage the life cycle of the - * underlying buffer. Note that the string data must be immutable - * and that the data must be Latin-1 and not UTF-8, which would require - * special treatment internally in the engine and do not allow efficient - * indexing. Use String::New or convert to 16 bit data for non-Latin1. - */ - - class V8_EXPORT ExternalOneByteStringResource - : public ExternalStringResourceBase { - public: - /** - * Override the destructor to manage the life cycle of the underlying - * buffer. - */ - ~ExternalOneByteStringResource() override = default; - - /** - * The string data from the underlying buffer. If the resource is cacheable - * then data() must return the same value for all invocations. - */ - virtual const char* data() const = 0; - - /** The number of Latin-1 characters in the string.*/ - virtual size_t length() const = 0; - - /** - * Returns the cached data from the underlying buffer. If the resource is - * uncacheable or if UpdateDataCache() was not called before, it has - * undefined behaviour. - */ - const char* cached_data() const { - CheckCachedDataInvariants(); - return cached_data_; - } - - /** - * Update {cached_data_} with the data from the underlying buffer. This can - * be called only for cacheable resources. - */ - void UpdateDataCache(); - - protected: - ExternalOneByteStringResource() = default; - - private: - void CheckCachedDataInvariants() const; - - const char* cached_data_ = nullptr; - }; - - /** - * If the string is an external string, return the ExternalStringResourceBase - * regardless of the encoding, otherwise return NULL. The encoding of the - * string is returned in encoding_out. - */ - V8_INLINE ExternalStringResourceBase* GetExternalStringResourceBase( - Encoding* encoding_out) const; - - /** - * Get the ExternalStringResource for an external string. Returns - * NULL if IsExternal() doesn't return true. - */ - V8_INLINE ExternalStringResource* GetExternalStringResource() const; - - /** - * Get the ExternalOneByteStringResource for an external one-byte string. - * Returns NULL if IsExternalOneByte() doesn't return true. - */ - const ExternalOneByteStringResource* GetExternalOneByteStringResource() const; - - V8_INLINE static String* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - /** - * Allocates a new string from a UTF-8 literal. This is equivalent to calling - * String::NewFromUtf(isolate, "...").ToLocalChecked(), but without the check - * overhead. - * - * When called on a string literal containing '\0', the inferred length is the - * length of the input array minus 1 (for the final '\0') and not the value - * returned by strlen. - **/ - template - static V8_WARN_UNUSED_RESULT Local NewFromUtf8Literal( - Isolate* isolate, const char (&literal)[N], - NewStringType type = NewStringType::kNormal) { - static_assert(N <= kMaxLength, "String is too long"); - return NewFromUtf8Literal(isolate, literal, type, N - 1); - } - - /** Allocates a new string from UTF-8 data. Only returns an empty value when - * length > kMaxLength. **/ - static V8_WARN_UNUSED_RESULT MaybeLocal NewFromUtf8( - Isolate* isolate, const char* data, - NewStringType type = NewStringType::kNormal, int length = -1); - - /** Allocates a new string from Latin-1 data. Only returns an empty value - * when length > kMaxLength. **/ - static V8_WARN_UNUSED_RESULT MaybeLocal NewFromOneByte( - Isolate* isolate, const uint8_t* data, - NewStringType type = NewStringType::kNormal, int length = -1); - - /** Allocates a new string from UTF-16 data. Only returns an empty value when - * length > kMaxLength. **/ - static V8_WARN_UNUSED_RESULT MaybeLocal NewFromTwoByte( - Isolate* isolate, const uint16_t* data, - NewStringType type = NewStringType::kNormal, int length = -1); - - /** - * Creates a new string by concatenating the left and the right strings - * passed in as parameters. - */ - static Local Concat(Isolate* isolate, Local left, - Local right); - - /** - * Creates a new external string using the data defined in the given - * resource. When the external string is no longer live on V8's heap the - * resource will be disposed by calling its Dispose method. The caller of - * this function should not otherwise delete or modify the resource. Neither - * should the underlying buffer be deallocated or modified except through the - * destructor of the external string resource. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal NewExternalTwoByte( - Isolate* isolate, ExternalStringResource* resource); - - /** - * Associate an external string resource with this string by transforming it - * in place so that existing references to this string in the JavaScript heap - * will use the external string resource. The external string resource's - * character contents need to be equivalent to this string. - * Returns true if the string has been changed to be an external string. - * The string is not modified if the operation fails. See NewExternal for - * information on the lifetime of the resource. - */ - bool MakeExternal(ExternalStringResource* resource); - - /** - * Creates a new external string using the one-byte data defined in the given - * resource. When the external string is no longer live on V8's heap the - * resource will be disposed by calling its Dispose method. The caller of - * this function should not otherwise delete or modify the resource. Neither - * should the underlying buffer be deallocated or modified except through the - * destructor of the external string resource. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal NewExternalOneByte( - Isolate* isolate, ExternalOneByteStringResource* resource); - - /** - * Associate an external string resource with this string by transforming it - * in place so that existing references to this string in the JavaScript heap - * will use the external string resource. The external string resource's - * character contents need to be equivalent to this string. - * Returns true if the string has been changed to be an external string. - * The string is not modified if the operation fails. See NewExternal for - * information on the lifetime of the resource. - */ - bool MakeExternal(ExternalOneByteStringResource* resource); - - /** - * Returns true if this string can be made external. - */ - bool CanMakeExternal() const; - - /** - * Returns true if the strings values are equal. Same as JS ==/===. - */ - bool StringEquals(Local str) const; - - /** - * Converts an object to a UTF-8-encoded character array. Useful if - * you want to print the object. If conversion to a string fails - * (e.g. due to an exception in the toString() method of the object) - * then the length() method returns 0 and the * operator returns - * NULL. - */ - class V8_EXPORT Utf8Value { - public: - Utf8Value(Isolate* isolate, Local obj); - ~Utf8Value(); - char* operator*() { return str_; } - const char* operator*() const { return str_; } - int length() const { return length_; } - - // Disallow copying and assigning. - Utf8Value(const Utf8Value&) = delete; - void operator=(const Utf8Value&) = delete; - - private: - char* str_; - int length_; - }; - - /** - * Converts an object to a two-byte (UTF-16-encoded) string. - * If conversion to a string fails (eg. due to an exception in the toString() - * method of the object) then the length() method returns 0 and the * operator - * returns NULL. - */ - class V8_EXPORT Value { - public: - Value(Isolate* isolate, Local obj); - ~Value(); - uint16_t* operator*() { return str_; } - const uint16_t* operator*() const { return str_; } - int length() const { return length_; } - - // Disallow copying and assigning. - Value(const Value&) = delete; - void operator=(const Value&) = delete; - - private: - uint16_t* str_; - int length_; - }; - - private: - void VerifyExternalStringResourceBase(ExternalStringResourceBase* v, - Encoding encoding) const; - void VerifyExternalStringResource(ExternalStringResource* val) const; - ExternalStringResource* GetExternalStringResourceSlow() const; - ExternalStringResourceBase* GetExternalStringResourceBaseSlow( - String::Encoding* encoding_out) const; - - static Local NewFromUtf8Literal(Isolate* isolate, - const char* literal, - NewStringType type, int length); - - static void CheckCast(v8::Data* that); -}; - -// Zero-length string specialization (templated string size includes -// terminator). -template <> -inline V8_WARN_UNUSED_RESULT Local String::NewFromUtf8Literal( - Isolate* isolate, const char (&literal)[1], NewStringType type) { - return String::Empty(isolate); -} - -/** - * Interface for iterating through all external resources in the heap. - */ -class V8_EXPORT ExternalResourceVisitor { - public: - virtual ~ExternalResourceVisitor() = default; - virtual void VisitExternalString(Local string) {} -}; - -/** - * A JavaScript symbol (ECMA-262 edition 6) - */ -class V8_EXPORT Symbol : public Name { - public: - /** - * Returns the description string of the symbol, or undefined if none. - */ - V8_DEPRECATE_SOON("Use Symbol::Description(isolate)") - Local Description() const; - Local Description(Isolate* isolate) const; - - /** - * Create a symbol. If description is not empty, it will be used as the - * description. - */ - static Local New(Isolate* isolate, - Local description = Local()); - - /** - * Access global symbol registry. - * Note that symbols created this way are never collected, so - * they should only be used for statically fixed properties. - * Also, there is only one global name space for the descriptions used as - * keys. - * To minimize the potential for clashes, use qualified names as keys. - */ - static Local For(Isolate* isolate, Local description); - - /** - * Retrieve a global symbol. Similar to |For|, but using a separate - * registry that is not accessible by (and cannot clash with) JavaScript code. - */ - static Local ForApi(Isolate* isolate, Local description); - - // Well-known symbols - static Local GetAsyncIterator(Isolate* isolate); - static Local GetHasInstance(Isolate* isolate); - static Local GetIsConcatSpreadable(Isolate* isolate); - static Local GetIterator(Isolate* isolate); - static Local GetMatch(Isolate* isolate); - static Local GetReplace(Isolate* isolate); - static Local GetSearch(Isolate* isolate); - static Local GetSplit(Isolate* isolate); - static Local GetToPrimitive(Isolate* isolate); - static Local GetToStringTag(Isolate* isolate); - static Local GetUnscopables(Isolate* isolate); - - V8_INLINE static Symbol* Cast(Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Symbol(); - static void CheckCast(Data* that); -}; - -/** - * A JavaScript number value (ECMA-262, 4.3.20) - */ -class V8_EXPORT Number : public Primitive { - public: - double Value() const; - static Local New(Isolate* isolate, double value); - V8_INLINE static Number* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Number(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript value representing a signed integer. - */ -class V8_EXPORT Integer : public Number { - public: - static Local New(Isolate* isolate, int32_t value); - static Local NewFromUnsigned(Isolate* isolate, uint32_t value); - int64_t Value() const; - V8_INLINE static Integer* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Integer(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript value representing a 32-bit signed integer. - */ -class V8_EXPORT Int32 : public Integer { - public: - int32_t Value() const; - V8_INLINE static Int32* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Int32(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript value representing a 32-bit unsigned integer. - */ -class V8_EXPORT Uint32 : public Integer { - public: - uint32_t Value() const; - V8_INLINE static Uint32* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - Uint32(); - static void CheckCast(v8::Data* that); -}; - -/** - * A JavaScript BigInt value (https://tc39.github.io/proposal-bigint) - */ -class V8_EXPORT BigInt : public Primitive { - public: - static Local New(Isolate* isolate, int64_t value); - static Local NewFromUnsigned(Isolate* isolate, uint64_t value); - /** - * Creates a new BigInt object using a specified sign bit and a - * specified list of digits/words. - * The resulting number is calculated as: - * - * (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...) - */ - static MaybeLocal NewFromWords(Local context, int sign_bit, - int word_count, const uint64_t* words); - - /** - * Returns the value of this BigInt as an unsigned 64-bit integer. - * If `lossless` is provided, it will reflect whether the return value was - * truncated or wrapped around. In particular, it is set to `false` if this - * BigInt is negative. - */ - uint64_t Uint64Value(bool* lossless = nullptr) const; - - /** - * Returns the value of this BigInt as a signed 64-bit integer. - * If `lossless` is provided, it will reflect whether this BigInt was - * truncated or not. - */ - int64_t Int64Value(bool* lossless = nullptr) const; - - /** - * Returns the number of 64-bit words needed to store the result of - * ToWordsArray(). - */ - int WordCount() const; - - /** - * Writes the contents of this BigInt to a specified memory location. - * `sign_bit` must be provided and will be set to 1 if this BigInt is - * negative. - * `*word_count` has to be initialized to the length of the `words` array. - * Upon return, it will be set to the actual number of words that would - * be needed to store this BigInt (i.e. the return value of `WordCount()`). - */ - void ToWordsArray(int* sign_bit, int* word_count, uint64_t* words) const; - - V8_INLINE static BigInt* Cast(v8::Data* data) { -#ifdef V8_ENABLE_CHECKS - CheckCast(data); -#endif - return static_cast(data); - } - - private: - BigInt(); - static void CheckCast(v8::Data* that); -}; - -Local String::Empty(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kEmptyStringRootIndex); - return Local(reinterpret_cast(slot)); -} - -String::ExternalStringResource* String::GetExternalStringResource() const { - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - - ExternalStringResource* result; - if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) { - internal::Isolate* isolate = I::GetIsolateForHeapSandbox(obj); - A value = - I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset, - internal::kExternalStringResourceTag); - result = reinterpret_cast(value); - } else { - result = GetExternalStringResourceSlow(); - } -#ifdef V8_ENABLE_CHECKS - VerifyExternalStringResource(result); -#endif - return result; -} - -String::ExternalStringResourceBase* String::GetExternalStringResourceBase( - String::Encoding* encoding_out) const { - using A = internal::Address; - using I = internal::Internals; - A obj = *reinterpret_cast(this); - int type = I::GetInstanceType(obj) & I::kFullStringRepresentationMask; - *encoding_out = static_cast(type & I::kStringEncodingMask); - ExternalStringResourceBase* resource; - if (type == I::kExternalOneByteRepresentationTag || - type == I::kExternalTwoByteRepresentationTag) { - internal::Isolate* isolate = I::GetIsolateForHeapSandbox(obj); - A value = - I::ReadExternalPointerField(isolate, obj, I::kStringResourceOffset, - internal::kExternalStringResourceTag); - resource = reinterpret_cast(value); - } else { - resource = GetExternalStringResourceBaseSlow(encoding_out); - } -#ifdef V8_ENABLE_CHECKS - VerifyExternalStringResourceBase(resource, *encoding_out); -#endif - return resource; -} - -// --- Statics --- - -V8_INLINE Local Undefined(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kUndefinedValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -V8_INLINE Local Null(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kNullValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -V8_INLINE Local True(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kTrueValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -V8_INLINE Local False(Isolate* isolate) { - using S = internal::Address; - using I = internal::Internals; - I::CheckInitialized(isolate); - S* slot = I::GetRoot(isolate, I::kFalseValueRootIndex); - return Local(reinterpret_cast(slot)); -} - -Local Boolean::New(Isolate* isolate, bool value) { - return value ? True(isolate) : False(isolate); -} - -} // namespace v8 - -#endif // INCLUDE_V8_PRIMITIVE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-profiler.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-profiler.h deleted file mode 100644 index f2354cac38e..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-profiler.h +++ /dev/null @@ -1,1122 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_PROFILER_H_ -#define V8_V8_PROFILER_H_ - -#include - -#include -#include -#include - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-message.h" // NOLINT(build/include_directory) -#include "v8-persistent-handle.h" // NOLINT(build/include_directory) - -/** - * Profiler support for the V8 JavaScript engine. - */ -namespace v8 { - -class HeapGraphNode; -struct HeapStatsUpdate; -class Object; - -using NativeObject = void*; -using SnapshotObjectId = uint32_t; - -struct CpuProfileDeoptFrame { - int script_id; - size_t position; -}; - -namespace internal { -class CpuProfile; -} // namespace internal - -} // namespace v8 - -#ifdef V8_OS_WIN -template class V8_EXPORT std::vector; -#endif - -namespace v8 { - -struct V8_EXPORT CpuProfileDeoptInfo { - /** A pointer to a static string owned by v8. */ - const char* deopt_reason; - std::vector stack; -}; - -} // namespace v8 - -#ifdef V8_OS_WIN -template class V8_EXPORT std::vector; -#endif - -namespace v8 { - -/** - * CpuProfileNode represents a node in a call graph. - */ -class V8_EXPORT CpuProfileNode { - public: - struct LineTick { - /** The 1-based number of the source line where the function originates. */ - int line; - - /** The count of samples associated with the source line. */ - unsigned int hit_count; - }; - - // An annotation hinting at the source of a CpuProfileNode. - enum SourceType { - // User-supplied script with associated resource information. - kScript = 0, - // Native scripts and provided builtins. - kBuiltin = 1, - // Callbacks into native code. - kCallback = 2, - // VM-internal functions or state. - kInternal = 3, - // A node that failed to symbolize. - kUnresolved = 4, - }; - - /** Returns function name (empty string for anonymous functions.) */ - Local GetFunctionName() const; - - /** - * Returns function name (empty string for anonymous functions.) - * The string ownership is *not* passed to the caller. It stays valid until - * profile is deleted. The function is thread safe. - */ - const char* GetFunctionNameStr() const; - - /** Returns id of the script where function is located. */ - int GetScriptId() const; - - /** Returns resource name for script from where the function originates. */ - Local GetScriptResourceName() const; - - /** - * Returns resource name for script from where the function originates. - * The string ownership is *not* passed to the caller. It stays valid until - * profile is deleted. The function is thread safe. - */ - const char* GetScriptResourceNameStr() const; - - /** - * Return true if the script from where the function originates is flagged as - * being shared cross-origin. - */ - bool IsScriptSharedCrossOrigin() const; - - /** - * Returns the number, 1-based, of the line where the function originates. - * kNoLineNumberInfo if no line number information is available. - */ - int GetLineNumber() const; - - /** - * Returns 1-based number of the column where the function originates. - * kNoColumnNumberInfo if no column number information is available. - */ - int GetColumnNumber() const; - - /** - * Returns the number of the function's source lines that collect the samples. - */ - unsigned int GetHitLineCount() const; - - /** Returns the set of source lines that collect the samples. - * The caller allocates buffer and responsible for releasing it. - * True if all available entries are copied, otherwise false. - * The function copies nothing if buffer is not large enough. - */ - bool GetLineTicks(LineTick* entries, unsigned int length) const; - - /** Returns bailout reason for the function - * if the optimization was disabled for it. - */ - const char* GetBailoutReason() const; - - /** - * Returns the count of samples where the function was currently executing. - */ - unsigned GetHitCount() const; - - /** Returns id of the node. The id is unique within the tree */ - unsigned GetNodeId() const; - - /** - * Gets the type of the source which the node was captured from. - */ - SourceType GetSourceType() const; - - /** Returns child nodes count of the node. */ - int GetChildrenCount() const; - - /** Retrieves a child node by index. */ - const CpuProfileNode* GetChild(int index) const; - - /** Retrieves the ancestor node, or null if the root. */ - const CpuProfileNode* GetParent() const; - - /** Retrieves deopt infos for the node. */ - const std::vector& GetDeoptInfos() const; - - static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; - static const int kNoColumnNumberInfo = Message::kNoColumnInfo; -}; - - -/** - * CpuProfile contains a CPU profile in a form of top-down call tree - * (from main() down to functions that do all the work). - */ -class V8_EXPORT CpuProfile { - public: - /** Returns CPU profile title. */ - Local GetTitle() const; - - /** Returns the root node of the top down call tree. */ - const CpuProfileNode* GetTopDownRoot() const; - - /** - * Returns number of samples recorded. The samples are not recorded unless - * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true. - */ - int GetSamplesCount() const; - - /** - * Returns profile node corresponding to the top frame the sample at - * the given index. - */ - const CpuProfileNode* GetSample(int index) const; - - /** - * Returns the timestamp of the sample. The timestamp is the number of - * microseconds since some unspecified starting point. - * The point is equal to the starting point used by GetStartTime. - */ - int64_t GetSampleTimestamp(int index) const; - - /** - * Returns time when the profile recording was started (in microseconds) - * since some unspecified starting point. - */ - int64_t GetStartTime() const; - - /** - * Returns time when the profile recording was stopped (in microseconds) - * since some unspecified starting point. - * The point is equal to the starting point used by GetStartTime. - */ - int64_t GetEndTime() const; - - /** - * Deletes the profile and removes it from CpuProfiler's list. - * All pointers to nodes previously returned become invalid. - */ - void Delete(); -}; - -enum CpuProfilingMode { - // In the resulting CpuProfile tree, intermediate nodes in a stack trace - // (from the root to a leaf) will have line numbers that point to the start - // line of the function, rather than the line of the callsite of the child. - kLeafNodeLineNumbers, - // In the resulting CpuProfile tree, nodes are separated based on the line - // number of their callsite in their parent. - kCallerLineNumbers, -}; - -// Determines how names are derived for functions sampled. -enum CpuProfilingNamingMode { - // Use the immediate name of functions at compilation time. - kStandardNaming, - // Use more verbose naming for functions without names, inferred from scope - // where possible. - kDebugNaming, -}; - -enum CpuProfilingLoggingMode { - // Enables logging when a profile is active, and disables logging when all - // profiles are detached. - kLazyLogging, - // Enables logging for the lifetime of the CpuProfiler. Calls to - // StartRecording are faster, at the expense of runtime overhead. - kEagerLogging, -}; - -// Enum for returning profiling status. Once StartProfiling is called, -// we want to return to clients whether the profiling was able to start -// correctly, or return a descriptive error. -enum class CpuProfilingStatus { - kStarted, - kAlreadyStarted, - kErrorTooManyProfilers -}; - -/** - * Delegate for when max samples reached and samples are discarded. - */ -class V8_EXPORT DiscardedSamplesDelegate { - public: - DiscardedSamplesDelegate() {} - - virtual ~DiscardedSamplesDelegate() = default; - virtual void Notify() = 0; -}; - -/** - * Optional profiling attributes. - */ -class V8_EXPORT CpuProfilingOptions { - public: - // Indicates that the sample buffer size should not be explicitly limited. - static const unsigned kNoSampleLimit = UINT_MAX; - - /** - * \param mode Type of computation of stack frame line numbers. - * \param max_samples The maximum number of samples that should be recorded by - * the profiler. Samples obtained after this limit will be - * discarded. - * \param sampling_interval_us controls the profile-specific target - * sampling interval. The provided sampling - * interval will be snapped to the next lowest - * non-zero multiple of the profiler's sampling - * interval, set via SetSamplingInterval(). If - * zero, the sampling interval will be equal to - * the profiler's sampling interval. - * \param filter_context If specified, profiles will only contain frames - * using this context. Other frames will be elided. - */ - CpuProfilingOptions( - CpuProfilingMode mode = kLeafNodeLineNumbers, - unsigned max_samples = kNoSampleLimit, int sampling_interval_us = 0, - MaybeLocal filter_context = MaybeLocal()); - - CpuProfilingMode mode() const { return mode_; } - unsigned max_samples() const { return max_samples_; } - int sampling_interval_us() const { return sampling_interval_us_; } - - private: - friend class internal::CpuProfile; - - bool has_filter_context() const { return !filter_context_.IsEmpty(); } - void* raw_filter_context() const; - - CpuProfilingMode mode_; - unsigned max_samples_; - int sampling_interval_us_; - CopyablePersistentTraits::CopyablePersistent filter_context_; -}; - -/** - * Interface for controlling CPU profiling. Instance of the - * profiler can be created using v8::CpuProfiler::New method. - */ -class V8_EXPORT CpuProfiler { - public: - /** - * Creates a new CPU profiler for the |isolate|. The isolate must be - * initialized. The profiler object must be disposed after use by calling - * |Dispose| method. - */ - static CpuProfiler* New(Isolate* isolate, - CpuProfilingNamingMode = kDebugNaming, - CpuProfilingLoggingMode = kLazyLogging); - - /** - * Synchronously collect current stack sample in all profilers attached to - * the |isolate|. The call does not affect number of ticks recorded for - * the current top node. - */ - static void CollectSample(Isolate* isolate); - - /** - * Disposes the CPU profiler object. - */ - void Dispose(); - - /** - * Changes default CPU profiler sampling interval to the specified number - * of microseconds. Default interval is 1000us. This method must be called - * when there are no profiles being recorded. - */ - void SetSamplingInterval(int us); - - /** - * Sets whether or not the profiler should prioritize consistency of sample - * periodicity on Windows. Disabling this can greatly reduce CPU usage, but - * may result in greater variance in sample timings from the platform's - * scheduler. Defaults to enabled. This method must be called when there are - * no profiles being recorded. - */ - void SetUsePreciseSampling(bool); - - /** - * Starts collecting a CPU profile. Title may be an empty string. Several - * profiles may be collected at once. Attempts to start collecting several - * profiles with the same title are silently ignored. - */ - CpuProfilingStatus StartProfiling( - Local title, CpuProfilingOptions options, - std::unique_ptr delegate = nullptr); - - /** - * Starts profiling with the same semantics as above, except with expanded - * parameters. - * - * |record_samples| parameter controls whether individual samples should - * be recorded in addition to the aggregated tree. - * - * |max_samples| controls the maximum number of samples that should be - * recorded by the profiler. Samples obtained after this limit will be - * discarded. - */ - CpuProfilingStatus StartProfiling( - Local title, CpuProfilingMode mode, bool record_samples = false, - unsigned max_samples = CpuProfilingOptions::kNoSampleLimit); - /** - * The same as StartProfiling above, but the CpuProfilingMode defaults to - * kLeafNodeLineNumbers mode, which was the previous default behavior of the - * profiler. - */ - CpuProfilingStatus StartProfiling(Local title, - bool record_samples = false); - - /** - * Stops collecting CPU profile with a given title and returns it. - * If the title given is empty, finishes the last profile started. - */ - CpuProfile* StopProfiling(Local title); - - /** - * Generate more detailed source positions to code objects. This results in - * better results when mapping profiling samples to script source. - */ - static void UseDetailedSourcePositionsForProfiling(Isolate* isolate); - - private: - CpuProfiler(); - ~CpuProfiler(); - CpuProfiler(const CpuProfiler&); - CpuProfiler& operator=(const CpuProfiler&); -}; - -/** - * HeapSnapshotEdge represents a directed connection between heap - * graph nodes: from retainers to retained nodes. - */ -class V8_EXPORT HeapGraphEdge { - public: - enum Type { - kContextVariable = 0, // A variable from a function context. - kElement = 1, // An element of an array. - kProperty = 2, // A named object property. - kInternal = 3, // A link that can't be accessed from JS, - // thus, its name isn't a real property name - // (e.g. parts of a ConsString). - kHidden = 4, // A link that is needed for proper sizes - // calculation, but may be hidden from user. - kShortcut = 5, // A link that must not be followed during - // sizes calculation. - kWeak = 6 // A weak reference (ignored by the GC). - }; - - /** Returns edge type (see HeapGraphEdge::Type). */ - Type GetType() const; - - /** - * Returns edge name. This can be a variable name, an element index, or - * a property name. - */ - Local GetName() const; - - /** Returns origin node. */ - const HeapGraphNode* GetFromNode() const; - - /** Returns destination node. */ - const HeapGraphNode* GetToNode() const; -}; - - -/** - * HeapGraphNode represents a node in a heap graph. - */ -class V8_EXPORT HeapGraphNode { - public: - enum Type { - kHidden = 0, // Hidden node, may be filtered when shown to user. - kArray = 1, // An array of elements. - kString = 2, // A string. - kObject = 3, // A JS object (except for arrays and strings). - kCode = 4, // Compiled code. - kClosure = 5, // Function closure. - kRegExp = 6, // RegExp. - kHeapNumber = 7, // Number stored in the heap. - kNative = 8, // Native object (not from V8 heap). - kSynthetic = 9, // Synthetic object, usually used for grouping - // snapshot items together. - kConsString = 10, // Concatenated string. A pair of pointers to strings. - kSlicedString = 11, // Sliced string. A fragment of another string. - kSymbol = 12, // A Symbol (ES6). - kBigInt = 13 // BigInt. - }; - - /** Returns node type (see HeapGraphNode::Type). */ - Type GetType() const; - - /** - * Returns node name. Depending on node's type this can be the name - * of the constructor (for objects), the name of the function (for - * closures), string value, or an empty string (for compiled code). - */ - Local GetName() const; - - /** - * Returns node id. For the same heap object, the id remains the same - * across all snapshots. - */ - SnapshotObjectId GetId() const; - - /** Returns node's own size, in bytes. */ - size_t GetShallowSize() const; - - /** Returns child nodes count of the node. */ - int GetChildrenCount() const; - - /** Retrieves a child by index. */ - const HeapGraphEdge* GetChild(int index) const; -}; - - -/** - * An interface for exporting data from V8, using "push" model. - */ -class V8_EXPORT OutputStream { - public: - enum WriteResult { - kContinue = 0, - kAbort = 1 - }; - virtual ~OutputStream() = default; - /** Notify about the end of stream. */ - virtual void EndOfStream() = 0; - /** Get preferred output chunk size. Called only once. */ - virtual int GetChunkSize() { return 1024; } - /** - * Writes the next chunk of snapshot data into the stream. Writing - * can be stopped by returning kAbort as function result. EndOfStream - * will not be called in case writing was aborted. - */ - virtual WriteResult WriteAsciiChunk(char* data, int size) = 0; - /** - * Writes the next chunk of heap stats data into the stream. Writing - * can be stopped by returning kAbort as function result. EndOfStream - * will not be called in case writing was aborted. - */ - virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate* data, int count) { - return kAbort; - } -}; - -/** - * HeapSnapshots record the state of the JS heap at some moment. - */ -class V8_EXPORT HeapSnapshot { - public: - enum SerializationFormat { - kJSON = 0 // See format description near 'Serialize' method. - }; - - /** Returns the root node of the heap graph. */ - const HeapGraphNode* GetRoot() const; - - /** Returns a node by its id. */ - const HeapGraphNode* GetNodeById(SnapshotObjectId id) const; - - /** Returns total nodes count in the snapshot. */ - int GetNodesCount() const; - - /** Returns a node by index. */ - const HeapGraphNode* GetNode(int index) const; - - /** Returns a max seen JS object Id. */ - SnapshotObjectId GetMaxSnapshotJSObjectId() const; - - /** - * Deletes the snapshot and removes it from HeapProfiler's list. - * All pointers to nodes, edges and paths previously returned become - * invalid. - */ - void Delete(); - - /** - * Prepare a serialized representation of the snapshot. The result - * is written into the stream provided in chunks of specified size. - * The total length of the serialized snapshot is unknown in - * advance, it can be roughly equal to JS heap size (that means, - * it can be really big - tens of megabytes). - * - * For the JSON format, heap contents are represented as an object - * with the following structure: - * - * { - * snapshot: { - * title: "...", - * uid: nnn, - * meta: { meta-info }, - * node_count: nnn, - * edge_count: nnn - * }, - * nodes: [nodes array], - * edges: [edges array], - * strings: [strings array] - * } - * - * Nodes reference strings, other nodes, and edges by their indexes - * in corresponding arrays. - */ - void Serialize(OutputStream* stream, - SerializationFormat format = kJSON) const; -}; - - -/** - * An interface for reporting progress and controlling long-running - * activities. - */ -class V8_EXPORT ActivityControl { - public: - enum ControlOption { - kContinue = 0, - kAbort = 1 - }; - virtual ~ActivityControl() = default; - /** - * Notify about current progress. The activity can be stopped by - * returning kAbort as the callback result. - */ - virtual ControlOption ReportProgressValue(int done, int total) = 0; -}; - -/** - * AllocationProfile is a sampled profile of allocations done by the program. - * This is structured as a call-graph. - */ -class V8_EXPORT AllocationProfile { - public: - struct Allocation { - /** - * Size of the sampled allocation object. - */ - size_t size; - - /** - * The number of objects of such size that were sampled. - */ - unsigned int count; - }; - - /** - * Represents a node in the call-graph. - */ - struct Node { - /** - * Name of the function. May be empty for anonymous functions or if the - * script corresponding to this function has been unloaded. - */ - Local name; - - /** - * Name of the script containing the function. May be empty if the script - * name is not available, or if the script has been unloaded. - */ - Local script_name; - - /** - * id of the script where the function is located. May be equal to - * v8::UnboundScript::kNoScriptId in cases where the script doesn't exist. - */ - int script_id; - - /** - * Start position of the function in the script. - */ - int start_position; - - /** - * 1-indexed line number where the function starts. May be - * kNoLineNumberInfo if no line number information is available. - */ - int line_number; - - /** - * 1-indexed column number where the function starts. May be - * kNoColumnNumberInfo if no line number information is available. - */ - int column_number; - - /** - * Unique id of the node. - */ - uint32_t node_id; - - /** - * List of callees called from this node for which we have sampled - * allocations. The lifetime of the children is scoped to the containing - * AllocationProfile. - */ - std::vector children; - - /** - * List of self allocations done by this node in the call-graph. - */ - std::vector allocations; - }; - - /** - * Represent a single sample recorded for an allocation. - */ - struct Sample { - /** - * id of the node in the profile tree. - */ - uint32_t node_id; - - /** - * Size of the sampled allocation object. - */ - size_t size; - - /** - * The number of objects of such size that were sampled. - */ - unsigned int count; - - /** - * Unique time-ordered id of the allocation sample. Can be used to track - * what samples were added or removed between two snapshots. - */ - uint64_t sample_id; - }; - - /** - * Returns the root node of the call-graph. The root node corresponds to an - * empty JS call-stack. The lifetime of the returned Node* is scoped to the - * containing AllocationProfile. - */ - virtual Node* GetRootNode() = 0; - virtual const std::vector& GetSamples() = 0; - - virtual ~AllocationProfile() = default; - - static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; - static const int kNoColumnNumberInfo = Message::kNoColumnInfo; -}; - -/** - * An object graph consisting of embedder objects and V8 objects. - * Edges of the graph are strong references between the objects. - * The embedder can build this graph during heap snapshot generation - * to include the embedder objects in the heap snapshot. - * Usage: - * 1) Define derived class of EmbedderGraph::Node for embedder objects. - * 2) Set the build embedder graph callback on the heap profiler using - * HeapProfiler::AddBuildEmbedderGraphCallback. - * 3) In the callback use graph->AddEdge(node1, node2) to add an edge from - * node1 to node2. - * 4) To represent references from/to V8 object, construct V8 nodes using - * graph->V8Node(value). - */ -class V8_EXPORT EmbedderGraph { - public: - class Node { - public: - /** - * Detachedness specifies whether an object is attached or detached from the - * main application state. While unkown in general, there may be objects - * that specifically know their state. V8 passes this information along in - * the snapshot. Users of the snapshot may use it to annotate the object - * graph. - */ - enum class Detachedness : uint8_t { - kUnknown = 0, - kAttached = 1, - kDetached = 2, - }; - - Node() = default; - virtual ~Node() = default; - virtual const char* Name() = 0; - virtual size_t SizeInBytes() = 0; - /** - * The corresponding V8 wrapper node if not null. - * During heap snapshot generation the embedder node and the V8 wrapper - * node will be merged into one node to simplify retaining paths. - */ - virtual Node* WrapperNode() { return nullptr; } - virtual bool IsRootNode() { return false; } - /** Must return true for non-V8 nodes. */ - virtual bool IsEmbedderNode() { return true; } - /** - * Optional name prefix. It is used in Chrome for tagging detached nodes. - */ - virtual const char* NamePrefix() { return nullptr; } - - /** - * Returns the NativeObject that can be used for querying the - * |HeapSnapshot|. - */ - virtual NativeObject GetNativeObject() { return nullptr; } - - /** - * Detachedness state of a given object. While unkown in general, there may - * be objects that specifically know their state. V8 passes this information - * along in the snapshot. Users of the snapshot may use it to annotate the - * object graph. - */ - virtual Detachedness GetDetachedness() { return Detachedness::kUnknown; } - - Node(const Node&) = delete; - Node& operator=(const Node&) = delete; - }; - - /** - * Returns a node corresponding to the given V8 value. Ownership is not - * transferred. The result pointer is valid while the graph is alive. - */ - virtual Node* V8Node(const v8::Local& value) = 0; - - /** - * Adds the given node to the graph and takes ownership of the node. - * Returns a raw pointer to the node that is valid while the graph is alive. - */ - virtual Node* AddNode(std::unique_ptr node) = 0; - - /** - * Adds an edge that represents a strong reference from the given - * node |from| to the given node |to|. The nodes must be added to the graph - * before calling this function. - * - * If name is nullptr, the edge will have auto-increment indexes, otherwise - * it will be named accordingly. - */ - virtual void AddEdge(Node* from, Node* to, const char* name = nullptr) = 0; - - virtual ~EmbedderGraph() = default; -}; - -/** - * Interface for controlling heap profiling. Instance of the - * profiler can be retrieved using v8::Isolate::GetHeapProfiler. - */ -class V8_EXPORT HeapProfiler { - public: - enum SamplingFlags { - kSamplingNoFlags = 0, - kSamplingForceGC = 1 << 0, - }; - - /** - * Callback function invoked during heap snapshot generation to retrieve - * the embedder object graph. The callback should use graph->AddEdge(..) to - * add references between the objects. - * The callback must not trigger garbage collection in V8. - */ - typedef void (*BuildEmbedderGraphCallback)(v8::Isolate* isolate, - v8::EmbedderGraph* graph, - void* data); - - /** - * Callback function invoked during heap snapshot generation to retrieve - * the detachedness state of an object referenced by a TracedReference. - * - * The callback takes Local as parameter to allow the embedder to - * unpack the TracedReference into a Local and reuse that Local for different - * purposes. - */ - using GetDetachednessCallback = EmbedderGraph::Node::Detachedness (*)( - v8::Isolate* isolate, const v8::Local& v8_value, - uint16_t class_id, void* data); - - /** Returns the number of snapshots taken. */ - int GetSnapshotCount(); - - /** Returns a snapshot by index. */ - const HeapSnapshot* GetHeapSnapshot(int index); - - /** - * Returns SnapshotObjectId for a heap object referenced by |value| if - * it has been seen by the heap profiler, kUnknownObjectId otherwise. - */ - SnapshotObjectId GetObjectId(Local value); - - /** - * Returns SnapshotObjectId for a native object referenced by |value| if it - * has been seen by the heap profiler, kUnknownObjectId otherwise. - */ - SnapshotObjectId GetObjectId(NativeObject value); - - /** - * Returns heap object with given SnapshotObjectId if the object is alive, - * otherwise empty handle is returned. - */ - Local FindObjectById(SnapshotObjectId id); - - /** - * Clears internal map from SnapshotObjectId to heap object. The new objects - * will not be added into it unless a heap snapshot is taken or heap object - * tracking is kicked off. - */ - void ClearObjectIds(); - - /** - * A constant for invalid SnapshotObjectId. GetSnapshotObjectId will return - * it in case heap profiler cannot find id for the object passed as - * parameter. HeapSnapshot::GetNodeById will always return NULL for such id. - */ - static const SnapshotObjectId kUnknownObjectId = 0; - - /** - * Callback interface for retrieving user friendly names of global objects. - */ - class ObjectNameResolver { - public: - /** - * Returns name to be used in the heap snapshot for given node. Returned - * string must stay alive until snapshot collection is completed. - */ - virtual const char* GetName(Local object) = 0; - - protected: - virtual ~ObjectNameResolver() = default; - }; - - /** - * Takes a heap snapshot and returns it. - */ - const HeapSnapshot* TakeHeapSnapshot( - ActivityControl* control = nullptr, - ObjectNameResolver* global_object_name_resolver = nullptr, - bool treat_global_objects_as_roots = true, - bool capture_numeric_value = false); - - /** - * Starts tracking of heap objects population statistics. After calling - * this method, all heap objects relocations done by the garbage collector - * are being registered. - * - * |track_allocations| parameter controls whether stack trace of each - * allocation in the heap will be recorded and reported as part of - * HeapSnapshot. - */ - void StartTrackingHeapObjects(bool track_allocations = false); - - /** - * Adds a new time interval entry to the aggregated statistics array. The - * time interval entry contains information on the current heap objects - * population size. The method also updates aggregated statistics and - * reports updates for all previous time intervals via the OutputStream - * object. Updates on each time interval are provided as a stream of the - * HeapStatsUpdate structure instances. - * If |timestamp_us| is supplied, timestamp of the new entry will be written - * into it. The return value of the function is the last seen heap object Id. - * - * StartTrackingHeapObjects must be called before the first call to this - * method. - */ - SnapshotObjectId GetHeapStats(OutputStream* stream, - int64_t* timestamp_us = nullptr); - - /** - * Stops tracking of heap objects population statistics, cleans up all - * collected data. StartHeapObjectsTracking must be called again prior to - * calling GetHeapStats next time. - */ - void StopTrackingHeapObjects(); - - /** - * Starts gathering a sampling heap profile. A sampling heap profile is - * similar to tcmalloc's heap profiler and Go's mprof. It samples object - * allocations and builds an online 'sampling' heap profile. At any point in - * time, this profile is expected to be a representative sample of objects - * currently live in the system. Each sampled allocation includes the stack - * trace at the time of allocation, which makes this really useful for memory - * leak detection. - * - * This mechanism is intended to be cheap enough that it can be used in - * production with minimal performance overhead. - * - * Allocations are sampled using a randomized Poisson process. On average, one - * allocation will be sampled every |sample_interval| bytes allocated. The - * |stack_depth| parameter controls the maximum number of stack frames to be - * captured on each allocation. - * - * NOTE: This is a proof-of-concept at this point. Right now we only sample - * newspace allocations. Support for paged space allocation (e.g. pre-tenured - * objects, large objects, code objects, etc.) and native allocations - * doesn't exist yet, but is anticipated in the future. - * - * Objects allocated before the sampling is started will not be included in - * the profile. - * - * Returns false if a sampling heap profiler is already running. - */ - bool StartSamplingHeapProfiler(uint64_t sample_interval = 512 * 1024, - int stack_depth = 16, - SamplingFlags flags = kSamplingNoFlags); - - /** - * Stops the sampling heap profile and discards the current profile. - */ - void StopSamplingHeapProfiler(); - - /** - * Returns the sampled profile of allocations allocated (and still live) since - * StartSamplingHeapProfiler was called. The ownership of the pointer is - * transferred to the caller. Returns nullptr if sampling heap profiler is not - * active. - */ - AllocationProfile* GetAllocationProfile(); - - /** - * Deletes all snapshots taken. All previously returned pointers to - * snapshots and their contents become invalid after this call. - */ - void DeleteAllHeapSnapshots(); - - void AddBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, - void* data); - void RemoveBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, - void* data); - - void SetGetDetachednessCallback(GetDetachednessCallback callback, void* data); - - /** - * Default value of persistent handle class ID. Must not be used to - * define a class. Can be used to reset a class of a persistent - * handle. - */ - static const uint16_t kPersistentHandleNoClassId = 0; - - private: - HeapProfiler(); - ~HeapProfiler(); - HeapProfiler(const HeapProfiler&); - HeapProfiler& operator=(const HeapProfiler&); -}; - -/** - * A struct for exporting HeapStats data from V8, using "push" model. - * See HeapProfiler::GetHeapStats. - */ -struct HeapStatsUpdate { - HeapStatsUpdate(uint32_t index, uint32_t count, uint32_t size) - : index(index), count(count), size(size) { } - uint32_t index; // Index of the time interval that was changed. - uint32_t count; // New value of count field for the interval with this index. - uint32_t size; // New value of size field for the interval with this index. -}; - -#define CODE_EVENTS_LIST(V) \ - V(Builtin) \ - V(Callback) \ - V(Eval) \ - V(Function) \ - V(InterpretedFunction) \ - V(Handler) \ - V(BytecodeHandler) \ - V(LazyCompile) \ - V(RegExp) \ - V(Script) \ - V(Stub) \ - V(Relocation) - -/** - * Note that this enum may be extended in the future. Please include a default - * case if this enum is used in a switch statement. - */ -enum CodeEventType { - kUnknownType = 0 -#define V(Name) , k##Name##Type - CODE_EVENTS_LIST(V) -#undef V -}; - -/** - * Representation of a code creation event - */ -class V8_EXPORT CodeEvent { - public: - uintptr_t GetCodeStartAddress(); - size_t GetCodeSize(); - Local GetFunctionName(); - Local GetScriptName(); - int GetScriptLine(); - int GetScriptColumn(); - /** - * NOTE (mmarchini): We can't allocate objects in the heap when we collect - * existing code, and both the code type and the comment are not stored in the - * heap, so we return those as const char*. - */ - CodeEventType GetCodeType(); - const char* GetComment(); - - static const char* GetCodeEventTypeName(CodeEventType code_event_type); - - uintptr_t GetPreviousCodeStartAddress(); -}; - -/** - * Interface to listen to code creation and code relocation events. - */ -class V8_EXPORT CodeEventHandler { - public: - /** - * Creates a new listener for the |isolate|. The isolate must be initialized. - * The listener object must be disposed after use by calling |Dispose| method. - * Multiple listeners can be created for the same isolate. - */ - explicit CodeEventHandler(Isolate* isolate); - virtual ~CodeEventHandler(); - - /** - * Handle is called every time a code object is created or moved. Information - * about each code event will be available through the `code_event` - * parameter. - * - * When the CodeEventType is kRelocationType, the code for this CodeEvent has - * moved from `GetPreviousCodeStartAddress()` to `GetCodeStartAddress()`. - */ - virtual void Handle(CodeEvent* code_event) = 0; - - /** - * Call `Enable()` to starts listening to code creation and code relocation - * events. These events will be handled by `Handle()`. - */ - void Enable(); - - /** - * Call `Disable()` to stop listening to code creation and code relocation - * events. - */ - void Disable(); - - private: - CodeEventHandler(); - CodeEventHandler(const CodeEventHandler&); - CodeEventHandler& operator=(const CodeEventHandler&); - void* internal_listener_; -}; - -} // namespace v8 - - -#endif // V8_V8_PROFILER_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-promise.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-promise.h deleted file mode 100644 index 9da8e4b4e86..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-promise.h +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PROMISE_H_ -#define INCLUDE_V8_PROMISE_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -#ifndef V8_PROMISE_INTERNAL_FIELD_COUNT -// The number of required internal fields can be defined by embedder. -#define V8_PROMISE_INTERNAL_FIELD_COUNT 0 -#endif - -/** - * An instance of the built-in Promise constructor (ES6 draft). - */ -class V8_EXPORT Promise : public Object { - public: - /** - * State of the promise. Each value corresponds to one of the possible values - * of the [[PromiseState]] field. - */ - enum PromiseState { kPending, kFulfilled, kRejected }; - - class V8_EXPORT Resolver : public Object { - public: - /** - * Create a new resolver, along with an associated promise in pending state. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal New( - Local context); - - /** - * Extract the associated promise. - */ - Local GetPromise(); - - /** - * Resolve/reject the associated promise with a given value. - * Ignored if the promise is no longer pending. - */ - V8_WARN_UNUSED_RESULT Maybe Resolve(Local context, - Local value); - - V8_WARN_UNUSED_RESULT Maybe Reject(Local context, - Local value); - - V8_INLINE static Resolver* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Resolver(); - static void CheckCast(Value* obj); - }; - - /** - * Register a resolution/rejection handler with a promise. - * The handler is given the respective resolution/rejection value as - * an argument. If the promise is already resolved/rejected, the handler is - * invoked at the end of turn. - */ - V8_WARN_UNUSED_RESULT MaybeLocal Catch(Local context, - Local handler); - - V8_WARN_UNUSED_RESULT MaybeLocal Then(Local context, - Local handler); - - V8_WARN_UNUSED_RESULT MaybeLocal Then(Local context, - Local on_fulfilled, - Local on_rejected); - - /** - * Returns true if the promise has at least one derived promise, and - * therefore resolve/reject handlers (including default handler). - */ - bool HasHandler() const; - - /** - * Returns the content of the [[PromiseResult]] field. The Promise must not - * be pending. - */ - Local Result(); - - /** - * Returns the value of the [[PromiseState]] field. - */ - PromiseState State(); - - /** - * Marks this promise as handled to avoid reporting unhandled rejections. - */ - void MarkAsHandled(); - - /** - * Marks this promise as silent to prevent pausing the debugger when the - * promise is rejected. - */ - void MarkAsSilent(); - - V8_INLINE static Promise* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - static const int kEmbedderFieldCount = V8_PROMISE_INTERNAL_FIELD_COUNT; - - private: - Promise(); - static void CheckCast(Value* obj); -}; - -/** - * PromiseHook with type kInit is called when a new promise is - * created. When a new promise is created as part of the chain in the - * case of Promise.then or in the intermediate promises created by - * Promise.{race, all}/AsyncFunctionAwait, we pass the parent promise - * otherwise we pass undefined. - * - * PromiseHook with type kResolve is called at the beginning of - * resolve or reject function defined by CreateResolvingFunctions. - * - * PromiseHook with type kBefore is called at the beginning of the - * PromiseReactionJob. - * - * PromiseHook with type kAfter is called right at the end of the - * PromiseReactionJob. - */ -enum class PromiseHookType { kInit, kResolve, kBefore, kAfter }; - -using PromiseHook = void (*)(PromiseHookType type, Local promise, - Local parent); - -// --- Promise Reject Callback --- -enum PromiseRejectEvent { - kPromiseRejectWithNoHandler = 0, - kPromiseHandlerAddedAfterReject = 1, - kPromiseRejectAfterResolved = 2, - kPromiseResolveAfterResolved = 3, -}; - -class PromiseRejectMessage { - public: - PromiseRejectMessage(Local promise, PromiseRejectEvent event, - Local value) - : promise_(promise), event_(event), value_(value) {} - - V8_INLINE Local GetPromise() const { return promise_; } - V8_INLINE PromiseRejectEvent GetEvent() const { return event_; } - V8_INLINE Local GetValue() const { return value_; } - - private: - Local promise_; - PromiseRejectEvent event_; - Local value_; -}; - -using PromiseRejectCallback = void (*)(PromiseRejectMessage message); - -} // namespace v8 - -#endif // INCLUDE_V8_PROMISE_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-proxy.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-proxy.h deleted file mode 100644 index a08db8805c6..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-proxy.h +++ /dev/null @@ -1,50 +0,0 @@ - -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_PROXY_H_ -#define INCLUDE_V8_PROXY_H_ - -#include "v8-context.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * An instance of the built-in Proxy constructor (ECMA-262, 6th Edition, - * 26.2.1). - */ -class V8_EXPORT Proxy : public Object { - public: - Local GetTarget(); - Local GetHandler(); - bool IsRevoked() const; - void Revoke(); - - /** - * Creates a new Proxy for the target object. - */ - static MaybeLocal New(Local context, - Local local_target, - Local local_handler); - - V8_INLINE static Proxy* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - Proxy(); - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_PROXY_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-regexp.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-regexp.h deleted file mode 100644 index 3791bc03687..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-regexp.h +++ /dev/null @@ -1,105 +0,0 @@ - -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_REGEXP_H_ -#define INCLUDE_V8_REGEXP_H_ - -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-object.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Context; - -/** - * An instance of the built-in RegExp constructor (ECMA-262, 15.10). - */ -class V8_EXPORT RegExp : public Object { - public: - /** - * Regular expression flag bits. They can be or'ed to enable a set - * of flags. - * The kLinear value ('l') is experimental and can only be used with - * --enable-experimental-regexp-engine. RegExps with kLinear flag are - * guaranteed to be executed in asymptotic linear time wrt. the length of - * the subject string. - */ - enum Flags { - kNone = 0, - kGlobal = 1 << 0, - kIgnoreCase = 1 << 1, - kMultiline = 1 << 2, - kSticky = 1 << 3, - kUnicode = 1 << 4, - kDotAll = 1 << 5, - kLinear = 1 << 6, - kHasIndices = 1 << 7, - }; - - static constexpr int kFlagCount = 8; - - /** - * Creates a regular expression from the given pattern string and - * the flags bit field. May throw a JavaScript exception as - * described in ECMA-262, 15.10.4.1. - * - * For example, - * RegExp::New(v8::String::New("foo"), - * static_cast(kGlobal | kMultiline)) - * is equivalent to evaluating "/foo/gm". - */ - static V8_WARN_UNUSED_RESULT MaybeLocal New(Local context, - Local pattern, - Flags flags); - - /** - * Like New, but additionally specifies a backtrack limit. If the number of - * backtracks done in one Exec call hits the limit, a match failure is - * immediately returned. - */ - static V8_WARN_UNUSED_RESULT MaybeLocal NewWithBacktrackLimit( - Local context, Local pattern, Flags flags, - uint32_t backtrack_limit); - - /** - * Executes the current RegExp instance on the given subject string. - * Equivalent to RegExp.prototype.exec as described in - * - * https://tc39.es/ecma262/#sec-regexp.prototype.exec - * - * On success, an Array containing the matched strings is returned. On - * failure, returns Null. - * - * Note: modifies global context state, accessible e.g. through RegExp.input. - */ - V8_WARN_UNUSED_RESULT MaybeLocal Exec(Local context, - Local subject); - - /** - * Returns the value of the source property: a string representing - * the regular expression. - */ - Local GetSource() const; - - /** - * Returns the flags bit field. - */ - Flags GetFlags() const; - - V8_INLINE static RegExp* Cast(Value* value) { -#ifdef V8_ENABLE_CHECKS - CheckCast(value); -#endif - return static_cast(value); - } - - private: - static void CheckCast(Value* obj); -}; - -} // namespace v8 - -#endif // INCLUDE_V8_REGEXP_H_ diff --git a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-script.h b/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-script.h deleted file mode 100644 index d17089932cc..00000000000 --- a/android/sdk/src/main/jni/third_party/v8/latest/official-release/include/v8/v8-script.h +++ /dev/null @@ -1,771 +0,0 @@ -// Copyright 2021 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef INCLUDE_V8_SCRIPT_H_ -#define INCLUDE_V8_SCRIPT_H_ - -#include -#include - -#include -#include - -#include "v8-data.h" // NOLINT(build/include_directory) -#include "v8-local-handle.h" // NOLINT(build/include_directory) -#include "v8-maybe.h" // NOLINT(build/include_directory) -#include "v8-message.h" // NOLINT(build/include_directory) -#include "v8config.h" // NOLINT(build/include_directory) - -namespace v8 { - -class Function; -class Object; -class PrimitiveArray; -class Script; - -namespace internal { -class BackgroundDeserializeTask; -struct ScriptStreamingData; -} // namespace internal - -/** - * A container type that holds relevant metadata for module loading. - * - * This is passed back to the embedder as part of - * HostImportModuleDynamicallyCallback for module loading. - */ -class V8_EXPORT ScriptOrModule { - public: - /** - * The name that was passed by the embedder as ResourceName to the - * ScriptOrigin. This can be either a v8::String or v8::Undefined. - */ - Local GetResourceName(); - - /** - * The options that were passed by the embedder as HostDefinedOptions to - * the ScriptOrigin. - */ - Local GetHostDefinedOptions(); -}; - -/** - * A compiled JavaScript script, not yet tied to a Context. - */ -class V8_EXPORT UnboundScript { - public: - /** - * Binds the script to the currently entered context. - */ - Local +``` + + > 特别说明,对 actions 替换后会重新创建动画,需手动启动新动画。有两种处理方式: + > + > * 替换 actions => 延迟一定时间(如setTimeout)后 或者在 `actionsDidUpdate` 勾子内 `(2.14.0 版本后支持)`,调用 `this.[animation ref].start()`(推荐) + > * 设置 `playing = false` => 替换 actions => 延迟一定时间(如setTimeout)后 或者在 `actionsDidUpdate` 勾子内 `(2.14.0 版本后支持)`,设置 `playing = true` + + > `2.6.0` 及以上版本支持 `backgroundColor` 背景色渐变动画,参考 [渐变色动画DEMO](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/animations/color-change.vue) + > + > * 设置 `actions` 对 `backgroundColor` 进行修饰 + > * 设置 `valueType` 为 `color` + > * 设置 `startValue` 和 `toValue` 为 [color值](api/style/color.md) + + > `2.12.2` 及以上版本支持循环播放参数 `repeatCount: 'loop'` 写法,低版本请使用 `repeatCount: -1` + +## 事件 + +| 参数 | 描述 | 类型 | 支持平台 | +| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | +| start | 动画开始时触发,最低支持版本 `2.5.2` | `Function` | `Android、iOS、Web-Renderer、Voltron` | +| end | 动画结束时触发,最低支持版本 `2.5.2` | `Function`| `Android、iOS、Web-Renderer、Voltron` | +| repeat | 每次循环播放时触发,最低支持版本 `2.5.2` | `Function` | `Android、Voltron` | +| actionsDidUpdate | 替换 actions 且动画对象创建成功后触发,可以在这个时机重新启动动画,最低支持版本 `2.14.0` | `Function` | `Android、iOS、Voltron` | + +## 方法 + +> 最低支持版本 2.5.2 + +### start + +`() => void` 手动触发动画开始(`playing`属性置为`true`也会自动触发`start`函数调用) + +### pause + +`() => void` 手动触发动画暂停(`playing`属性置为`false`也会自动触发`pause`函数调用) + +### resume + +`() => void` 手动触发动画继续(`playing`属性置为`false`后再置为`true`会自动触发`resume`函数调用) + +### create + +`() => void` 手动触发动画创建 + +### reset + +`() => void` 重置开始标记 + +### destroy + +`() => void` 销毁动画 + +--- + +# dialog + +[[范例:demo-dialog.vue]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/demo-dialog.vue) + +用于模态弹窗,默认透明背景色,需要加一个带背景色的 `
` 填充。 + +## 参数 + +| 参数 | 描述 | 类型 | 支持平台 | +| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | +| animationType | 动画效果 | `enum(none, slide, fade, slide_fade)` | `Android、iOS、Web-Renderer、Voltron` | +| supportedOrientations | 支持屏幕翻转方向 | `enum(portrait, portrait-upside-down, landscape, landscape-left, landscape-right)[]` | `iOS` | +| immersionStatusBar | 是否是沉浸式状态栏。`default: true` | `boolean` | `Android、Voltron` | +| darkStatusBarText | 是否是亮色主体文字,默认字体是黑色的,改成 true 后会认为 Modal 背景为暗色调,字体就会改成白色。 | `boolean` | `Android、iOS、Voltron` | +| autoHideStatusBar | 是否在`Modal`显示时自动隐藏状态栏。Android 中仅 api28 以上生效。 `default: false` | `boolean` | `Android` | +| autoHideNavigationBar | 是否在`Modal`显示时自动隐藏导航栏。 `default: false` | `boolean` | `Android` | + +| transparent | 背景是否是透明的。`default: true` | `boolean` | `Android、iOS、Web-Renderer、Voltron` | + +## 事件 + +| 事件名称 | 描述 | 类型 | 支持平台 | +| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | +| show | 在`Modal`显示时会执行此回调函数。 | `Function` | `Android、iOS、Web-Renderer、Voltron` | +| orientationChange | 屏幕旋转方向改变 | `Function` | `Android、iOS` | +| requestClose | 在 `Modal`请求关闭时会执行此回调函数,一般时在 Android 系统里按下硬件返回按钮时触发,一般要在里面处理关闭弹窗。 | `Function` | `Android、Voltron` | + +--- + +# swiper + +[[范例:demo-swiper.vue]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/demo-swiper.vue) + +支持翻页的容器,它的每一个子容器组件会被视作一个单独的页面,对应终端 `ViewPager`组件, 里面只能包含 `` 组件。 + +## 参数 + +| 参数 | 描述 | 类型 | 支持平台 | +| ------------------------ | ------------------------------------------------------------ | -------------------------------------------- | -------- | +| bounces | 是否开启回弹效果,默认 `true` | `boolean` | `iOS、Voltron` | +| current | 实时改变当前所处页码 | `number` | `Android、iOS、Web-Renderer、Voltron` | +| initialPage | 指定一个数字,用于决定初始化后默认显示的页面index,默认不指定的时候是0 | `number` | `Android、iOS、Web-Renderer、Voltron` | +| needAnimation | 切换页面时是否需要动画。 | `boolean` | `Android、iOS、Voltron` | +| scrollEnabled | 指定ViewPager是否可以滑动,默认为true | `boolean` | `Android、iOS、Web-Renderer、Voltron` | +| direction | 设置viewPager滚动方向,不设置默认横向滚动,设置 `vertical` 为竖向滚动 | `string` | `Android、Voltron` | + +## 事件 + +| 事件名称 | 描述 | 类型 | 支持平台 | +| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | +| dragging | 拖动时触发。 | `Function` | `Android、iOS、Web-Renderer、Voltron` | +| dropped | 拖拽松手时触发,就是确定了滚动的页面时触发。 | `Function` | `Android、iOS、Web-Renderer、Voltron` | +| stateChanged* | 手指行为发生改变时触发,包含了 idle、dragging、settling 三种状态,通过 state 参数返回 | `Function` | `Android、iOS、Web-Renderer、Voltron` | + +* stateChanged 三种值的意思: + * idle 空闲状态 + * dragging 拖拽中 + * settling 松手后触发,然后马上回到 idle + +--- + +# swiper-slide + +[[范例:demo-swiper.vue]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/demo-swiper.vue) + +翻页子容器组件容器。 + +--- + +# pull-header + +[[范例:demo-pull-header.vue]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/demo-pull-header-footer.vue) + +下拉刷新组件,嵌套在 `ul` 中作为第一个子元素使用 + +## 事件 + +| 事件名称 | 描述 | 类型 | 支持平台 | +| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | +| idle | 滑动距离在 pull-header 区域内触发一次,参数 contentOffset | `Function` | `Android、iOS、Voltron` | +| pulling | 滑动距离超出 pull-header 后触发一次,参数 contentOffset | `Function` | `Android、iOS、Voltron` | +| released | 滑动超出距离,松手后触发一次 | `Function` | `Android、iOS、Voltron` | + +## 方法 + +### collapsePullHeader + +`(otions: { time: number }) => void` 收起顶部刷新条 ``。当使用了 `pull-header` 后,每当下拉刷新结束需要主动调用该方法收回 pull-header。 + +> options 参数,最低支持版本 `2.14.0` +> +>* time: number: 可指定延迟多久后收起 PullHeader,单位ms + +--- + +# pull-footer + +[[范例:demo-pull-footer.vue]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/demo-pull-header-footer.vue) + +上拉刷新组件,嵌套在 `ul` 中作为最后一个子元素使用 + +## 事件 + +| 事件名称 | 描述 | 类型 | 支持平台 | +| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | +| idle | 滑动距离在 pull-footer 区域内触发一次,参数 contentOffset | `Function` | `Android、iOS、Voltron` | +| pulling | 滑动距离超出 pull-footer 后触发一次,参数 contentOffset | `Function` | `Android、iOS、Voltron` | +| released | 滑动超出距离松手后触发一次 | `Function` | `Android、iOS、Voltron` | + +## 方法 + +### collapsePullFooter + +`() => void` 收起底部刷新条 ``。 + +--- + +# waterfall + +> 最低支持版本 2.9.0 + +[[范例:demo-waterfall]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/demo-waterfall.vue) + +瀑布流组件,子元素必须是 `waterfall-item` ,瀑布流组件下拉刷新需在最外层用`ul-refresh-wrapper`, 可在`waterfall` 内用 `pull-footer` 展示上拉加载文案。 + +## 参数 + +| 参数 | 描述 | 类型 | 支持平台 | +| ----------------- | ----------------------------------------------------- | ---------- | -------- | +| columnSpacing | 瀑布流每列之前的水平间距 | `number` | `Android、iOS、Voltron` | +| interItemSpacing | item 间的垂直间距 | `number` | `Android、iOS、Voltron` | +| contentInset | 内容缩进 ,默认值 `{ top:0, left:0, bottom:0, right:0 }` | `Object` | `Android、iOS、Voltron` | +| containBannerView | 是否包含`bannerView`,只能有一个bannerView, (`Android` 暂不支持,`iOS` 3.3.2版本起已废弃该属性,请使用`waterfall-item`组件`isHeader/isFooter`属性代替) | `boolean` | `iOS、Voltron` | +| containPullHeader | 是否包含`pull-header`;`Android` 暂不支持,可以用 `ul-refresh` 组件替代 | `boolean` | `iOS、Voltron` | +| containPullFooter | 是否包含 `pull-footer` | `boolean` | `Android、iOS、Voltron` | +| numberOfColumns | 瀑布流列数量,Default: 2 | `number` | `Android、iOS、Voltron` | +| preloadItemNumber | 滑动到瀑布流底部前提前预加载的 item 数量 | `number` | `Android、iOS、Voltron` | +| showScrollIndicator | 是否显示滚动条。(iOS 3.3.2版本起支持) `default: true` | `boolean` | `iOS` | + +## 事件 + +| 事件名称 | 描述 | `类型` | 支持平台 | +| --------------------- | -------------- | ---------- | -------- | +| endReached | 当所有的数据都已经渲染过,并且列表被滚动到最后一条时,将触发 `onEndReached` 回调。 | `Function` | `Android、iOS、Voltron` | +| scroll | 当触发 `WaterFall` 的滑动事件时回调。`startEdgePos`表示距离 List 顶部边缘滚动偏移量;`endEdgePos`表示距离 List 底部边缘滚动偏移量;`firstVisibleRowIndex`表示当前可见区域内第一个元素的索引;`lastVisibleRowIndex`表示当前可见区域内最后一个元素的索引;`visibleRowFrames`表示当前可见区域内所有 item 的信息(x,y,width,height) | `{ nativeEvent: { startEdgePos: number, endEdgePos: number, firstVisibleRowIndex: number, lastVisibleRowIndex: number, visibleRowFrames: Object[] } }` | `Android、iOS、Voltron` | + +## 方法 + +### scrollToIndex + +`(obj: { index: number, animated: boolean }) => void` 通知 Waterfall 滑动到第几个 item。 + +> * `index`: number - 滑动到的第 index 个 item +> * `animated`: boolean - 滑动过程是否使用动画, 默认 `true` + +### scrollToContentOffset + +`(obj: { xOffset: number, yOffset: number, animated: boolean }) => void` 通知 Waterfall 滑动到某个具体坐标偏移值(offset)的位置。 + +> * `xOffset`: number - 滑动到 X 方向的 offset +> * `yOffset`: number - 滑动到 Y 方向的 offset +> * `animated`: boolean - 滑动过程是否使用动画,默认 `true` + +--- + +# waterfall-item + +> 最低支持版本 2.9.0 + +瀑布流组件 Cell 容器,瀑布流子元素 + +| 参数 | 描述 | 类型 | 支持平台 | +| --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- |------------------------| +| type | 指定一个函数,在其中返回对应条目的类型(返回Number类型的自然数,默认是0),List 将对同类型条目进行复用,所以合理的类型拆分,可以很好地提升 List 性能。 | `number` | `Android、iOS、Voltron` | +| key | 指定一个函数,在其中返回对应条目的 Key 值,详见 [Vue 官网](//vuejs.org/v2/guide/list.html) | `string` | `Android、iOS、Voltron` | +| isHeader | 指定该Item是否为Header(即bannerView,显示在内容区顶部) | `boolean` | `iOS`(3.3.2版本起支持)、Ohos | +| isFooter | 指定该Item是否为Footer(显示在内容区底部) | `boolean` | `iOS`(3.3.2版本起支持)、Ohos | diff --git a/docs/api/hippy-vue/feedback.md b/docs/api/hippy-vue/feedback.md new file mode 100644 index 00000000000..f346e07efbe --- /dev/null +++ b/docs/api/hippy-vue/feedback.md @@ -0,0 +1,28 @@ +# Hippy-Vue 常见反馈 + +## 1. 如何开始一个hippy vue 项目 + +可以先参考我们的文档 和 demo + +https://hippyjs.org/#/hippy-vue/introduction +https://github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo + +## 2. Hippy Vue中span的换行符会被 trim + +3.x hippy-vue的版本,Hippy默认开启了 Vue.config.trimWhitespace 这个参数。而 hippy-vue 2.x的版本是不开的, 这个也是为了和未来 vue3 版本的规划对齐 +https://github.com/vuejs/core/pull/1600 + +方案建议: +a. 在 hippy.js 文件加一句 Vue.config.trimWhitespace = false,这样配置就和安卓版本完全对齐了。这个参数会对产物有一些影响,也可以让你们前端同事再重新评估一下。 + +b. 因为现在 hippy 没有提供换行组件 br标签 或者 white-space 的 css,如果需要换行,则不适用span,而是重新创建一个 text文本组件 + +## 3. hippy-vue-next-style-parser,这个包的作用 + +这个包用于处理 vue-next 的 css parse 和 match 逻辑 + +## 4. Hippy 是否支持 Vite 构建 + +已支持,目前只有腾讯内部版,腾讯业务可联系 端框架小助手 + + diff --git a/docs/api/hippy-vue/introduction.md b/docs/api/hippy-vue/introduction.md new file mode 100644 index 00000000000..b4d3e1dfd84 --- /dev/null +++ b/docs/api/hippy-vue/introduction.md @@ -0,0 +1,39 @@ + +# hippy-vue 介绍 + +hippy-vue 基于官方 Vue 2.x 源代码,通过改写 [node-ops](//github.com/Tencent/Hippy/blob/master/packages/hippy-vue/src/runtime/node-ops.js) 外挂实现自定义渲染层,但不仅仅是个到终端的渲染层,还同时实现前端组件到终端的映射、CSS 语法解析。和其它跨端框架不同,它尽力将 Web 端的开发体验带到终端上来,同时保持了对 Web 生态的兼容。 + +--- + +# 架构图 + +hippy-vue 架构图 +
+
+ +# 初始化 + +```javascript +import Vue from '@hippy/vue'; +import App from './app.vue'; +const app = new Vue({ + // 终端指定的 App 名称 + appName: 'Demo', + rootView: '#root', + // 渲染入口 + render: h => h(App), +}); + +/** + * $start 是 Hippy 启动完以后触发的回调 + * @param {Function} callback - 引擎加载成功后回调函数 + * @param {Object} instance - 业务vue实例对象 + * @param {Object} initialProps - 终端给前端的初始化参数,终端可以将一些启动需要的自定义属性放到入口文件里 + */ +app.$start((instance, initialProps) => { + console.log('instance', instance, 'initialProps', initialProps); +}); + +// 如果需要在首个 View 渲染时就获取到 initialProps,可以通过直接读取 app.$options.$superProps + +``` diff --git a/docs/api/hippy-vue/native-event.md b/docs/api/hippy-vue/native-event.md new file mode 100644 index 00000000000..ce5a637f129 --- /dev/null +++ b/docs/api/hippy-vue/native-event.md @@ -0,0 +1,88 @@ +# 事件 + +有一些事件不是发给单个 UI,而是发给整个业务的,例如屏幕的翻转、网络的变化等等,我们称之它为 `终端事件`。 + +Hippy 提供了两种方式来管理全局事件: + ++ `Hippy.on`、`Hippy.off`、`Hippy.emit` 是框架无关的全局事件 EventBus,主要用来监听如 `dealloc`、`destroyInstance` 等特殊 C++ 底层事件,也可以手动定制 JS 内的全局事件。 + ++ `app.$on`、`app.$off`、`app.$emit` 是 Vue 定制的 EventBus,除了可以手动定制 JS 内的全局事件外,所有全局 `NativeEvent` 都由其来分发,如 `rotate` 事件等。 + +--- + +# 事件监听器 + +这里监听 rotate 的事件,里面有回调参数 result。 + +```js +// 将入口文件中 setApp() 时保存的 Vue 实例取出来。 +const app = getApp(); + +export default { + method: { + listener(rsp) { + console.log(rsp.result); + } + }, + mounted() { + // 通过 app 监听 rotate 事件,并通过 this.listener 在事件发生时触发回调。 + app.$on('rotate', this.listener); + } +} + +``` + +# 事件触发 + +如果需要手动发送事件,可以通过 `app.$emit` 触发。 + +```js +const app = getApp(); +app.$emit('rotate', { width: 100, height: 100 }); +``` + +# 事件卸载 + +如果不需要使用的时候记得调用一下移除监听的方法,一般放在组件的卸载生命周期中执行。 + +```js +const app = getApp(); +app.$off('rotate', this.listener); +``` + +# JS 引擎销毁事件 + +`最低支持版本 2.3.4` + +当 hippy js 引擎被销毁前会触发该事件,能够保证回调函数里的最后一句 js 代码被执行到,hippy 业务可以通过监听 `dealloc` 事件做一些离开时的操作,但回调函数不能使用 `async` + +```jsx +Hippy.on('dealloc', () => { + // do something +}); +``` + +# 界面节点销毁事件 + +`最低支持版本 2.3.4` + +当 RootView 被卸载时调用该事件,与 `dealloc` 不同的是该事件早于 `dealloc` 触发,但不会阻塞 JS 线程。 + +```jsx +Hippy.on('destroyInstance', () => { + // do something +}); +``` + +# 容器大小改变事件 + +!> iOS 最低支持版本 `2.16.0` + +当容器大小改变时,如屏幕旋转、折叠屏切换等,会触发该事件 + +```jsx +app.$on('onSizeChanged', ({rootViewId, oldWidth, oldHeight, width, height}) => { + // rootViewId: root view id; oldWidth: 旧的宽度;oldHeight: 旧的高度;width: 新的宽度; height: 新的高度; + console.log('size', rootViewId, oldWidth, oldHeight, width, height); +}); +``` diff --git a/docs/hippy-vue/router.md b/docs/api/hippy-vue/router.md similarity index 100% rename from docs/hippy-vue/router.md rename to docs/api/hippy-vue/router.md diff --git a/docs/api/hippy-vue/style.md b/docs/api/hippy-vue/style.md new file mode 100644 index 00000000000..93758bb6657 --- /dev/null +++ b/docs/api/hippy-vue/style.md @@ -0,0 +1,47 @@ +# 样式 + +标准 Hippy 中长度单位是不允许带有单位,不过为了和浏览器保持兼容,hippy-vue 采取了 1px = 1pt 的方案进行换算,把 CSS 单位中的 px 直接去掉变成了 Hippy 中不带单位的数字。 + +HippyVue 提供了 `beforeLoadStyle` 的 Vue options 勾子函数,供开发者做定制化修改 CSS 样式,如 + +```js + new Vue({ + // ... + beforeLoadStyle(decl) { + let { type, property, value } = decl; + console.log('property|value', property, value); // => height, 1rem + // 比如可以对 rem 单位进行处理 + if(typeof value === 'string' && /rem$/.test(value)) { + // ...value = xxx + } + return { ...decl, value} + } + }); +``` + +beforeLoadStyle 默认是对全局节点生效的,针对不需要执行 beforeLoadStyle 的节点,可以对节点设置属性 beforeLoadStyleDisabled。 +对于所有节点(如 div、p、button等均可使用) + +```js +
+
+``` + +# CSS 选择器 + +目前已经实现了基本的 `Universal`、`Type`、`ID`、`Class`、`Grouping` 选择器,而且可以支持除兄弟组合器以外的基本组合关系。 + +## Scoped & Attribute + +> `2.15.0` 版本增加支持 Vue `scoped` 样式能力, `2.15.2` 支持子组件根元素样式合并 + +> `2.15.1` 版本增加支持 `Attribute` 选择器和 Vue `deep` 深度选择器 + +如何开启? + +1. 升级 `@hippy/vue` 和 `@hippy/vue-css-loader` 到 `2.15.1+` 版本 +2. Vue2.0 设置全局开关 `Vue.config.scoped = true;`(Vue2.0 默认 `scoped` 和 `Attribute` 选择器能力关闭,Vue3.0 默认开启无需设置开关) + + + diff --git a/docs/api/hippy-vue/vue-native.md b/docs/api/hippy-vue/vue-native.md new file mode 100644 index 00000000000..d5bca3599d3 --- /dev/null +++ b/docs/api/hippy-vue/vue-native.md @@ -0,0 +1,404 @@ + + +# 模块 + +hippy-vue 通过在 Vue 上绑定了一个 `Native` 属性,实现获取终端设备信息、以及调用终端模块。也可以用来监测是否在 Hippy 环境下运行。 + +> 对应 Demo: [demo-vue-native.vue](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/native-demos/demo-vue-native.vue) + +--- + +# 获取终端信息 + +它无需任何方法,直接取值即可。 + +## version + +获取 hippy-vue 的版本 + +* 示例 + +```javascript +console.log(Vue.Native.version); // => 2.0.0 +``` + +## Device + +获取设备名称,iPhone 可以拿到具体的 iPhone 型号,Android 设备暂时只能拿到 `Android device`的文本。 + +## OSVersion + +iOS 版本。 + +## APILevel + +Android 操作系统版本。 + +## SDKVersion + +Hippy 终端 SDK 版本。 + +## Platform + +获取操作系统类型。 + +* 示例 + +```javascript +console.log(Vue.Native.Platform); // => android +``` + +## Dimensions + +获取屏幕分辨率。 + +* 示例 + +```javascript +const { window, screen } = Vue.Native.Dimensions; +console.log(`屏幕尺寸:${screen.height}x${screen.width}`); // => 640x480 +console.log(`带状态栏的窗口尺寸:${window.height}x${window.width}`); // => 640x460 +``` + +## PixelRatio + +获取设备像素比例。 + +* 示例 + +```javascript +console.log(Vue.Native.PixelRatio); // => 3 +``` + +## isIPhoneX + +获取是否是异形屏幕的 iPhoneX。 + +## screenIsVertical + +屏幕是否切换成横屏。 + +## OnePixel + +一个像素的 dp/pt 值。 + +## Localization + +>* 最低支持版本 2.8.0 + +输出国际化相关信息,`object: { country: string , language: string, direction: number }`, 其中 `direction` 为 0 表示 LTR 方向,1 表示 RTL 方向 + +--- + +# AsyncStorage + +>* 最低支持版本 2.7.0 +>* AsyncStorage 能力与挂载在全局变量下的 localStorage 模块一致,localStorage 可以在所有版本使用 + +[[AsyncStorage 范例(与Hippy-React AsyncStorage 一致)]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/modules/AsyncStorage/index.jsx) + +AsyncStorage 是一个简单的、异步的、持久化的 Key-Value 存储系统。 + +* 示例: + +``` js +Vue.Native.AsyncStorage.setItem('itemKey', 'itemValue'); +Vue.Native.AsyncStorage.getItem('itemKey'); +``` + +## 方法 + +### AsyncStorage.getAllKeys + +`() => Promise` 获取 AsyncStorage 所有的key。 + +### AsyncStorage.getItem + +`(key: string) => Promise` 根据 key 值获取对应数据。 + +> * key: string - 需要获取值的目标 key + +### AsyncStorage.multiGet + +`(key: string[]) => Promise<[key: string, value: string][]>` 一次性用多个 key 值的数组去批量请求缓存数据,返回值将在回调函数以键值对的二维数组形式返回。 + +> * key: string[] - 需要获取值的目标 key 数组 + +### AsyncStorage.multiRemove + +`(key: string[]) => void` 调用此函数批量删除 AsyncStorage 里面在传入的 keys 数组存在的 key 值。 + +> * key: string[] - 需要删除的目标 key 数组 + +### AsyncStorage.multiSet + +`(keyValuePairs: [key: string, value: string][]) => void` 调用这个函数可以批量存储键值对对象。 + +> * keyValuePairs: [key: string, value: string][] - 需要设置的储键值二维数组 + +### AsyncStorage.removeItem + +`(key: string) => void` 根据 key 值删除对应数据。 + +> * key: string - 需要删除的目标 key + +### AsyncStorage.setItem + +`(key: string, value: string) => void` 根据 key 和 value 设置保存键值对。 + +> * key: string - 需要获取值的目标 key +> * value: string - 需要获取值的目标值 + +--- + +# BackAndroid + +[[BackAndroid 范例]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/main-native.js) + +可以监听 Android 实体键的回退,在退出前做操作或拦截实体键的回退。 + +>* 最低支持版本 2.7.0 +>* 注意:该方法需要终端拦截实体返回按钮的事件,可以参考 [android-demo 的 onBackPressed 方法](//github.com/Tencent/Hippy/blob/v3.0-dev/framework/examples/android-demo/src/main/java/com/openhippy/example/PageConfiguration.kt) + +## 方法 + +### BackAndroid.addListener + +`(handler: () => boolean) => { remove: Function }` 监听Android实体健回退,触发时执行 handler 回调函数。回调函数返回 true 时,拦截终端的回退操作;回调函数返回 false 时, 就不会拦截回退。该方法会返回包含 `remove()` 方法的对象,可通过调用 `remove()` 方法移除监听,同 `BackAndroid.removeListener`。 + +> * handler: Function - 实体键回退时触发的回调函数 + +### BackAndroid.exitApp + +`() => void`直接执行终端的退出 App 逻辑。 + +### BackAndroid.removeListener + +`(handler: () => boolean) => void` 移除 BackAndroid 关于Android实体健回退事件的监听器。 + +* handler: Function - 建议使用 `addListener` 返回的包含 `remove()` 方法的对象,也可以是之前 BackAndroid 的回调函数。 + +--- + +# callNative/callNativeWithPromise + +调用终端模块的方法,`callNative` 一般用于无返回的模块方法调用,`callNativeWithPromise` 一般用于有返回的模块方法调用,它会返回一个带着结果的 Promise。 + +# callUIFunction + +调用组件定义的终端方法 + +`callUIFunction(instance: ref, method: string, options: Array)` + +> * instance: 组件的引用 Ref +> * method:方法名称,如 ListView 的 `scrollToIndex` +> * options: 需传递的数据,如 ListView 的 `[xIndex, yIndex, animated]` + +注: 也可以传入 callback 参数,这个是 Hippy 内部 API, 不推荐使用,源码可参考: + +[callUIFunction接口实现源码](https://github.com/Tencent/Hippy/blob/main/driver/js/packages/hippy-vue/src/runtime/native.ts) + +--- + +# Clipboard + +剪贴板读写模块,但是目前只支持纯文本。 + +## 方法 + +### getString() + +返回值: + +* string + +### setString(content) + +| 参数 | 类型 | 必需 | 参数意义 | +| -------- | -------- | -------- | -------- | +| content | string | 是 | 保存进入剪贴板的内容 | + +--- + +# ConsoleModule + +> 最低支持版本 2.10.0 + +提供了将前端日志输出到 iOS 终端日志和 [Android logcat](//developer.android.com/studio/command-line/logcat) 的能力 + +## 方法 + +### ConsoleModule.log + +`(...value: string) => void` + +### ConsoleModule.info + +`(...value: string) => void` + +### ConsoleModule.warn + +`(...value: string) => void` + +### ConsoleModule.error + +`(...value: string) => void` + +> * `log` 和 `info` 默认都输出为终端 INFO 级别日志 +> * Hippy 2.10.0 版本之后将原始 js 的 `console` 方法与 `ConsoleModule` 方法进行分离,`console` 不再输出日志到终端 + +--- + +# Cookie + +Hippy 中通过 fetch 服务返回的 `set-cookie` Header 会自动将 Cookie 保存起来,下次再发出请求的时候就会带上,业务可以获取或者修改保存好的 Cookie。 + +## 方法 + +### getAll(url) + +| 参数 | 类型 | 必需 | 参数意义 | +| -------- | -------- | -------- | -------- | +| url | string | 是 | 获取指定 url 下的所有 cookies,`2.14.0` 版本后过期的 Cookies 将不再返回。 | + +返回值: + +* `Prmoise`,获取到诸如 `name=hippy;network=mobile` 的字符串。 + +### set(url, keyValue, expireDate) + +参数: + +| 参数 | 类型 | 必需 | 参数意义 | +| -------- | -------- | -------- | -------- | +| url | string | 是 | 设置指定 URL 下设置的 cookie | +| keyValue | string | 是 | 需要设置成 cookie 的完整字符串,例如 `name=hippy;network=mobile`,`2.14.0` 版本后设置 `空字符串` 会强制清除(过期)指定域名下的所有 Cookies | +| expireDate | Date | 否 | Date 类型的过期时间,不填不过期, 内部会通过 `toUTCString` 转成 `String` 传给客户端 | + +--- + +# getElemCss + +获取具体节点的 CSS 样式。 + +> 最低支持版本 `2.10.1` + +`(ref: ElementNode) => {}` + +* 示例: + +```js +this.demon1Point = this.$refs['demo-1-point']; +console.log(Vue.Native.getElemCss(this.demon1Point)) // => { height: 80, left: 0, position: "absolute" } +``` + +--- + +# ImageLoader + +通过该模块可以对远程图片进行相应操作 + +> 最低支持版本 `2.7.0` + +## 方法 + +### ImageLoader.getSize + +`(url: string) => Promise<{width, height}>` 获取图片大小(会同时预加载图片)。 + +> * url - 图片地址 + +### ImageLoader.prefetch + +`(url: string) => void` 用于预加载图片。 + +> * url - 图片地址 + +--- + +# measureInAppWindow + +> 最低支持版本 `2.11.0` + +测量在 App 窗口范围内某个组件的尺寸和位置,注意需要保证节点实例真正上屏后(layout事件后)才能调用该方法。 + +`(ref) => Promise<{top: number, left: number, right: number, bottom: number, width: number, height: number}>` + +> * Promise resolve 的参数可以获取到引用组件在 App 窗口范围内的坐标值和宽高,如果出错或 [节点被优化(仅在Android)](api/style/layout?id=collapsable) 会返回 { top: -1, left: -1, right: -1, bottom: -1, width: -1, height: -1 } + +--- + +# getBoundingClientRect + +> 最低支持版本 `2.15.3`,原有 `measureInWindow` 和 `measureInAppWindow` 将逐渐废弃 + +测量元素在宿主容器(RootView)或者 App 窗口(屏幕)范围内的尺寸和位置。 + +`(instance: ref, options: { relToContainer: boolean }) => Promise` + +> * instance: 元素或组件的引用 Ref。 +> * options: 可选参数,`relToContainer` 表示是否相对宿主容器(RootView)进行测量,默认 `false` 相对 App 窗口或屏幕进行测量。当对宿主容器(RootView)进行测量时,`iOS` 包含顶部状态栏高度,`Android` 不包含。 +> * DOMRect: 与 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect) 一致的返回参数, 可以获取元素相应的位置信息和尺寸,如果出错或者 [节点被优化(仅在Android)](api/style/layout?id=collapsable),会触发 `Promise.reject`。 + +--- + +# NetInfo + +通过该接口可以获得当前设备的网络状态;也可以注册一个监听器,当系统网络切换的时候,得到网络变化通知。 + +> 最低支持版本 `2.7.0` + +安卓的开发者,在请求网络状态之前,你需要在app的 `AndroidManifest.xml` 加入以下配置 : + +```xml + +``` + +## 网络状态 + +以异步的方式判断设备是否联网,以及是否使用了移动数据网络。 + +* `NONE` - 设备处于离线状态。 +* `WIFI` - 设备通过wifi联网 +* `CELL` - 设备通过移动网络联网 +* `UNKNOWN` - 出现异常或联网状态不可知 + +## 方法 + +### NetInfo.addEventListener + +`(eventName: string, handler: Function) => NetInfoRevoker` 添加一个网络变化监听器。 + +> * eventName: 'change' - 事件名称 +> * handler: ({ network_info:string }) => any - 网络发生变化时触发的回调函数 + +### NetInfo.fetch + +`() => Promise` 用于获取当前的网络状态。 + +### NetInfo.removeEventListener + +`(eventName: string, handler: NetInfoRevoker | Function) => void` 移除事件监听器 + +> * eventName: 'change' - 事件名称 +> * handler: Function - 需要删除的对应事件监听。 + +--- + +# parseColor + +色值类型转换,通过该 API 获取终端可识别的 `int32` 类型色值。可应用于与终端直接通讯(如 `callNative`) 时的接口传参。 + +| 参数 | 类型 | 必需 | 参数意义 | +| -------- | -------- | -------- | -------- | +| color | `string` `number` | 是 | 转换的色值,支持类型:`rgb`,`rgba`, `hex` | + +返回值: + +* `number`: 返回值为终端可识别的 `int32Color` + +* 示例: + +``` js +const int32Color = Vue.Native.parseColor('#40b883') // int32Color: 4282431619 +``` diff --git a/docs/api/hippy-vue/vue3.md b/docs/api/hippy-vue/vue3.md new file mode 100644 index 00000000000..4443e269301 --- /dev/null +++ b/docs/api/hippy-vue/vue3.md @@ -0,0 +1,427 @@ +# Hippy-Vue-Next (基于Vue3) + +
+ +# 介绍 + +@hippy/vue-next 基于 @hippy/vue 的已有逻辑。通过 Vue3.x 提供的 [createRenderer()](//github.com/vuejs/vue-next/blob/v3.0.0-alpha.0/packages/runtime-core/src/renderer.ts#L154),无需侵入 Vue 代码直接通过外部库的方式引用 Vue, +可以及时跟随 Vue 生态,在实现原理上与 @hippy/vue 基本一致。 + +@hippy/vue-next 全部代码采用 typescript 进行编写,可以拥有更好的程序健壮性和类型提示,并且 @hippy/vue-next 在整体架构上也进行了一定程度的优化。 + +# 架构图 + +hippy-vue-next 架构图 +
+
+ +# 如何使用 + +@hippy/vue-next 支持的能力与 @hippy/vue 基本一致。因此关于 Hippy-Vue 的组件、模块、样式等就不做额外声明了,可以直接参考 [Hippy-Vue](api/hippy-vue/introduction) +中的相关内容,本文档仅对差异部分进行说明: + +## 初始化 + +```javascript +// app.ts +import { defineComponent, ref } from 'vue'; +import { type HippyApp, createApp } from '@hippy/vue-next'; + +// 创建 Hippy App 实例,需要注意 Vue3.x 使用 Typescript,因此需要使用 defineComponent 将组件对象进行包裹 +const app: HippyApp = createApp(defineComponent({ + setup() { + const counter = ref(0); + return { + counter, + } + } +}), { + // Hippy App Name 必传,示例项目可以使用 Demo + appName: 'Demo', +}); + +// 启动 Hippy App +app.$start().then(({ superProps, rootViewId }) => { + // superProps 是 Native 传入的初始化参数,如果需要做路由预处理等操作,则可以让 Native 将对应参数传入 + // rootViewId 是 Native 当前 Hippy 实例所挂载的 Native 的根节点的 id + // mount app,完成渲染上屏 + app.mount('#mount'); +}) +``` + +如果要使用 Vue-Router,则需要使用另外的初始化逻辑 + +```javascript +// Vue + Vue Router + +// app.vue + + + +// index.vue + + + +// app.ts +import { defineComponent, ref } from 'vue'; +import { type HippyApp, createApp } from '@hippy/vue-next'; +import { createHippyRouter } from '@hippy/vue-router-next-history'; +import { type Router } from 'vue-router'; +import App from 'app.vue'; + +// 创建 Hippy App 实例,需要注意 Vue3.x 使用 Typescript,因此需要使用 defineComponent 将组件对象进行包裹 +const app: HippyApp = createApp(App, { + // Hippy App Name,必传,示例项目可以使用 Demo + appName: 'Demo', +}); + +// 路由列表 +const routes = [ + { + path: '/', + component: Index, + }, +]; + +// 创建路由对象 +const router: Router = createHippyRouter({ + routes, +}); + +// 使用路由 +app.use(router); + +// 启动 Hippy App +app.$start().then(({ superProps, rootViewId }) => { + // superProps 是 Native 传入的初始化参数,如果需要做路由预处理等操作,则可以让 Native 将对应参数传入 + // rootViewId 是 Native 当前 Hippy 实例所挂载的 Native 的跟节点的 id + + // 因为现在使用的是vue-router的memory history,因此需要手动推送初始位置,否则router将无法ready + // 浏览器上则是由vue-router根据location.href去匹配,默认推送根路径'/',如果想要实现类似浏览器中默认跳转到指定页面,可以让终端同学将初始化的 path + // 从 superProps 中传入,然后再通过 path 的值去进行 router.push({ path: 'other path' }) 等操作 + router.push('/'); + + // mount app,完成渲染上屏 + app.mount('#mount'); +}) +``` + +> @hippy/vue-router-next-history 对 vue-router 的 history 模式做了处理,为 Android 加上了触发物理返回键时优先回退历史记录的逻辑 + +如果不需要这个逻辑,可以直接使用原生 vue-router 来实现路由: + +```javascript +import { createRouter, createMemoryHistory, type Router } from 'vue-router'; + +// 路由列表 +const routes = [ + { + path: '/', + component: Index, + }, +]; + +const router: Router = createRouter({ + history: createMemoryHistory(), + routes, +}); +``` + +# 服务端渲染 + +@hippy/vue-next 现已支持服务端渲染,具体代码可以查看[示例项目](https://github.com/Tencent/Hippy/tree/main/examples/hippy-vue-next-ssr-demo)中的 SSR +部分,关于 Vue SSR 的实现及原理,可以参考[官方文档](https://cn.vuejs.org/guide/scaling-up/ssr.html)。 + +## 如何使用SSR + +请参考[示例项目](https://github.com/Tencent/Hippy/tree/main/examples/hippy-vue-next-ssr-demo)说明文档中的 How To Use SSR + +## 实现原理 + +### SSR 架构图 + +hippy-vue-next SSR 架构图 + +### 详细说明 + +@hippy/vue-next SSR 的实现涉及到了编译时,客户端运行时,以及服务端运行时三个运行环境。在 vue-next ssr的基础上,我们开发了 @hippy/vue-next-server-renderer +用于服务端运行时节点的渲染,开发了 @hippy/vue-next-compiler-ssr 用于编译时 vue 模版文件的编译。以及 @hippy/vue-next-style-parser 用于服务端渲染得到的 +Native Node List 的样式插入。下面我们通过一个模版的编译和运行时过程来说明 @hippy/vue-next SSR 做了哪些事情 + +我们有形如`
`的一段模版 + +- 编译时 + + 模版经过 @hippy/vue-next-compiler-ssr 的处理,得到了形如 + + ```javascript + _push(`{"id":${ssrGetUniqueId()},"index":0,"name":"View","tagName":"div","props":{"class":"test-class","id": "test",},"children":[]},`) + ``` + + 的 render function + +- 服务端运行时 + + 在服务端运行时,编译时得到的 render function 执行后得到了对应节点的 json object。注意 render function 中的 + ssrGetUniqueId 方法,是在 @hippy/vue-next-server-renderer 中提供的,在这里 server-renderer 还会对 + 节点的属性值等进行处理,最后得到 Native Node 的 json object + + ```javascript + { "id":1,"index":0,"name":"View","tagName":"div","props":{"class":"test-class","id": "test",},"children":[] } + ``` + + > 对于手写的非 sfc 模版的渲染函数,在 compiler 中无法处理,也是在 server-renderer 中执行的 + +- 客户端运行时 + + 在客户端运行时,通过 @hippy/vue-next-style-parser,给服务端返回的节点插入样式,并直接调用 hippy native 提供的 + native API,将返回的 Native Node 对象作为参数传入,并完成节点的渲染上屏。 完成节点上屏之后,再通过系统提供的 + global.dynamicLoad 异步加载客户端异步版 jsBundle,完成客户端 Hydrate 并执行后续流程。 + +## 初始化差异 + +SSR 版本的 Demo 初始化与异步版的初始化有一些差异部分,这里对其中的差异部分做一个详细的说明 + +- src/main-native.ts 变更 + +1. 使用 createSSRApp 替换之前的 createApp,createApp 仅支持 CSR 渲染,而 createSSRApp 同时支持 CSR 和 SSR +2. 在初始化时候新增了 ssrNodeList 参数,作为 Hydrate 的初始化节点列表。这里我们服务端返回的初始化节点列表保存在了 global.hippySSRNodes 中,并将其作为参数在createSSRApp时传入 +3. 将 app.mount 放到 router.isReady 完成后调用,因为如果不等待路由完成,会与服务端渲染的节点有所不同,导致 Hydrate 时报错 + +```javascript +- import { createApp } from '@hippy/vue-next'; ++ import { createSSRApp } from '@hippy/vue-next'; +- const app: HippyApp = createApp(App, { ++ const app: HippyApp = createSSRApp(App, { + // ssr rendered node list, use for hydration ++ ssrNodeList: global.hippySSRNodes, +}); ++ router.isReady().then(() => { ++ // mount app ++ app.mount('#root'); ++ }); +``` + +- src/main-server.ts 新增 + +main-server.ts 是在服务端运行的业务 jsBundle,因此不需要做代码分割。整体构建为一个 bundle 即可。其核心功能就是在服务端完成首屏渲染逻辑,并将得到的首屏 Hippy 节点进行处理,插入节点属性和 store(如果存在)后返回, +以及返回当前已生成节点的最大 uniqueId 供客户端后续使用。 + +>注意,服务端代码是同步执行的,如果有数据请求走了异步方式,可能会出现还没有拿到数据,请求就已经返回了的情况。对于这个问题,Vue SSR 提供了专用 API 来处理这个问题: +>[onServerPrefetch](https://cn.vuejs.org/api/composition-api-lifecycle.html#onserverprefetch)。 +>在 [Demo](https://github.com/Tencent/Hippy/blob/main/examples/hippy-vue-next-ssr-demo/src/app.vue) 的 app.vue 中也有 onServerPrefetch 的使用示例 + +- server.ts 新增 + +server.ts 是服务端执行的入口文件,其作用是提供 Web Server,接收客户端的 SSR CGI 请求,并将结果作为响应数据返回给客户端,包括了渲染节点列表,store,以及全局的样式列表。 + +- src/main-client.ts 新增 + +main-client.ts 是客户端执行的入口文件,与之前纯客户端渲染不同,SSR的客户端入口文件仅包含了获取首屏节点请求、插入首屏节点样式、以及将节点插入终端完成渲染的相关逻辑。 + +- src/ssr-node-ops.ts 新增 + +ssr-node-ops.ts 封装了不依赖 @hippy/vue-next 运行时的 SSR 节点的插入,更新,删除等操作逻辑 + +- src/webpack-plugin.ts 新增 + +webpack-plugin.ts 封装了 SSR 渲染所需 Hippy App 的初始化逻辑 + +# 其他差异说明 + +目前 `@hippy/vue-next` 与 `@hippy/vue` 功能上基本对齐,不过在 API 方面与 @hippy/vue 有一些区别,以及还有一些问题还没有解决,这里做些说明: + +- Vue.Native + + 在 @hippy/vue 中,Native 提供的能力是通过挂载在全局 Vue 对象的 Native 属性来提供的,在 Vue3.x 中这种实现方式不再可行,因此现在 Native 属性需通过 @hippy/vue-next 导出来使用 + + ```javascript + import { Native } from '@hippy/vue-next'; + + console.log('do somethig', Native.xxx) + ``` + +- registerElement + + @hippy/vue 中 `registerElement` 方法是挂在全局 Vue 中,与 Native 类似,@hippy/vue-next 中 `registerElement` 方法也是单独提供了导出 + + ```javascript + import { registerElement } from '@hippy/vue-next'; + ``` + +- 全局事件 + + 在 @hippy/vue 中,全局事件是挂载在 Vue 上的,在 @hippy/vue-next 中,提供了单独的 `EventBus` 事件总线来处理该问题 + + ```javascript + import { EventBus } from '@hippy/vue-next'; + + // 监听容器大小改变事件 + EventBus.$on('onSizeChanged', ({ oldWidth, oldHeight, width, height }) => { + // oldWidth: 旧的宽度;oldHeight: 旧的高度;width: 新的宽度; height: 新的高度 + console.log('size', oldWidth, oldHeight, width, height); + }); + // 触发全局事件 + EventBus.$emit('eventName', { + ...args, // 事件参数 + }); + ``` + +- v-model 指令 + + 因为 Vue3.x 中内置指令的实现采用的是编译时插入代码的方式,目前 v-model 指令还没有找到很好的办法去处理,这里可以先使用临时解决办法实现对应功能 + + ```javascript + // 具体的可以参考 demo 中的 demo-input.vue 中的示例 + + + ``` + +- Keep-Alive HMR 问题 + + 在示例代码中,我们的路由组件是包裹在 Keep-Alive 组件内的,但是目前使用 Keep-Alive 包裹的路由组件无法实现开发时热更新,需要刷新整个实例才能完成刷新。 + 如果是不包裹在 Keep-Alive 中则没有这个问题。目前官方[该问题](https://github.com/vuejs/core/pull/5165)也尚未解决,等待官方解决后升级 Vue 即可解决该问题。 + + !> vue@3.2.45+ 已经修复了该[问题](https://github.com/vuejs/core/pull/7049),使用3.2.45及以上版本进行开发时,keep-alive内的组件也可以热更新了 + +- Vue3.x 变量 Proxy 问题 + + 因为 3.x 的响应式是通过 Proxy 代理对象来实现的,所以我们得到的对象其实是 Proxy 的实例而非原始对象,因此调用终端接口时需要注意,终端并不认识 Proxy 对象,需要使用 Vue 提供的 [`toRaw`](https://cn.vuejs.org/api/reactivity-advanced.html#toraw) 方法来拿到原始的对象并传递给终端接口。 + +- Native 接口和自定义组件的类型提示 + + @hippy/vue-next 提供了 Native 模块接口的 Typescript 类型提示,如果有业务自定义的 Native 接口,也可以采用类似的方式进行扩展 + + ```javascript + declare module '@hippy/vue-next' { + export interface NativeInterfaceMap { + // 用户自定义的 Native 接口,接下来你可以在调用 Native.callNative,Native.callNativeWithPromise 时拥有类型提示了 + } + } + ``` + + @hippy/vue-next 也参考 `lib.dom.d.ts` 的事件声明提供了事件类型,具体可以参考 hippy-event.ts 文件。如果需要在内置的事件上进行扩展,可以采用类似方式 + + ```javascript + declare module '@hippy/vue-next' { + export interface HippyEvent { + testProp: number; + } + } + ``` + + 在使用 `registerElement` 去注册组件的时候,利用了 typescript 的 `type narrowing`,在 switch case 中提供了准确的类型提示。如果在业务注册自定义组件的时候也需要类型提示,可以采用如下方式: + + ```javascript + export interface HippyGlobalEventHandlersEventMap { + // extend new event name and related event interface + onTest: CustomEvent; + // extend existing event interface + onAnotherTest: HippyEvent; + } + ``` + + 更多信息可以参考 demo 里的 [extend.ts](https://github.com/Tencent/Hippy/blob/main/examples/hippy-vue-next-demo/src/extend.ts). + +- whitespace 处理 + + Vue2.x Vue-Loader `compilerOptions.whitespace` 默认值为 `preserve`, Vue3.x 默认值为 `condense`(可参考 [Vue3 whitespace说明](https://cn.vuejs.org/api/application.html#app-config-compileroptions-whitespace))。 + + 关闭 `trim` 能力的配置方式也有所不同,改在了 `createApp` 的参数中进行设置。 + + ```javascript + // entry file + const app: HippyApp = createApp(App, { + // hippy native module name + appName: 'Demo', + // trimWhitespace default is true + trimWhitespace: false, + }); + + // webpack script + rules: [ + { + test: /\.vue$/, + use: [ + { + loader: vueLoader, + options: { + compilerOptions: { + // whitespace handler, default is 'condense' + whitespace: 'condense', + }, + }, + }], + }, + ] + ``` + +- dialog 差异 + + `` 组件的第一个子元素不能设置 `{ position: absolute }` 样式,如果想将 `` 内容铺满全屏,可以给第一个子元素设置 `{ flex: 1 }` 样式或者显式设置 width 和 height 数值。这与 Hippy3.0 的逻辑保持一致。 + +- 书写 SSR 友好的代码 + + 因 SSR 的渲染方式和生命周期等与客户端渲染方式有一些差异,因此需要在代码编写过程中注意,这里可以参考[Vue官方的SSR指引](https://cn.vuejs.org/guide/scaling-up/ssr.html#writing-ssr-friendly-code) + +- Vue 构建结果体积问题 + + 因为 @hippy/vue-next 项目使用的是已编译的 Vue 组件,所以并不依赖于 Vue 的编译器,而默认的 webpack 打包会使用完整版本的 Vue 进行构建,会将不需要的编译器也打包在构建产物中,因此需要指定使用运行时版本的 Vue 产物 + + ```javascript + // scripts/hippy-webpack.android.js + const aliases = { + // ...other options + // hippy 仅需要运行时的 Vue,在这里指定 + vue$: 'vue/dist/vue.runtime.esm-bundler.js', + }; + ``` + +# 示例 + +更多使用请参考 [示例项目](https://github.com/Tencent/Hippy/tree/main/examples/hippy-vue-next-demo). diff --git a/docs/api/hippy-vue/web.md b/docs/api/hippy-vue/web.md new file mode 100644 index 00000000000..8f58ee928f6 --- /dev/null +++ b/docs/api/hippy-vue/web.md @@ -0,0 +1,5 @@ +# 转 Web + +## WebRenderer 方案 + +Hippy 全新 [`WebRenderer`](development/web-integration-guidelines.md) 方案,增加基于公共通信协议的转换层,业务开发者可以使用同一套 Hippy 语法开发的业务代码,映射成 JS 实现的组件和模块,上层无论使用 React,Vue 或者其他第三方框架,都可以实现兼容,可参考。 diff --git a/docs/guide/network-request.md b/docs/api/network-request.md similarity index 92% rename from docs/guide/network-request.md rename to docs/api/network-request.md index 619c0aa1c45..7e14a88d14a 100644 --- a/docs/guide/network-request.md +++ b/docs/api/network-request.md @@ -4,6 +4,8 @@ Hippy 直接支持 W3C 标准的 fetch 和 WebSocket 接口,可以通过这两个方法对服务器进行访问。 +--- + # fetch Hippy 提供了跟 W3C 标准基本一致的 [fetch](//developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API) 方法,可以直接参考 [MDN](//developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API)。 @@ -20,6 +22,8 @@ fetch('//mywebsite.com/mydata.json'); fetch 函数也支持 HTTP 请求的配置。 +> 低版本仅支持 `method | headers | body` 参数设置,`2.14.0` 及以上版本支持所有自定义参数透传,如 `redirect: 'follow'` + ```javascript fetch('//mywebsite.com/endpoint/', { method: 'POST', @@ -31,6 +35,7 @@ fetch('//mywebsite.com/endpoint/', { firstParam: 'yourValue', secondParam: 'yourOtherValue', }), + redirect: 'follow', // `2.14.0` 及以上版本支持 }); ``` @@ -147,7 +152,7 @@ import { View } from "@hippy/react"; export default class WebSocketExpo extends React.Component { componentWillMount() { - this.webSocekt = new WebSocket("ws://websocket.test.qq.com/websocket"); + this.webSocekt = new WebSocket("ws://websocket.xx.com/websocket"); this.webSocekt.onopen = () => { this._webSocketOpened = true; console.log("WebSocket onOpen"); @@ -194,6 +199,6 @@ export default class WebSocketExpo extends React.Component { Hippy 在接收来自服务器的 `set-cookie` header 时,会自动种入 cookie,下次再请求同域名服务时,就自动带上之前种下的 cookie。 -但和浏览器不同,Hippy 内提供提供了 NetworkModule 提供了对 cookie 读取和修改,详情可以参考 hippy-react 的 [NetworkModule](hippy-react/modules.md?id=networkmodule),或者 hippy-vue 的 [Vue.Native.Cookie](/hippy-vue/vue-native.md?id=cookie) 文档。 +但和浏览器不同,Hippy 内提供了 `NetworkModule` 对 cookie 读取和修改,详情可以参考 hippy-react 的 [NetworkModule](api/hippy-react/modules.md?id=networkmodule),或者 hippy-vue 的 [Vue.Native.Cookie](api/hippy-vue/vue-native.md?id=cookie) 文档。 > 浏览器中对 Cookie 的读写时通过 document 对象操作的,但是 Hippy 中暂时不能直接出现全局的 document,否则部分库会运行一些在浏览器中才有的 document 方法,但 Hippy 中并没有,会导致崩溃。 diff --git a/docs/api/performance.md b/docs/api/performance.md new file mode 100755 index 00000000000..5a5e1ba891b --- /dev/null +++ b/docs/api/performance.md @@ -0,0 +1,759 @@ +# **Hippy 业务冷启动性能优化指引** + +## **背景** + +经常有业务咨询 Hippy 有哪些优化手段,以及业务性能问题应该怎么分析,有哪些监控工具,本篇文档则系统的介绍了 Hippy 冷启动的性能优化的最佳实践。 + + + +## **冷启动阶段:** + +介绍一下Hippy应用冷启动有哪些阶段 + +​ 1. Hippy 运行环境启动 - 终端耗时 (启动) + +​ 2. 加载 Bundle的 JS 文件 - JS 引擎耗时 (自执行) + +​ 3. 应用实例的执行 - JS 引擎耗时(JS运行) + +​ a. 业务代码逻辑执行 + +​ b. 业务 IO(网络、JS API)等待 + +​ c. React/Vue 框架 DIFF 耗时 + +​ d. Hippy JS SDK计算耗时 + +​ 4. 上屏显示 - 终端耗时 (渲染) + +​ a. Hippy DOM 构建、排版耗时 + +​ b. Hippy 渲染上屏耗时 + +详细介绍参考:[Hippy冷启动核心逻辑和数据梳理](https://doc.weixin.qq.com/doc/w3_AJcAmQbdAFwmCbIe8OPScGUN6amkw?scode=AJEAIQdfAAo1QKXNGAAJcAmQbdAFw) + +我们把启动阶段分为 4个阶段:Hippy 启动、Bundle加载、**应用实例执行**、渲染上屏。 + +不同规模的 Hippy 业务,这些阶段耗时不尽相同,大家可以先测试各阶段耗时占比,再针对性的来分析。 + + + +Hippy 团队过去有一些经验可供参考: + +​ 1. 一般耗时大头是阶段 3 (一半耗时占比超过 50%) + +业务可重点排查 **业务 JS 执行耗时**、**IO(网络、JS API)等待耗时。**此外,**节点数过多、CSS 属性比较复杂**,也会影响 Hippy SDK的计算耗时 + +​ 2. JS Bundle包过大,会影响阶段 2 的耗时 + +​ 3. 节点数过多,节点层级比较深,渲染样式比较复杂,会影响阶段 3 的耗时 + + + +## **如何监控定位:** + +### **1.** **线上监控:** + +​在 Hippy 3.0,我们设计了用于性能分析的 Performance API: + +[Hippy 性能监控设计文档](https://doc.weixin.qq.com/doc/w3_ANsAsgZ1ACcBlbHY905RpW7Qj1vij?scode=AJEAIQdfAAosjxQAlNANsAsgZ1ACc) + + + +Performance API 冷启动打点指标: + +| **指标** | **对应 Key** | +| -------------------- | ------------------------ | +| Hippy 引擎加载开始 | hippyNativeInitStart | +| JS 引擎加载开始 | hippyJsEngineInitStart | +| JS 引擎加载结束 | hippyJsEngineInitEnd | +| Hippy 引擎加载结束 | hippyNativeInitEnd | +| JS Bundle 自执行耗时 | bundleInfo[] | +| 业务入口执行开始 | hippyRunApplicationStart | +| 业务入口执行结束 | hippyRunApplicationEnd | +| 首帧绘制开始 | hippyFirstFrameStart | +| 首帧绘制结束 | hippyFirstFrameEnd | +| 启动耗时 | duration | + + + +监控方式: + +​ 1. Hippy 3.x版本:可以接入最新 aegis-sdk (腾讯内部咨询 端框架小助手),已经基于 performance api,可以直接获取打点数据 + + + +​ 2. Hippy 2.x 版本可以基于业务代码打点,获取启动阶段的近似耗时数据。可参考:https://km.woa.com/articles/show/557810?kmref=search&from_page=1&no=1 + + + +### **2.** **Profile 工具:** + +​ 1. Perfdog + +​ a. 可查看 FPS, CPU, GPU, 内存等变化情况 + +​ 2. 安卓系统自带工具: + +​ a. GPU 渲染模式分析: 通过在 Android 设备的设置 APP 的开发者选项里打开 “ GPU 渲染模式分析” 选项,选择 ” 在屏幕上显示为条形图 “ 。 + +​ b. 过度绘制:Android 设备的设置 APP 的开发者选项里打开 “ 调试 GPU 过度绘制 ” + +​ c. 查看界面边界:系统设置 – 开发者选项 – 绘图 --显示布局边界 + +​ 3. iOS系统 simulator 模拟器 + +​ a. Debug 下自带分析工具 Color Blended Layers 图层绘制 Color Off-screen Rendered 离屏渲染 + +​ 4. Profile工具 + +​ a. Android Studio Profiler + +​ b. Xcode Instruments + +​ **c.** **Hippy Devtools (也在进一步完善中,欢迎大家提需求),如下示例:** + + + +**如何优化:** + +定位到耗时点,接下来就可以针对性分析。 + +先简单介绍常用的优化: + +​ 1. 预加载:大幅降低 1-2 阶段耗时 + +​ 2. 预渲染/SSR/Native-Vue:大幅降低 1-3阶段耗时 + +​ 3. 数据预拉取:降低 3阶段 IO 等待耗时 + +​ 4. JSI、动态加载、节点数优化:降低 3 阶段耗时 + +​ 5. 节点缓存/渲染优化/图片缓存:降低 4 阶段耗时 + +​ 6. 骨架屏优化/Loading:优化交互体验 + +... + + + +接下来详细介绍这些优化点: + + + +### **1.** **预加载** + +通过提前执行1+2阶段逻辑优化首屏耗时。 + +这两个阶段耗时主要被封装在HippyBridge中,因此可以通过提前初始化HippyBridge达成目的。 + + + +iOS 代码示例: + +``` javascript +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:nil bundleURL:url moduleProvider:^NSArray> * { + return nil; // 或返回希望替换的module实例 +} launchOptions:option executorKey:nil]; + +// 将bridge保存起来 +``` + +安卓代码示例: + +``` javascript +mHippyEngine.initEngine(new HippyEngine.EngineListener() { + @Override + public void onInitialized(EngineInitStatus statusCode, String msg) { + if (statusCode == EngineInitStatus.STATUS_OK) { + HippyBundleLoader loader = ...; + // e.g.: + // new HippyAssetBundleLoader(context, assetName, true, "demo"); + // new HippyFileBundleLoader(filePath, true, "demo"); + mHippyEngine.preloadModule(loader); + } + } +} +``` + + +优点: + +​ 1. 不依赖页面数据,在任何页面都可考虑使用预加载 + +​ 2. 前端也可以在预加载时提前fetch数据 + +缺点: + +​ 1. 优化效果相对预渲染不够明显 + + + +### **2.** **预渲染** + +如果还希望在预加载基础上继续优化体验,还可以进一步提前执行步骤 3 的逻辑。 + +优点: + +​ 1. 优化效果十分明显 + +缺点: + +​ 1. 内存开销大 + +​ 2. 无法对动态数据的页面使用 + +​ 3. 页面发版会导致命中率降低 + +​ 4. 预渲染时的Dimension可能与访问时不一致,导致布局异常 + +​ 5. 在Android上预渲染只能使用AppContext,导致页面打开后也无法使用依赖Activity的能力,例如Modal(Dialog)组件 + + + +接入代码示例: + +iOS 代码示例 + + + +``` javascript +HippyRootView *hippyRootView = [[HippyRootView alloc] + initWithBridge:bridge + businessURL:businessURL + moduleName:appName + initialProperties:properties + delegate:delegate]; +// 将hippyRootView保存起来 +``` + + + + + +执行这一步后,HippyRootView内部将会执行实例的加载,但由于rootView未被真正挂在到VC的UI树上,所以暂时不可见。 + +当需要显示的时候可以在VC的view上将hippyRootView加为子view。 + + + +``` javascript +[parent addSubview:hippyRootView]; + +// 必要时可以更新一下frame +hippyRootView.frame = newFrame; + +// 如果在addSubview后还有其他的subview的添加,可以考虑通过bringSubviewToFront将hippyRootView改为最前方显示 +[parent bringSubviewToFront:hippyRootView]; +``` + + + + + + + +安卓代码示例: + +除了需要把 ModuleLoadParams.context 设置为 AppContext 外,其余步骤和常规加载一致。 + + + +``` javascript +HippyEngine.ModuleLoadParams loadParams = new HippyEngine.ModuleLoadParams(); +loadParams.context = getApplicationContext(); +... +mHippyView = mHippyEngine.loadModule(loadParams, listener, null); +``` + + + + + +### **3.** **SSR** + +SSR 代替预渲染方案的另一选择。 + +方案原理:把 1-3 阶段放在服务端执行,解析成最终的 Hippy指令 的字符串,启动时直接反序列化 Hippy指令,下发Hippy终端执行渲染。 + +优化效果:性能数据与预渲染接近 + +详见QQ游戏中心优化 https://km.woa.com/articles/show/564026?kmref=search&from_page=1&no=1 + + + +优点: + +​ 1. 可不依赖终端方案方案,前端执行 + +​ 2. 相比预渲染方案更节省内存 + +缺点: + +​ 1. 需要执行事件挂载逻辑,可交互时间会延迟 + +​ 2. 会带来服务器的运营成本 + + +### **4.** **数据预请求:** + +在不方便应用 预渲染/SSR/Native-Vue的场景。可以考虑提前下载数据,节省 3阶段 网络 IO 耗时: + +​ 1. 可以在终端预请求,在启动Hippy后,把数据传给前端 + +​ 2. 可以结合预加载,在前端 JS 自执行阶段,前端预请求数据。等待组件渲染时直接使用。 + + + +### **5.** **节点缓存** + +​ 1. Dom Node 缓存(安卓) + +接入方案详见:https://doc.openhippy.com/#/feature/feature2.0/dom-cache + +​ 2. RenderNode 缓存(3.0 安卓) + +接入方案详见:https://doc.openhippy.com/#/feature/feature3.0/render-node-snapshot + + + + + +### **6.** **JS 引擎优化** + +在不方便做 JS 预加载的场景,如果要优化 JS 自执行耗时,可以考虑对 JS 引擎本身做优化: + +#### **6.1.** **V8 编译开启 Code Cache** + +把编译和解析的结果缓存下来,等到下次遇到相同的文件,直接跳过这个过程,把直接缓存好的数据拿来使用; + +​Hippy 2.0: Hermes 接入指引文档:https://iwiki.woa.com/p/4007348225 + +​Hippy 3.0 Hermes会直接集成,文档待补充。 + + + + + +### **7.** **bundle 包动态加载** + +接入文档指引:https://iwiki.woa.com/p/491739348 + +Hippy 打包插件只支持一个jsbundle包的生成。随着业务逻辑越来越复杂,jsbundle越来越大、包的加载时间越来越长。为了解决这个问题,Hippy 在 2.2.0 版本增添了动态加载能力,Hippy 的开发人员可以按照业务需求来动态引入 JS。 + +Hippy 在 2.5.5 版本增加了远程网络加载模式的支持,业务可对每个bundle自定义不同的加载模式。 + + + +webpack打包脚本中引入插件:HippyDynamicImportPlugin + + + +``` javascript +const HippyDynamicImportPlugin = require('@hippy/hippy-dynamic-import-plugin'); + +module.exports = { + ... + plugins: [ + new HippyDynamicImportPlugin(), + ], +}; +``` + + + + + + + +​ (1)加载本地 JS 包: + +​ 与 Web 开发动态加载能力一样,直接使用 import() 语法即可 + + + +​ (2)加载远程 JS 包: + + i. webpack打包脚本配置全局 publicPath(可选) + + + +``` javascript + // webpack output 配置 + output: { + ... + publicPath: 'https://xxxx/hippy/hippyVueDemo/', +}, +``` + + + + + +ii. 在业务代码引用分包的入口配置 magic comment的 webpackChunkName(必须) 和 customChunkPath(可选),如果没有配置customChunkPath,会默认使用全局 publicPath; 以 Hippy-Vue 为例: + + + +``` javascript + // Hippy-Vue 配置 + AsyncComponentFromHttp: () => import(/* customChunkPath: "https://xxx/hippy/hippyVueDemo/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue') + .then(res => res) + .catch(err => console.error('import async remote component error', err)) +``` + + + + + + + + + +### **8.** **JS API 优化** + +#### **8.1.** **JS Bridge -> JSI** + +​接入方案详见:https://doc.openhippy.com/#/feature/feature2.0/jsi + +​优化效果: + +Android 代码示例: + + + +``` javascript +// 初始化引擎开启 enableTurbo +val initParams = HippyEngine.EngineInitParams() +initParams.enableTurbo = true + +// 定义 module +@HippyNativeModule(name = "demoTurbo") +class DemoTurboModule(context: HippyEngineContext?) : HippyNativeModuleBase(context) { + ... + @HippyMethod(isSync = true) + fun getNum(num: Double): Double = num + ... +} +``` + + + + + +​iOS 代码示例: + + + +``` javascript +// 方式一:bridge初始化时通过配置参数设置生效 +NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO)}; +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:[NSURL fileURLWithPath:commonBundlePath] + moduleProvider:nil + launchOptions:launchOptions + executorKey:@"demoTurbo"]; + +// 方式二:bridge初始化完成后,设置属性生效 +HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:nil + businessURL:nil + moduleName:@"demoTurbo" + initialProperties:@{@"isSimulator": @(isSimulator)} + launchOptions:nil + shareOptions:nil + debugMode:YES + delegate:nil]; +rootView.bridge.enableTurbo = YES; +``` + + + + + + + +``` javascript +@implementation TurboConfig + +... + +// 注册模块 +HIPPY_EXPORT_TURBO_MODULE(TurboConfig) + +// 注册交互函数 +HIPPY_EXPORT_TURBO_METHOD(getInfo) { + return self.strInfo; +} +HIPPY_EXPORT_TURBO_METHOD(setInfo:(NSString *)string) { + self.strInfo = string; + return @(YES); +} + +... + +@end +``` + + + + + + + +Hippy-React 代码示例: + +https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/externals/Turbo/demoTurbo.js + +Hippy-Vue 代码示例: + +https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demoTurbo.js + + + +#### **8.2.** **减少首屏 JS API 调用次数** + + + +### **9.** **Hippy-Vue 优化** + +​ 1. 减少 getElemCss 方法的调用 + + + +``` javascript +Vue.Native.getElemCss() +``` + + + + + +​ 2. 减少 scoped 的使用 + +vue scoped 能力是 2.15.0 版本引入,scoped会转换为 属性选择器,因此解析性能会比较差; + +在 Hippy 3.0 版本,我们使用 css-module的方案优化了 scoped的解析方式,性能得到提升。 + +​ 3. 减少 CSS 属性选择器、伪类等样式的使用 + +​ 4. 升级 Hippy-Vue-Next(Vue3) + +Vue3 升级指引:https://hippyjs.org/#/hippy-vue/vue3 + +Vue3 相比 Vue2 做了 Diff算法优化、静态提升、事件缓存等优化,从Vue框架层面会带来性能提升。实测了 Vue3 和 Vue2 在Hippy框架下的数据对比: + + + +### **10. Hippy-React 优化** + +​ 1. Hippy React节点更新优化: + +https://iwiki.woa.com/p/1335183393 + +@hippy/react 在 2.12.0 版本应用上了最新的渲染优化,针对 react 16 和 react 17,先删除原来的 react-reconciler 包依赖,再分别引入 + + + +``` javascript +"@hippy/react-reconciler": "react16" +"@hippy/react-reconciler": "react17" +``` + + + + + +​ + +### **11.** **渲染优化:** + +#### 1. 减少首屏节点数、节点层级 + +- 可以借助客户端 IDE 来直观地查看 "DOM" 树,使用前端的 DevTools 的 View 树来检查冗余节点。 + +#### 2. 减少节点重复渲染的次数 + +- 可以在高频渲染节点的 `render` 函数中打点统计。 +- 使用 `shouldComponentUpdate`、`PureComponent` 等优化重复渲染。 + +#### 3. 节点优化:节点合并,扁平化(触发 Hippy 引擎优化) + +- 减少冗余事件挂载。 + +#### 4. 圆角、裁剪、描边等渲染性能较差,尽量减少使用 + +#### 5. 减少过度绘制 + +- 移除重复的背景色。 +- 减少图层覆盖。 + +#### 6. ListView + +- 尽量使用 `ListView` 代替 `ScrollView`,`ListView` 通过 View 的缓存与重用大大提升渲染性能。 +- 使用 `getRowType`,将 item 按类型合理拆分,同一类型的 item 的 `RowType` 相同,可复用。 +- 严格保持 `ListView` item 的 DOM 结构一致: + - **hippy-vue**:item 中的节点可以用 `v-show`,不要用 `v-if`。 + - **hippy-react**:item 中的节点尽量不要用 `if` 条件来改变节点结构。 + +#### 7. ViewPager + +- `ViewPager` 的子节点尽量不要全加载,实现懒加载。 + +#### 8. Image + +- 图片压缩。 +- 图片按需加载。 +- 避免同时使用 `src` 和 `background`。 +- 大图放 CDN。 +- 减少 base64 图片使用。 +- 图片缓存(内存缓存、磁盘缓存)。 + +​ 代码示例:在自定义ImageLoader中实现自己的缓存逻辑,也可使用第三方图片加载库,如 slide 等。 + + + +``` javascript +HippyEngine.EngineInitParams initParams = new HippyEngine.EngineInitParams(); +// 必须:宿主(Hippy的使用者)的Context +// 若存在多个Activity加载多个业务jsbundle的情况,则这里初始化引擎时建议使用Application的Context +initParams.context = this; +... +// 必须:图片加载器 +initParams.imageLoader = new MyImageLoader(this.getApplicationContext()); +``` + + + + + + + +### **12.** **业务逻辑执行优化** + +此外,也要检查业务代码自身的耗时,并做针对性优化。 + +​ 1. 防抖节流:对滚动事件、数据上报等进行防抖节流,避免频繁触发计算 + +​ 2. 耗时逻辑检查是否可以放在首屏后执行 + + + +### **13.** **交互优化** + +除了上面的优化手段,交互优化在一些场景也是十分重要的,可以提升打开体验,让页面视觉上更流畅。 + +​ 1. 骨架屏优化 + +​ 2. Loading + +​ 3. 切换动画 + + + +## **总结:** + +优化总结、是否需要 终端/前端 同学支持。 + +| 优化方案 | 方案介绍 | 接入成本 | 优化效果 | 终端/前端工作 | +| -------------------- | ------------------------------ | -------- | ---------- | -------------- | +| 预加载 | 优化 JS Bundle包加载 | 中 | 中 | 终端工作 | +| 预渲染 | 基于预加载,进一步优化渲染耗时 | 中 | 好 | 终端工作 | +| SSR | 预渲染的替代方案 | 中 | 好 | 前端工作 | +| Native-Vue | 预渲染的另一种替代方案 | 高 | 好 | 前端工作 | +| 数据预请求 | 节省 IO 耗时 | 低 | 中 | 终端或前端工作 | +| 节点缓存 | 仅安卓支持,优化渲染耗时明显 | 低 | 中 | 终端工作 | +| JS引擎优化(Hermes) | 性能比JSC优化明显 | 高 | 好 | 终端工作 | +| Bundle动态加载 | 分包加载,节省 JS 执行耗时 | 中 | 中 | 前端工作 | +| JS API优化(JSI) | JSI 接口同步调用,等待耗时降低 | 低 | 中 | 前端工作 | +| Hippy-Vue 逻辑优化 | 优化 css 解析耗时 | 低 | 好 | 前端工作 | +| Hippy-React 逻辑优化 | 渲染队列优化 | 低 | 中 | 前端工作 | +| 渲染优化 | 组件使用的渲染耗时优化 | 低 | 中 | 前端工作 | +| 业务逻辑优化 | 业务自身逻辑优化 | 无 | 中 | 前端工作 | +| 交互优化 | 业务自身优化交互 | 无 | 体验上优化 | 前端工作 | + + + +## **参考资料:** + +​ 1. K歌 Hippy性能优化分享(一) + +https://km.woa.com/articles/show/511822?kmref=search&from_page=1&no=7 + +​ 2. k歌 Hippy性能优化分享(二) + +https://km.woa.com/articles/show/484172?kmref=search&from_page=1&no=5 + +​ 3. k歌 Hippy性能优化分享 (三) + +https://km.woa.com/articles/show/504866?kmref=search&from_page=1&no=3 + +​ 4. k歌渲染优化 + +https://km.woa.com/articles/show/465625?kmref=search&from_page=1&no=2 + +​ 5. 小说 Hippy性能优化 + +https://km.woa.com/articles/show/484172?kmref=search&from_page=1&no=5 + +​ 6. 浏览器小说阅读器内存优化 + +https://km.woa.com/articles/show/468088?kmref=search&from_page=1&no=6 + +​ 7. QQ 增值Hippy性能优化 + +https://km.woa.com/articles/show/516658?kmref=search&from_page=1&no=4 + +​ 8. QQ直播Hippy性能优化 + +https://km.woa.com/articles/show/557810?kmref=search&from_page=1&no=1 + +​ 9. QQ游戏中心Hippy SSR优化 + +https://km.woa.com/articles/show/564026?kmref=search&from_page=1&no=1 + +​ 10. QQ 音乐Hippy性能监控工具建设 + +https://km.woa.com/articles/show/494153?kmref=search&from_page=1&no=6 + +​ 11. 浏览器 Hermes 引擎优化性能 + +https://km.woa.com/articles/show/567715?kmref=search&from_page=1&no=4 + +​ 12. QB长视频业务优化-接入Hermes引擎 + +https://km.woa.com/articles/show/564575?kmref=search&from_page=1&no=7 + +​ 13. Hippy 内存、CPU性能优化 + +https://km.woa.com/articles/show/484158?kmref=search&from_page=1&no=8 + +​ 14. 闪现社区首屏优化 + +https://km.woa.com/articles/show/474636?kmref=search&from_page=1&no=9 + +​ 15. NativeVue:解决Hippy等类RN框架首屏白屏的极致方案 + +https://km.woa.com/articles/show/527262?kmref=search&from_page=1&no=10 + +​ 16. Hippy profile工具实现的思考 + +https://km.woa.com/articles/show/397231?kmref=search&from_page=1&no=6 + +https://km.woa.com/articles/show/445938 + +​ 17. 记一次Hippy-React优化 + +https://km.woa.com/articles/show/431695?kmref=search&from_page=1&no=9 + +​ 18. Flutter性能优化最佳实践 + +[Flutter 应用性能优化最佳实践 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter](https://flutter.cn/docs/perf/best-practices) + +​ 19. React Native 性能综述 + +[性能综述 · React Native 中文网](https://reactnative.cn/docs/performance) + +​ 20. 营地性能优化 + +https://km.woa.com/articles/show/599930?kmref=search&from_page=1&no=10 + + diff --git a/docs/api/style/_sidebar.md b/docs/api/style/_sidebar.md new file mode 100644 index 00000000000..dda9aa7c24b --- /dev/null +++ b/docs/api/style/_sidebar.md @@ -0,0 +1,34 @@ + + +* hippy-react + * [介绍](api/hippy-react/introduction.md) + * [组件](api/hippy-react/components.md) + * [模块](api/hippy-react/modules.md) + * [样式](api/hippy-react/style.md) + * [事件](api/hippy-react/native-event.md) + * [手势系统](api/hippy-react/gesture.md) + * [自定义组件和模块](api/hippy-react/customize.md) + * [转 Web](api/hippy-react/web.md) + * [常见反馈](api/hippy-react/feedback.md) +* hippy-vue + * [介绍](api/hippy-vue/introduction.md) + * [核心组件](api/hippy-vue/components.md) + * [扩展组件](api/hippy-vue/external-components.md) + * [模块](api/hippy-vue/vue-native.md) + * [样式](api/hippy-vue/style.md) + * [事件](api/hippy-vue/native-event.md) + * [自定义组件和模块](api/hippy-vue/customize.md) + * [路由](api/hippy-vue/router.md) + * [转 Web](api/hippy-vue/web.md) + * [Vue 3.x](api/hippy-vue/vue3.md) + * [常见反馈](api/hippy-vue/feedback.md) +* 样式 + * [布局](api/style/layout.md) + * [外观](api/style/appearance.md) + * [颜色](api/style/color.md) + * [变形](api/style/transform.md) + * [更改终端属性](api/style/setNativeProps.md) + * [常见反馈](api/style/feedback.md) +* [网络请求](api/network-request.md) +* [性能监控](api/performance.md) +* [定时器](api/timer.md) diff --git a/docs/api/style/appearance.md b/docs/api/style/appearance.md new file mode 100644 index 00000000000..e96d56b7f03 --- /dev/null +++ b/docs/api/style/appearance.md @@ -0,0 +1,330 @@ +# 外观 + +包含了前景、背景、边框、透明度、字体等外观样式 + +--- + +# borderColor + +> Android 默认值为 `transparent`,iOS 默认值为 `black` + +| 类型 | 必需 | 支持平台 +| ------------------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# borderTopColor + +> Android 默认值为 `transparent`,iOS 默认值为 `black` + +| 类型 | 必需 | 支持平台 +| ------------------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# borderBottomColor + +> Android 默认值为 `transparent`,iOS 默认值为 `black` + +| 类型 | 必需 | 支持平台 +| ------------------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# borderLeftColor + +> Android 默认值为 `transparent`,iOS 默认值为 `black` + +| 类型 | 必需 | 支持平台 +| ------------------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# borderRightColor + +> Android 默认值为 `transparent`,iOS 默认值为 `black` + +| 类型 | 必需 | 支持平台 +| ------------------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# borderRadius + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# borderTopLeftRadius + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# borderTopRightRadius + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# borderBottomLeftRadius + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# borderBottomRightRadius + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# borderWidth + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# borderTopWidth + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | iOS + +# borderBottomWidth + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | iOS + +# borderLeftWidth + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | iOS + +# borderRightWidth + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | iOS + +# backgroundColor + +| 类型 | 必需 | 支持平台 +| ------------------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# borderStyle + +> 默认值为 `solid` + +| 类型 | 必需 | 支持平台 +| --------------------------------- | -------- | --- | +| enum('solid', 'dotted', 'dashed') | 否 | Android、iOS。dotted、dashed 暂仅支持 iOS + + +# boxShadow + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| [Hippy-React 参考例子](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/BoxShadow/index.jsx) | 否 | Android、iOS,Android实现有差异(详见例子) +| [Hippy-Vue 参考例子](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-shadow.vue) | 否 | Android、iOS,Android实现有差异(详见例子) + +# color + +字体颜色 + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# fontFamily + +字体名,如 `PingFangSC-Regular` + +若需自定义字体,参考 [自定义字体说明](feature/feature2.0/custom-font) + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| string | 否 | Android、iOS + +# fontSize + +字体大小 + +> 默认值为 `14` + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# fontStyle + +字体样式 + +> 默认值为 `normal` + +| 类型 | 必需 | 支持平台 | +| ------------------------ | ---- | ------------ | +| enum('normal', 'italic') | 否 | Android、iOS | + +# fontWeight + +字体粗细 + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/font-weight) + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number \| string | 否 | Android、iOS + +> Android API 28 以下仅支持 `normal`和 `bold` 两种字重,其它字重效果需配合 `fontFamily` 实现,Android API 28 及以上可以支持设置`1` - `1000`的字重值。 + +# letterSpacing + +文本字符间距 + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/letter-spacing) + +!> hippy-vue 需采用 @hippy/vue-css-loader `2.14.1` 以上版本 + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# opacity + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| number | 否 | Android、iOS + +# textDecoration + +同 `textDecorationLine` + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| enum('underline', 'line-through', 'none') | 否 | Android、iOS | + +# textDecorationColor + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文本的修饰线颜色 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| [color](api/style/color.md) | 否 | iOS | + +# textDecorationLine + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文本的修饰线类型 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| enum('underline', 'line-through', 'none') | 否 | Android、iOS | + +# textDecorationStyle + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文本的修饰线样式 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| enum('dotted', 'dashed', 'solid') | 否 | iOS | + +# textShadowColor + +> 最低支持版本 2.10.0 + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文字阴影颜色 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| [color](api/style/color.md) | 否 | Android、iOS | + +# textShadowOffset + +> 最低支持版本 2.10.0 + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文字阴影偏移量 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| object: { x: number, y: number } | 否 | Android、iOS | + +# textShadowOffsetX + +> * 最低支持版本 2.10.0 +> * 注意 hippy-vue class 样式只支持合并写法 `text-shadow-offset: 1px 1px`,不支持拆分 + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文字阴影X轴偏移量 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| number | 否 | Android、iOS | + +# textShadowOffsetY + +> * 最低支持版本 2.10.0 +> * 注意 hippy-vue class 样式只支持合并写法 `text-shadow-offset: 1px 1px`,不支持拆分 + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文字阴影Y轴偏移量 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| number | 否 | Android、iOS | + +# textShadowRadius + +> 最低支持版本 2.10.0 + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue) + +文字阴影半径 + +| 类型 | 必需 | 平台 | +| ------ | -------- | --------| +| number | 否 | Android、iOS | + +# tintColor + +[Hippy-React 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Image/index.jsx) + +[Hippy-Vue 范例](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-img.vue) + +对图片进行染色(对非纯色图片进行有透明度的染色时,Android 和 iOS 的 `blendMode` 默认值有差异) + +| 类型 | 必需 | 支持平台 +| ------------------ | -------- | --- | +| [color](api/style/color.md) | 否 | Android、iOS + +# visibility + +| 类型 | 必需 | 支持平台 +| ------ | -------- | --- | +| enum('visible'[default], 'hidden') | 否 | Android(2.14.5)、iOS(2.9.0) + diff --git a/docs/style/color.md b/docs/api/style/color.md similarity index 99% rename from docs/style/color.md rename to docs/api/style/color.md index c061469da7c..acc0a778d54 100644 --- a/docs/style/color.md +++ b/docs/api/style/color.md @@ -4,6 +4,8 @@ 颜色属性取值具体可以查询[CSS的颜色配置](//developer.mozilla.org/zh-CN/docs/Web/CSS/color_value). +--- + # RGB Hippy 支持 `rgb()` and `rgba()`。 diff --git a/docs/api/style/feedback.md b/docs/api/style/feedback.md new file mode 100644 index 00000000000..e8b37e03db5 --- /dev/null +++ b/docs/api/style/feedback.md @@ -0,0 +1,22 @@ +# CSS 样式常见反馈 + +## 1. Hippy 设置百分比失效 + +Hippy 自研了排版引擎 [Taitank](https://github.com/Tencent/taitank), 为了追求极致的性能, 阉割了百分比的实现。 +常见场景实现方案参考: + +> 需要设置高度 100% + +可设置 flex: 1 + +> 需要设置宽度 50% + +可通过 Dimensions.screen 接口获取屏幕尺寸大小,然后计算相应百分比值 + +> 需要百分比实现 + +可以终端修改编译设置,把排版引擎切换为 [Yoga](https://doc.openhippy.com/#/feature/feature3.0/layout) + +## 2. hippy支持 css var 的写法吗 + +可以先用 postcss 相关的插件来支持 diff --git a/docs/api/style/layout.md b/docs/api/style/layout.md new file mode 100644 index 00000000000..7f7d73437f5 --- /dev/null +++ b/docs/api/style/layout.md @@ -0,0 +1,439 @@ +# 布局 + +Hippy 的样式排版使用了 Flex 布局。值得注意的是,尚不兼容网页的百分比布局。 + +--- + + + +# alignItems + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/align-items) + +`alignItems`决定了子元素在次轴方向的排列方式(此样式设置在父元素上)。例如若子元素本来是沿着竖直方向排列的(即主轴竖直,次轴水平),则 `alignItems` 决定了它们在水平方向的排列方式。此样式和 CSS 中的 `alignItems` 表现一致,默认值为 `stretch`。 + +| 类型 | 必需 | +| --------------------------------------------------------------- | -------- | +| enum('flex-start', 'flex-end', 'center', 'stretch', 'baseline') | 否 | + +# alignSelf + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/align-self) + +`alignSelf`决定了元素在父元素的次轴方向的排列方式(此样式设置在子元素上),其值会覆盖父元素的 `alignItems` 的值。其表现和 CSS 上的 `align-self` 一致,默认值为 `auto`。 + +| 类型 | 必需 | +| ----------------------------------------------------------------------- | -------- | +| enum('auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline') | 否 | + + +# backgroundImage + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/background-image) + +`backgroundImage` 值可以直接传入背景图片地址或渐变色。 + +| 类型 | 必需 | +| --------------- | -------- | +| string | 否 | + +> `2.8.1` 版本后支持终端本地图片能力,可通过 webpack `file-loader` 加载。 + +> 渐变色目前支持 `linear-gradient` 线性渐变 `(最低支持版本 2.8.0)` [[MDN 文档]](//developer.mozilla.org/zh-CN/docs/orphaned/Web/CSS/linear-gradient()),支持使用 `linear-gradient([ [ [ | to [top | bottom] || [left | right] ],]? [, ]+)` 格式; 其中 `angle` 支持 deg、turn、rad 单位;`color-stop` 支持设置多个颜色和百分比。DEMO: [HippyReact](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/View/index.jsx) [HippyVue](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-div.vue) +>
+>
+> 注意: +> +> + Android 如果使用 `to [top | bottom] || [left | right]` 四个顶角设置渐变角度,`color-stop` 不能使用百分比; +> + iOS `color-stop` 百分比只能从小到大依次显式设置,不能部分省略,即 `red 10%, yellow 20%, blue 50%`,不能是 `red 10%, yellow 20%, blue 10%` + +# backgroundPositionX + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/background-position) + +`backgroundPositionX` 指定背景图片的初始位置的横轴X坐标。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# backgroundPositionY + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/background-position) + +`backgroundPositionY` 指定背景图片的初始位置的竖轴Y坐标。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# backgroundSize + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/background-size) + +`backgroundSize` 设置背景图片大小。 + +| 类型 | 必需 | +| --------------- | -------- | +| enum('cover', 'contain') | 否 | + +# collapsable + +Android 里如果一个 `View` 只用于布局它的子组件,则它可能会为了优化而从原生布局树中移除,因此该节点 DOM 的引用会丢失 `(比如调用 measureInAppWindow 无法获取到大小和位置信息)`。 把此属性设为 `false` 可以禁用这个优化,以确保对应视图在原生结构中存在。`(也可作为 View 的 Attribute 属性设置)`, 默认值为 `true`。 + +| 类型 | 必需 | 支持平台 +| --------------- | -------- | ---- | +| enum('false', 'true'[default]) | 否 | Android + +# display + +Hippy 默认采用 Flex 布局。同时,因为仅支持 Flex 布局,所以不需要手写 `display: flex` 即可使用。 + +| 类型 | 必需 | +| --------------- | -------- | +| enum('flex') | 否 | + +# flex + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/flex) + +在 Hippy 中 flex 的表现和 CSS 有些区别。 flex 在 Hippy 中只能为整数值。 + +| 类型 | 必需 | +| ------ | -------- | +| number | 否 | + +# flexBasis + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/flex-basis) + +`flex-basis` 指定了 flex 元素在主轴方向上的初始大小。 + +| 类型 | 必需 | +| ------ | -------- | +| number | 否 | + +# flexDirection + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/flex-direction) + +`flexDirection` 决定了容器的子元素的排列方向:`row` 代表水平排列, `column` 代表垂直排列。其他两个参数是反向排列。 +它跟 css 的 flex-direction 定义一样,但 Web CSS 是默认值为 `row`,而 Hippy 默认值为 `column`。 + +| 类型 | 必需 | +| ------------------------------------------------------ | -------- | +| enum('row', 'row-reverse', 'column', 'column-reverse') | 否 | + +# flexGrow + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/flex-grow) + +`flexGrow` 定义伸缩项目的扩展能力。它接受一个不带单位的值做为一个比例。主要用来决定伸缩容器剩余空间按比例应扩展多少空间。 + +如果所有伸缩项目的 `flex-grow` 设置了 `1`,那么每个伸缩项目将设置为一个大小相等的剩余空间。如果你给其中一个伸缩项目设置了 `flex-grow` 值为 `2`,那么这个伸缩项目所占的剩余空间是其他伸缩项目所占剩余空间的两倍。 默认值为 `0` + +| 类型 | 必需 | +| ------ | -------- | +| number | 否 | + +# flexShrink + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/flex-shrink ) + +`flexShrink` 属性指定了 flex 元素的收缩规则。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。Web CSS 是默认值为 `1`,Hippy 中默认值为 `0`。 + +| 类型 | 必需 | +| ------ | -------- | +| number | 否 | + +# flexWrap + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/flex-wrap) + +`flexWrap` 定义了子元素如何在接触到父容器底部时执行换行的行为。默认值为 `nowrap`。 + +| 类型 | 必需 | +| ---------------------- | -------- | +| enum('wrap', 'nowrap') | 否 | + +# height + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/height) + +`height` 定义了容器的高度,单位为 pt + +| 类型 | 必需 | +| --------------- | -------- | +| number, | 否 | + +# justifyContent + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/justify-content) + +`justifyContent` 定义了浏览器如何分配顺着父容器主轴的弹性元素之间及其周围的空间。默认值为 `flex-start`。 + +| 类型 | 必需 | +| ----------------------------------------------------------------------------------------- | -------- | +| enum('flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly') | 否 | + +# left + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/left) + +`left` 值是指将本组件定位到距离左边多少个逻辑像素(左边的定义取决于position属性)。 + +它的表现和 CSS 上的 left 类似,但注意在 Hippy 上只能使用逻辑像素值(数字单位),而不能使用百分比、em或是任何其他单位。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# lineHeight + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/line-height) + +`lineHeight` 属性用于设置多行元素的空间量,如多行文本的间距,hippy里仅支持设置具体数值。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# margin + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/margin) + +设置 `margin` 与同时对`marginTop`, `marginLeft`, `marginBottom`, 和 `marginRight`设置了同样的值效果一致。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# marginBottom + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/margin-bottom) + +`marginBottom` 和 CSS 的 `margin-bottom` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# marginHorizontal + +设置 `marginHorizontal` 与同时设置 `marginLeft` and `marginRight`一个值效果一致. + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# marginLeft + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/margin-left) + +`marginLeft` 与 CSS 的 `margin-left` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# marginRight + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/margin-right) + +`marginRight` 与 CSS 的 `margin-right` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# marginTop + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/margin-top) + +`marginTop` 和 CSS 的 `margin-top` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# marginVertical + +设置 `marginVertical` 与同时设置 `marginTop` and `marginBottom`一个值效果一致。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# maxHeight + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/max-height) + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# maxWidth + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/max-width) + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# minHeight + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/min-height) + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# minWidth + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/min-width) + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# overflow + +`overflow` 定义了子元素超过父容器宽高度后的显示情况 `overflow: hidden` 的情况会导致子元素被父容器切割超出显示范围的部分 `overflow: visible` 会让子容器正常显示全部,即使超出父容器的显示范围。 + +!> 由于历史原因,Android 默认全部元素为 `overflow: hidden`, iOS 为 `overflow: visible` + +| 类型 | 必需 | +| ----------------------------------- | -------- | +| enum('visible', 'hidden') | 否 | + +# padding + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/padding) + +设置 `padding` 与同时设置`paddingTop`, `paddingBottom`, `paddingLeft`, 和 `paddingRight`一个值时效果一致。 + +| 类型 | 必需 | +| --------------- | -------- | +| numbe | 否 | + +# paddingBottom + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/padding-bottom) + +`paddingBottom` 与 CSS 的 `padding-bottom` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# paddingHorizontal + +设置 `paddingHorizontal` 与同时设置 `paddingLeft` 和 `paddingRight`一个值时效果一致. + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# paddingLeft + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/padding-left) + +`paddingLeft` 与 CSS 的 `padding-left` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# paddingRight + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/padding-right) + +`paddingRight` 和 CSS 的 `padding-right` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# paddingTop + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/padding-top) + +`paddingTop` 和 CSS 的 `padding-top` 类似。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# paddingVertical + +设置 `paddingVertical` 与同时设置 `paddingTop` 和 `paddingBottom`一个值时效果一致. + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# position + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/position) + +`position` 在 Hippy 里表现与 CSS基本一致, 但是所有时候都是默认为 `relative`, 所以当元素设置 `absolute` 的时候可以保证永远只对上一级父元素绝对定位。 + +它和 CSS 的 `position` 属性类似,但 hippy 内的 `position` 只有 `absolute` 与 `relative` 两个属性。 + +| 类型 | 必需 | +| ---------------------------- | -------- | +| enum('absolute', 'relative') | 否 | + +# right + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/right) + +`right` 值是指将本组件定位到距离右边多少个逻辑像素(右边的定义取决于position属性)。 + +它的表现和 CSS 上的 right 类似,但注意在 Hippy 上只能使用逻辑像素值(数字单位),而不能使用百分比、em或是任何其他单位。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# textAlign + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/text-align) + +`textAlign` 指定行内文字如何相对它的块父元素对齐,默认值为 `left` + +| 类型 | 必需 | +| --------------- | -------- | +| enum('left', 'center', 'right') | 否 | + +# top + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/top) + +`top` 值是指将本组件定位到距离顶部多少个逻辑像素(顶部的定义取决于position属性)。 + +它的表现和 CSS 上的 top 类似,但注意在 Hippy 上只能使用逻辑像素值(数字单位),而不能使用百分比、em或是任何其他单位。 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# width + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/width) + +`width`定义了容器的宽度 + +| 类型 | 必需 | +| --------------- | -------- | +| number | 否 | + +# zIndex + +[[MDN 文档]](//developer.mozilla.org/zh-CN/docs/Web/CSS/z-index) + +`zIndex` 决定了容器排列的顺序。一般情况下,你无需直接使用 `zIndex`,容器元素会按照节点树的顺序依次渲染,在后面的元素会覆盖前面的元素(如果有覆盖情况的话)。`zIndex` 可以在你需要手动指定绘制层级的情况使用。 + +| 类型 | 必需 | +| ------ | -------- | +| number | 否 | diff --git a/docs/style/setNativeProps.md b/docs/api/style/setNativeProps.md similarity index 98% rename from docs/style/setNativeProps.md rename to docs/api/style/setNativeProps.md index 0f0c2b8fba3..4f277a57caf 100644 --- a/docs/style/setNativeProps.md +++ b/docs/api/style/setNativeProps.md @@ -2,7 +2,9 @@ 在做一些高频动画效果时由于需要经历JS层的多次重新渲染,会出现滞后卡顿的现象,`setNativeProps`提供了`ElementNode`下"简单粗暴"的方法直接修改终端原生组件的样式来优化性能,该方法目前只能修改 `style` 样式,其余属性暂不支持。P.S. 可能产生的数据同步等逻辑上的副作用需要业务自行解决 -## React +--- + +# React [[范例:SetNativeProps.jsx]](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/externals/SetNativeProps/index.jsx) @@ -27,7 +29,7 @@ ``` -## Vue +# Vue [[范例:demo-set-native-props.vue]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-set-native-props.vue) diff --git a/docs/api/style/transform.md b/docs/api/style/transform.md new file mode 100644 index 00000000000..85360cfb318 --- /dev/null +++ b/docs/api/style/transform.md @@ -0,0 +1,36 @@ +# 变形 + +该类样式可以对组件元素做一些基础变形,例如缩放、旋转、扭曲等等。 + +--- + +# transform + +`transform` 可以传入多个变形的参数数组,完成对原元素的变形操作。例如: + +```jsx +transform: [{ rotateX: '45deg' }, { rotateZ: '0.785398rad' }] +``` + +它与 CSS 的 transform 参数类似,请参考 [MDN](//developer.mozilla.org/zh-CN/docs/Web/CSS/transform) 上的详细信息。 + +| 参数 | 描述 | 类型 | 支持平台 | +| ----------- | ------------------------------------------------------------ | -------- | -------------- | +| perspective | 指定观察者与 z=0 平面的距离,默认值`1280`,Android 从 `3.2.0` 版本开始支持 | `number` | `Android、iOS` | +| rotate | 旋转,角度或弧度 | `string` | `Android、iOS` | +| rotateX | X轴旋转,角度或弧度 | `string` | `Android、iOS` | +| rotateY | Y轴旋转,角度或弧度 | `string` | `Android、iOS` | +| rotateZ | Z轴旋转(同rotate) | `string` | `Android、iOS` | +| scale | 缩放 | `number` | `Android、iOS` | +| scaleX | X轴缩放 | `number` | `Android、iOS` | +| scaleY | Y轴缩放 | `number` | `Android、iOS` | +| translateX | X轴平移 | `number` | `Android、iOS` | +| translateY | Y轴平移 | `number` | `Android、iOS` | +| skewX | X轴倾斜,角度或弧度 | `string` | `iOS` | +| skewY | Y轴倾斜,角度或弧度 | `string` | `iOS` | + +!> Android 不支持 `skewX` 和 `skewY` 。 + +!> Android 从 `3.2.0` 版本开始支持设置perspective,并把默认值改为和 iOS 一致。 + +!> Android 旧版本处理多个变形参数的顺序是反转的,从 `3.2.0` 开始改为和 iOS 一致。 diff --git a/docs/guide/timer.md b/docs/api/timer.md similarity index 98% rename from docs/guide/timer.md rename to docs/api/timer.md index c0d5235a6ef..670e031432f 100644 --- a/docs/guide/timer.md +++ b/docs/api/timer.md @@ -4,7 +4,9 @@ Hippy 端定时器用法与 Web 端 Javascript 用法一致,可以直接使用。 -## 方法 +--- + +# 方法 * [setTimeout](//developer.mozilla.org/zh-CN/docs/Web/API/Window/setTimeout) * [clearTimeout](//developer.mozilla.org/zh-CN/docs/Web/API/WindowTimers/clearTimeout) diff --git a/docs/architecture/_sidebar.md b/docs/architecture/_sidebar.md new file mode 100644 index 00000000000..7c68468b242 --- /dev/null +++ b/docs/architecture/_sidebar.md @@ -0,0 +1,10 @@ + + +* [Hippy 整体架构](architecture/introduction.md) +* [HippyCore 架构](architecture/core.md) +* [Android 渲染原理](architecture/render/android/native-render.md) +* [iOS 渲染原理](architecture/render/ios/native-render.md) +* [Ohos 渲染原理](architecture/render/ohos/native-render.md) +* [Voltron/Flutter 渲染原理](architecture/render/voltron/voltron-render.md) +* [Web 渲染原理](architecture/render/web/web-render.md) +* [排版盒模型](architecture/layout.md) diff --git a/docs/architecture/core.md b/docs/architecture/core.md new file mode 100644 index 00000000000..a2de7125da8 --- /dev/null +++ b/docs/architecture/core.md @@ -0,0 +1,99 @@ +# HippyCore 架构 + +Hippy 开发的时候,前端 JS 经常需要访问一些双端(Android 和 iOS)通用能力,Hippy 推荐使用 `internalBinding` 来实现底层能力扩展(我们将这项能力称为 [Core 架构](//github.com/Tencent/Hippy/tree/master/core)),它和 Node.js 的 internalBinding 一样,使用 C++ 进行开发,直接共享 JS 和 C++ 运行环境和数据,提供了非常高的 JS 和终端通信性能。 + +它的原理是在 JS 环境中直接插入函数、类等方式,JS 使用这些函数或方法,可以直接访问 C++ 代码。 + +但如果涉及到平台相关,依然需要分平台桥接。 + +目前 Hippy 里的[定时器](api/timer.md)和[日志](feature/feature2.0/console.md)模块都是使用 Core 实现。 + +![Core 架构对比](../assets/img/hippy-core.png) + +# C++ 模块扩展 + +我们将以 TestModule 为例,从头扩展一个 Module,这个 Module 将展示前端如何调用终端能力,并且把结果返回给前端。 + +## 继承 ModuleBase + +在 [driver/js/include/driver/modules/](//github.com/Tencent/Hippy/tree/v3.0-dev/driver/js/include/driver/modules) 下创建 test-module.h + +```cpp +#ifndef CORE_MODULES_TEST_MODULE_H_ +#define CORE_MODULES_TEST_MODULE_H_ + +#include "core/modules/module-base.h" +#include "core/napi/callback-info.h" + +class TestModule : public ModuleBase { + public: + explicit TestModule(hippy::napi::napi_context context){}; + void RetStr(hippy::napi::CallbackInfo& info); + void Print(hippy::napi::CallbackInfo& info); +}; + +#endif // CORE_MODULES_TEST_MODULE_H_ +``` + +在 [driver/js/src/modules/](//github.com/Tencent/Hippy/tree/v3.0-dev/driver/js/src/modules) 下创建 test-module.cc + +```cpp +#include "core/modules/module-register.h" +#include "core/modules/test-module.h" +#include "core/napi/js-native-api.h" +#include "core/base/logging.h" +REGISTER_MODULE(TestModule, RetStr) +REGISTER_MODULE(TestModule, Print) + +void TestModule::RetStr(hippy::napi::CallbackInfo& info) { + std::shared_ptr env = info.GetEnv(); + hippy::napi::napi_context context = env->getContext(); + HIPPY_CHECK(context); + + info.GetReturnValue()->Set(hippy::napi::napi_create_string(context, "hello world")); +} + +void TestModule::Print(hippy::napi::CallbackInfo& info) { + std::shared_ptr env = info.GetEnv(); + hippy::napi::napi_context context = env->getContext(); + HIPPY_CHECK(context); + HIPPY_LOG(hippy::Debug, "hello world"); + + info.GetReturnValue()->SetUndefined(); +} + +``` + +# JS 桥接 + +双平台通用模块一般放在 [core/js/global](//github.com/Tencent/Hippy/tree/master/core/js/global) 下,我们在 global 下 增加 TestModule.js + +```js +const TestModule = internalBinding('TestModule'); + +global.TestModule = TestModule; +``` + +[core/js/entry/](//github.com/Tencent/Hippy/tree/master/core/js/entry) 下双平台 hippy.js 里增加 + +```js +require('../../global/TestModule.js'); +``` + +在 Hippy 目录下运行 `npm run buildcore`,会生成对应双平台的 C++ 源代码: + +* [native-source-code-android.cc](//github.com/Tencent/Hippy/blob/master/core/napi/v8/native-source-code-android.cc) +* [native-source-code-ios.cc](//github.com/Tencent/Hippy/blob/master/core/napi/jsc/native-source-code-ios.cc) + +# 重新编译 Core + +无需做别的改动,重新编译终端 SDK 即可,终端 SDK 能够链接到 `core` 目录中的对应 C++ 代码,需要注意 Android 需要准备好 cmake、ndk 等等编译环境。 + +# 效果 + +```js +global.TestModule.Print(); +global.TestModule.RetStr(); +2019-11-08 17:32:57.630 7004-7066/? D/HippyCore: hello world +``` + diff --git a/docs/architecture/introduction.md b/docs/architecture/introduction.md new file mode 100644 index 00000000000..012905c7c4e --- /dev/null +++ b/docs/architecture/introduction.md @@ -0,0 +1,38 @@ +# Hippy 整体架构 + +--- + +# Hippy 3.x 架构 + +Hippy 正在进行 3.x 架构的升级,在 3.x 中业务与渲染层中的具体实现可根据用户实际场景进行切换:业务层上不再局限于 JS 驱动,也支持切换其它任意 DSL 语言进行驱动;DOM Manager 从 Java/OC 下沉到 C++,作为中间枢纽,除了接收处理来自上层的消息进行 DOM Tree 的创建和维护外,还负责与不同渲染引擎,排版引擎和调试工具的对接通信;在渲染层中,渲染引擎除了支持现有原生(Native)渲染之外,还可以选择其他渲染 Renderer,如 Flutter(Voltron) 渲染。Hippy 3.x 能够弥补当前 Hippy 2.x 在性能,双端一致性以及组件支持方面的一些短板,敬请期待! + +
+3.0架构 + +## 驱动层 + +驱动层为业务封装了对接DOM层的渲染指令和底层接口, 用户可以使用 Hippy 框架提供的 React/Vue 驱动层来开发业务,也支持切换其它任意DSL 语言进行驱动。详见 [Hippy-React](api/hippy-react/introduction)、[Hippy-Vue](api/hippy-vue/introduction)。 + +## DOM层 + +DOM Manager 从 Java/OC 抽离到 C++,作为中间枢纽,除了接收处理来自上层的消息,进行 DOM Tree 的创建和维护外,还负责与不同渲染引擎,排版引擎和调试工具的对接通信。 + +## 渲染层 + +* Native Renderer:使用 Android/iOS/Ohos 原生组件进行渲染, 详见 [Android](architecture/render/android/native-render)、[iOS](architecture/render/ios/native-render)、[Ohos](architecture/render/ohos/native-render)。 +* Voltron Renderer:使用 Flutter 渲染, 详见 [Voltron](architecture/render/voltron/voltron-render)。 +* Web Renderer:使用 WebView 渲染(Web 同构), 详见 [Web](architecture/render/web/web-render)。 + +
+
+
+ +# Hippy 2.x 架构 + +Hippy 2.x 架构主要分成三层,UI(JS) 层 `Hippy-React` 和 `Hippy-Vue` 负责驱动 UI 指令生成;中间层 [C++ HippyCore](architecture/core.md) 负责抹平平台差异性和提供高性能模块;渲染层 `Android` 和 `iOS` 负责提供终端底层模块、组件,并与布局引擎通信 + +
+ +![2.0架构](../assets/img/2.0-structure.png) + + diff --git a/docs/architecture/layout.md b/docs/architecture/layout.md new file mode 100644 index 00000000000..61fde2b42f5 --- /dev/null +++ b/docs/architecture/layout.md @@ -0,0 +1,122 @@ +# 布局与单位 + +--- + +# 盒模型 + +Hippy 为了方便前端开发便于理解,样式也采用了 CSS 的盒模型构建。当 Hippy 在进行布局的时候,渲染引擎会根据 CSS-Box 模型将所有元素表示为一个矩形盒子,样式配置决定这些盒子的大小,位置以及属性(颜色,背景,边框尺寸...). + +在 Hippy 中,使用标准盒模型描述这些矩形盒子中的每一个。这个模型描述了元素所占空间的内容。每个盒子有四个边:外边距边, 边框边, 内填充边 与 内容边。 + +> PS: Hippy 的盒模型布局对应的是CSS的 `box-sizing` 属性的 `border-box` 类型,具体表现与宽高边距计算可参考[MDN文档 box-sizing](//developer.mozilla.org/zh-CN/docs/Web/CSS/box-sizing)。 + +![盒模型](../assets/img/border-box.png) + +* [width](api/style/layout.md?id=width) +* [height](api/style/layout.md?id=height) +* [padding](api/style/layout.md?id=padding) +* [margin](api/style/layout.md?id=margin) +* [border](api/style/layout.md?id=borderWidth) + +# 布局(Flex) + +Hippy 中,为了方便移动端编写布局,所以默认支持了现在移动端最流行的 `Flex` 布局。同时,因为仅支持 `Flex` 布局,所以不需要手写 `display: flex` 即可使用。 +Flex 布局与 Web 的 Flex 类似,它们都旨在提供一个更加有效的方式制定、调整和分布一个容器里的项目布局,即使他们的大小是未知或者是动态的。Flex 规定了弹性元素如何伸长或缩短,以适应flex容器中的可用空间。CSS 版教程文档可以参考[这篇](http://www.w3cplus.com/css3/a-visual-guide-to-css3-flexbox-properties.html) + +## flexDirection + +flexDirection 属性指定了内部元素是如何在 flex 容器中布局的,定义了主轴的方向(水平或垂直)。 + +> 注意:Hippy 的 flexDirection 与 Web 的 flex-direction 默认值有区别, Web 默认为 `row`, Hippy 默认为 `column`。 + +flexDirection +
+
+ +| 类型 | 必需 |默认| +| ------ | -------- |---| +| enum('row', 'row-reverse', 'column', 'column-reverse')| 否 |'column'| + +## alignItems + +alignItems 定义了伸缩项目可以在伸缩容器次轴方向的排列方式 + +* flex-start(默认值):伸缩项目在侧轴起点边的外边距紧靠住该行在侧轴起始的边。 +* flex-end:伸缩项目在侧轴终点边的外边距靠住该行在侧轴终点的边 。 +* center:伸缩项目的外边距盒在该行的侧轴上居中放置。 +* baseline:伸缩项目根据他们的基线对齐。 +* stretch:伸缩项目拉伸填充整个伸缩容器。此值会使项目的外边距盒的尺寸在遵照「min/max-width/height」属性的限制下尽可能接近所在行的尺寸。 + +| 类型 | 必需 |默认| +| ------ | -------- |---| +| enum('flex-start', 'flex-end', 'center', 'baseline', 'stretch') | 否 |'flex-start'| + +## justifyContent + +justifyContent 定义了伸缩项目沿着主轴线的对齐方式。 + +* flex-start(默认值):伸缩项目向一行的起始位置靠齐。 +* flex-end:伸缩项目向一行的结束位置靠齐。 +* center:伸缩项目向一行的中间位置靠齐。 +* space-between:伸缩项目会平均地分布在行里。第一个伸缩项目在一行中的最开始位置,最后一个伸缩项目在一行中最终点位置。 +* space-around:伸缩项目会平均地分布在行里,两端保留一半的空间。 + +| 类型 | 必需 |默认| +| ------ | -------- |---| +| enum('flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly') | 否 |'flex-start'| + +## flex + +flex 属性数值, 定义了 flex 容器的子节点项可以占用容器中剩余空间的大小。默认值为 0,即不占用剩余空间。如果定义了 flex 数字且为正数的时候,则 + +```text +每个元素占用的剩余空间=自己的 flex 数值 / 所有同一级子容器的 flex 数字之和 +``` + +当 flex 设置为 -1 的时候,默认情况会显示正常宽高。然而, 如果剩余空间不足的话,此设置了 `flex: -1` 的容器将会收缩到其 minWidth 的宽度与 minHeight 的高度来显示。 + +| 类型 | 必需 |默认| +| ------ | -------- |---| +| number| 否 |0| + +## flexBasis + +flexBasis 设置伸缩基准值,剩余的空间按比率进行伸缩,负值无效,只能为 0 或正数。 + +| 类型 | 必需 |默认| +| ------ | -------- |---| +| number | 否 |auto| + +## flexGrow + +flexGrow 定义伸缩项目的扩展能力。它接受一个不带单位的值做为一个比例,主要用来决定伸缩容器剩余空间应按比例扩展多少空间。 + +如果所有伸缩项目的 flex-grow 设置了 1,那么每个伸缩项目将设置为一个大小相等的剩余空间。如果你给其中一个伸缩项目设置了 flex-grow 值为 2,那么这个伸缩项目所占的剩余空间是其他伸缩项目所占剩余空间的两倍。 + +| 类型 | 必需 |默认| +| ------ | -------- |---| +| number | 否 |0| + +## flexShrink + +flexShrink 定义伸缩项目收缩的能力。 + +> 注意:Hippy 中 flexShrink 默认值为 0,与 Web 标准有差异 + +| 类型 | 必需 |默认| +| ------ | -------- |---| +| number | 否 |0| + +# 长度单位 + +Hippy 现在暂时不支持百分比的长度值,只支持具体数值(number)。单位为 dp,具体换算公式为: + +```text +实际真机长度值 = 屏幕缩放比例 * Hippy 样式长度值 +``` + +屏幕缩放比例 可以通过 `PixelRatio.get()`(hippy-react) 或 `Vue.Native.PixelRatio`(hippy-vue) 获取,如 iPhone 8 为 2,iPhone X 为 3,以 iPhone 8 为例: + +* 屏幕真实宽度为 750px +* PixelRatio 为 2 +* 所以 Hippy 的全屏宽度为`750/2 = 375` diff --git a/docs/architecture/render/android/native-render.md b/docs/architecture/render/android/native-render.md new file mode 100644 index 00000000000..17b230096bf --- /dev/null +++ b/docs/architecture/render/android/native-render.md @@ -0,0 +1,133 @@ +# Android Native Renderer + +--- + +## Flatten UI + + Flatten UI是一种终端视图层级优化的方法,在Hippy 2.0的基础上实现这种优化方案,并不是简单的改造渲染逻辑就可以实现的,这里还依赖整体UI结构调整,缓存池改造,以及细粒度复用等重构完成后才能支持Flatten UI最终优化的实现,所以Flatten UI在3.0可以理解为一整套解决方案的升级,而不是单一的局部优化。 + +### 层级优化对比 + + 在2.0中通过针对只参与排版的节点不创建实体view的方法来减少终端UI层级,在此基础上,3.0 Flatten UI采用子元素直接在父view上完成渲染的方法将UI层级进一步打平,通过下面这个demo我们可以看到不同阶段优化效果对比: + +```js + + + + hello world + + +``` + + ![UI层级优化效果对比](../../../assets/img/flatten-ui-1.png) + +- 无层级优化情况下dom -> render -> view 一一对应 +- 2.0将只参与排版的节点在render中被优化,render节点和view一一对应 +- 3.0在2.0的基础上进一步优化view层级,部分子节点直接渲染在父节点的view上 + +### UI 主体结构的改造 + +### 2.0 UI主体结构 + + ![2.0 UI主体结构](../../../assets/img/flatten-ui-2.png) + +- HippyViewGroup是我们页面中最常见的元素,但绝大部分view是不需要展示图片与处理图片属性的,从imageview派生出来让view组件变得异常臃肿; +- AsyncImageView是HippyViewGroup的基类,也是属于Support-ui里面的一个基础组件,这个基类里面包括图片拉取管理,drawable的管理与渲染诸多逻辑,让组件渲染与view强耦合在一起,除了设计不合理以外代码实现质量也较差。 +- Support-ui目录下的所有组件逻辑未来会全部废弃。 + +### 3.0 UI主体结构 + + ![3.0 UI主体结构](../../../assets/img/flatten-ui-3.png) + +- 废弃 suppor-ui AsyncImageView,使用轻量化FlatViewGroup替代,FlatViewGroup只负责子节点渲染顺序的管理; +- 通过新增Component体系实现view属性与渲染属性处理逻辑的分离; +- Component由Render Node持有,负责Drawable的管理,可以在不依赖view的情况下完成独立渲染; +- Image Component extends Component,主要包括image相关属性处理以及image loader对接逻辑。 + +### 缓存池改造 + +在2.0中只针对预创建view,base64与本地图片的数据做了缓存,既没有抽象出统一的缓存访问接口,也无法做很好的扩展来支持其它流程的缓存优化,所以在3.0定义了一套标准的缓存访问接口,重构了所有缓存相关的代码实现结构,并扩展了基于view的复用池与常用object的复用池。 + +- PreCreateViewPool + + 预创建view缓存池,当在dom线程接收到create node指令时,会创建对应的create render node task并放入队列中,等batch的时候把队列中的task放到UI线程批量执行,在此之前还需要执行排版相关的逻辑,为了让UI线程能提前处理一部分任务,当接收到create node指令时,就直接在UI线程创建对应的view并放到缓存池,等到UI 线程执行batch的时候就可以直接从缓存池取出使用,这样可以最大化UI线程和dom线程task的并行执行,减少整个流程的耗时该缓存池对于开发者来说是透明的,每次batch执行结束后就会清空,内部使用SparseArray的数据结构进行存储,直接使用view id做key + +- RecycleViewPool + + 基于view type的view缓存池,主要使用在Recycler view滚动时候,recycler view item子view的回收,具体回收机制可以参考下一节细粒度复用的介绍该缓存池内部使用Map>进行存储,view的class name作为key值,每个类型的view pool default pool size为8 + +- ImageDataPool + + Image data缓存池,该缓存池内部使用LruCache进行存储,key值由image uri后32位做hashcode计算得出,当前设置的default pool size为24 + +- RecycleObjectPool + + 常用频繁创建对象的缓存池,类似于系统Message的使用,使用完成后做recycle,获取的时候直接obtain from pool,避免临时对象的频繁创建和销毁带来GC问题,该缓存池内部使用Map>进行存储,当前设置的default pool size为12,缓存池定义为static对象,也就是所有Hippyengine和页面都共享同一个缓存池,目前VFS ResourceDataHolder与ImageDataHolder对象的使用已经接入,后续其它常用对象的创建接入会继续扩展 + +### 细粒度复用 + +#### 2.0复用机制 + + 在2.0中主要通过recycler view自身item pool对ViewHolder进行缓存,这里的缓冲池分类主要依赖item type,也就是每个item的UI样式,由前端开发者自行分类定义,由于很多开发者对item type分类不精准甚至根本就没有去设置item type,再加上本身SDK的diff机制不够最优,导致这种强依赖item type的缓存复用机制效率很低,有概率会引起列表滚动的掉帧不流畅。 + + ![2.0复用机制](../../../assets/img/flatten-ui-4.png) + +#### 3.0复用机制 + + 3.0增加以view为单位的缓存池,在list view滚动过程中不论是item被淘汰还是被复用,都会先拆解item,将子view放到复用池彻底解决同样type item内部由于子节点结构差异造成的复用率低的问题,取消Patch机制,整个复用diff过程不产生任何多余的临时对象。 + + ![3.0复用机制](../../../assets/img/flatten-ui-5.png) + + 增加基于view type缓存池的细粒度复用机制以后,已经最大程度上减弱的对item type分类的依赖,也就是说即使前端item type不设置,也可以获得较好的复用性能。细粒度复用可以很好优化列表滚动性能,同时也是保证Flatten UI的体系的一个必要能力,因为在滚动的候,下一个即将展示的节点有可能是一个偏平化的节点,不需要创建view,如果没有view的缓存池,那么上一个从item pool取出的item会把子view全部delete掉,造成很大的性能损耗。 + +#### View复用属性Diff与重置 + + 当view被复用时,view被设置的属性还是之前关联node所带的属性,需要把新关联node属性重新设置到view上,才能保证组件显示和行为的正确性。 + +2.0 属性Diff与重置主要步骤: + +1. 全量递归对比所有子节点,如果节点类型不匹配的,生成create或者delete patch; +2. 如果节点类型匹配的,全量递归遍历所有属性,逐一进行value的对比,得到update props patch; +3. 把所有patch执行应用到view上。 + +--- + +3.0 属性Diff与重置主要步骤: + +1. 直接遍历新关联node的非渲染属性并设置到view上; +2. 对比获取old node中存在但new node中不存在的属性; +3. 把上一步获取到的diff属性在view上做reset。 + +--- + +对比3.0和2.0的属性Diff与重置实现,3.0具有以下优势: + +- 由于渲染属性与view已经解耦,所以在属性遍历与设置的时候可以直接跳过渲染相关的属性; +- 不再需要进行节点类型的对比; +- 获取diff属性的时候不需要做value的对比,只需要做containsKey的判断找出新节点不包含的属性; +- 不需要生成任何patch临时对象。 + +#### FlatViewGroup子节点渲染管理 + +FlatViewGroup直接派生于系统ViewGroup,作为 text view,imge view与普通view组件的基类,相对于原来suppor-ui AsyncImageView要轻量化很多,只包含子节点渲染顺序相关的处理逻辑,所以基于FlatViewGroup派生的组件不论在创建耗时上还是代码可维护方面比2.0都有明显提升。 +子节点遍历与渲染最关键要支持扁平化元素与常规view混合的组合,例如: + +![扁平化元素与普通view混合渲染](../../../assets/img/flatten-ui-6.png) + +#### 触发扁平化渲染的条件 + +- 必须是View,Image,Text三种元素之一 + +使用SDK内置以上三种基础组件可以支持扁平化渲染,其它组件或者宿主自定义组件暂时还不支持 + +- 必须是叶子节点 + +只有作为叶子节点的元素才会被扁平化渲染,text节点一定是叶子节点,虽然text可以嵌套,但text子节点在终端做了合并,不会生成实际的Render node节点,只会有VirtualNode与其对应 + +- 父节点必须是View或者派生于View的组件 + +这里主要针对宿主自定义View,SDK核心组件List view item,View pager item以及Scroll view的第一个子节点都是从view组件派生出来,它们下面的子节点是都可以满足这个条件的 + +- 该节点没有设置View属性 + +View属性主要包括click,touch事件监听,focus相关事件以及transform属性 diff --git a/docs/architecture/render/ios/native-render.md b/docs/architecture/render/ios/native-render.md new file mode 100644 index 00000000000..de0a6d12efc --- /dev/null +++ b/docs/architecture/render/ios/native-render.md @@ -0,0 +1,183 @@ +# iOS Native Renderer + +在Hippy中,RenderManager负责将Dom层节点构建的Dom树转换为对应的Render节点与Render树,并负责驱动最终的UI展示。 + +Hippy抽象了RenderManager的接口,允许接入方自行实现RenderManager接口,并实现上屏操作。其中Native Renderer由Hippy默认实现,通过Native组件构建出整个Hippy界面。 + +NativeRenderManager负责实现Hippy::RenderManager的抽象接口,并将Render树的构建与UI上屏的行为交由HippyUIManager处理。 + +HippyUIManager负责处理以下行为: + +- Render节点的创建与管理 +- RooView与RootNode绑定与管理(不持有) +- UI节点的实时创建、懒加载创建与管理 +- UI事件的绑定与回调 +- 管理UI组件的依赖的功能(vfs, image decoder, ...) +- Vsync信号回调 + +## UI构建 + +### 概览 + +在Hippy3.0的体系中,存在三颗与UI相关的树结构: + +- Dom树 + + Dom树是有driver层驱动dom manager构建的第一棵树结构,运行于dom线程,记录了每棵节点的原始信息与节点的父子关系。当前节点的名称以dom属性的形式记录,dom节点并没有类型区分,所有dom节点行为一致。 + +- Render树 + + Dom树并不能直接用于构建UI,其中原因有3: + + - Dom树所有行为都在dom线程中进行,无法与UI线程交互。 + - Dom节点只包含有原始属性,未进行任何处理。 + - ○在某些场景下,Dom结构并不与最终的UI结构一致。 + + 因此,需要构建另外一个树,起到承上启下的作用。 + + Render树的特点有: + - Render节点由dom节点构建,并负责处理dom节点的原始信息,可供UI直接调用。并不保证与Dom树完全一致。 + - Render节点类型与UI类型对应,即不同的UI组件可能对应不同的Render节点类型。 + - Render所有行为都运行于主线程,可直接与UI交互。 + +- UI树 + + NativeRender的最终上屏方案,由Render驱动构建,并能与Render直接交互。 + +### UI创建流程 + +- driver层驱动创建dom节点,并将所有创建的dom节点一次性打包发送给render_manager +- render_manager根据dom节点信息构建出对应的render节点与树结构,并做一些预处理以满足UI构建需求 +- 之后render_manager将根据render数选择性构建UI树结构并上屏 + +![image](../../../assets/img/ui_process.png) + +### UI懒加载 + +在UI构建过程中,并不是每一个UI组件都是实时构建。部分长列表组件及其子组件,基于性能考虑,只有在需要显示时才构建。 + +为此,需要设定render节点的懒加载属性,以保证UI的懒创建。 + +在iOS中,此能力由`[HippyShadowView creationType:NativeRenderCreationType]`属性控制。 +![image](../../../assets/img/lazy_load1.png) +对于懒加载组件,需要手动调用创建方法才会创建。 +![image](../../../assets/img/lazy_load2.png) + +### Text组件构建 + +Text组件算是一个比较特殊的组件,相对于其他组件,其有两个特色:`测量`与`合并`。 + +- 测量:一个普通的组件,其布局结果完全有layout系统计算,无需与render系统交互。但是对于text组件,需要由render系统设置测量函数,由render系统计算出其长宽。 +![image](../../../assets/img/text_measure.png) + +- 合并:富文本结构,在dom树中,是一个text节点持有一个或者多个text类型子节点。但是在render系统中,render_manager会将其合并为一个text节点,与UI结构保持一致。之后便是正常的上屏流程。 + +### 长列表组件 + +目前hippy中包含的长列表组件为ListView和WaterfallView,其子组件遵循懒加载策略,必要时才会创建。 + +为此,长列表组件会将其子render node节点作为数据源,在创建UI时,会先根据数据源节点信息找到对应的render节点,然后实时创建UI。 + +![image](../../../assets/img/list.png) + +### 长列表组件内存策略 + +基本策略:长列表在停止滑动后,将屏幕外一定数量的,距离屏幕当前可见范围内最远的Item组件删除,避免内存占用过大。 + +```objectivec + +//计算出某个indexPath值距离屏幕可见范围内的visibleIndexPaths的最近距离 +- (NSInteger)differenceFromIndexPath:(NSIndexPath *)indexPath + againstVisibleIndexPaths:(NSArray *)visibleIndexPaths { + NSIndexPath *firstIndexPath = [visibleIndexPaths firstObject]; + NSIndexPath *lastIndexPath = [visibleIndexPaths lastObject]; + NSUInteger diffFirst = [self differenceFromIndexPath:indexPath againstAnother:firstIndexPath]; + NSUInteger diffLast = [self differenceFromIndexPath:indexPath againstAnother:lastIndexPath]; + return MIN(diffFirst, diffLast); +} + +- (NSArray *)findFurthestIndexPathsFromScreen { + NSUInteger visibleItemsCount = [[self.collectionView visibleCells] count]; + NSUInteger maxCachedItemCount = [self maxCachedItemCount] == NSUIntegerMax ? visibleItemsCount * 3 : [self maxCachedItemCount]; + NSUInteger cachedCount = [_cachedItems count]; + NSInteger cachedCountToRemove = cachedCount > maxCachedItemCount ? cachedCount - maxCachedItemCount : 0; + if (0 != cachedCountToRemove) { + NSArray *visibleIndexPaths = [_collectionView indexPathsForVisibleItems]; + NSArray *sortedCachedItemKey = [[_cachedItems allKeys] sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { + NSIndexPath *ip1 = obj1; + NSIndexPath *ip2 = obj2; + NSUInteger ip1Diff = [self differenceFromIndexPath:ip1 againstVisibleIndexPaths:visibleIndexPaths]; + NSUInteger ip2Diff = [self differenceFromIndexPath:ip2 againstVisibleIndexPaths:visibleIndexPaths]; + //按照当前indexPath与屏幕可见范围内的indexPath距离由近到远排序 + if (ip1Diff > ip2Diff) { + return NSOrderedAscending; + } + else if (ip1Diff < ip2Diff) { + return NSOrderedDescending; + } + else { + return NSOrderedSame; + } + }]; + NSArray *result = [sortedCachedItemKey subarrayWithRange:NSMakeRange(0, cachedCountToRemove)]; + return result; + } + return nil; +} + +- (void)purgeFurthestIndexPathsFromScreen { + NSArray *furthestIndexPaths = [self findFurthestIndexPathsFromScreen]; + //purge view + //找到距离最远的indexPathes,删除 + NSArray *objects = [_cachedItems objectsForKeys:furthestIndexPaths notFoundMarker:@(-1)]; + [self.renderImpl purgeViewsFromComponentTags:objects onRootTag:self.rootTag]; + //purge cache + [_cachedItems removeObjectsForKeys:furthestIndexPaths]; +} + +``` + +### Image Decoder + +各业务会选择不同的图片格式就计入,而iOS api默认支持的图片格式有限。这种情况下,需要提供接口,处理默认不支持的图片格式解码。 + +为此我们声明了一份协议HippyImageProviderProtocol,专门处理各类型Image的解码工作。 + +接入方如果有自定义格式,需要实现一份protocol。 + +#### HippyImageProviderProtocol + +`HippyImageProviderProtocol`包含有两类方法:必须实现的和可选实现的。 + +必须实现的方法负责处理图片解码的基本操作,而可选实现的用于处理动图。 +接入方可同时添加多个解码器,HippySDK 在需要时,会按照解码器添加反序询问各解码器能否处理当前数据。如果不能,则会询问下个解码器,直至获取了对应的解码器,或者使用默认解码器。 + +如果没有解码器能处理对应的数据,则直接返回空图片对象。 + +| 方法名 | 说明 | +|--------|------| +| 必须实现 | +| +(BOOL)canHandleData:(NSData *)data | 询问当前解码器是否能处理数据 | +| +(BOOL)isAnimatedData:(NSData *)data | 询问当前解码器数据是否是动图 | +| -(void)setImageData:(NSData *)data | 设置图片原始数据 | +| -(UIImage *)image | 返回图片对象 | +| 可选实现 | +| -(NSUInteger)imageCount | 返回图片帧数(仅限于动图)| +| -(UIImage *)imageAtFrame:(NSUInteger)frame | 返回指定帧图片 | +| -(NSUIneger)loopCount | 返回动图循环次数 | +| -(double)delayTimeAtFrame:(NSUInteger)frame | 返回指定帧延迟时长 | + +#### HippyDefaultImageProvider + +Hippy3.0默认实现了一套decoder作为默认decoder,实现对系统支持的格式进行解码操作。任何没有decoder处理的数据,最终都会由HippyDefaultImageProvider调用系统API CGImageSource进行处理。 + +>默认支持PNG, JPG, GIF等常见格式 + +#### 动图实现逻辑 + +- Hipp3.0SDK的动图逻辑由NativeRenderAnimatedImage和NativeRenderAnimatedImageView负责。 +- 这是一个生产者-消费者模型。NativeRenderAnimatedImage负责生产,NativeRenderAnimatedImageView负责消费。 +- NativeRenderAnimatedImageView实现一个vsync回调,每次回调向NativeRenderAnimatedImage询问当前帧对应的Image +- NativeRenderAnimatedImage持有HippyImageProviderProtocol实例,负责解析动图,并返回对应帧的Image + +![image](../../../assets/img/animated_image.png) diff --git a/docs/architecture/render/ohos/native-render.md b/docs/architecture/render/ohos/native-render.md new file mode 100644 index 00000000000..634c27e85e1 --- /dev/null +++ b/docs/architecture/render/ohos/native-render.md @@ -0,0 +1,37 @@ +# Ohos Native Renderer + +--- + +Hippy 渲染器对接了 Ohos 的 ArkUI。ArkUI 提供了声明式 [TS API](https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V13/arkui-api-V13) 和过程式 [C API](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/_ark_u_i___native_module.md),TS API 开发方便,但性能不如 C API。 +Hippy 内部使用 C API 实现 UI 组件的绘制,同时支持业务通过 TS API 来实现自定义组件,也支持通过 C API 来实现自定义组件。 + +Hippy Ohos 整体架构: + +![image](../../../assets/img/ohos_hippy_arch.png) + +其中渲染系统,分两部分: + +- C++渲染器:负责几乎所有组件渲染和流程管理。 +- TS渲染器:负责业务接入根组件、自定义组件、Web组件。(Web组件没有C接口) + +## 自定义组件 + +支持两种语言实现自定义组件,TS和C,TS自定义组件开发方便,C自定义组件性能更好。一般页面内少量组件自定义,建议使用TS自定义组件,性能够用,对于极端性能场景,比如自定义Image、Text等基础组件,使用C自定义组件可以获得更好的性能。 + + +TS 语言实现自定义组件原理图: + +![image](../../../assets/img/ohos_custom_ts_comp.png) + +C 语言实现自定义组件原理图: + +![image](../../../assets/img/ohos_custom_c_comp.png) + +## TS 语言和 C 组件 + +迁移老业务页面时,有的业务会在native侧直接操作hippy的组件来实现一些联动。 +设计一套通用的跨语言操作接口给业务调用。接口对齐前端,从而减少业务理解成本。 + +正常前端操作、业务Native侵入操作、鸿蒙兼容方法对比图: + +![image](../../../assets/img/ohos_ts_op_c_comp.png) diff --git a/docs/architecture/render/tdf/_sidebar.md b/docs/architecture/render/tdf/_sidebar.md new file mode 100644 index 00000000000..b20335c2001 --- /dev/null +++ b/docs/architecture/render/tdf/_sidebar.md @@ -0,0 +1,3 @@ + + +* [TDFRender 使用](tdf/integration.md) diff --git a/docs/architecture/render/tdf/integration.md b/docs/architecture/render/tdf/integration.md new file mode 100644 index 00000000000..e4b5446c016 --- /dev/null +++ b/docs/architecture/render/tdf/integration.md @@ -0,0 +1,46 @@ +# TDFRender 介绍 + +TDFRender 是 c++ 实现的跨平台渲染器,统一了 Android / iOS 平台的组件实现和事件处理。 + +这篇教程,讲述了 Android / iOS 工程如何使用 TDFRender。 + +--- + +# Android / iOS 集成 + +集成 Hippy 的方法: + +* Android 平台同 [Android 集成](../android/integration.md) +* iOS 平台同 [iOS 集成](../ios/integration.md) + +# 使用 TDFRender + +## Android Demo 体验 + +### 1.引入 TDFRender 模块 + +gradle.properties 文件修改: +![tdf1](../assets/img/tdf_demo1.png) + +### 2.引入暂用 maven 源 + +```text +maven { url "https://mirrors.tencent.com/repository/maven/tdfcore" } +``` + +build.gradle 文件修改: +![tdf2](../assets/img/tdf_demo2.png) + +### 3.打开 TDFRender + +framework/android/src/main/java/com/tencent/mtt/hippy/HippyEngineManagerImpl.java 文件修改: +![tdf3](../assets/img/tdf_demo3.png) + +### 4.Demo 添加依赖 + +framework/examples/android-demo/build.gradle 文件修改: +![tdf4](../assets/img/tdf_demo4.png) + +## iOS Demo 体验 + +规划中。 diff --git a/docs/architecture/render/voltron/voltron-render.md b/docs/architecture/render/voltron/voltron-render.md new file mode 100644 index 00000000000..e110c289f0e --- /dev/null +++ b/docs/architecture/render/voltron/voltron-render.md @@ -0,0 +1,45 @@ +# Voltron Renderer + +在Hippy3.0中,我们增加了全新的Flutter渲染引擎丰富Hippy的使用生态,我们致力于将Flutter生态与Hippy进行深度的结合,接下来,我们将会对Voltron进行一些原理性的介绍。 + +## Voltron 渲染原理 + +### Hippy3.0 UI创建流程 + +从Hippy整体架构中我们可以发现,Hippy3.0中所有的渲染器都基于相同的整体流程 + +![image](../../../assets/img/voltron-render-1.png) + +Driver层(这里目前支持Javascript作为驱动)驱动DomManager进行Dom操作(包括创建,更新,移动,删除),Dom操作完成后经过Layout将布局信息汇总,并将所有创建的节点一次性打包发送给RenderManage,最后由不同渲染器的RenderManager进行渲染。 + +### UI 创建流程 + +![image](../../../assets/img/voltron-render-2.png) + +1. UI创建的起始点在`Driver`层,这里我们拿`Javascript Framework`作为例子,目前我们主要支持`Vue2`,`Vue3`,`React`三大框架,不管是你采用哪个上层框架,最终我们都会将DOM操作汇集到`SceneBuilder`(`SceneBuilder`是在`C++`侧注册进V8的处理DOM操作的类)上,其中`CreateNode`,`UpdateNode`,`MoveNode`,`DeleteNode`负责对`DOM`进行创建,更新,移动及删除,`AddEventListener`,`RemoveEventListener`负责处理事件的绑定和解绑,`Build`则负责通知一次操作的结束 +2. 通过`Driver`的驱动,`C++`侧的`DOM Manager`就可以获得完整的`DOM`信息,在接收到`Build`信号后,执行`SyncWithRenderManager`,通知`RenderManager`进行批量处理,首先是`FlushDomOperations`,更新元素的`DOM Tree`,然后`FlushEventOperations`,对`DOM`进行事件绑定解绑,最终`DoAndFlushLayout`,进行完整的布局计算,将`Layout`信息赋值给每一个`DOM`元素,最后,调用`EndBatch`通知`RenderManager`结束此次操作,需要注意的是,上述每一步操作都会通过`ffi`调用到`Dart`侧,接下来就是`Dart`侧的相关操作。 +3. 刚才我们提到,上述的所有操作都会调用到`Dart`侧,所以`Dart`侧也会有一个`RenderManager`负责下一步操作,在`FlushDomOperations`结束后,`Dart`侧会生成一颗`RenderNode Tree`,`FlushEventOperations`,`DoAndFlushLayout`都完成后,`RenderNode`就具备了足够的渲染条件,此时接收到`Build`信号,`RenderNode`就会开始对`ViewModel`(`ViewModel`本身是继承自`ChangeNotifier`,`Voltron`采用了`Provider`框架进行状态管理)进行操作,操作结束后,`ViewModel`调用自身的`Update`方法,通知元素进行更新,后续完全交给`Flutter`。 + +### UI 属性样式事件等实现 + +![image](../../../assets/img/voltron-render-3.png) + +1. 通过前面的UI 创建流程,我们可以得知,前端的组件通过一系列`DOM`操作在`Dart`侧会生成对应的`ViewModel`,而`ViewModel`上存放了所有需要渲染的信息,那么对`ViewModel`的操作如何触发页面的渲染呢。 +2. `Flutter`是一个声明式的UI框架,遵循`UI=F(State)`的模式,所以这里我们使用Provider状态管理来对组件进行封装,结合`Selector`的模式,以及重写`ViewModel`的相等操作符,这样在`ViewModel`触发`Update`操作后,元素自身就会检测变更情况,决定是否要进行`Build`操作,接下来,我们来看一下针对不同的样式,我们如何来进行处理。 +3. `Voltron`的整个`Widget`设计是基于层叠结构来做的,首先是最外层的`Layout`信息,我们交给`Positioned`组件来进行绝对定位(部分组件不需要绝对定位则可以不包裹这一层),`DecoratedBox`负责处理圆角,边框,阴影,形状,渐变,背景图像等,`ConstrainedBox`负责处理宽高,`Opacity`负责透明度,事件和手势操作我们使用`GestureDetector`和`Listener`,形变采用`Transform`,通过一系列的操作,公共属性都能够得到很好的支持,那么最内部的则是核心Widget,比如图片我们使用`ImageWidget`,文字我们使用`TextWidget`,iframe可以使用`WebViewWidget`等等 + + + +## Voltron Render 特点及答疑 + +1. 接入Voltron后,前端需要改动吗? + 答:上层前端框架完全兼容,Hippy-React和Hippy-Vue均可直接在Voltron中运行,Native侧的自定义模块和事件等经过封装后也可直接在Voltron中调用。 + +2. 接入Voltron后,Flutter组件可以使用吗? + 答:完全可以,可以参考[Voltron 自定义组件](development/native-component?id=voltron)对Flutter生态中的组件进行自定义的扩展。 + +3. 其他特性介绍 + - 完整的保留了 Hippy Native的优势,包括热更,跨平台等。 + - 具备天然的双端一致性保证。 + - 更高效的组件扩展,双端开发工作量合而为一,复用庞大的Flutter生态。 + - 更多优势等你探索。 diff --git a/docs/architecture/render/web/web-render.md b/docs/architecture/render/web/web-render.md new file mode 100644 index 00000000000..ba374f640a8 --- /dev/null +++ b/docs/architecture/render/web/web-render.md @@ -0,0 +1,92 @@ +# Web Renderer + +`Web Renderer`方案从实现的方案、机制和各种处理事件响应的逻辑与顺序都与终端保持高度一致性。使得`Web-Renderer`能够直接使用Hippy基于`Native方案`构建的`jsbundle.js`产物,在高度保持与终端侧渲染效果一致的情况下,使得复用JS层代码变的可能和简单。 +___ + +## 原理解析 + +### Hippy2.0方案 + +![enter image description here#430px #264px](../../../assets/img/web-renderer-f1.webp) + +![enter image description here#430px #264px](../../../assets/img/web-renderer-f1p.webp) + +上面第一章图是当前hippy的架构图,里面比较细节的展示了js、c++、native的各自组成内容。然后第二张图是在前端的角度,做了一些简化和抽象后的架构图。 + +### JS运行环境 + +当前`hippy2.0`的方案下,JS相关的代码一般由两部分组成,一部分是业务也就是平时大家写的,还有一部分是`hippy-react`和`hippy-vue`,这里面是对hippy终端提供的基础功能、协议的封装。而除开这两部分内容还有一部分内容是js逻辑是在c++里面的,在js引擎创建的时候会注入进去。这块代码主要是用来进行js运行环境的提供,如一些环境变量、全局的api(settimeout)等以支持UI框架的运行。 + +### 桥的实现 + +这里的`js-bridge`用以将js产生的数据和调用序列化后传递给终端。 + +### 调用解析/调用分发 + +终端在接受到js侧传递过来的数据时,需要进行解析然后分发给对应的处理对象进行处理。 + +### 组件/模块/事件的实现 + +是调用分发的承接者,如:调用解析到要创建一个组件,则就会将这个调用分发到组件这里然后创建出一个组件出来。 + +### 基于中间层的实现 + +![enter image description here#430px #264px](../../../assets/img/web-renderer-f2.webp) +在前面的内容,我们提到了hippy2.0方案中的几个关键的内容,其中在“桥的实现”和“调用解析分发”那里平凡提到了js侧产生的数据,接下来将详细讲述一些这些数据是什么、能干些什么。 + +上图是hippy终端方案交互层的抽象,现在的`hippy2.0`的方案中`js引擎`运转后会输出一些列的数据,其中包了ui指令(用来创建组件、更新组件、删除组件)、模块的功能调用、组件的api调用等。终端在接收和处理各种指令后,也会向js引擎派发事件、js侧的api调用、callback。 + +我们在这里将这块用来交互的内容称为**中间层**,这块中间层的内容是由hippy方案这么多年演进并且稳定下来的。是**标准化的、平台无关的**。这块中间层的内容,终端有一套完整的解析和处理逻辑,也正是因为这套逻辑才能构建出ui并且产生正确的交互。理论上来说只要能够完成对中间层内容的正确解析和实现,就能够实现与终端一直的渲染效果。 + +接下来看两个交互数据的例子: + +```json +createNode +{ + "id": 64, + "pId": 20, + "index": 0, + "name": "View", + "props": { + "onLayout": true, + "style": { + "flex": 1 + }, + }, + "tagName": "View" +} +``` + +这是一个创建组件的指令, + +- `creatNode`指明是要进行`ui创建` +- `id`代表终端和Web用来对这个`ui`的唯一标识 +- `pId`代表这个节点创建后将要被插入到哪个父节点下 +- `index`代表了插入到父节点下的第几个位置 +- `name`代表了创建的是一个什么类型的组件 +- `props`是对这个组件的哪些属性进行设置已经参数是什么 + +``` json +receiveUIComponentEvent +[ + 287, + "onPageSelected", + { + "position": 0 + } +] +``` + +这是一个终端对前端的ui事件指令,在数组中 + +- 第一个数字代表了这个`ui事件`要分发给`id`为287的这个组件, +- 第二个参数`onPageSelected`标识这次分发的事件的名称, +- 第三个参数代表这个事件携带的参数。 + +通过上面的内容可以看出正式通过js和终端不断的交互,然后解析这些交互内容并且分发到实现对象上,来构造ui,响应用户的操作。所以Web场景下,也需要完成对这些内容的解析和实现,这样才能从机制、流程和功能甚至是异常情况都达到与终端的一致性。从而实现比较平滑的进行渲染层切换,开发者在不同渲染层的成本也会更低更低。而Web-Renderer正是在浏览器上完成了这一系列的标准内容解析和功能提供,让Web-Renderer可以使用相同的构建产物,并且表现上高度一致 + +### 基于中间层实现,Native VS Web 流程对比 + +![enter image description here#430px #264px](../../../assets/img/web-renderer-f3.webp) + +在基于中间层这个技术关键点完成Web-Renderer方案后,可以看到与Native方案的对比,Web-Renderer使用与其相同的构建产物,一致的渲染流程。而不同的是最后落地到的UI和功能上,一个是落地到浏览器提供的上面,一个是落地到 Android/iOS提供的上面。 diff --git a/docs/assets/css/slidebar.min.css b/docs/assets/css/slidebar.min.css new file mode 100644 index 00000000000..03edb69944d --- /dev/null +++ b/docs/assets/css/slidebar.min.css @@ -0,0 +1 @@ +.sidebar-nav>ul{margin-left:20px}.sidebar-nav ul:not(.app-sub-sidebar)>li{position:relative;cursor:pointer;margin-left:4px}.sidebar-nav ul:not(.app-sub-sidebar)>li::before{content:'';display:block;position:absolute;top:8px;left:-20px;height:14px;width:14px}.sidebar-nav ul:not(.app-sub-sidebar)>li.folder::before{background:center/contain no-repeat url(data:image/svg+xml;base64,PHN2ZyB0PSIxNTk4NTQ1NjIzOTMxIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjgxNzMiCiAgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiPgogIDxwYXRoCiAgICBkPSJNODEyLjggMjY4LjhsLTE4NS42LTE4NS42Yy0xMi44LTEyLjgtMjguOC0xOS4yLTQ0LjgtMTkuMkgyNTZjLTM1LjIgMC02NCAyOC44LTY0IDY0djc2OGMwIDM1LjIgMjguOCA2NCA2NCA2NGg1MTJjMzUuMiAwIDY0LTI4LjggNjQtNjRWMzEzLjZjMC0xNi02LjQtMzItMTkuMi00NC44eiBtLTcwLjQgMTkuMkg2MDhWMTUzLjZMNzQyLjQgMjg4ek03MDQgODk2SDI1NlYxMjhoMjg4djE2MGMwIDM1LjIgMjguOCA2NCA2NCA2NGgxNjB2NTQ0aC02NHoiCiAgICBwLWlkPSI4MTc0Ij48L3BhdGg+Cjwvc3ZnPgo=)}.sidebar-nav ul:not(.app-sub-sidebar)>li.file::before{background:center/contain no-repeat url(data:image/svg+xml;base64,PHN2ZyB0PSIxNTk4NTQ1NjIzOTMxIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjgxNzMiCiAgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiPgogIDxwYXRoCiAgICBkPSJNODEyLjggMjY4LjhsLTE4NS42LTE4NS42Yy0xMi44LTEyLjgtMjguOC0xOS4yLTQ0LjgtMTkuMkgyNTZjLTM1LjIgMC02NCAyOC44LTY0IDY0djc2OGMwIDM1LjIgMjguOCA2NCA2NCA2NGg1MTJjMzUuMiAwIDY0LTI4LjggNjQtNjRWMzEzLjZjMC0xNi02LjQtMzItMTkuMi00NC44eiBtLTcwLjQgMTkuMkg2MDhWMTUzLjZMNzQyLjQgMjg4ek03MDQgODk2SDI1NlYxMjhoMjg4djE2MGMwIDM1LjIgMjguOCA2NCA2NCA2NGgxNjB2NTQ0aC02NHoiCiAgICBwLWlkPSI4MTc0Ij48L3BhdGg+Cjwvc3ZnPgo=)} \ No newline at end of file diff --git a/docs/assets/css/vue.css b/docs/assets/css/vue.css new file mode 100644 index 00000000000..73addc93b20 --- /dev/null +++ b/docs/assets/css/vue.css @@ -0,0 +1 @@ +*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready) [data-cloak],body:not(.ready)>nav{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}.emoji{height:1.2rem;vertical-align:middle}.progress{background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:999999}.search a:hover{color:var(--theme-color,#42b983)}.search .search-keyword{color:var(--theme-color,#42b983);font-style:normal;font-weight:700}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}a[disabled]{cursor:not-allowed;opacity:.6}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}li input[type=checkbox]{margin:0 .2em .25em 0;vertical-align:middle}.app-nav{margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:10}.app-nav.no-badge{margin-right:25px}.app-nav p{margin:0}.app-nav>a{margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;transition:color .3s}.app-nav a:hover{color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid var(--theme-color,#42b983);color:var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 1rem;padding:5px 0;position:relative;cursor:pointer}.app-nav li ul{background-color:#fff;border:1px solid;border-color:#ddd #ddd #ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:auto;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:1rem;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner:hover .octo-arm{-webkit-animation:octocat-wave .56s ease-in-out;animation:octocat-wave .56s ease-in-out}.github-corner svg{color:#fff;fill:var(--theme-color,#42b983);height:80px;width:80px}main{display:block;position:relative;width:100vw;height:100%;z-index:0}main.hidden{display:none}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0 0;position:absolute;top:0;bottom:0;left:0;transition:transform .25s ease-out;width:300px;z-index:20}.sidebar>h1{margin:0 auto 1rem;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar li.collapse .app-sub-sidebar{display:none}.sidebar ul{margin:0 0 0 15px;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:0 0;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53.3%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53.3%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:0;padding:10px;position:absolute;bottom:0;left:0;text-align:center;transition:opacity .3s;width:284px;z-index:30;cursor:pointer}.sidebar-toggle:hover .sidebar-toggle-button{opacity:.4}.sidebar-toggle span{background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;position:absolute;top:0;right:0;bottom:0;left:300px;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:80%;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section iframe{border:1px solid #eee;width:1px;min-width:100%}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{background-color:#f8f8f8;border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;height:20px;width:20px;text-align:center;top:14px}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:1rem}.markdown-section ul.task-list>li{list-style-type:none}body.close .sidebar{transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;min-height:100vh;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.app-nav,.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto;padding:30px 30px 10px 10px}body.close .sidebar{transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);transition:background-color 1s;width:284px;padding:10px}body.close .content{transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner:hover .octo-arm{-webkit-animation:none;animation:none}.github-corner .octo-arm{-webkit-animation:octocat-wave .56s ease-in-out;animation:octocat-wave .56s ease-in-out}}@-webkit-keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}section.cover{align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;width:100vw;display:none}section.cover.show{display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;top:0;height:100%;width:100%}section.cover .cover-main{flex:1;margin:-20px 16px 0;text-align:center;position:relative}section.cover a{color:inherit;text-decoration:none}section.cover a:hover{text-decoration:none}section.cover p{line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:2.5rem;font-weight:300;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-.4375rem;font-size:1rem;position:absolute}section.cover blockquote{font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-radius:2rem;border:1px solid var(--theme-color,#42b983);box-sizing:border-box;color:var(--theme-color,#42b983);display:inline-block;font-size:1.05rem;letter-spacing:.1rem;margin:.5rem 1rem;padding:.75em 2rem;text-decoration:none;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:var(--theme-color,#42b983);color:#fff}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid var(--theme-color,#42b983);transition:color .3s}section.cover blockquote>p>a:hover{color:var(--theme-color,#42b983)}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar li:before{content:"-";padding-right:4px;float:left}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:2rem;margin:0 0 1rem}.markdown-section h2{font-size:1.75rem;margin:45px 0 .8rem}.markdown-section h3{font-size:1.5rem;margin:40px 0 .6rem}.markdown-section h4{font-size:1.25rem}.markdown-section h5{font-size:1rem}.markdown-section h6{color:#777;font-size:1rem}.markdown-section figure,.markdown-section p{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:1.6rem;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code,.markdown-section output:after,.markdown-section pre{font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section code,.markdown-section pre{background-color:#f8f8f8}.markdown-section output,.markdown-section pre{margin:1.2em 0;position:relative}.markdown-section output,.markdown-section pre>code{border-radius:2px;display:block}.markdown-section output:after,.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial}.markdown-section code{border-radius:2px;color:#e96900;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section>:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code{font-size:.8rem}.markdown-section pre{padding:0 1.4rem;line-height:1.5rem;overflow:auto;word-wrap:normal}.markdown-section pre>code{color:#525252;font-size:.8rem;padding:2.2em 5px;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;white-space:inherit}.markdown-section output{padding:1.7rem 1.4rem;border:1px dotted #ccc}.markdown-section output>:first-child{margin-top:0}.markdown-section output>:last-child{margin-bottom:0}.markdown-section code:after,.markdown-section code:before,.markdown-section output:after,.markdown-section output:before{letter-spacing:.05rem}.markdown-section output:after,.markdown-section pre:after{color:#ccc;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0}.markdown-section output:after,.markdown-section pre:after{content:attr(data-lang)}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:var(--theme-color,#42b983)}.token.function,.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:1.5rem;position:relative;left:auto} diff --git a/docs/assets/img/2.0-structure.png b/docs/assets/img/2.0-structure.png new file mode 100644 index 00000000000..97207720aac Binary files /dev/null and b/docs/assets/img/2.0-structure.png differ diff --git a/docs/assets/img/3.0-demo-create.png b/docs/assets/img/3.0-demo-create.png new file mode 100644 index 00000000000..23585f0848d Binary files /dev/null and b/docs/assets/img/3.0-demo-create.png differ diff --git a/docs/assets/img/3.0-demo-helloworld.png b/docs/assets/img/3.0-demo-helloworld.png new file mode 100644 index 00000000000..14dbe00df10 Binary files /dev/null and b/docs/assets/img/3.0-demo-helloworld.png differ diff --git a/docs/assets/img/3.0-demo-home.png b/docs/assets/img/3.0-demo-home.png new file mode 100644 index 00000000000..42637ec7454 Binary files /dev/null and b/docs/assets/img/3.0-demo-home.png differ diff --git a/docs/assets/img/3.0-demo-page-management.png b/docs/assets/img/3.0-demo-page-management.png new file mode 100644 index 00000000000..3df9604515e Binary files /dev/null and b/docs/assets/img/3.0-demo-page-management.png differ diff --git a/docs/assets/img/3.0-demo.png b/docs/assets/img/3.0-demo.png new file mode 100644 index 00000000000..f2be10f8bfe Binary files /dev/null and b/docs/assets/img/3.0-demo.png differ diff --git a/docs/assets/img/3.0-performance-fps.png b/docs/assets/img/3.0-performance-fps.png new file mode 100644 index 00000000000..53deac33d72 Binary files /dev/null and b/docs/assets/img/3.0-performance-fps.png differ diff --git a/docs/assets/img/3.0-performance-memory.png b/docs/assets/img/3.0-performance-memory.png new file mode 100644 index 00000000000..3ab10e004b6 Binary files /dev/null and b/docs/assets/img/3.0-performance-memory.png differ diff --git a/docs/assets/img/3.0-performance-start.png b/docs/assets/img/3.0-performance-start.png new file mode 100644 index 00000000000..021a9baf8e4 Binary files /dev/null and b/docs/assets/img/3.0-performance-start.png differ diff --git a/docs/assets/img/3.0-performance0.png b/docs/assets/img/3.0-performance0.png new file mode 100644 index 00000000000..7cc75f1b747 Binary files /dev/null and b/docs/assets/img/3.0-performance0.png differ diff --git a/docs/assets/img/3.0-performance1.png b/docs/assets/img/3.0-performance1.png new file mode 100644 index 00000000000..b94fe94598c Binary files /dev/null and b/docs/assets/img/3.0-performance1.png differ diff --git a/docs/assets/img/3.0-performance2.png b/docs/assets/img/3.0-performance2.png new file mode 100644 index 00000000000..2690dcec0eb Binary files /dev/null and b/docs/assets/img/3.0-performance2.png differ diff --git a/docs/assets/img/3.0-structure.png b/docs/assets/img/3.0-structure.png new file mode 100644 index 00000000000..990b44e19f7 Binary files /dev/null and b/docs/assets/img/3.0-structure.png differ diff --git a/docs/assets/img/IVW_23.png b/docs/assets/img/IVW_23.png new file mode 100644 index 00000000000..1f9df16c2e1 Binary files /dev/null and b/docs/assets/img/IVW_23.png differ diff --git a/docs/assets/img/android-studio-jdk.png b/docs/assets/img/android-studio-jdk.png new file mode 100644 index 00000000000..6c2755dcba0 Binary files /dev/null and b/docs/assets/img/android-studio-jdk.png differ diff --git a/docs/assets/img/animated_image.png b/docs/assets/img/animated_image.png new file mode 100644 index 00000000000..10ba7a6dde7 Binary files /dev/null and b/docs/assets/img/animated_image.png differ diff --git a/docs/assets/img/baodaxiao.png b/docs/assets/img/baodaxiao.png new file mode 100644 index 00000000000..4c44ceb193c Binary files /dev/null and b/docs/assets/img/baodaxiao.png differ diff --git a/docs/assets/img/border-box.png b/docs/assets/img/border-box.png new file mode 100644 index 00000000000..4b61c8f4b35 Binary files /dev/null and b/docs/assets/img/border-box.png differ diff --git a/docs/assets/img/bugly-hippy-alert.png b/docs/assets/img/bugly-hippy-alert.png new file mode 100644 index 00000000000..5e146aa7bca Binary files /dev/null and b/docs/assets/img/bugly-hippy-alert.png differ diff --git a/docs/assets/img/bugly-hippy-config.png b/docs/assets/img/bugly-hippy-config.png new file mode 100644 index 00000000000..b25a143edaf Binary files /dev/null and b/docs/assets/img/bugly-hippy-config.png differ diff --git a/docs/assets/img/bugly-hippy-log.png b/docs/assets/img/bugly-hippy-log.png new file mode 100644 index 00000000000..03065647a88 Binary files /dev/null and b/docs/assets/img/bugly-hippy-log.png differ diff --git a/docs/assets/img/bugly-hippy-metric.png b/docs/assets/img/bugly-hippy-metric.png new file mode 100644 index 00000000000..112d79a7724 Binary files /dev/null and b/docs/assets/img/bugly-hippy-metric.png differ diff --git a/docs/assets/img/bugly-hippy-multi.png b/docs/assets/img/bugly-hippy-multi.png new file mode 100644 index 00000000000..57f98b65fad Binary files /dev/null and b/docs/assets/img/bugly-hippy-multi.png differ diff --git a/docs/assets/img/bugly-hippy-overview.png b/docs/assets/img/bugly-hippy-overview.png new file mode 100644 index 00000000000..77141d0743c Binary files /dev/null and b/docs/assets/img/bugly-hippy-overview.png differ diff --git a/docs/assets/img/bugly-hippy-waterfall.png b/docs/assets/img/bugly-hippy-waterfall.png new file mode 100644 index 00000000000..d4dd2917888 Binary files /dev/null and b/docs/assets/img/bugly-hippy-waterfall.png differ diff --git a/docs/assets/img/check-font.png b/docs/assets/img/check-font.png new file mode 100644 index 00000000000..46ad0cb5e93 Binary files /dev/null and b/docs/assets/img/check-font.png differ diff --git a/docs/assets/img/chrome-inspect-process.png b/docs/assets/img/chrome-inspect-process.png new file mode 100644 index 00000000000..32989d844d8 Binary files /dev/null and b/docs/assets/img/chrome-inspect-process.png differ diff --git a/docs/assets/img/chrome-inspect.png b/docs/assets/img/chrome-inspect.png new file mode 100644 index 00000000000..4a6b6dd42f5 Binary files /dev/null and b/docs/assets/img/chrome-inspect.png differ diff --git a/docs/assets/img/confirm-font.png b/docs/assets/img/confirm-font.png new file mode 100644 index 00000000000..2a2358fee4a Binary files /dev/null and b/docs/assets/img/confirm-font.png differ diff --git a/docs/assets/img/copy-font.png b/docs/assets/img/copy-font.png new file mode 100644 index 00000000000..f822a02c433 Binary files /dev/null and b/docs/assets/img/copy-font.png differ diff --git a/docs/assets/img/dynamic_import.png b/docs/assets/img/dynamic_import.png new file mode 100644 index 00000000000..4c6f1cd955a Binary files /dev/null and b/docs/assets/img/dynamic_import.png differ diff --git a/docs/assets/img/element-inspect.png b/docs/assets/img/element-inspect.png new file mode 100644 index 00000000000..04d40716400 Binary files /dev/null and b/docs/assets/img/element-inspect.png differ diff --git a/docs/assets/img/elements-inspect.webm b/docs/assets/img/elements-inspect.webm new file mode 100644 index 00000000000..1336b33c573 Binary files /dev/null and b/docs/assets/img/elements-inspect.webm differ diff --git a/docs/assets/img/flatten-ui-1.png b/docs/assets/img/flatten-ui-1.png new file mode 100644 index 00000000000..8a61a838edd Binary files /dev/null and b/docs/assets/img/flatten-ui-1.png differ diff --git a/docs/assets/img/flatten-ui-2.png b/docs/assets/img/flatten-ui-2.png new file mode 100644 index 00000000000..a72b1949847 Binary files /dev/null and b/docs/assets/img/flatten-ui-2.png differ diff --git a/docs/assets/img/flatten-ui-3.png b/docs/assets/img/flatten-ui-3.png new file mode 100644 index 00000000000..0bc3bc32f33 Binary files /dev/null and b/docs/assets/img/flatten-ui-3.png differ diff --git a/docs/assets/img/flatten-ui-4.png b/docs/assets/img/flatten-ui-4.png new file mode 100644 index 00000000000..e358f5605c5 Binary files /dev/null and b/docs/assets/img/flatten-ui-4.png differ diff --git a/docs/assets/img/flatten-ui-5.png b/docs/assets/img/flatten-ui-5.png new file mode 100644 index 00000000000..c81fa6a8dc4 Binary files /dev/null and b/docs/assets/img/flatten-ui-5.png differ diff --git a/docs/assets/img/flatten-ui-6.png b/docs/assets/img/flatten-ui-6.png new file mode 100644 index 00000000000..aaca398f9a4 Binary files /dev/null and b/docs/assets/img/flatten-ui-6.png differ diff --git a/docs/assets/img/flex-direction.png b/docs/assets/img/flex-direction.png new file mode 100644 index 00000000000..57e5b15aa2e Binary files /dev/null and b/docs/assets/img/flex-direction.png differ diff --git a/docs/assets/img/follow_animation.gif b/docs/assets/img/follow_animation.gif new file mode 100644 index 00000000000..9b0370cae3d Binary files /dev/null and b/docs/assets/img/follow_animation.gif differ diff --git a/docs/assets/img/font-project-setup.png b/docs/assets/img/font-project-setup.png new file mode 100644 index 00000000000..1d0d31e8e74 Binary files /dev/null and b/docs/assets/img/font-project-setup.png differ diff --git a/docs/assets/img/hippy-core.png b/docs/assets/img/hippy-core.png new file mode 100644 index 00000000000..3933a15040f Binary files /dev/null and b/docs/assets/img/hippy-core.png differ diff --git a/docs/assets/img/hippy-dev-output.png b/docs/assets/img/hippy-dev-output.png new file mode 100644 index 00000000000..0290ab885d8 Binary files /dev/null and b/docs/assets/img/hippy-dev-output.png differ diff --git a/docs/assets/img/hippy-logo.ico b/docs/assets/img/hippy-logo.ico new file mode 100644 index 00000000000..98186b50268 Binary files /dev/null and b/docs/assets/img/hippy-logo.ico differ diff --git a/docs/assets/img/hippy-logo.png b/docs/assets/img/hippy-logo.png new file mode 100644 index 00000000000..0d022c064ff Binary files /dev/null and b/docs/assets/img/hippy-logo.png differ diff --git a/docs/assets/img/hippy-react-dev-process.png b/docs/assets/img/hippy-react-dev-process.png new file mode 100644 index 00000000000..6074c27d96a Binary files /dev/null and b/docs/assets/img/hippy-react-dev-process.png differ diff --git a/docs/assets/img/hippy-react-devtools.webm b/docs/assets/img/hippy-react-devtools.webm new file mode 100644 index 00000000000..9a01368ca2f Binary files /dev/null and b/docs/assets/img/hippy-react-devtools.webm differ diff --git a/docs/assets/img/hippy-react.png b/docs/assets/img/hippy-react.png new file mode 100644 index 00000000000..cd58d53659f Binary files /dev/null and b/docs/assets/img/hippy-react.png differ diff --git a/docs/assets/img/hippy-vue-devtools.webm b/docs/assets/img/hippy-vue-devtools.webm new file mode 100644 index 00000000000..f48f58eb21d Binary files /dev/null and b/docs/assets/img/hippy-vue-devtools.webm differ diff --git a/docs/assets/img/hippy-vue-next-arch-cn.png b/docs/assets/img/hippy-vue-next-arch-cn.png new file mode 100644 index 00000000000..cae2187095a Binary files /dev/null and b/docs/assets/img/hippy-vue-next-arch-cn.png differ diff --git a/docs/assets/img/hippy-vue-next-ssr-arch-cn.png b/docs/assets/img/hippy-vue-next-ssr-arch-cn.png new file mode 100644 index 00000000000..df95922560e Binary files /dev/null and b/docs/assets/img/hippy-vue-next-ssr-arch-cn.png differ diff --git a/docs/assets/img/hippy-vue.png b/docs/assets/img/hippy-vue.png new file mode 100644 index 00000000000..9c151543264 Binary files /dev/null and b/docs/assets/img/hippy-vue.png differ diff --git a/docs/assets/img/hmr.gif b/docs/assets/img/hmr.gif new file mode 100644 index 00000000000..d70b04a572a Binary files /dev/null and b/docs/assets/img/hmr.gif differ diff --git a/docs/assets/img/info-plist.png b/docs/assets/img/info-plist.png new file mode 100644 index 00000000000..70ad1d81e00 Binary files /dev/null and b/docs/assets/img/info-plist.png differ diff --git a/docs/assets/img/inspectDebugInfo.png b/docs/assets/img/inspectDebugInfo.png new file mode 100644 index 00000000000..9865242cced Binary files /dev/null and b/docs/assets/img/inspectDebugInfo.png differ diff --git a/docs/assets/img/ios-remote-debug-config.png b/docs/assets/img/ios-remote-debug-config.png new file mode 100644 index 00000000000..d7e46a41fa4 Binary files /dev/null and b/docs/assets/img/ios-remote-debug-config.png differ diff --git a/docs/assets/img/ios-safari-config.png b/docs/assets/img/ios-safari-config.png new file mode 100644 index 00000000000..8a29aa1f898 Binary files /dev/null and b/docs/assets/img/ios-safari-config.png differ diff --git a/docs/assets/img/ios-simulator.png b/docs/assets/img/ios-simulator.png new file mode 100644 index 00000000000..6aa53567c55 Binary files /dev/null and b/docs/assets/img/ios-simulator.png differ diff --git a/docs/assets/img/jsbao.png b/docs/assets/img/jsbao.png new file mode 100644 index 00000000000..f5b2b09a162 Binary files /dev/null and b/docs/assets/img/jsbao.png differ diff --git a/docs/assets/img/jsi_structure.png b/docs/assets/img/jsi_structure.png new file mode 100644 index 00000000000..574c5c31416 Binary files /dev/null and b/docs/assets/img/jsi_structure.png differ diff --git a/docs/assets/img/jsi_type_android.png b/docs/assets/img/jsi_type_android.png new file mode 100644 index 00000000000..327d0e0e72e Binary files /dev/null and b/docs/assets/img/jsi_type_android.png differ diff --git a/docs/assets/img/lazy_load1.png b/docs/assets/img/lazy_load1.png new file mode 100644 index 00000000000..4574c1c0271 Binary files /dev/null and b/docs/assets/img/lazy_load1.png differ diff --git a/docs/assets/img/lazy_load2.png b/docs/assets/img/lazy_load2.png new file mode 100644 index 00000000000..c8a90c57143 Binary files /dev/null and b/docs/assets/img/lazy_load2.png differ diff --git a/docs/assets/img/list.png b/docs/assets/img/list.png new file mode 100644 index 00000000000..f928d9d69a3 Binary files /dev/null and b/docs/assets/img/list.png differ diff --git a/docs/assets/img/listmeicun.png b/docs/assets/img/listmeicun.png new file mode 100644 index 00000000000..7c3287a1145 Binary files /dev/null and b/docs/assets/img/listmeicun.png differ diff --git a/docs/assets/img/listxingneng.png b/docs/assets/img/listxingneng.png new file mode 100644 index 00000000000..9db4e189310 Binary files /dev/null and b/docs/assets/img/listxingneng.png differ diff --git a/docs/assets/img/ohos_custom_c_comp.png b/docs/assets/img/ohos_custom_c_comp.png new file mode 100644 index 00000000000..8632a59548f Binary files /dev/null and b/docs/assets/img/ohos_custom_c_comp.png differ diff --git a/docs/assets/img/ohos_custom_ts_comp.png b/docs/assets/img/ohos_custom_ts_comp.png new file mode 100644 index 00000000000..798fcb68970 Binary files /dev/null and b/docs/assets/img/ohos_custom_ts_comp.png differ diff --git a/docs/assets/img/ohos_hippy_arch.png b/docs/assets/img/ohos_hippy_arch.png new file mode 100644 index 00000000000..5d8fe16d2c0 Binary files /dev/null and b/docs/assets/img/ohos_hippy_arch.png differ diff --git a/docs/assets/img/ohos_jsvm_debug1.png b/docs/assets/img/ohos_jsvm_debug1.png new file mode 100644 index 00000000000..edb537f9d59 Binary files /dev/null and b/docs/assets/img/ohos_jsvm_debug1.png differ diff --git a/docs/assets/img/ohos_jsvm_debug2.png b/docs/assets/img/ohos_jsvm_debug2.png new file mode 100644 index 00000000000..57234321636 Binary files /dev/null and b/docs/assets/img/ohos_jsvm_debug2.png differ diff --git a/docs/assets/img/ohos_jsvm_debug3.png b/docs/assets/img/ohos_jsvm_debug3.png new file mode 100644 index 00000000000..e9740d2e336 Binary files /dev/null and b/docs/assets/img/ohos_jsvm_debug3.png differ diff --git a/docs/assets/img/ohos_ts_op_c_comp.png b/docs/assets/img/ohos_ts_op_c_comp.png new file mode 100644 index 00000000000..5fa7708052f Binary files /dev/null and b/docs/assets/img/ohos_ts_op_c_comp.png differ diff --git a/docs/assets/img/pk_animation.gif b/docs/assets/img/pk_animation.gif new file mode 100644 index 00000000000..e18e0485a8a Binary files /dev/null and b/docs/assets/img/pk_animation.gif differ diff --git a/docs/assets/img/qg-team.png b/docs/assets/img/qg-team.png new file mode 100644 index 00000000000..b26db85e4c1 Binary files /dev/null and b/docs/assets/img/qg-team.png differ diff --git a/docs/assets/img/qq-group.png b/docs/assets/img/qq-group.png new file mode 100644 index 00000000000..915d6314d60 Binary files /dev/null and b/docs/assets/img/qq-group.png differ diff --git a/docs/assets/img/remote-debug-demo.webm b/docs/assets/img/remote-debug-demo.webm new file mode 100644 index 00000000000..7f37a2674cb Binary files /dev/null and b/docs/assets/img/remote-debug-demo.webm differ diff --git a/docs/assets/img/remote-debug-webpack-output.png b/docs/assets/img/remote-debug-webpack-output.png new file mode 100644 index 00000000000..142b8464fbb Binary files /dev/null and b/docs/assets/img/remote-debug-webpack-output.png differ diff --git a/docs/assets/img/render-snapshot-performance.png b/docs/assets/img/render-snapshot-performance.png new file mode 100644 index 00000000000..cee5b63a9a5 Binary files /dev/null and b/docs/assets/img/render-snapshot-performance.png differ diff --git a/docs/assets/img/safari-dev-process.png b/docs/assets/img/safari-dev-process.png new file mode 100644 index 00000000000..25314cdab09 Binary files /dev/null and b/docs/assets/img/safari-dev-process.png differ diff --git a/docs/assets/img/smile_animation.gif b/docs/assets/img/smile_animation.gif new file mode 100644 index 00000000000..ef75a349670 Binary files /dev/null and b/docs/assets/img/smile_animation.gif differ diff --git a/docs/assets/img/tdf_demo1.png b/docs/assets/img/tdf_demo1.png new file mode 100644 index 00000000000..f2decb5b670 Binary files /dev/null and b/docs/assets/img/tdf_demo1.png differ diff --git a/docs/assets/img/tdf_demo2.png b/docs/assets/img/tdf_demo2.png new file mode 100644 index 00000000000..2465ac0fd49 Binary files /dev/null and b/docs/assets/img/tdf_demo2.png differ diff --git a/docs/assets/img/tdf_demo3.png b/docs/assets/img/tdf_demo3.png new file mode 100644 index 00000000000..ba9367db1b4 Binary files /dev/null and b/docs/assets/img/tdf_demo3.png differ diff --git a/docs/assets/img/tdf_demo4.png b/docs/assets/img/tdf_demo4.png new file mode 100644 index 00000000000..d0029d3534e Binary files /dev/null and b/docs/assets/img/tdf_demo4.png differ diff --git a/docs/assets/img/text_measure.png b/docs/assets/img/text_measure.png new file mode 100644 index 00000000000..a2af9fbd9be Binary files /dev/null and b/docs/assets/img/text_measure.png differ diff --git a/docs/assets/img/tv.png b/docs/assets/img/tv.png new file mode 100644 index 00000000000..3278bdfd1a7 Binary files /dev/null and b/docs/assets/img/tv.png differ diff --git a/docs/assets/img/ui_process.png b/docs/assets/img/ui_process.png new file mode 100644 index 00000000000..f0285cccde6 Binary files /dev/null and b/docs/assets/img/ui_process.png differ diff --git a/docs/assets/img/vfs-chain.png b/docs/assets/img/vfs-chain.png new file mode 100644 index 00000000000..42229ea4aea Binary files /dev/null and b/docs/assets/img/vfs-chain.png differ diff --git a/docs/assets/img/vfs-processor.png b/docs/assets/img/vfs-processor.png new file mode 100644 index 00000000000..9668d1f8c87 Binary files /dev/null and b/docs/assets/img/vfs-processor.png differ diff --git a/docs/assets/img/voltron-render-1.png b/docs/assets/img/voltron-render-1.png new file mode 100644 index 00000000000..170957b6461 Binary files /dev/null and b/docs/assets/img/voltron-render-1.png differ diff --git a/docs/assets/img/voltron-render-2.png b/docs/assets/img/voltron-render-2.png new file mode 100644 index 00000000000..42bde1c11d7 Binary files /dev/null and b/docs/assets/img/voltron-render-2.png differ diff --git a/docs/assets/img/voltron-render-3.png b/docs/assets/img/voltron-render-3.png new file mode 100644 index 00000000000..0db6baff0be Binary files /dev/null and b/docs/assets/img/voltron-render-3.png differ diff --git a/docs/assets/img/voov.png b/docs/assets/img/voov.png new file mode 100644 index 00000000000..e6a1c965c05 Binary files /dev/null and b/docs/assets/img/voov.png differ diff --git a/docs/assets/img/web-renderer-f1.webp b/docs/assets/img/web-renderer-f1.webp new file mode 100644 index 00000000000..b4c7ffe4281 Binary files /dev/null and b/docs/assets/img/web-renderer-f1.webp differ diff --git a/docs/assets/img/web-renderer-f1p.webp b/docs/assets/img/web-renderer-f1p.webp new file mode 100644 index 00000000000..7c9f48f6ae4 Binary files /dev/null and b/docs/assets/img/web-renderer-f1p.webp differ diff --git a/docs/assets/img/web-renderer-f2.webp b/docs/assets/img/web-renderer-f2.webp new file mode 100644 index 00000000000..6b49ebc9432 Binary files /dev/null and b/docs/assets/img/web-renderer-f2.webp differ diff --git a/docs/assets/img/web-renderer-f3.webp b/docs/assets/img/web-renderer-f3.webp new file mode 100644 index 00000000000..02f27672ace Binary files /dev/null and b/docs/assets/img/web-renderer-f3.webp differ diff --git a/docs/assets/img/wechat-group.jpeg b/docs/assets/img/wechat-group.jpeg new file mode 100644 index 00000000000..de2741817b3 Binary files /dev/null and b/docs/assets/img/wechat-group.jpeg differ diff --git a/docs/assets/img/wii-team.png b/docs/assets/img/wii-team.png new file mode 100644 index 00000000000..900600862d4 Binary files /dev/null and b/docs/assets/img/wii-team.png differ diff --git a/docs/assets/js/docsify-sidebar-collapse.min.js b/docs/assets/js/docsify-sidebar-collapse.min.js new file mode 100644 index 00000000000..2b067c7e250 --- /dev/null +++ b/docs/assets/js/docsify-sidebar-collapse.min.js @@ -0,0 +1 @@ +!function(e){("object"!=typeof exports||"undefined"==typeof module)&&"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";function e(e,n){var t,a=(n=void 0===n?{}:n).insertAt;e&&"undefined"!=typeof document&&(t=document.head||document.getElementsByTagName("head")[0],(n=document.createElement("style")).type="text/css","top"===a&&t.firstChild?t.insertBefore(n,t.firstChild):t.appendChild(n),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e)))}var t;function a(e){e&&null!=t&&(e=e.getBoundingClientRect().top,document.querySelector(".sidebar").scrollBy(0,e-t))}function n(){requestAnimationFrame(function(){var e=document.querySelector(".app-sub-sidebar > .active");if(e)for(e.parentNode.parentNode.querySelectorAll(".app-sub-sidebar").forEach(function(e){return e.classList.remove("open")});e.parentNode.classList.contains("app-sub-sidebar")&&!e.parentNode.classList.contains("open");)e.parentNode.classList.add("open"),e=e.parentNode})}function o(e){t=e.target.getBoundingClientRect().top;var n=d(e.target,"LI",2);n&&(n.classList.contains("open")?(n.classList.remove("open"),setTimeout(function(){n.classList.add("collapse")},0)):(function(e){if(e)for(e.classList.remove("open","active");e&&"sidebar-nav"!==e.className&&e.parentNode;)"LI"!==e.parentNode.tagName&&"app-sub-sidebar"!==e.parentNode.className||e.parentNode.classList.remove("open"),e=e.parentNode}(s()),i(n),setTimeout(function(){n.classList.remove("collapse")},0)),a(n))}function s(){var e=document.querySelector(".sidebar-nav .active");return e||(e=d(document.querySelector('.sidebar-nav a[href="'.concat(decodeURIComponent(location.hash).replace(/ /gi,"%20"),'"]')),"LI",2))&&e.classList.add("active"),e}function i(e){if(e)for(e.classList.add("open","active");e&&"sidebar-nav"!==e.className&&e.parentNode;)"LI"!==e.parentNode.tagName&&"app-sub-sidebar"!==e.parentNode.className||e.parentNode.classList.add("open"),e=e.parentNode}function d(e,n,t){if(e&&e.tagName===n)return e;for(var a=0;e;){if(t<++a)return;if(e.parentNode.tagName===n)return e.parentNode;e=e.parentNode}}e(".sidebar-nav > ul > li ul {\n display: none;\n}\n\n.app-sub-sidebar {\n display: none;\n}\n\n.app-sub-sidebar.open {\n display: block;\n}\n\n.sidebar-nav .open > ul:not(.app-sub-sidebar),\n.sidebar-nav .active:not(.collapse) > ul {\n display: block;\n}\n\n/* 抖动 */\n.sidebar-nav li.open:not(.collapse) > ul {\n display: block;\n}\n\n.active + ul.app-sub-sidebar {\n display: block;\n}\n"),document.addEventListener("scroll",n);e("@media screen and (max-width: 768px) {\n /* 移动端适配 */\n .markdown-section {\n max-width: none;\n padding: 16px;\n }\n /* 改变原来按钮热区大小 */\n .sidebar-toggle {\n padding: 0 0 10px 10px;\n }\n /* my pin */\n .sidebar-pin {\n appearance: none;\n outline: none;\n position: fixed;\n bottom: 0;\n border: none;\n width: 40px;\n height: 40px;\n background: transparent;\n }\n}\n");var r,c="DOCSIFY_SIDEBAR_PIN_FLAG";function l(){var e="true"===(e=localStorage.getItem(c));localStorage.setItem(c,!e),e?(document.querySelector(".sidebar").style.transform="translateX(0)",document.querySelector(".content").style.transform="translateX(0)"):(document.querySelector(".sidebar").style.transform="translateX(300px)",document.querySelector(".content").style.transform="translateX(300px)")}768 ul"),1),a(t),n(e)}),e.ready(function(){document.querySelector(".sidebar-nav").addEventListener("click",o)})})}); \ No newline at end of file diff --git a/docs/assets/js/docsify.js b/docs/assets/js/docsify.js new file mode 100644 index 00000000000..2a60120a2f0 --- /dev/null +++ b/docs/assets/js/docsify.js @@ -0,0 +1,9279 @@ +(function () { + /** + * Create a cached version of a pure function. + * @param {*} fn The function call to be cached + * @void + */ + + function cached(fn) { + var cache = Object.create(null); + return function(str) { + var key = isPrimitive(str) ? str : JSON.stringify(str); + var hit = cache[key]; + return hit || (cache[key] = fn(str)); + }; + } + + /** + * Hyphenate a camelCase string. + */ + var hyphenate = cached(function (str) { + return str.replace(/([A-Z])/g, function (m) { return '-' + m.toLowerCase(); }); + }); + + var hasOwn = Object.prototype.hasOwnProperty; + + /** + * Simple Object.assign polyfill + * @param {Object} to The object to be merged with + * @returns {Object} The merged object + */ + var merge = + Object.assign || + function(to) { + var arguments$1 = arguments; + + for (var i = 1; i < arguments.length; i++) { + var from = Object(arguments$1[i]); + + for (var key in from) { + if (hasOwn.call(from, key)) { + to[key] = from[key]; + } + } + } + + return to; + }; + + /** + * Check if value is primitive + * @param {*} value Checks if a value is primitive + * @returns {Boolean} Result of the check + */ + function isPrimitive(value) { + return typeof value === 'string' || typeof value === 'number'; + } + + /** + * Performs no operation. + * @void + */ + function noop() {} + + /** + * Check if value is function + * @param {*} obj Any javascript object + * @returns {Boolean} True if the passed-in value is a function + */ + function isFn(obj) { + return typeof obj === 'function'; + } + + /** + * Check if url is external + * @param {String} string url + * @returns {Boolean} True if the passed-in url is external + */ + function isExternal(url) { + var match = url.match( + /^([^:/?#]+:)?(?:\/{2,}([^/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/ + ); + + if ( + typeof match[1] === 'string' && + match[1].length > 0 && + match[1].toLowerCase() !== location.protocol + ) { + return true; + } + if ( + typeof match[2] === 'string' && + match[2].length > 0 && + match[2].replace( + new RegExp( + ':(' + { 'http:': 80, 'https:': 443 }[location.protocol] + ')?$' + ), + '' + ) !== location.host + ) { + return true; + } + return false; + } + + var inBrowser = !false; + + var isMobile = document.body.clientWidth <= 600; + + /** + * @see https://github.com/MoOx/pjax/blob/master/lib/is-supported.js + */ + var supportsPushState = + + (function() { + // Borrowed wholesale from https://github.com/defunkt/jquery-pjax + return ( + window.history && + window.history.pushState && + window.history.replaceState && + // PushState isn’t reliable on iOS until 5. + !navigator.userAgent.match( + /((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/ + ) + ); + })(); + + var cacheNode = {}; + + /** + * Get Node + * @param {String|Element} el A DOM element + * @param {Boolean} noCache Flag to use or not use the cache + * @return {Element} The found node element + */ + function getNode(el, noCache) { + if ( noCache === void 0 ) noCache = false; + + if (typeof el === 'string') { + if (typeof window.Vue !== 'undefined') { + return find(el); + } + + el = noCache ? find(el) : cacheNode[el] || (cacheNode[el] = find(el)); + } + + return el; + } + + var $ = document; + + var body = $.body; + + var head = $.head; + + /** + * Find elements + * @param {String|Element} el The root element where to perform the search from + * @param {Element} node The query + * @returns {Element} The found DOM element + * @example + * find('nav') => document.querySelector('nav') + * find(nav, 'a') => nav.querySelector('a') + */ + function find(el, node) { + return node ? el.querySelector(node) : $.querySelector(el); + } + + /** + * Find all elements + * @param {String|Element} el The root element where to perform the search from + * @param {Element} node The query + * @returns {Array} An array of DOM elements + * @example + * findAll('a') => [].slice.call(document.querySelectorAll('a')) + * findAll(nav, 'a') => [].slice.call(nav.querySelectorAll('a')) + */ + function findAll(el, node) { + return [].slice.call( + node ? el.querySelectorAll(node) : $.querySelectorAll(el) + ); + } + + function create(node, tpl) { + node = $.createElement(node); + if (tpl) { + node.innerHTML = tpl; + } + + return node; + } + + function appendTo(target, el) { + return target.appendChild(el); + } + + function before(target, el) { + return target.insertBefore(el, target.children[0]); + } + + function on(el, type, handler) { + isFn(type) + ? window.addEventListener(el, type) + : el.addEventListener(type, handler); + } + + function off(el, type, handler) { + isFn(type) + ? window.removeEventListener(el, type) + : el.removeEventListener(type, handler); + } + + /** + * Toggle class + * @param {String|Element} el The element that needs the class to be toggled + * @param {Element} type The type of action to be performed on the classList (toggle by default) + * @param {String} val Name of the class to be toggled + * @void + * @example + * toggleClass(el, 'active') => el.classList.toggle('active') + * toggleClass(el, 'add', 'active') => el.classList.add('active') + */ + function toggleClass(el, type, val) { + el && el.classList[val ? type : 'toggle'](val || type); + } + + function style(content) { + appendTo(head, create('style', content)); + } + + /** + * Fork https://github.com/bendrucker/document-ready/blob/master/index.js + * @param {Function} callback The callbacack to be called when the page is loaded + * @returns {Number|void} If the page is already laoded returns the result of the setTimeout callback, + * otherwise it only attaches the callback to the DOMContentLoaded event + */ + function documentReady(callback, doc) { + if ( doc === void 0 ) doc = document; + + var state = doc.readyState; + + if (state === 'complete' || state === 'interactive') { + return setTimeout(callback, 0); + } + + doc.addEventListener('DOMContentLoaded', callback); + } + + var dom = /*#__PURE__*/Object.freeze({ + __proto__: null, + getNode: getNode, + $: $, + body: body, + head: head, + find: find, + findAll: findAll, + create: create, + appendTo: appendTo, + before: before, + on: on, + off: off, + toggleClass: toggleClass, + style: style, + documentReady: documentReady + }); + + var decode = decodeURIComponent; + var encode = encodeURIComponent; + + function parseQuery(query) { + var res = {}; + + query = query.trim().replace(/^(\?|#|&)/, ''); + + if (!query) { + return res; + } + + // Simple parse + query.split('&').forEach(function(param) { + var parts = param.replace(/\+/g, ' ').split('='); + + res[parts[0]] = parts[1] && decode(parts[1]); + }); + + return res; + } + + function stringifyQuery(obj, ignores) { + if ( ignores === void 0 ) ignores = []; + + var qs = []; + + for (var key in obj) { + if (ignores.indexOf(key) > -1) { + continue; + } + + qs.push( + obj[key] + ? ((encode(key)) + "=" + (encode(obj[key]))).toLowerCase() + : encode(key) + ); + } + + return qs.length ? ("?" + (qs.join('&'))) : ''; + } + + var isAbsolutePath = cached(function (path) { + return /(:|(\/{2}))/g.test(path); + }); + + var removeParams = cached(function (path) { + return path.split(/[?#]/)[0]; + }); + + var getParentPath = cached(function (path) { + if (/\/$/g.test(path)) { + return path; + } + + var matchingParts = path.match(/(\S*\/)[^/]+$/); + return matchingParts ? matchingParts[1] : ''; + }); + + var cleanPath = cached(function (path) { + return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/'); + }); + + var resolvePath = cached(function (path) { + var segments = path.replace(/^\//, '').split('/'); + var resolved = []; + for (var i = 0, len = segments.length; i < len; i++) { + var segment = segments[i]; + if (segment === '..') { + resolved.pop(); + } else if (segment !== '.') { + resolved.push(segment); + } + } + + return '/' + resolved.join('/'); + }); + + /** + * Normalises the URI path to handle the case where Docsify is + * hosted off explicit files, i.e. /index.html. This function + * eliminates any path segments that contain `#` fragments. + * + * This is used to map browser URIs to markdown file sources. + * + * For example: + * + * http://example.org/base/index.html#/blah + * + * would be mapped to: + * + * http://example.org/base/blah.md. + * + * See here for more information: + * + * https://github.com/docsifyjs/docsify/pull/1372 + * + * @param {string} path The URI path to normalise + * @return {string} { path, query } + */ + + function normaliseFragment(path) { + return path + .split('/') + .filter(function (p) { return p.indexOf('#') === -1; }) + .join('/'); + } + + function getPath() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return cleanPath(args.map(normaliseFragment).join('/')); + } + + var replaceSlug = cached(function (path) { + return path.replace('#', '?id='); + }); + + function endsWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + + var cached$1 = {}; + + function getAlias(path, alias, last) { + var match = Object.keys(alias).filter(function (key) { + var re = cached$1[key] || (cached$1[key] = new RegExp(("^" + key + "$"))); + return re.test(path) && path !== last; + })[0]; + + return match + ? getAlias(path.replace(cached$1[match], alias[match]), alias, path) + : path; + } + + function getFileName(path, ext) { + return new RegExp(("\\.(" + (ext.replace(/^\./, '')) + "|html)$"), 'g').test(path) + ? path + : /\/$/g.test(path) + ? (path + "README" + ext) + : ("" + path + ext); + } + + var History = function History(config) { + this.config = config; + }; + + History.prototype.getBasePath = function getBasePath () { + return this.config.basePath; + }; + + History.prototype.getFile = function getFile (path, isRelative) { + if ( path === void 0 ) path = this.getCurrentPath(); + + var ref = this; + var config = ref.config; + var base = this.getBasePath(); + var ext = typeof config.ext === 'string' ? config.ext : '.md'; + + path = config.alias ? getAlias(path, config.alias) : path; + path = getFileName(path, ext); + path = path === ("/README" + ext) ? config.homepage || path : path; + path = isAbsolutePath(path) ? path : getPath(base, path); + + if (isRelative) { + path = path.replace(new RegExp(("^" + base)), ''); + } + + return path; + }; + + History.prototype.onchange = function onchange (cb) { + if ( cb === void 0 ) cb = noop; + + cb(); + }; + + History.prototype.getCurrentPath = function getCurrentPath () {}; + + History.prototype.normalize = function normalize () {}; + + History.prototype.parse = function parse () {}; + + History.prototype.toURL = function toURL (path, params, currentRoute) { + var local = currentRoute && path[0] === '#'; + var route = this.parse(replaceSlug(path)); + + route.query = merge({}, route.query, params); + path = route.path + stringifyQuery(route.query); + path = path.replace(/\.md(\?)|\.md$/, '$1'); + + if (local) { + var idIndex = currentRoute.indexOf('?'); + path = + (idIndex > 0 ? currentRoute.substring(0, idIndex) : currentRoute) + + path; + } + + if (this.config.relativePath && path.indexOf('/') !== 0) { + var currentDir = currentRoute.substring( + 0, + currentRoute.lastIndexOf('/') + 1 + ); + return cleanPath(resolvePath(currentDir + path)); + } + + return cleanPath('/' + path); + }; + + function replaceHash(path) { + var i = location.href.indexOf('#'); + location.replace(location.href.slice(0, i >= 0 ? i : 0) + '#' + path); + } + var HashHistory = /*@__PURE__*/(function (History) { + function HashHistory(config) { + History.call(this, config); + this.mode = 'hash'; + } + + if ( History ) HashHistory.__proto__ = History; + HashHistory.prototype = Object.create( History && History.prototype ); + HashHistory.prototype.constructor = HashHistory; + + HashHistory.prototype.getBasePath = function getBasePath () { + var path = window.location.pathname || ''; + var base = this.config.basePath; + + // This handles the case where Docsify is served off an + // explicit file path, i.e.`/base/index.html#/blah`. This + // prevents the `/index.html` part of the URI from being + // remove during routing. + // See here: https://github.com/docsifyjs/docsify/pull/1372 + var basePath = endsWith(path, '.html') + ? path + '#/' + base + : path + '/' + base; + return /^(\/|https?:)/g.test(base) ? base : cleanPath(basePath); + }; + + HashHistory.prototype.getCurrentPath = function getCurrentPath () { + // We can't use location.hash here because it's not + // consistent across browsers - Firefox will pre-decode it! + var href = location.href; + var index = href.indexOf('#'); + return index === -1 ? '' : href.slice(index + 1); + }; + + /** @param {((params: {source: TODO}) => void)} [cb] */ + HashHistory.prototype.onchange = function onchange (cb) { + if ( cb === void 0 ) cb = noop; + + // The hashchange event does not tell us if it originated from + // a clicked link or by moving back/forward in the history; + // therefore we set a `navigating` flag when a link is clicked + // to be able to tell these two scenarios apart + var navigating = false; + + on('click', function (e) { + var el = e.target.tagName === 'A' ? e.target : e.target.parentNode; + + if (el && el.tagName === 'A' && !/_blank/.test(el.target)) { + navigating = true; + } + }); + + on('hashchange', function (e) { + var source = navigating ? 'navigate' : 'history'; + navigating = false; + cb({ event: e, source: source }); + }); + }; + + HashHistory.prototype.normalize = function normalize () { + var path = this.getCurrentPath(); + + path = replaceSlug(path); + + if (path.charAt(0) === '/') { + return replaceHash(path); + } + + replaceHash('/' + path); + }; + + /** + * Parse the url + * @param {string} [path=location.herf] URL to be parsed + * @return {object} { path, query } + */ + HashHistory.prototype.parse = function parse (path) { + if ( path === void 0 ) path = location.href; + + var query = ''; + + var hashIndex = path.indexOf('#'); + if (hashIndex >= 0) { + path = path.slice(hashIndex + 1); + } + + var queryIndex = path.indexOf('?'); + if (queryIndex >= 0) { + query = path.slice(queryIndex + 1); + path = path.slice(0, queryIndex); + } + + return { + path: path, + file: this.getFile(path, true), + query: parseQuery(query), + }; + }; + + HashHistory.prototype.toURL = function toURL (path, params, currentRoute) { + return '#' + History.prototype.toURL.call(this, path, params, currentRoute); + }; + + return HashHistory; + }(History)); + + /** @typedef {any} TODO */ + + var HTML5History = /*@__PURE__*/(function (History) { + function HTML5History(config) { + History.call(this, config); + this.mode = 'history'; + } + + if ( History ) HTML5History.__proto__ = History; + HTML5History.prototype = Object.create( History && History.prototype ); + HTML5History.prototype.constructor = HTML5History; + + HTML5History.prototype.getCurrentPath = function getCurrentPath () { + var base = this.getBasePath(); + var path = window.location.pathname; + + if (base && path.indexOf(base) === 0) { + path = path.slice(base.length); + } + + return (path || '/') + window.location.search + window.location.hash; + }; + + HTML5History.prototype.onchange = function onchange (cb) { + var this$1 = this; + if ( cb === void 0 ) cb = noop; + + on('click', function (e) { + var el = e.target.tagName === 'A' ? e.target : e.target.parentNode; + + if (el && el.tagName === 'A' && !/_blank/.test(el.target)) { + e.preventDefault(); + var url = el.href; + // solve history.pushState cross-origin issue + if (this$1.config.crossOriginLinks.indexOf(url) !== -1) { + window.open(url, '_self'); + } else { + window.history.pushState({ key: url }, '', url); + } + cb({ event: e, source: 'navigate' }); + } + }); + + on('popstate', function (e) { + cb({ event: e, source: 'history' }); + }); + }; + + /** + * Parse the url + * @param {string} [path=location.href] URL to be parsed + * @return {object} { path, query } + */ + HTML5History.prototype.parse = function parse (path) { + if ( path === void 0 ) path = location.href; + + var query = ''; + + var queryIndex = path.indexOf('?'); + if (queryIndex >= 0) { + query = path.slice(queryIndex + 1); + path = path.slice(0, queryIndex); + } + + var base = getPath(location.origin); + var baseIndex = path.indexOf(base); + + if (baseIndex > -1) { + path = path.slice(baseIndex + base.length); + } + + return { + path: path, + file: this.getFile(path), + query: parseQuery(query), + }; + }; + + return HTML5History; + }(History)); + + /** + * @typedef {{ + * path?: string + * }} Route + */ + + /** @type {Route} */ + var lastRoute = {}; + + /** @typedef {import('../Docsify').Constructor} Constructor */ + + /** + * @template {!Constructor} T + * @param {T} Base - The class to extend + */ + function Router(Base) { + return /*@__PURE__*/(function (Base) { + function Router() { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + Base.apply(this, args); + + this.route = {}; + } + + if ( Base ) Router.__proto__ = Base; + Router.prototype = Object.create( Base && Base.prototype ); + Router.prototype.constructor = Router; + + Router.prototype.updateRender = function updateRender () { + this.router.normalize(); + this.route = this.router.parse(); + body.setAttribute('data-page', this.route.file); + }; + + Router.prototype.initRouter = function initRouter () { + var this$1 = this; + + var config = this.config; + var mode = config.routerMode || 'hash'; + var router; + + if (mode === 'history' && supportsPushState) { + router = new HTML5History(config); + } else { + router = new HashHistory(config); + } + + this.router = router; + this.updateRender(); + lastRoute = this.route; + + // eslint-disable-next-line no-unused-vars + router.onchange(function (params) { + this$1.updateRender(); + this$1._updateRender(); + + if (lastRoute.path === this$1.route.path) { + this$1.$resetEvents(params.source); + return; + } + + this$1.$fetch(noop, this$1.$resetEvents.bind(this$1, params.source)); + lastRoute = this$1.route; + }); + }; + + return Router; + }(Base)); + } + + var RGX = /([^{]*?)\w(?=\})/g; + + var MAP = { + YYYY: 'getFullYear', + YY: 'getYear', + MM: function (d) { + return d.getMonth() + 1; + }, + DD: 'getDate', + HH: 'getHours', + mm: 'getMinutes', + ss: 'getSeconds', + fff: 'getMilliseconds' + }; + + function tinydate (str, custom) { + var parts=[], offset=0; + + str.replace(RGX, function (key, _, idx) { + // save preceding string + parts.push(str.substring(offset, idx - 1)); + offset = idx += key.length + 1; + // save function + parts.push(custom && custom[key] || function (d) { + return ('00' + (typeof MAP[key] === 'string' ? d[MAP[key]]() : MAP[key](d))).slice(-key.length); + }); + }); + + if (offset !== str.length) { + parts.push(str.substring(offset)); + } + + return function (arg) { + var out='', i=0, d=arg||new Date(); + for (; i 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments$1[_key]; + } + + return apply(func, thisArg, args); + }; + } + + function unconstruct(func) { + return function () { + var arguments$1 = arguments; + + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments$1[_key2]; + } + + return construct(func, args); + }; + } + + /* Add properties to a lookup table */ + function addToSet(set, array) { + if (setPrototypeOf) { + // Make 'in' and truthy checks like Boolean(set.constructor) + // independent of any properties defined on Object.prototype. + // Prevent prototype setters from intercepting set as a this value. + setPrototypeOf(set, null); + } + + var l = array.length; + while (l--) { + var element = array[l]; + if (typeof element === 'string') { + var lcElement = stringToLowerCase(element); + if (lcElement !== element) { + // Config presets (e.g. tags.js, attrs.js) are immutable. + if (!isFrozen(array)) { + array[l] = lcElement; + } + + element = lcElement; + } + } + + set[element] = true; + } + + return set; + } + + /* Shallow clone an object */ + function clone(object) { + var newObject = create$1(null); + + var property = void 0; + for (property in object) { + if (apply(hasOwnProperty, object, [property])) { + newObject[property] = object[property]; + } + } + + return newObject; + } + + /* IE10 doesn't support __lookupGetter__ so lets' + * simulate it. It also automatically checks + * if the prop is function or getter and behaves + * accordingly. */ + function lookupGetter(object, prop) { + while (object !== null) { + var desc = getOwnPropertyDescriptor(object, prop); + if (desc) { + if (desc.get) { + return unapply(desc.get); + } + + if (typeof desc.value === 'function') { + return unapply(desc.value); + } + } + + object = getPrototypeOf(object); + } + + function fallbackValue(element) { + console.warn('fallback value for', element); + return null; + } + + return fallbackValue; + } + + var html = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']); + + // SVG + var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']); + + var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']); + + // List of SVG elements that are disallowed by default. + // We still need to know them so that we can do namespace + // checks properly in case one wants to add them to + // allow-list. + var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', 'feimage', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']); + + var mathMl = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']); + + // Similarly to SVG, we want to know all MathML elements, + // even those that we disallow by default. + var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']); + + var text = freeze(['#text']); + + var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']); + + var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']); + + var mathMl$1 = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']); + + var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']); + + // eslint-disable-next-line unicorn/better-regex + var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode + var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm); + var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape + var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape + var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape + ); + var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); + var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex + ); + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + + function _toConsumableArray$1(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + + var getGlobal = function getGlobal() { + return typeof window === 'undefined' ? null : window; + }; + + /** + * Creates a no-op policy for internal use only. + * Don't export this function outside this module! + * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory. + * @param {Document} document The document object (to determine policy name suffix) + * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types + * are not supported). + */ + var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) { + if ((typeof trustedTypes === 'undefined' ? 'undefined' : _typeof(trustedTypes)) !== 'object' || typeof trustedTypes.createPolicy !== 'function') { + return null; + } + + // Allow the callers to control the unique policy name + // by adding a data-tt-policy-suffix to the script element with the DOMPurify. + // Policy creation with duplicate names throws in Trusted Types. + var suffix = null; + var ATTR_NAME = 'data-tt-policy-suffix'; + if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) { + suffix = document.currentScript.getAttribute(ATTR_NAME); + } + + var policyName = 'dompurify' + (suffix ? '#' + suffix : ''); + + try { + return trustedTypes.createPolicy(policyName, { + createHTML: function createHTML(html$$1) { + return html$$1; + } + }); + } catch (_) { + // Policy creation failed (most likely another DOMPurify script has + // already run). Skip creating the policy, as this will only cause errors + // if TT are enforced. + console.warn('TrustedTypes policy ' + policyName + ' could not be created.'); + return null; + } + }; + + function createDOMPurify() { + var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal(); + + var DOMPurify = function DOMPurify(root) { + return createDOMPurify(root); + }; + + /** + * Version label, exposed for easier checks + * if DOMPurify is up to date or not + */ + DOMPurify.version = '2.3.1'; + + /** + * Array of elements that DOMPurify removed during sanitation. + * Empty if nothing was removed. + */ + DOMPurify.removed = []; + + if (!window || !window.document || window.document.nodeType !== 9) { + // Not running in a browser, provide a factory function + // so that you can pass your own Window + DOMPurify.isSupported = false; + + return DOMPurify; + } + + var originalDocument = window.document; + + var document = window.document; + var DocumentFragment = window.DocumentFragment, + HTMLTemplateElement = window.HTMLTemplateElement, + Node = window.Node, + Element = window.Element, + NodeFilter = window.NodeFilter, + _window$NamedNodeMap = window.NamedNodeMap, + NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, + Text = window.Text, + Comment = window.Comment, + DOMParser = window.DOMParser, + trustedTypes = window.trustedTypes; + + + var ElementPrototype = Element.prototype; + + var cloneNode = lookupGetter(ElementPrototype, 'cloneNode'); + var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling'); + var getChildNodes = lookupGetter(ElementPrototype, 'childNodes'); + var getParentNode = lookupGetter(ElementPrototype, 'parentNode'); + + // As per issue #47, the web-components registry is inherited by a + // new document created via createHTMLDocument. As per the spec + // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) + // a new empty registry is used when creating a template contents owner + // document, so we use that as our parent document to ensure nothing + // is inherited. + if (typeof HTMLTemplateElement === 'function') { + var template = document.createElement('template'); + if (template.content && template.content.ownerDocument) { + document = template.content.ownerDocument; + } + } + + var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument); + var emptyHTML = trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML('') : ''; + + var _document = document, + implementation = _document.implementation, + createNodeIterator = _document.createNodeIterator, + createDocumentFragment = _document.createDocumentFragment, + getElementsByTagName = _document.getElementsByTagName; + var importNode = originalDocument.importNode; + + + var documentMode = {}; + try { + documentMode = clone(document).documentMode ? document.documentMode : {}; + } catch (_) {} + + var hooks = {}; + + /** + * Expose whether this browser supports running the full DOMPurify. + */ + DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9; + + var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR, + ERB_EXPR$$1 = ERB_EXPR, + DATA_ATTR$$1 = DATA_ATTR, + ARIA_ATTR$$1 = ARIA_ATTR, + IS_SCRIPT_OR_DATA$$1 = IS_SCRIPT_OR_DATA, + ATTR_WHITESPACE$$1 = ATTR_WHITESPACE; + var IS_ALLOWED_URI$$1 = IS_ALLOWED_URI; + + /** + * We consider the elements and attributes below to be safe. Ideally + * don't add any new ones but feel free to remove unwanted ones. + */ + + /* allowed element names */ + + var ALLOWED_TAGS = null; + var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(html), _toConsumableArray$1(svg), _toConsumableArray$1(svgFilters), _toConsumableArray$1(mathMl), _toConsumableArray$1(text))); + + /* Allowed attribute names */ + var ALLOWED_ATTR = null; + var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray$1(html$1), _toConsumableArray$1(svg$1), _toConsumableArray$1(mathMl$1), _toConsumableArray$1(xml))); + + /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ + var FORBID_TAGS = null; + + /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ + var FORBID_ATTR = null; + + /* Decide if ARIA attributes are okay */ + var ALLOW_ARIA_ATTR = true; + + /* Decide if custom data attributes are okay */ + var ALLOW_DATA_ATTR = true; + + /* Decide if unknown protocols are okay */ + var ALLOW_UNKNOWN_PROTOCOLS = false; + + /* Output should be safe for common template engines. + * This means, DOMPurify removes data attributes, mustaches and ERB + */ + var SAFE_FOR_TEMPLATES = false; + + /* Decide if document with ... should be returned */ + var WHOLE_DOCUMENT = false; + + /* Track whether config is already set on this instance of DOMPurify. */ + var SET_CONFIG = false; + + /* Decide if all elements (e.g. style, script) must be children of + * document.body. By default, browsers might move them to document.head */ + var FORCE_BODY = false; + + /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html + * string (or a TrustedHTML object if Trusted Types are supported). + * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead + */ + var RETURN_DOM = false; + + /* Decide if a DOM `DocumentFragment` should be returned, instead of a html + * string (or a TrustedHTML object if Trusted Types are supported) */ + var RETURN_DOM_FRAGMENT = false; + + /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM + * `Node` is imported into the current `Document`. If this flag is not enabled the + * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by + * DOMPurify. + * + * This defaults to `true` starting DOMPurify 2.2.0. Note that setting it to `false` + * might cause XSS from attacks hidden in closed shadowroots in case the browser + * supports Declarative Shadow: DOM https://web.dev/declarative-shadow-dom/ + */ + var RETURN_DOM_IMPORT = true; + + /* Try to return a Trusted Type object instead of a string, return a string in + * case Trusted Types are not supported */ + var RETURN_TRUSTED_TYPE = false; + + /* Output should be free from DOM clobbering attacks? */ + var SANITIZE_DOM = true; + + /* Keep element content when removing element? */ + var KEEP_CONTENT = true; + + /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead + * of importing it into a new Document and returning a sanitized copy */ + var IN_PLACE = false; + + /* Allow usage of profiles like html, svg and mathMl */ + var USE_PROFILES = {}; + + /* Tags to ignore content of when KEEP_CONTENT is true */ + var FORBID_CONTENTS = null; + var DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']); + + /* Tags that are safe for data: URIs */ + var DATA_URI_TAGS = null; + var DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']); + + /* Attributes safe for values like "javascript:" */ + var URI_SAFE_ATTRIBUTES = null; + var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']); + + var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; + var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; + var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'; + /* Document namespace */ + var NAMESPACE = HTML_NAMESPACE; + var IS_EMPTY_INPUT = false; + + /* Keep a reference to config to pass to hooks */ + var CONFIG = null; + + /* Ideally, do not touch anything below this line */ + /* ______________________________________________ */ + + var formElement = document.createElement('form'); + + /** + * _parseConfig + * + * @param {Object} cfg optional config literal + */ + // eslint-disable-next-line complexity + var _parseConfig = function _parseConfig(cfg) { + if (CONFIG && CONFIG === cfg) { + return; + } + + /* Shield configuration object from tampering */ + if (!cfg || (typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') { + cfg = {}; + } + + /* Shield configuration object from prototype pollution */ + cfg = clone(cfg); + + /* Set configuration parameters */ + ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS; + ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR; + URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES; + DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS; + FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS; + FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {}; + FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {}; + USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false; + ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true + ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true + ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false + SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false + WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false + RETURN_DOM = cfg.RETURN_DOM || false; // Default false + RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false + RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT !== false; // Default true + RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false + FORCE_BODY = cfg.FORCE_BODY || false; // Default false + SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true + KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true + IN_PLACE = cfg.IN_PLACE || false; // Default false + IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1; + NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE; + if (SAFE_FOR_TEMPLATES) { + ALLOW_DATA_ATTR = false; + } + + if (RETURN_DOM_FRAGMENT) { + RETURN_DOM = true; + } + + /* Parse profile info */ + if (USE_PROFILES) { + ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(text))); + ALLOWED_ATTR = []; + if (USE_PROFILES.html === true) { + addToSet(ALLOWED_TAGS, html); + addToSet(ALLOWED_ATTR, html$1); + } + + if (USE_PROFILES.svg === true) { + addToSet(ALLOWED_TAGS, svg); + addToSet(ALLOWED_ATTR, svg$1); + addToSet(ALLOWED_ATTR, xml); + } + + if (USE_PROFILES.svgFilters === true) { + addToSet(ALLOWED_TAGS, svgFilters); + addToSet(ALLOWED_ATTR, svg$1); + addToSet(ALLOWED_ATTR, xml); + } + + if (USE_PROFILES.mathMl === true) { + addToSet(ALLOWED_TAGS, mathMl); + addToSet(ALLOWED_ATTR, mathMl$1); + addToSet(ALLOWED_ATTR, xml); + } + } + + /* Merge configuration parameters */ + if (cfg.ADD_TAGS) { + if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { + ALLOWED_TAGS = clone(ALLOWED_TAGS); + } + + addToSet(ALLOWED_TAGS, cfg.ADD_TAGS); + } + + if (cfg.ADD_ATTR) { + if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { + ALLOWED_ATTR = clone(ALLOWED_ATTR); + } + + addToSet(ALLOWED_ATTR, cfg.ADD_ATTR); + } + + if (cfg.ADD_URI_SAFE_ATTR) { + addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR); + } + + if (cfg.FORBID_CONTENTS) { + if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { + FORBID_CONTENTS = clone(FORBID_CONTENTS); + } + + addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS); + } + + /* Add #text in case KEEP_CONTENT is set to true */ + if (KEEP_CONTENT) { + ALLOWED_TAGS['#text'] = true; + } + + /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */ + if (WHOLE_DOCUMENT) { + addToSet(ALLOWED_TAGS, ['html', 'head', 'body']); + } + + /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */ + if (ALLOWED_TAGS.table) { + addToSet(ALLOWED_TAGS, ['tbody']); + delete FORBID_TAGS.tbody; + } + + // Prevent further manipulation of configuration. + // Not available in IE8, Safari 5, etc. + if (freeze) { + freeze(cfg); + } + + CONFIG = cfg; + }; + + var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']); + + var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']); + + /* Keep track of all possible SVG and MathML tags + * so that we can perform the namespace checks + * correctly. */ + var ALL_SVG_TAGS = addToSet({}, svg); + addToSet(ALL_SVG_TAGS, svgFilters); + addToSet(ALL_SVG_TAGS, svgDisallowed); + + var ALL_MATHML_TAGS = addToSet({}, mathMl); + addToSet(ALL_MATHML_TAGS, mathMlDisallowed); + + /** + * + * + * @param {Element} element a DOM element whose namespace is being checked + * @returns {boolean} Return false if the element has a + * namespace that a spec-compliant parser would never + * return. Return true otherwise. + */ + var _checkValidNamespace = function _checkValidNamespace(element) { + var parent = getParentNode(element); + + // In JSDOM, if we're inside shadow DOM, then parentNode + // can be null. We just simulate parent in this case. + if (!parent || !parent.tagName) { + parent = { + namespaceURI: HTML_NAMESPACE, + tagName: 'template' + }; + } + + var tagName = stringToLowerCase(element.tagName); + var parentTagName = stringToLowerCase(parent.tagName); + + if (element.namespaceURI === SVG_NAMESPACE) { + // The only way to switch from HTML namespace to SVG + // is via . If it happens via any other tag, then + // it should be killed. + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === 'svg'; + } + + // The only way to switch from MathML to SVG is via + // svg if parent is either or MathML + // text integration points. + if (parent.namespaceURI === MATHML_NAMESPACE) { + return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); + } + + // We only allow elements that are defined in SVG + // spec. All others are disallowed in SVG namespace. + return Boolean(ALL_SVG_TAGS[tagName]); + } + + if (element.namespaceURI === MATHML_NAMESPACE) { + // The only way to switch from HTML namespace to MathML + // is via . If it happens via any other tag, then + // it should be killed. + if (parent.namespaceURI === HTML_NAMESPACE) { + return tagName === 'math'; + } + + // The only way to switch from SVG to MathML is via + // and HTML integration points + if (parent.namespaceURI === SVG_NAMESPACE) { + return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName]; + } + + // We only allow elements that are defined in MathML + // spec. All others are disallowed in MathML namespace. + return Boolean(ALL_MATHML_TAGS[tagName]); + } + + if (element.namespaceURI === HTML_NAMESPACE) { + // The only way to switch from SVG to HTML is via + // HTML integration points, and from MathML to HTML + // is via MathML text integration points + if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) { + return false; + } + + if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) { + return false; + } + + // Certain elements are allowed in both SVG and HTML + // namespace. We need to specify them explicitly + // so that they don't get erronously deleted from + // HTML namespace. + var commonSvgAndHTMLElements = addToSet({}, ['title', 'style', 'font', 'a', 'script']); + + // We disallow tags that are specific for MathML + // or SVG and should never appear in HTML namespace + return !ALL_MATHML_TAGS[tagName] && (commonSvgAndHTMLElements[tagName] || !ALL_SVG_TAGS[tagName]); + } + + // The code should never reach this place (this means + // that the element somehow got namespace that is not + // HTML, SVG or MathML). Return false just in case. + return false; + }; + + /** + * _forceRemove + * + * @param {Node} node a DOM node + */ + var _forceRemove = function _forceRemove(node) { + arrayPush(DOMPurify.removed, { element: node }); + try { + // eslint-disable-next-line unicorn/prefer-dom-node-remove + node.parentNode.removeChild(node); + } catch (_) { + try { + node.outerHTML = emptyHTML; + } catch (_) { + node.remove(); + } + } + }; + + /** + * _removeAttribute + * + * @param {String} name an Attribute name + * @param {Node} node a DOM node + */ + var _removeAttribute = function _removeAttribute(name, node) { + try { + arrayPush(DOMPurify.removed, { + attribute: node.getAttributeNode(name), + from: node + }); + } catch (_) { + arrayPush(DOMPurify.removed, { + attribute: null, + from: node + }); + } + + node.removeAttribute(name); + + // We void attribute values for unremovable "is"" attributes + if (name === 'is' && !ALLOWED_ATTR[name]) { + if (RETURN_DOM || RETURN_DOM_FRAGMENT) { + try { + _forceRemove(node); + } catch (_) {} + } else { + try { + node.setAttribute(name, ''); + } catch (_) {} + } + } + }; + + /** + * _initDocument + * + * @param {String} dirty a string of dirty markup + * @return {Document} a DOM, filled with the dirty markup + */ + var _initDocument = function _initDocument(dirty) { + /* Create a HTML document */ + var doc = void 0; + var leadingWhitespace = void 0; + + if (FORCE_BODY) { + dirty = '' + dirty; + } else { + /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */ + var matches = stringMatch(dirty, /^[\r\n\t ]+/); + leadingWhitespace = matches && matches[0]; + } + + var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty; + /* + * Use the DOMParser API by default, fallback later if needs be + * DOMParser not work for svg when has multiple root element. + */ + if (NAMESPACE === HTML_NAMESPACE) { + try { + doc = new DOMParser().parseFromString(dirtyPayload, 'text/html'); + } catch (_) {} + } + + /* Use createHTMLDocument in case DOMParser is not available */ + if (!doc || !doc.documentElement) { + doc = implementation.createDocument(NAMESPACE, 'template', null); + try { + doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload; + } catch (_) { + // Syntax error if dirtyPayload is invalid xml + } + } + + var body = doc.body || doc.documentElement; + + if (dirty && leadingWhitespace) { + body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null); + } + + /* Work on whole document or just its body */ + if (NAMESPACE === HTML_NAMESPACE) { + return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0]; + } + + return WHOLE_DOCUMENT ? doc.documentElement : body; + }; + + /** + * _createIterator + * + * @param {Document} root document/fragment to create iterator for + * @return {Iterator} iterator instance + */ + var _createIterator = function _createIterator(root) { + return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false); + }; + + /** + * _isClobbered + * + * @param {Node} elm element to check for clobbering attacks + * @return {Boolean} true if clobbered, false if safe + */ + var _isClobbered = function _isClobbered(elm) { + if (elm instanceof Text || elm instanceof Comment) { + return false; + } + + if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function') { + return true; + } + + return false; + }; + + /** + * _isNode + * + * @param {Node} obj object to check whether it's a DOM node + * @return {Boolean} true is object is a DOM node + */ + var _isNode = function _isNode(object) { + return (typeof Node === 'undefined' ? 'undefined' : _typeof(Node)) === 'object' ? object instanceof Node : object && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'; + }; + + /** + * _executeHook + * Execute user configurable hooks + * + * @param {String} entryPoint Name of the hook's entry point + * @param {Node} currentNode node to work on with the hook + * @param {Object} data additional hook parameters + */ + var _executeHook = function _executeHook(entryPoint, currentNode, data) { + if (!hooks[entryPoint]) { + return; + } + + arrayForEach(hooks[entryPoint], function (hook) { + hook.call(DOMPurify, currentNode, data, CONFIG); + }); + }; + + /** + * _sanitizeElements + * + * @protect nodeName + * @protect textContent + * @protect removeChild + * + * @param {Node} currentNode to check for permission to exist + * @return {Boolean} true if node was killed, false if left alive + */ + var _sanitizeElements = function _sanitizeElements(currentNode) { + var content = void 0; + + /* Execute a hook if present */ + _executeHook('beforeSanitizeElements', currentNode, null); + + /* Check if element is clobbered or can clobber */ + if (_isClobbered(currentNode)) { + _forceRemove(currentNode); + return true; + } + + /* Check if tagname contains Unicode */ + if (stringMatch(currentNode.nodeName, /[\u0080-\uFFFF]/)) { + _forceRemove(currentNode); + return true; + } + + /* Now let's check the element's type and name */ + var tagName = stringToLowerCase(currentNode.nodeName); + + /* Execute a hook if present */ + _executeHook('uponSanitizeElement', currentNode, { + tagName: tagName, + allowedTags: ALLOWED_TAGS + }); + + /* Detect mXSS attempts abusing namespace confusion */ + if (!_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) { + _forceRemove(currentNode); + return true; + } + + /* Mitigate a problem with templates inside select */ + if (tagName === 'select' && regExpTest(/
'
+          + (escaped ? code$1 : escape$2(code$1, true))
+          + '
\n'; + } + + return '
'
+        + (escaped ? code$1 : escape$2(code$1, true))
+        + '
\n'; + }; + + Renderer.prototype.blockquote = function blockquote (quote) { + return '
\n' + quote + '
\n'; + }; + + Renderer.prototype.html = function html (html$1) { + return html$1; + }; + + Renderer.prototype.heading = function heading (text, level, raw, slugger) { + if (this.options.headerIds) { + return '' + + text + + '\n'; + } + // ignore IDs + return '' + text + '\n'; + }; + + Renderer.prototype.hr = function hr () { + return this.options.xhtml ? '
\n' : '
\n'; + }; + + Renderer.prototype.list = function list (body, ordered, start) { + var type = ordered ? 'ol' : 'ul', + startatt = (ordered && start !== 1) ? (' start="' + start + '"') : ''; + return '<' + type + startatt + '>\n' + body + '\n'; + }; + + Renderer.prototype.listitem = function listitem (text) { + return '
  • ' + text + '
  • \n'; + }; + + Renderer.prototype.checkbox = function checkbox (checked) { + return ' '; + }; + + Renderer.prototype.paragraph = function paragraph (text) { + return '

    ' + text + '

    \n'; + }; + + Renderer.prototype.table = function table (header, body) { + if (body) { body = '' + body + ''; } + + return '\n' + + '\n' + + header + + '\n' + + body + + '
    \n'; + }; + + Renderer.prototype.tablerow = function tablerow (content) { + return '\n' + content + '\n'; + }; + + Renderer.prototype.tablecell = function tablecell (content, flags) { + var type = flags.header ? 'th' : 'td'; + var tag = flags.align + ? '<' + type + ' align="' + flags.align + '">' + : '<' + type + '>'; + return tag + content + '\n'; + }; + + // span level renderer + Renderer.prototype.strong = function strong (text) { + return '' + text + ''; + }; + + Renderer.prototype.em = function em (text) { + return '' + text + ''; + }; + + Renderer.prototype.codespan = function codespan (text) { + return '' + text + ''; + }; + + Renderer.prototype.br = function br () { + return this.options.xhtml ? '
    ' : '
    '; + }; + + Renderer.prototype.del = function del (text) { + return '' + text + ''; + }; + + Renderer.prototype.link = function link (href, title, text) { + href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href); + if (href === null) { + return text; + } + var out = ''; + return out; + }; + + Renderer.prototype.image = function image (href, title, text) { + href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href); + if (href === null) { + return text; + } + + var out = '' + text + '' : '>'; + return out; + }; + + Renderer.prototype.text = function text (text$1) { + return text$1; + }; + + return Renderer; + }()); + + /** + * TextRenderer + * returns only the textual part of the token + */ + var TextRenderer = /*@__PURE__*/(function () { + function TextRenderer () {} + + TextRenderer.prototype.strong = function strong (text) { + return text; + }; + + TextRenderer.prototype.em = function em (text) { + return text; + }; + + TextRenderer.prototype.codespan = function codespan (text) { + return text; + }; + + TextRenderer.prototype.del = function del (text) { + return text; + }; + + TextRenderer.prototype.html = function html (text) { + return text; + }; + + TextRenderer.prototype.text = function text (text$1) { + return text$1; + }; + + TextRenderer.prototype.link = function link (href, title, text) { + return '' + text; + }; + + TextRenderer.prototype.image = function image (href, title, text) { + return '' + text; + }; + + TextRenderer.prototype.br = function br () { + return ''; + }; + + return TextRenderer; + }()); + + /** + * Slugger generates header id + */ + var Slugger = /*@__PURE__*/(function () { + function Slugger() { + this.seen = {}; + } + + Slugger.prototype.serialize = function serialize (value) { + return value + .toLowerCase() + .trim() + // remove html tags + .replace(/<[!\/a-z].*?>/ig, '') + // remove unwanted chars + .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '') + .replace(/\s/g, '-'); + }; + + /** + * Finds the next safe (unique) slug to use + */ + Slugger.prototype.getNextSafeSlug = function getNextSafeSlug (originalSlug, isDryRun) { + var slug = originalSlug; + var occurenceAccumulator = 0; + if (this.seen.hasOwnProperty(slug)) { + occurenceAccumulator = this.seen[originalSlug]; + do { + occurenceAccumulator++; + slug = originalSlug + '-' + occurenceAccumulator; + } while (this.seen.hasOwnProperty(slug)); + } + if (!isDryRun) { + this.seen[originalSlug] = occurenceAccumulator; + this.seen[slug] = 0; + } + return slug; + }; + + /** + * Convert string to unique id + * @param {object} options + * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator. + */ + Slugger.prototype.slug = function slug (value, options) { + if ( options === void 0 ) options = {}; + + var slug = this.serialize(value); + return this.getNextSafeSlug(slug, options.dryrun); + }; + + return Slugger; + }()); + + var defaults$4 = defaults.defaults; + + var unescape$1 = helpers.unescape; + + /** + * Parsing & Compiling + */ + var Parser = /*@__PURE__*/(function () { + function Parser(options) { + this.options = options || defaults$4; + this.options.renderer = this.options.renderer || new Renderer(); + this.renderer = this.options.renderer; + this.renderer.options = this.options; + this.textRenderer = new TextRenderer(); + this.slugger = new Slugger(); + } + + /** + * Static Parse Method + */ + Parser.parse = function parse (tokens, options) { + var parser = new Parser(options); + return parser.parse(tokens); + }; + + /** + * Static Parse Inline Method + */ + Parser.parseInline = function parseInline (tokens, options) { + var parser = new Parser(options); + return parser.parseInline(tokens); + }; + + /** + * Parse Loop + */ + Parser.prototype.parse = function parse (tokens, top) { + if ( top === void 0 ) top = true; + + var out = '', + i, + j, + k, + l2, + l3, + row, + cell, + header, + body, + token, + ordered, + start, + loose, + itemBody, + item, + checked, + task, + checkbox; + + var l = tokens.length; + for (i = 0; i < l; i++) { + token = tokens[i]; + switch (token.type) { + case 'space': { + continue; + } + case 'hr': { + out += this.renderer.hr(); + continue; + } + case 'heading': { + out += this.renderer.heading( + this.parseInline(token.tokens), + token.depth, + unescape$1(this.parseInline(token.tokens, this.textRenderer)), + this.slugger); + continue; + } + case 'code': { + out += this.renderer.code(token.text, + token.lang, + token.escaped); + continue; + } + case 'table': { + header = ''; + + // header + cell = ''; + l2 = token.header.length; + for (j = 0; j < l2; j++) { + cell += this.renderer.tablecell( + this.parseInline(token.tokens.header[j]), + { header: true, align: token.align[j] } + ); + } + header += this.renderer.tablerow(cell); + + body = ''; + l2 = token.cells.length; + for (j = 0; j < l2; j++) { + row = token.tokens.cells[j]; + + cell = ''; + l3 = row.length; + for (k = 0; k < l3; k++) { + cell += this.renderer.tablecell( + this.parseInline(row[k]), + { header: false, align: token.align[k] } + ); + } + + body += this.renderer.tablerow(cell); + } + out += this.renderer.table(header, body); + continue; + } + case 'blockquote': { + body = this.parse(token.tokens); + out += this.renderer.blockquote(body); + continue; + } + case 'list': { + ordered = token.ordered; + start = token.start; + loose = token.loose; + l2 = token.items.length; + + body = ''; + for (j = 0; j < l2; j++) { + item = token.items[j]; + checked = item.checked; + task = item.task; + + itemBody = ''; + if (item.task) { + checkbox = this.renderer.checkbox(checked); + if (loose) { + if (item.tokens.length > 0 && item.tokens[0].type === 'text') { + item.tokens[0].text = checkbox + ' ' + item.tokens[0].text; + if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') { + item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text; + } + } else { + item.tokens.unshift({ + type: 'text', + text: checkbox + }); + } + } else { + itemBody += checkbox; + } + } + + itemBody += this.parse(item.tokens, loose); + body += this.renderer.listitem(itemBody, task, checked); + } + + out += this.renderer.list(body, ordered, start); + continue; + } + case 'html': { + // TODO parse inline content if parameter markdown=1 + out += this.renderer.html(token.text); + continue; + } + case 'paragraph': { + out += this.renderer.paragraph(this.parseInline(token.tokens)); + continue; + } + case 'text': { + body = token.tokens ? this.parseInline(token.tokens) : token.text; + while (i + 1 < l && tokens[i + 1].type === 'text') { + token = tokens[++i]; + body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text); + } + out += top ? this.renderer.paragraph(body) : body; + continue; + } + default: { + var errMsg = 'Token with "' + token.type + '" type was not found.'; + if (this.options.silent) { + console.error(errMsg); + return; + } else { + throw new Error(errMsg); + } + } + } + } + + return out; + }; + + /** + * Parse Inline Tokens + */ + Parser.prototype.parseInline = function parseInline (tokens, renderer) { + renderer = renderer || this.renderer; + var out = '', + i, + token; + + var l = tokens.length; + for (i = 0; i < l; i++) { + token = tokens[i]; + switch (token.type) { + case 'escape': { + out += renderer.text(token.text); + break; + } + case 'html': { + out += renderer.html(token.text); + break; + } + case 'link': { + out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer)); + break; + } + case 'image': { + out += renderer.image(token.href, token.title, token.text); + break; + } + case 'strong': { + out += renderer.strong(this.parseInline(token.tokens, renderer)); + break; + } + case 'em': { + out += renderer.em(this.parseInline(token.tokens, renderer)); + break; + } + case 'codespan': { + out += renderer.codespan(token.text); + break; + } + case 'br': { + out += renderer.br(); + break; + } + case 'del': { + out += renderer.del(this.parseInline(token.tokens, renderer)); + break; + } + case 'text': { + out += renderer.text(token.text); + break; + } + default: { + var errMsg = 'Token with "' + token.type + '" type was not found.'; + if (this.options.silent) { + console.error(errMsg); + return; + } else { + throw new Error(errMsg); + } + } + } + } + return out; + }; + + return Parser; + }()); + + var merge$3 = helpers.merge; + var checkSanitizeDeprecation$1 = helpers.checkSanitizeDeprecation; + var escape$3 = helpers.escape; + + var getDefaults = defaults.getDefaults; + var changeDefaults = defaults.changeDefaults; + var defaults$5 = defaults.defaults; + + /** + * Marked + */ + function marked(src, opt, callback) { + // throw error in case of non string input + if (typeof src === 'undefined' || src === null) { + throw new Error('marked(): input parameter is undefined or null'); + } + if (typeof src !== 'string') { + throw new Error('marked(): input parameter is of type ' + + Object.prototype.toString.call(src) + ', string expected'); + } + + if (typeof opt === 'function') { + callback = opt; + opt = null; + } + + opt = merge$3({}, marked.defaults, opt || {}); + checkSanitizeDeprecation$1(opt); + + if (callback) { + var highlight = opt.highlight; + var tokens; + + try { + tokens = Lexer.lex(src, opt); + } catch (e) { + return callback(e); + } + + var done = function(err) { + var out; + + if (!err) { + try { + out = Parser.parse(tokens, opt); + } catch (e) { + err = e; + } + } + + opt.highlight = highlight; + + return err + ? callback(err) + : callback(null, out); + }; + + if (!highlight || highlight.length < 3) { + return done(); + } + + delete opt.highlight; + + if (!tokens.length) { return done(); } + + var pending = 0; + marked.walkTokens(tokens, function(token) { + if (token.type === 'code') { + pending++; + setTimeout(function () { + highlight(token.text, token.lang, function(err, code) { + if (err) { + return done(err); + } + if (code != null && code !== token.text) { + token.text = code; + token.escaped = true; + } + + pending--; + if (pending === 0) { + done(); + } + }); + }, 0); + } + }); + + if (pending === 0) { + done(); + } + + return; + } + + try { + var tokens$1 = Lexer.lex(src, opt); + if (opt.walkTokens) { + marked.walkTokens(tokens$1, opt.walkTokens); + } + return Parser.parse(tokens$1, opt); + } catch (e) { + e.message += '\nPlease report this to https://github.com/markedjs/marked.'; + if (opt.silent) { + return '

    An error occurred:

    '
    +          + escape$3(e.message + '', true)
    +          + '
    '; + } + throw e; + } + } + + /** + * Options + */ + + marked.options = + marked.setOptions = function(opt) { + merge$3(marked.defaults, opt); + changeDefaults(marked.defaults); + return marked; + }; + + marked.getDefaults = getDefaults; + + marked.defaults = defaults$5; + + /** + * Use Extension + */ + + marked.use = function(extension) { + var opts = merge$3({}, extension); + if (extension.renderer) { + var renderer = marked.defaults.renderer || new Renderer(); + var loop = function ( prop ) { + var prevRenderer = renderer[prop]; + renderer[prop] = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var ret = extension.renderer[prop].apply(renderer, args); + if (ret === false) { + ret = prevRenderer.apply(renderer, args); + } + return ret; + }; + }; + + for (var prop in extension.renderer) loop( prop ); + opts.renderer = renderer; + } + if (extension.tokenizer) { + var tokenizer = marked.defaults.tokenizer || new Tokenizer(); + var loop$1 = function ( prop ) { + var prevTokenizer = tokenizer[prop$1]; + tokenizer[prop$1] = function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var ret = extension.tokenizer[prop$1].apply(tokenizer, args); + if (ret === false) { + ret = prevTokenizer.apply(tokenizer, args); + } + return ret; + }; + }; + + for (var prop$1 in extension.tokenizer) loop$1( prop ); + opts.tokenizer = tokenizer; + } + if (extension.walkTokens) { + var walkTokens = marked.defaults.walkTokens; + opts.walkTokens = function (token) { + extension.walkTokens(token); + if (walkTokens) { + walkTokens(token); + } + }; + } + marked.setOptions(opts); + }; + + /** + * Run callback for every token + */ + + marked.walkTokens = function(tokens, callback) { + for (var i$3 = 0, list$3 = tokens; i$3 < list$3.length; i$3 += 1) { + var token = list$3[i$3]; + + callback(token); + switch (token.type) { + case 'table': { + for (var i = 0, list = token.tokens.header; i < list.length; i += 1) { + var cell = list[i]; + + marked.walkTokens(cell, callback); + } + for (var i$2 = 0, list$2 = token.tokens.cells; i$2 < list$2.length; i$2 += 1) { + var row = list$2[i$2]; + + for (var i$1 = 0, list$1 = row; i$1 < list$1.length; i$1 += 1) { + var cell$1 = list$1[i$1]; + + marked.walkTokens(cell$1, callback); + } + } + break; + } + case 'list': { + marked.walkTokens(token.items, callback); + break; + } + default: { + if (token.tokens) { + marked.walkTokens(token.tokens, callback); + } + } + } + } + }; + + /** + * Parse Inline + */ + marked.parseInline = function(src, opt) { + // throw error in case of non string input + if (typeof src === 'undefined' || src === null) { + throw new Error('marked.parseInline(): input parameter is undefined or null'); + } + if (typeof src !== 'string') { + throw new Error('marked.parseInline(): input parameter is of type ' + + Object.prototype.toString.call(src) + ', string expected'); + } + + opt = merge$3({}, marked.defaults, opt || {}); + checkSanitizeDeprecation$1(opt); + + try { + var tokens = Lexer.lexInline(src, opt); + if (opt.walkTokens) { + marked.walkTokens(tokens, opt.walkTokens); + } + return Parser.parseInline(tokens, opt); + } catch (e) { + e.message += '\nPlease report this to https://github.com/markedjs/marked.'; + if (opt.silent) { + return '

    An error occurred:

    '
    +          + escape$3(e.message + '', true)
    +          + '
    '; + } + throw e; + } + }; + + /** + * Expose + */ + + marked.Parser = Parser; + marked.parser = Parser.parse; + + marked.Renderer = Renderer; + marked.TextRenderer = TextRenderer; + + marked.Lexer = Lexer; + marked.lexer = Lexer.lex; + + marked.Tokenizer = Tokenizer; + + marked.Slugger = Slugger; + + marked.parse = marked; + + var marked_1 = marked; + + /** + * Render github corner + * @param {Object} data URL for the View Source on Github link + * @param {String} cornerExternalLinkTarge value of the target attribute of the link + * @return {String} SVG element as string + */ + function corner(data, cornerExternalLinkTarge) { + if (!data) { + return ''; + } + + if (!/\/\//.test(data)) { + data = 'https://github.com/' + data; + } + + data = data.replace(/^git\+/, ''); + // Double check + cornerExternalLinkTarge = cornerExternalLinkTarge || '_blank'; + + return ( + "
    " + + '' + + '' + ); + } + + /** + * Renders main content + * @param {Object} config Configuration object + * @returns {String} HTML of the main content + */ + function main(config) { + var name = config.name ? config.name : ''; + + var aside = + '' + + ''; + return ( + "
    " + aside + + '
    ' + + '
    ' + + '
    ' + + '
    ' + ); + } + + /** + * Cover Page + * @returns {String} Cover page + */ + function cover() { + var SL = ', 100%, 85%'; + var bgc = + 'linear-gradient(to left bottom, ' + + "hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 0%," + + "hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 100%)"; + + return ( + "
    " + + '
    ' + + '
    ' + + '
    ' + ); + } + + /** + * Render tree + * @param {Array} toc Array of TOC section links + * @param {String} tpl TPL list + * @return {String} Rendered tree + */ + function tree(toc, tpl) { + if ( tpl === void 0 ) tpl = '
      {inner}
    '; + + if (!toc || !toc.length) { + return ''; + } + + var innerHTML = ''; + toc.forEach(function (node) { + var title = node.title.replace(/(<([^>]+)>)/g, ''); + innerHTML += "
  • " + (node.title) + "
  • "; + if (node.children) { + innerHTML += tree(node.children, tpl); + } + }); + return tpl.replace('{inner}', innerHTML); + } + + function helper(className, content) { + return ("

    " + (content.slice(5).trim()) + "

    "); + } + + function theme(color) { + return (""); + } + + /** + * Gen toc tree + * @link https://github.com/killercup/grock/blob/5280ae63e16c5739e9233d9009bc235ed7d79a50/styles/solarized/assets/js/behavior.coffee#L54-L81 + * @param {Array} toc List of TOC elements + * @param {Number} maxLevel Deep level + * @return {Array} Headlines + */ + function genTree(toc, maxLevel) { + var headlines = []; + var last = {}; + + toc.forEach(function (headline) { + var level = headline.level || 1; + var len = level - 1; + + if (level > maxLevel) { + return; + } + + if (last[len]) { + last[len].children = (last[len].children || []).concat(headline); + } else { + headlines.push(headline); + } + + last[level] = headline; + }); + + return headlines; + } + + var cache$1 = {}; + var re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g; + + function lower(string) { + return string.toLowerCase(); + } + + function slugify(str) { + if (typeof str !== 'string') { + return ''; + } + + var slug = str + .trim() + .replace(/[A-Z]+/g, lower) + .replace(/<[^>]+>/g, '') + .replace(re, '') + .replace(/\s/g, '-') + .replace(/-+/g, '-') + .replace(/^(\d)/, '_$1'); + var count = cache$1[slug]; + + count = hasOwn.call(cache$1, slug) ? count + 1 : 0; + cache$1[slug] = count; + + if (count) { + slug = slug + '-' + count; + } + + return slug; + } + + slugify.clear = function() { + cache$1 = {}; + }; + + function replace(m, $1) { + return ( + '' +
+      $1 +
+      '' + ); + } + + function emojify(text) { + return text + .replace(/:\+1:/g, ':thumbsup:') + .replace(/:-1:/g, ':thumbsdown:') + .replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g, function (m) { return m.replace(/:/g, '__colon__'); } + ) + .replace(/:(\w+?):/gi, ( window.emojify) || replace) + .replace(/__colon__/g, ':'); + } + + /** + * Converts a colon formatted string to a object with properties. + * + * This is process a provided string and look for any tokens in the format + * of `:name[=value]` and then convert it to a object and return. + * An example of this is ':include :type=code :fragment=demo' is taken and + * then converted to: + * + * ``` + * { + * include: '', + * type: 'code', + * fragment: 'demo' + * } + * ``` + * + * @param {string} str The string to parse. + * + * @return {object} The original string and parsed object, { str, config }. + */ + function getAndRemoveConfig(str) { + if ( str === void 0 ) str = ''; + + var config = {}; + + if (str) { + str = str + .replace(/^('|")/, '') + .replace(/('|")$/, '') + .replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g, function (m, key, value) { + if (key.indexOf(':') === -1) { + config[key] = (value && value.replace(/"/g, '')) || true; + return ''; + } + + return m; + }) + .trim(); + } + + return { str: str, config: config }; + } + + /** + * Remove the tag from sidebar when the header with link, details see issue 1069 + * @param {string} str The string to deal with. + * + * @return {string} str The string after delete the element. + */ + function removeAtag(str) { + if ( str === void 0 ) str = ''; + + return str.replace(/(<\/?a.*?>)/gi, ''); + } + + var imageCompiler = function (ref) { + var renderer = ref.renderer; + var contentBase = ref.contentBase; + var router = ref.router; + + return (renderer.image = function (href, title, text) { + var url = href; + var attrs = []; + + var ref = getAndRemoveConfig(title); + var str = ref.str; + var config = ref.config; + title = str; + + if (config['no-zoom']) { + attrs.push('data-no-zoom'); + } + + if (title) { + attrs.push(("title=\"" + title + "\"")); + } + + if (config.size) { + var ref$1 = config.size.split('x'); + var width = ref$1[0]; + var height = ref$1[1]; + if (height) { + attrs.push(("width=\"" + width + "\" height=\"" + height + "\"")); + } else { + attrs.push(("width=\"" + width + "\"")); + } + } + + if (config.class) { + attrs.push(("class=\"" + (config.class) + "\"")); + } + + if (config.id) { + attrs.push(("id=\"" + (config.id) + "\"")); + } + + if (!isAbsolutePath(href)) { + url = getPath(contentBase, getParentPath(router.getCurrentPath()), href); + } + + if (attrs.length > 0) { + return ("\"""); + } + + return ("\"""); + }); + }; + + var prism = createCommonjsModule(function (module) { + /* ********************************************** + Begin prism-core.js + ********************************************** */ + + /// + + var _self = (typeof window !== 'undefined') + ? window // if in browser + : ( + (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) + ? self // if in worker + : {} // if in node js + ); + + /** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT + * @author Lea Verou + * @namespace + * @public + */ + var Prism = (function (_self){ + + // Private helper vars + var lang = /\blang(?:uage)?-([\w-]+)\b/i; + var uniqueId = 0; + + + var _ = { + /** + * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the + * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load + * additional languages or plugins yourself. + * + * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. + * + * You obviously have to change this value before the automatic highlighting started. To do this, you can add an + * empty Prism object into the global scope before loading the Prism script like this: + * + * ```js + * window.Prism = window.Prism || {}; + * Prism.manual = true; + * // add a new + + + +``` + +#### 以 NPM 包方式使用 + +```shell +npm install -S @hippy/web-renderer +``` + +在入口文件内添加: + +```javascript +// 1. 导入 web renderer +import { HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; + +// 2. 导入业务 bundle 的入口文件,需放在 web renderer 导入之后 + +// 3. 创建 web engine,如果有业务自定义模块和组件,从此处传入 +``` + +### 加载业务 Bundle + +加载 bundle 包有多种方式,可根据业务需要灵活选择,只需要确保引入顺序在 WebRenderer 之后即可 + +#### 在模板文件内引用加载 + +```html + + + + + +``` + +#### 在入口文件内动态加载 + +```javascript +import { HippyWebEngine } from '@hippy/web-renderer'; + +const engine = HippyWebEngine.create(); + + engine.load('https://xxxx.com/hippy-bundle/index.bundle.js').then(() => { + engine.start({ + id: 'root', + name: 'example', + }); +}); +``` + +#### 业务源码直接引用 + +```javascript +import { HippyCallBack, HippyWebEngine, HippyWebModule, View } from '@hippy/web-renderer'; +// 导入业务 bundle 的入口文件,需放在 web renderer 导入之后 +import './main'; + + +const engine = HippyWebEngine.create(); +``` + +### 启动 WebRenderer + +加载完业务 bundle 后,调用相关 API 创建并启动 WebRenderer + +```js +// 创建 web engine,如果有业务自定义模块和组件,从此处传入 +// 如果只使用官方模块和组件,则直接使用 const engine = HippyWebEngine.create() 即可 +const engine = HippyWebEngine.create({ + modules: { + CustomCommonModule, + }, + components: { + CustomPageView, + }, +}); + +// 启动 web renderer +engine.start({ + // 挂载的 dom id + id: 'root', + // 模块名 + name: 'module-name', + // 模块启动参数,业务自定义, + // hippy-react 可以从 入口文件props里获取,hippy-vue可以从 app.$options.$superProps 里获取 + params: { + path: '/home', + singleModule: true, + isSingleMode: true, + business: '', + data: { }, + }, +}); +``` diff --git a/docs/development/native-module.md b/docs/development/native-module.md new file mode 100644 index 00000000000..49f749eeabb --- /dev/null +++ b/docs/development/native-module.md @@ -0,0 +1,648 @@ +# 自定义终端模块 + +很多时候 JS 需要访问对应终端的一些能力模块,比如数据库、下载、网络请求等,这时候就需要使用 Module 来暴露接口给JS使用。Hippy SDK 中默认实现了部分 Module,但这极有可能无法满足你的需求,这就需要你对 Module 进行扩展封装。Hippy支持 Android、iOS、Ohos、Flutter、Web(同构) 等平台的模块扩展。 + +
    + +# Android + +--- + +## Module扩展 + +我们将以 TestModule 为例,从头扩展一个 Module,这个 Module 将展示前端如何调用终端能力,并且把结果返回给前端。 + +终端扩展Module包括四步: + +1. 创建 `HippyNativeModuleBase` 的子类。 +2. 添加 `HippyNativeModule` 注解。 +3. 实现导出给 JS 的方法。 +4. 注册 Module。 + +## 1. 创建HippyNativeModuleBase的子类 + +首先我们需要创建`TestModule`类,并且继承`HippyNativeModuleBase`。 + +```java +package com.tencent.mtt.hippy.example.modules; + +import com.tencent.mtt.hippy.HippyEngineContext; +import com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase; + +public class TestModule extends HippyNativeModuleBase +{ + + public LogModule(HippyEngineContext context) + { + super(context); + } +} +``` + +## 2. 添加HippyNativeModule注解 + +HippyNativeModuleBase 要求增加注解 `@HippyNativeModule` 。 + +HippyNativeModule注解参数: + +- name:module名称,js调用时需要通过此属性找到对应的module实例对象。 +- names:module别名,支持同一个module设置不同的名称。 +- init:默认为false,即module在首次调用的时候才会进行实例初始化,如果设置为true,在引擎创建时候就会马上创建实例并初始化 + +> **注意:init参数在非必要的情况下不要设置为true,否则可能增加引擎启动的耗时。** + +``` java +@HippyNativeModule(name = "TestModule") +public class TestModule extends HippyNativeModuleBase +{ + ... +} +``` + +## 3. 实现导出给JS的方法 + +导出给 JS 使用的方法,必须使用注解 `@HippyMethod` ,方法必须为 `public` 类型,返回类型必须为 `void`。 + +支持的方法参数类型包括: + +- Java基本数据类型。 +- HippyArray:类似于ArrayList,线程非安全。 +- HippyMap:类似于HashMap,线程非安全。 +- 基于JSValue的新数据类型:注解参数useJSValueType设置为true时适用。 +- Promise:回调JS的触发器,通过 `resolve` 方法返回成功信息给JS。通过 `reject` 方法返回失败实现给JS。 + +HippyMethod注解参数: + +- name:接口名称,js调用时需要通过此参数找到对应的接口信息,并进行反射调用。 +- isSync:是否为JSI接口,JSI为同步调用接口,会卡住js线程,只适用于数据结构简单且size较小的数据传输,[JSI特性介绍](feature/feature2.0/jsi.md) +- useJSValueType:接口参数是否使用新数据类型,默认为false,即使用老的HippyMap与HippyArray类型接收参数,设置为true以后参数需要使用基于JSValue为基类的扩展数据类型,[新数据类型介绍](development/type-mapping.md) + +> **注意:新数据类型不能与HippyMap或HippyArray相互嵌套混用, 否则会导致数据编解码产生错误。** + +```java +@HippyMethod(name="log") +public void log(String msg) +{ + Log.d("TestModule", msg); +} + +@HippyMethod(name="helloNative") +public void helloNative(HippyMap hippyMap) +{ + String hello = hippyMap.getString("hello"); + Log.d("TestModule", hello); +} + +@HippyMethod(name = "helloNativeWithPromise") +public void helloNativeWithPromise(HippyMap hippyMap, Promise promise) +{ + // 这里回来的参数可以为java的基础类型,和hippymap与hippyarry, 但是前端调用的时候必须对应上 + String hello = hippyMap.getString("hello"); + Log.d("TestModule", hello); + if (true) + { + // TODO 如果模块这里处理成功回调resolve + HippyMap hippyMap1 = new HippyMap(); + hippyMap1.pushInt("code", 1); + hippyMap1.pushString("result", "hello i am from native"); + promise.resolve(hippyMap1); + } + else + { + // 失败就回调reject + HippyMap hippyMap1 = new HippyMap(); + hippyMap1.pushInt("code", -1); + promise.reject(hippyMap1); + } +} +``` + +## 4. 注册Module + +需要自定义'APIProvider'类,并实现SDK HippyAPIProvider interface,然后在`getNativeModules` 方法中添加这个 Module,这样它才能在JS中被访问到。 + +```java +public class MyAPIProvider implements HippyAPIProvider { + + @Override + public Map, Provider> getNativeModules(final HippyEngineContext context) + { + Map, Provider> modules = new HashMap<>(); + //regist the MyModule + modules.put(TestModule.class, new Provider() + { + @Override + public HippyNativeModuleBase get() + { + return new TestModule(context); + } + }); + } + + @Override + public List> getJavaScriptModules() {return null;} + + @Override + public List> getControllers() {return null;} +} +``` + +## 5. 注册APIProvider + +在HippyEngine初始化的EngineInitParams参数属性中设置providers。 + +``` java +List providers = new ArrayList<>(); +providers.add(new MyAPIProvider()); +initParams.providers = providers; +``` + + +## 注意事项 + +扩展Module中不能同步执行耗时操作,这可能卡住整个引擎通信线程。存在耗时场景,请使用异步线程处理。 + +## 混淆说明 + +扩展 Module 的类名和扩展方法名不能混淆,可以增加混淆例外。 + +``` java +-keep class * extends com.tencent.mtt.hippy.modules.nativemodules.HippyNativeModuleBase{ public *;} +``` + + +# iOS + +除了UI界面以外,APP开发中还会出现调用设备功能的场景,比如获取当前网络状态、发起HTTP网络请求等。SDK已经封装了一些常用功能,但自定义功能模块也是十分方便的。 + +> **注意:自定义模块及其方法的名称中不要带上 `Hippy` 几个字(不区分大小写),否则在 iOS 上可能会碰到找不到模块或方法的问题。** + +> 功能扩展中类和方法的导出和UI组件的类和方法的导出十分相似,建议先阅读UI组件扩展再来阅读功能扩展文章。 + +使用 `HIPPY_EXPORT_MODULE()` 扩展自定义功能后,每次APP启动时都会创建一个功能实例,并且以后前端调用组件功能使用的都是这个实例,可以理解为单例的意思。 +>功能没有属性这个概念,不要试图去给功能绑定属性。 + +每个功能都有类似于UI组件对应的方法导出, 同样也对应`callNative`、`callNativeWithCallbackId`、`callNativeWithPromise`三种调用方式。 + +我们将SDK中的功能模块分为两种类型: + +- 非事件型功能--当业务需要某种信息或者需要终端执行某项指令,直接通过接口调用终端代码即可。 +- 事件型功能--业务需要终端监听某个事件。当事件触发时,终端通知前端。 + +--- + +## 非事件型功能扩展 + +扩展一个非事件型功能组件包括以下工作: + +- 创建对应的功能类,并绑定前端组件, + >非事件型功能只需要继承自简单的NSObject类即可。在实现文件中使用 `HIPPY_EXPORT_MODULE()` 宏导出。 +- 绑定前端方法 + >与扩展UI组件类似,使用`HIPPY_EXPORT_METHOD()`宏绑定前端方法。注意方法名需要对齐。 + +TestModule.h + +```objectivec +@interface TestModule : NSObject +@end +``` + +TestModule.m + +``` objectivec +@implementation TestModule +HIPPY_EXPORT_MODULE() +HIPPY_EXPORT_METHOD(click) { + // 实现前端的click功能 +} +@end +``` + +## 事件型功能扩展 + +事件型功能除了拥有非事件型功能的全部特点外,还拥有事件监听与反馈的能力。前端可能有个 `MyModule.addListener(string eventname)` 方法调用用于驱动终端监听某个事件,以及一套接收终端事件回调的机制。因此终端将这些机制封装为一个基类`HippyEventObserverModule`。所有事件型功能都必须继承自这个基类并实现必要的方法。 +扩展一个事件型功能包括以下工作: + +- 创建对应的事件型功能类,必须继承自 `HippyEventObserverModule`,并绑定前端组件。 + >在实现文件中使用 `HIPPY_EXPORT_MODULE()` 宏导出。 +- 绑定前端方法 + + >与扩展UI组件类似,使用 `HIPPY_EXPORT_METHOD()` 宏绑定前端方法。注意方法名需要对齐。 + +- 实现 `[MyModule addEventObserverForName:]` 与 `[MyModule removeEventObserverForName:]` 方法用以开启、关闭对某个事件的监听行为 + + >这两个方法在基类 `HippyEventObserverModule` 中已经实现但未作任何处理,需要MyModule根据需要自行实现。同时这一步是否需要实现取决于前端是否有对应的MyModule.addListener()操作,即希望终端监听某个事件。若无,则终端可以不实现。 + +- 事件发生后通知前端 + + >终端使用 `[MyModule sendEvent:params:]` 方法通知前端。此方法在基类中已经实现。用户需要将制定参数填入并调用方法即可。 + >第一个参数为事件名,前端终端事件名必须一致。 + >第二个参数为事件信息,`NSDictionary`类型。 + +TestModule.h + +``` objectivec +//注意继承自HippyEventObserverModule +@interface TestModule : HippyEventObserverModule +@end +``` + +TestModule.m + +``` objectivec +@implementation TestModule +HIPPY_EXPORT_MODULE() +HIPPY_EXPORT_METHOD(click) { + // 实现前端的click功能 +} +- (void) addEventObserverForName:(NSString *)eventName { + // 监听customevent事件 + if ([eventName isEqualToString:@"customevent"]) { + addLisener(eventName); + } +} +- (void) removeEventObserverForName:(NSString *)eventName { + // 移除customevent事件 + if ([eventName isEqualToString:@"customevent"]) { + removeLisener(eventName); + } +} +- (void) eventOccur { + // 事件发生,通知前端 + [self sendEvent:@"customevent" params:@{@"key": @"value"}]; +} +@end +``` + +# Ohos + +很多时候 `JS` 需要访问对应终端的一些能力模块,比如数据库、下载、网络请求等,这时候就需要使用 `Module` 来暴露接口给JS使用。Ohos SDK 中默认实现了部分 `Module`,但这极有可能无法满足你的需求,这就需要你对 `Module` 进行扩展封装。 + +--- + +## Module扩展 + +我们将以 `ExampleNativeModule` 为例,从头扩展一个 `Module`,这个 `Module` 将展示前端如何调用终端能力,并且把结果返回给前端。 + +终端扩展 `Module` 的步骤: + +1. 创建 `HippyNativeModuleBase` 的子类。 +2. 实现导出给 JS 的方法。 +3. 注册 Module。 +4. 注册 HippyAPIProvider。 + +## 1. 创建 HippyNativeModuleBase 的子类 + +```typescript +export class ExampleNativeModule extends HippyNativeModuleBase { + public static readonly NAME = 'ExampleNativeModule' + + constructor(ctx: HippyEngineContext) { + super(ctx) + } + + public call(method: string, params: Array, promise: HippyModulePromise): HippyAny { + switch (method) { + case 'test': { + this.test(); + break; + } + case 'testPromise': { + this.testPromise(params, promise); + break; + } + case 'testSendEvent': { + this.testSendEvent(params, promise); + } + default: + super.call(method, params, promise); + } + return null; + } + + public test() { + LogUtils.i(ExampleNativeModule.NAME, 'module test'); + } + + public testPromise(params: Array, promise: HippyModulePromise) { + promise.resolve('test'); + } + + public testSendEvent(params: Array, promise: HippyModulePromise) { + LogUtils.i(ExampleNativeModule.NAME, 'testSendEvent'); + if (this.ctx != null && this.ctx.getModuleManager() != null) { + const eventModule = this.ctx.getModuleManager().getJavaScriptModule(EventDispatcher.MODULE_NAME); + if (eventModule != null) { + const event = 'testEvent'; + const params = new Map(); + params.set('testString', 'testStringValue'); + + const valueMap = new Map(); + valueMap.set('testString2', 'testStringValue2'); + params.set('testMap', valueMap); + + const array: HippyArray = []; + array.push(valueMap); + params.set('testArray', array); + + (eventModule as EventDispatcher).receiveNativeEvent(event, params); + } + } + } + +} +``` + +需要注意的是,这里与Android、iOS有几处不同。 + +1. 需要指定 NAME,设置为前端调用的 module name + +2. 需要实现 call 方法 + +## 2. 实现导出给 JS 的方法 + +例子见上一步 call 方法的实现。 + +## 3. 注册 Module + +```typescript +export class ExampleAPIProvider extends HippyAPIProvider { + getCustomNativeModuleCreatorMap(): Map | null { + let registerMap: Map = + new Map() + registerMap.set(ExampleNativeModule.NAME, + (ctx): HippyNativeModuleBase => new ExampleNativeModule(ctx)) + return registerMap; + } +} +``` + +## 4. 注册 HippyAPIProvider + +在 HippyEngine 初始化的 EngineInitParams 参数属性中设置 providers。 + +```typescript +params.providers = new Array(new ExampleAPIProvider()) +``` + +## Turbo Module扩展 + +和 Module 的扩展一致,不过还需要配置 isTurbo 方法,且不需要实现 call 方法,参考如下: + +```typescript +export class ExampleNativeTurboModule extends HippyNativeModuleBase { + public static readonly NAME = 'demoTurbo' + + constructor(ctx: HippyEngineContext) { + super(ctx) + } + + isTurbo(): boolean { + return true + } + + public getString(info: string): string { + return 'demoTurbo' + info; + } + + public getNum(num: number): number { + return num; + } + + public getBoolean(b: boolean): boolean { + return b; + } + + public getMap(map: HippyMap): HippyMap { + return map + } + + public getArray(array: HippyArray): HippyArray { + return array + } + + public getObject(obj: HippyAny): HippyAny { + return obj + } + + public getTurboConfig(): TurboConfig { + return new TurboConfig(); + } + + public printTurboConfig(turboConfig: TurboConfig): string { + return turboConfig.info; + } +} + +``` + + +# Voltron + +很多时候 `JS` 需要访问对应终端的一些能力模块,比如数据库、下载、网络请求等,这时候就需要使用 `Module` 来暴露接口给JS使用。Voltron SDK 中默认实现了部分 `Module`,但这极有可能无法满足你的需求,这就需要你对 `Module` 进行扩展封装。 + +--- + +## Module扩展 + +我们将以 `TestModule` 为例,从头扩展一个 `Module`,这个 `Module` 将展示前端如何调用终端能力,并且把结果返回给前端 + +终端扩展 `Module` 包括四步: + +1. 创建 `TestModule` +2. 实现导出给 `JS` 的方法。 +3. 注册 `Module`。 + +## 1. 创建 `TestModule` + +首先我们需要创建 `TestModule` ,并且继承 `VoltronNativeModule` 。 + +```dart +import 'package:voltron/voltron.dart'; + +class TestModule extends VoltronNativeModule { + static const String kModuleName = "TestModule"; + + TestModule(EngineContext context) : super(context); + + @override + Map get extraFuncMap => {}; + + @override + String get moduleName => kModuleName; +} +``` + +## 2. 实现导出给 `JS` 的方法 + + +```dart +class TestModule extends VoltronNativeModule { + static const String kModuleName = "TestModule"; + + // 这里定义方法名 + static const String kLogMethodName = "log"; + static const String kHelloNativeMethodName = "helloNative"; + static const String kHelloNativeWithPromiseMethodName = "helloNativeWithPromise"; + + TestModule(EngineContext context) : super(context); + + /*** + * log + * @param log + * @param promise + * 自定义了扩展了一个 log 的接口并且无回调 + */ + @VoltronMethod(kLogMethodName) + bool log(String log, JSPromise promise) { + // 这里回来的参数可以为 dart 的基础类型和 VoltronMap (对应前端{})与 VoltronArray (对应前端[]),但是前端调用的时候必须对应上 + LogUtils.d("TestModule", log); + return true; + } + + /*** + * helloNative + * @param voltronMap + * @param promise + * 自定义了扩展了一个helloNative的接口,传入复杂结构参数 + */ + @VoltronMethod(kHelloNativeMethodName) + bool helloNative(VoltronMap voltronMap, JSPromise promise) { + // 这里回来的参数可以为dart的基础类型和VoltronMap(对应前端{})与VoltronArray(对应前端[]),但是前端调用的时候必须对应上 + String? hello = voltronMap.get("hello"); + if (hello != null) { + LogUtils.d("TestModule", hello); + } + return true; + } + + /*** + * helloNativeWithPromise + * @param voltronMap + * @param promise + * 自定义了扩展了一个helloNativeWithPromise的接口,支持回调 + */ + @VoltronMethod(kHelloNativeWithPromiseMethodName) + bool helloNativeWithPromise(VoltronMap voltronMap, Promise promise) { + // 这里回来的参数可以为 dart 的基础类型和 VoltronMap (对应前端{})与 VoltronArray (对应前端[]),但是前端调用的时候必须对应上 + String? hello = voltronMap.get("hello"); + if (hello != null) { + LogUtils.d("TestModule", hello); + if (hello.isNotEmpty) { + // 如果模块这里处理成功回调 resolve + VoltronMap hippyMap1 = VoltronMap(); + hippyMap1.push("code", 1); + hippyMap1.push("result", "hello i am from native"); + promise.resolve(hippyMap1); + return true; + } + } + // 失败就回调 reject + VoltronMap hippyMap1 = VoltronMap(); + hippyMap1.push("code", -1); + promise.reject(hippyMap1); + return true; + } + + // 这里填写方法名与方法的对应关系 + @override + Map get extraFuncMap => { + kLogMethodName: log, + kHelloNativeMethodName: helloNative, + kHelloNativeWithPromiseMethodName: helloNativeWithPromise, + }; + + @override + String get moduleName => kModuleName; +} +``` + +!> 主要注意的是,这里与Hippy有几处不同 + +1. 不管前端调用 `callNative` ,还是 `callNativeWithPromise` ,终端这里最后一个参数始终为 `promise` ,这里是由于 `flutter` 与安卓不同,这里不存在反射,我们无法直接获取到方法中的参数个数,所以默认最后一个参数必须填写 `promise` ,如果你调用的是 `callNative` ,也不用过于关注,这里对你没有任何影响。 + +2. 方法必须返回 `bool`,返回值的最大作用主要是为了让用户能够明确自己必须要处理 `promise` 的状态,这里如果返回 `true` ,则外部会忽略,如果返回 `false` ,则外部会默认返回兜底值 + +```dart +bool helloNativeWithPromise(VoltronMap voltronMap, Promise promise) {} +``` + +## 3. 注册 `Module` + +上面的工作做完后,我们需要把模块注册进入 Voltron 应用,还记得初始化时的 `MyAPIProvider` 吗,这里我们要传入在 `nativeModuleGeneratorList` + +```dart +class MyAPIProvider implements APIProvider { + + // 这个是模块扩展 + @override + List get nativeModuleGeneratorList => [ + ModuleGenerator( + TestModule.kModuleName, + (context) => TestModule(context), + ), + ]; + + @override + List get javaScriptModuleGeneratorList => []; + + @override + List get controllerGeneratorList => []; +} +``` + + +# Web + +--- + +## 模块的扩展 + +扩展模块主要包括: + +1. 创建 `HippyWebModule` 的子类 +2. 设置 `Moduel` 的 `name` 属性 +3. 实现 `Module` 需要暴露给前端的 `API` + +其中 `HippyWebModule` 类标准化了 HippyWebRenderer 可使用的模块,提供了一些 HippyWebRenderer 的上下文,在一个自定义组件中有几个比较重要的属性: + +- name:定义了模块的名字,与 JS 业务侧使用 `callNative(moduleName,methodName)` 中的 `moduleName` 相对应 +- context:提供了一系列的方法 + +```javascript +sendEvent(type: string, params: any); //发送事件 +sendUiEvent(nodeId: number, type: string, params: any); // 发送 UI 相关事件 +sendGestureEvent(e: HippyTransferData.NativeGestureEvent); // 发送手势事件 +subscribe(evt: string, callback: Function); // 监听某个事件 +getModuleByName(moduleName: string); // 使用模块名获取模块 +``` + +### 例子 + +以 CustomModule 为例,从头介绍如何扩展 Module + +```javascript +import { HippyWebModule } from '@hippy/web-renderer'; +// 继承自 HippyWebModule +export class CustomModule extends HippyWebModule { + // 设置 Module的 name 属性 + name = 'CustomModule'; + // 实现API `getBrowserInfo` 和 `setBrowserTitle` ,分别提供了获取当前浏览器的信息和设置浏览器 title 的功能。 + // 在提供自定义模块的 api 时,api的参数为 `function name(arg1,arg2...argn,callBack)`,前面的n个参数对应业务侧调用时的传递参数,最后一个 `callback` 是当 JS 业务侧需要有返回值形式的调用时,提供返回结果的回调。 + getBrowserInfo(callBack) { + let data = {}; + ... + callBack.resolve(data); + } + + setBrowserTitle(title, callBack) { + if (title) { + window.document.title = title; + }; + ... + callBack.resolve(true); + // callBack.reject(null);执行失败时 + } +} +``` + diff --git a/docs/development/ohos-integration-guidelines.md b/docs/development/ohos-integration-guidelines.md new file mode 100644 index 00000000000..2393ad80ccb --- /dev/null +++ b/docs/development/ohos-integration-guidelines.md @@ -0,0 +1,225 @@ +# Hippy Ohos SDK集成指引 + +这篇教程,讲述了如何将 Hippy SDK 集成到一个现有的 Ohos 工程。 + +> 注:以下文档都是假设您已经具备一定的 Ohos 开发经验。 + +--- + +## 前期准备 + +- 已经安装 DevEco Studio 最新版本 + +## Demo 体验 + +- Ohos Har Demo:Har 包方式依赖 Hippy。 体验方法:DevEco 打开 hippy 项目根目录运行 entry_har。 +- Ohos Demo:源码依赖 Hippy。体验方法:DevEco 打开 hippy 项目根目录直接运行 entry。 + +> 注:一定是打开 Hippy 项目根目录,不是 Demo 的根目录 + +## 接入方式一:Har包快速接入 + +### 1. 创建一个 Ohos 工程 + +### 2. Har 包集成 + +- 配置 oh-package.json5,依赖 Hippy har 包 + +依赖远程 [ohpm](https://ohpm.openharmony.cn/) 上 Har 包: + + ```json + "dependencies": { + "hippy": "3.3.2" + } + ``` + +或者依赖本地 Har 包: + + ```json + "dependencies": { + "hippy": "file:./libs/hippy.har" + } + ``` + +- Hippy har包产物构建方法: + - DevEco Studio 打开 Hippy 根目录 + - DevEco Studio 里 Build Mode 选择 release 或 debug + - DevEco Studio 里选择 Hippy 模块下文件,比如选择 /framework/ohos/src/main/cpp/CMakeLists.txt + - DevEco Studio 菜单里 Build - Make Module 'hippy' + - 目录 /framework/ohos/build/default/outputs/default/ 里生成 hippy.har + +### 3. 初始化代码 + +- 获取 libhippy.so 接口对象和 UIAbility context + + ```TypeScript + import libHippy from 'libhippy.so' // libhippy.so下面可能会有红线提示,可忽略 + AppStorage.setOrCreate("libHippy", libHippy) + AppStorage.setOrCreate("abilityContext", this.context) + AppStorage.setOrCreate("mainWindow", mainWindow) + ``` + +> 注:App 直接集成 Hippy,context 使用 UIAbility context;如果 App 在一个模块里集成 Hippy,js 等资源也集成在模块里,context 使用 getContext().createModuleContext("moduleName"),否则会找不到 js 等资源。 + +- 创建 HippyEngine、初始化 HippyEngine、加载业务 bundle + + ```TypeScript + this.hippyEngine = createHippyEngine(params) + this.hippyEngine.initEngine() + this.hippyEngine?.loadModule() + ``` + +> 注:loadModule 需要在 initEngine 成功后调用,即回调结果返回 EngineInitStatus.STATUS_OK 后 + +- 组装 HippyRoot 组件 + + ```TypeScript + HippyRoot({ + hippyEngine: this.hippyEngine, + rootViewWrapper: this.rootViewWrapper, + onRenderException: (exception: HippyException) => { + this.exception = `${exception.message}\n${exception.stack}` + }, + }) + ``` + +> 注:确保这里 this.hippyEngine 和 this.rootViewWrapper 是有效值 + +### 4. 销毁代码 + +Hippy页面退出时,需要释放资源。 destroyModule 用来释放对应 loadModule 的页面资源,destroyEngine 用来释放对应 initEngine 的引擎环境资源。 +一定要先 destroyModule,返回后再 destroyEngine。 + + ```TypeScript + hippyEngine?.destroyModule(rootId, () => { + hippyEngine?.destroyEngine(); + }); + ``` + +具体可以参考 [Har Demo](https://github.com/Tencent/Hippy/tree/main/framework/examples/ohos-har-demo) 工程中 `EntryAbility.ets` `Index.ets` 实现 + +## 接入方式二:源码接入 + +> 源码接入主要为了方便在 App 项目里直接调试 Hippy 代码(c++ 和 ets 代码)。 + +### 1. 创建一个 Ohos 工程 + +### 2. Hippy 代码集成 + +- 拉取 hippy 代码到项目里(比如:根目录下,IDE 限制 Hippy 源代码一定要在依赖 Hippy 的项目/模块的目录或子目录里,否则编译会报ets文件路径无法解决的错误) + +> https://github.com/Tencent/Hippy.git,分支:main + +- 配置 oh-package.json5,依赖 Hippy 文件目录 + + ```json + "dependencies": { + "hippy": "file:../Hippy/framework/ohos/" + } + ``` + +### 3. Hippy C++ 代码编译配置 + +- 如果业务模块没有使用 C++,需 build-profile.json5 里配置使用,如下 + + ```json + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + }, +``` + +- CMakeLists.txt 内容如下 + + ```cmake +cmake_minimum_required(VERSION 3.14) +project(hippy) + +set(BIZ_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../") +set(HIPPY_ROOT_DIR "${BIZ_ROOT_DIR}/Hippy_src/framework/ohos/") +set(HIPPY_IMPL_CPP_DIR "${HIPPY_ROOT_DIR}/src/main/cpp/impl") + +add_subdirectory("${HIPPY_IMPL_CPP_DIR}" ./hippy_impl) + +add_library(${PROJECT_NAME} SHARED + +) + +target_link_libraries(${PROJECT_NAME} PUBLIC hippy_impl) + +set(SOURCE_SET + ) +set(PUBLIC_SOURCE_SET + ) +target_sources(${PROJECT_NAME} PRIVATE ${SOURCE_SET} PUBLIC ${PUBLIC_SOURCE_SET}) + ``` + +### 4. 初始化代码 + +- 获取 libhippy.so 接口对象和 UIAbility context + + ```TypeScript + import libHippy from 'libhippy.so' + AppStorage.setOrCreate("libHippy", libHippy) + AppStorage.setOrCreate("abilityContext", this.context) + AppStorage.setOrCreate("mainWindow", mainWindow) + ``` + +- 创建 HippyEngine、初始化 HippyEngine、加载业务 bundle + + ```TypeScript + this.hippyEngine = createHippyEngine(params) + this.hippyEngine.initEngine() + this.hippyEngine?.loadModule() + ``` + +- 组装 HippyRoot 组件 + + ```TypeScript + HippyRoot({ + hippyEngine: this.hippyEngine, + rootViewWrapper: this.rootViewWrapper, + onRenderException: (exception: HippyException) => { + this.exception = `${exception.message}\n${exception.stack}` + }, + }) + ``` + +### 5. 销毁代码 + +Hippy页面退出时,需要释放资源。 destroyModule 用来释放对应 loadModule 的页面资源,destroyEngine 用来释放对应 initEngine 的引擎环境资源。 +一定要先 destroyModule,返回后再 destroyEngine。 + + ```TypeScript + hippyEngine?.destroyModule(rootId, () => { + hippyEngine?.destroyEngine(); + }); + ``` + +具体可以参考 [Demo](https://github.com/Tencent/Hippy/tree/main/framework/examples/ohos-demo) 工程中 `EntryAbility.ets` 等实现 + +## 接入方式三:定制场景接入 + +- 对于需要直接依赖 hippy c++ 代码编译使用的定制场景,可参考 [Demo](https://github.com/Tencent/Hippy/tree/main/framework/examples/ohos-demo) 工程中 `CMakeLists.txt` 说明 + +## Hippy Har 包大小 + +- 最终集成的 Release Har 包大小为1.9M。 + +> 构建的 Har 包较大说明: +为了方便定位crash,配置了debugSymbol strip为false,构建的har包里so带详细符号,所以size较大,App集成后会自动strip掉符号变小。 +比如:har包有3.8M,其中解压后libhippy.so大小为13.9M,strip符号变小后har包大小为1.9M,解压后so大小为6.2M。 + +## 常见问题 + +### 页面白屏问题 + +- 先用 ArkUI Inspector 工具检查界面上是否有元素,其中 Hippy 组件的 id 都是 “HippyId+数字”的形式 +- 如果界面上有元素,但看着白屏,可能1:元素 size 为0,进而可能布局更新有问题,可能2:元素无可见属性设置,可能业务没有更新数据 +- 如果界面上无元素,可能 JS Bundle 加载失败,检查控制台 Log,搜索 “JSHCtx::RunScript” 关键词,检查附近 JS 文件是否加载到并正确执行 + +### 页面点击穿透问题 + +- 鸿蒙下 ArkUINode 里默认把所有组件的 HitTest 模式都设为了 TRANSPARENT,可能导致某些业务场景顶层的页面拦不住事件。 + - 原因和兼容方法:Hippy组件和自定义组件嵌套的复杂场景,鸿蒙默认又不裁剪overflow的部分,复杂场景容易出现点不了的问题。 所以兼容方法:默认HitTest都响应,业务具体场景要阻塞,鸿蒙上使用hit-test-ohos属性自己兼容。 (基于多数场景能点更重要,少数场景才有覆盖的假设)。 diff --git a/docs/development/privacy-developer-guide.md b/docs/development/privacy-developer-guide.md new file mode 100644 index 00000000000..8b4654e863f --- /dev/null +++ b/docs/development/privacy-developer-guide.md @@ -0,0 +1,117 @@ +# Hippy SDK 开发者合规指南 + +为帮助使用Hippy SDK的开发运营者(以下简称“您”)在符合个人信息保护相关法律法规、政策及标准的规定下合规接入、使用第三方SDK, Hippy (以下简称"我们")特制定《Hippy SDK开发者合规指南》(以下简称“文档”),便于您使用Hippy SDK 过程中符合相应的合规要求。请您在接入、使用Hippy SDK前,充分阅读和了解本文档内容。 + +## 一、接入/升级至满足监管新规的最新SDK版本 + +我们高度重视SDK的功能优化、个人信息安全和保护,将适时升级迭代SDK版本以提升产品的安全性和稳定性,确保符合相关法律法规及、监管及标准的最新合规要求。强烈建议您升级使用最新版本SDK,以便保障您正常使用SDK最新功能、避免因您更新不及时产生的不利影响(例如APP被通报或下架等)。
    +SDK更新后,我们会及时通过官网公告通知、SDK更新日志、站内信、弹窗、红点、邮件、短信或其他适当的方式中的一种或多种提醒您更新的内容,以便您及时了解SDK最新版本信息。同时,您可以访问SDK最新版本下载链接:[iOS / Android 下载链接](https://github.com/Tencent/Hippy/releases) [Harmony 下载链接](https://ohpm.openharmony.cn/#/cn/detail/hippy) + +## 二、APP隐私政策中应披露第三方SDK相关情况 + +请您确保您开发或运营的APP配备了符合监管要求的《隐私政策》文本。请您务必明确告知终端用户您的App集成了第三方SDK服务。您应在《隐私政策》中添加关于本SDK收集使用个人信息的目的、方式和范围等,并显示本SDK的开发运营者名称及隐私政策链接。您应在 APP 登录注册页面及 APP 首次运行时,通过弹窗、文本链接及附件等简洁明显且易于访问的方式,应当以清晰易懂的语言告知用户《隐私政策》,由用户在充分知情的前提下,作出自愿明确的意思表示。
    +我们提供以下告知文案示例供您参考,您可以通过文字或表格方式向用户告知。请您理解SDK不同版本提供的功能服务及所需的字段信息可能会因开发者的选择或配置不同而存在差异,因此请您参考SDK隐私政策及您实际接入使用的SDK运行情况向用户进行充分告知并获得用户的同意。 + +仅 iOS 参考示例: + +```markdown +第三方SDK名称:Hippy +第三方SDK提供方的公司名称:深圳市腾讯计算机系统有限公司 +使用目的及功能场景:使用Hippy开发框架进行跨平台功能开发 +处理的个人信息类型:手机型号 +实现SDK产品功能所需的权限:无 +第三方SDK隐私政策链接:https://hippy.tds.qq.com/#/development/privacy +``` + +仅 Android 参考示例: + +```markdown +第三方SDK名称:Hippy +第三方SDK提供方的公司名称:深圳市腾讯计算机系统有限公司 +使用目的及功能场景:使用Hippy开发框架进行跨平台功能开发 +处理的个人信息类型:无 +实现SDK产品功能所需的权限:无 +第三方SDK隐私政策链接:https://hippy.tds.qq.com/#/development/privacy +``` + +仅 Harmony 参考示例: + +```markdown +第三方SDK名称:Hippy +第三方SDK提供方的公司名称:深圳市腾讯计算机系统有限公司 +使用目的及功能场景:使用Hippy开发框架进行跨平台功能开发 +处理的个人信息类型:无 +实现SDK产品功能所需的权限:互联网访问权限、获取网络信息权限 +第三方SDK隐私政策链接:https://hippy.tds.qq.com/#/development/privacy +``` + +## 三、获得用户同意后再初始化SDK + +为满足法律法规及监管要求,您应确保在获得用户的同意后再初始化SDK,并在用户触发SDK具体功能服务后通过配置SDK的相关参数完成发送请求的调用。
    +1、确保在用户阅读APP隐私政策并取得用户授权之后,按APP功能需要在合适时机调用接口初始化SDK。反之,如果用户不同意《隐私政策》授权,则不能调用初始化接口。该接口仅进行初始化,不会获取个人信息。
    +2、请勿在用户同意隐私政策之前动态申请涉及用户个人信息的敏感设备权限;请勿在用户同意隐私政策前私自采集和上报个人信息(尤其注意Android_ID、OAID、IMEI、MAC地址、硬件序列号、应用安装列表等用户信息)。请勿在App处于未激活状态时(例如App在后台运行),请求SDK相关服务。 + +## 四、指导建议 + +请您重点关注,在APP安装、运行和使用相关功能时,您应遵从国家相关法律法规、监管政策及标准的要求,收集用户个人信息或申请敏感权限,不得存在以下违规行为:
    +(1)未经用户同意不得收集任何个人信息。
    +(2)非服务所必需或无合理应用场景下,用户拒绝相关授权申请后,应用不得自动退出或关闭。
    +(3)在用户明确拒绝权限申请后,APP不应向用户频繁弹窗或反复申请开启与当前服务场景无关的权限、影响用户正常使用,建议掌握合适时机申请敏感权限,不得影响其他功能可用。
    +(4)不得未明确告知用户索取权限的目的和用途。
    +(5)APP首次打开或运行中,未见使用权限对应的相关功能或服务时,不应提前向用户弹窗申请开启敏感权限。
    +(6)不得超出业务功能实际需要过度收集个人信息。 + +## 五、用户权利保障机制 + +如果您需要我们协助来实现您最终用户的其他个人信息主体权利请求,您可以通过“联系方式”来申请协助。 + +## 六、SDK所需系统权限说明 + +SDK所需系统权限依赖于App的场景调用,下面为您详细说明:
    + +仅 Harmony 版: + +| 权限名称 | 权限说明 | 与业务功能间的关系 | 权限申请时机 | +|------|----------|-------------------|---| +| ohos.permission.INTERNET | 连网权限 | 业务打开Hippy实现的页面时需要 | 业务打开Hippy页面时或提前下载页面js时 | +| ohos.permission.GET\_NETWORK\_INFO | 获取网络信息权限 | 业务打开Hippy实现的页面并有前端js调用时需要 | 业务页面前端js调用Hippy网络信息模块时 | + +## 七、联系方式 + +我们设立了专门的个人信息保护团队和个人信息保护负责人, 如果您和/或终端用户对本规则或个人信息保护相关事宜有任何疑问或投诉、建议时, 可以通过以下方式与我们联系:
    +(i)通过 腾讯客服(https://kf.qq.com/) 与我们联系;
    +(ii)将问题发送至Dataprivacy@tencent.com;
    +(iii)邮寄信件至: 中国广东省深圳市南山区海天二路33号腾讯滨海大厦 数据隐私保护部(收)邮编: 518054。
    +我们将尽快审核所涉问题, 并在15个工作日或法律法规规定的期限内予以反馈。 + +## 八、注意事项 + +### 1、您接入Hippy SDK前的合规自查 + +为确保您就本SDK的使用获得终端用户的授权,且遵守个人信息保护要求和合规流程,我们建议您在接入Hippy SDK前进行合规自查。
    +1)请仔细阅读并按本说明文档提示对您APP的《隐私政策》进行合规自查。
    +2)请务必做延迟初始化配置,确保获得用户同意后再初始化SDK。
    +3)当Hippy SDK基于最新的法律法规或监管要求进行更新后,请您在收到版本更新通知时及时将您APP集成的Hippy SDK升级到最新版本。
    +4)其他国家相关法律法规、监管政策及标准的要求。 + +### 2、Hippy SDK对您的合规审查 + +您应遵守个人信息保护相关的法律法规、监管政策及标准,并确保合规使用Hippy SDK服务。请您知悉,为确保您切实获得终端用户的授权,且您已满足个人信息保护相关合规要求,Hippy SDK可能视具体情况,在双方订立协议、开展合作前或合作过程中,对您进行必要的个人信息保护合规审查。在该等合规审查过程中,您应当提供必要的配合,包括但不限于:
    +1)要求您提供所共享的个人信息的合法来源证明及相关文件;
    +2)查阅您官网及其他公开渠道可获取的隐私政策文本;
    +3)试用您的 APP 以审查同意授权告知机制及其他合规机制。
    +如Hippy SDK发现存在不合规情形,您可能会被要求增加或补充相关合规措施,如您未按时增加或补充,Hippy SDK有权拒绝您使用服务。请您知悉,该等合规审查仅属于我们内部必要的合规程序,不构成任何形式的承诺与保证,不具有法律效力。 + +### 3、以下合规文件供开发者参考 + +(1)[《个人信息保护法》](http://www.npc.gov.cn/npc/c30834/202108/a8c4e3672c74491a80b53a172bb753fe.shtml)
    +(2)[《工业和信息化部关于进一步提升移动互联网应用服务能力的通知》](https://www.gov.cn/zhengce/zhengceku/2023-03/02/content_5744106.htm)
    +(3)[《工业和信息化部关于开展信息通信服务感知提升行动的通知》](http://www.gov.cn/zhengce/zhengceku/2021-11/06/content_5649420.htm)
    +(4)[《工业和信息化部关于开展纵深推进APP侵害用户权益专项整治行动的通知》](http://www.gov.cn/zhengce/zhengceku/2020-08/02/content_5531975.htm)
    +(5)[《工业和信息化部关于开展APP侵害用户权益专项整治工作的通知》](http://www.gov.cn/xinwen/2019-11/07/content_5449660.htm)
    +(6)[《App违法违规收集使用个人信息行为认定方法》](http://www.cac.gov.cn/2019-12/27/c_1578986455686625.htm)
    +(7)[《网络安全标准实践指南—移动互联网应用程序(App)收集使用个人信息自评估指南》](https://www.tc260.org.cn/upload/2020-07-22/1595396892533085831.pdf)
    +(8)[《常见类型移动互联网应用程序必要个人信息范围规定》](http://www.gov.cn/zhengce/zhengceku/2021-03/23/content_5595088.htm)
    +(9)[《GB/T 35273-2020信息安全技术 个人信息安全规范》](http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=4568F276E0F8346EB0FBA097AA0CE05E)
    +(10)[《网络安全标准实践指南—移动互联网应用程序(App)使用软件开发工具包(SDK)安全指引》](https://www.tc260.org.cn/front/postDetail.html?id=20201126161240)
    +(11)[《网络安全标准实践指南—移动互联网应用程序(App)系统权限申请使用指南》](https://www.tc260.org.cn/front/postDetail.html?id=20200918163359) diff --git a/docs/development/privacy.md b/docs/development/privacy.md new file mode 100644 index 00000000000..ec25a41959b --- /dev/null +++ b/docs/development/privacy.md @@ -0,0 +1,166 @@ +# Hippy SDK个人信息保护规则 + +*更新日期:25-09-03* +*生效日期:25-09-03* + +## 更新说明 + +我们对《Hippy SDK隐私保护指引》进行了更新,更新内容主要为: + +*25-09-03 更新内容:* + +完善 Harmony 隐私政策内容。 + +*24-04-10 更新内容:* + +尊敬的开发者:您好,为了优化Hippy SDK 功能体验,提升Hippy SDK安全防护能力,落实监管最新要求,我们移除了剪切板module及相关功能访问接口,升级后的Hippy SDK 版本为 Android v3.2.0,iOS v3.2.0,该版本已于2024年4月10日发布。 + +## 引言 + +Hippy SDK(以下简称“SDK产品”)由深圳市腾讯计算机系统有限公司(以下简称“我们”)开发, 公司注册地为深圳市南山区粤海街道麻岭社区科技中一路腾讯大厦35层。 + +《Hippy SDK个人信息保护规则》(以下简称“本规则”)主要向开发者及其终端用户(“终端用户”)告知,为了实现SDK产品的相关功能,SDK产品需收集、使用和处理终端用户个人信息的情况。 + +请开发者及终端用户认真阅读本规则。如您是开发者,请您确认充分了解并同意本规则后再集成SDK产品,如果您不同意本规则及按照本规则履行对应的用户个人信息保护义务,应立即停止接入及使用SDK产品。 + +特别说明: +如您是开发者,您应当: + +1. 遵守法律、法规收集、使用和处理终端用户的个人信息, 包括但不限于制定和公布有关个人信息保护的隐私政策等; + +2. 告知终端用户SDK产品收集、使用和处理终端用户个人信息的情况,并依法征得终端用户同意,在征得终端用户同意后初始化SDK产品; + +3. 在征得终端用户的同意前、以及在用户触发相应功能场景前,除非法律法规另有规定,不应收集任何终端用户的个人信息; + +4. 应按您的应用的具体功能场景,在用户触发具体功能场景时调用SDK的相应功能、调用相应权限或处理终端用户的个人信息,未到具体功能场景时不应调用相应的SDK功能、调用相应权限或处理终端用户的个人信息。 + +5. 向终端用户提供易于操作且满足法律法规要求的用户权利实现机制, 并告知终端用户如何查阅、复制、修改、删除个人信息, 撤回同意, 以及限制个人信息处理、转移个人信息、获取个人信息副本和注销账号; + +6. 遵守本规则的要求,并详细阅读《SDK接入使用文档》查看详细操作指引。 + +如开发者和终端用户对本规则内容有任何疑问或建议, 可随时通过本规则第八条提供的方式与我们联系。 + +## 一、我们收集的信息及我们如何使用信息 + +### (一) 为实现SDK产品功能所需收集的个人信息 + +为实现SDK产品的相应功能所必须,我们将向终端用户或开发者收集终端用户在使用与SDK产品相关的功能时产生的如下个人信息: + +#### 1. Hippy SDK iOS版 + +| 个人信息类型 | 使用目的及功能场景 | 处理方式 | +| --- | --- | --- | +|手机型号【必选】|提供调试服务时显示设备的基本信息,作为环境信息提供给开发框架的使用者|仅读取,不保存到本地,也不上传服务器| + +Hippy SDK iOS版当前不存在拓展功能,无可选个人信息。 + +#### 2. Hippy SDK Android版 + +Android版SDK不会为实现SDK产品功能而收集个人信息。 + +#### 3. Hippy SDK Harmony版 + +Harmony版SDK不会为实现SDK产品功能而收集个人信息。 + +### (二) 为实现SDK产品功能所需的权限 + +#### 1. Hippy SDK iOS版 + +SDK不会为实现SDK产品功能而申请敏感权限。 + +#### 2. Hippy SDK Android版 + +SDK不会为实现SDK产品功能而申请敏感权限。 + +#### 3. Hippy SDK Harmony版 + +| 权限名称 | 权限说明 | 权限使用目的 | +|------|----------|-------------------| +| ohos.permission.INTERNET | 连网权限 | 下载js和加载图片都需要连网 | +| ohos.permission.GET\_NETWORK\_INFO | 获取网络信息权限 | 判断网络类型是wifi或5g等需要 | + +### (三) 根据法律法规的规定,以下是征得用户同意的例外情形 + +1. 为订立、履行与终端用户的合同所必需; + +2. 为履行我们的法定义务所必需; + +3. 为应对突发公共卫生事件, 或者紧急情况下为保护终端用户的生命健康和财产安全所必需; + +4. 为公共利益实施新闻报道、舆论监督等行为, 在合理的范围内处理终端用户的个人信息; + +5. 依照本法规定在合理的范围内处理终端用户自行公开或者其他已经合法公开的个人信息; + +6. 法律行政法规规定的其他情形。 + +特别提示: 如我们收集的信息无法单独或结合其他信息识别到终端用户的个人身份, 其不属于法律意义上的个人信息。 + +## 二、第三方数据处理及信息的公开披露 + +我们不会与我们的关联公司、合作伙伴及第三方共享(“接收方”)终端用户的个人信息。 + +我们不会将终端用户的个人信息转移给任何公司、组织和个人, 但以下情况除外: + +1. 事先告知终端用户转移个人信息的种类、目的、方式和范围,并征得终端用户的单独同意; + +2. 如涉及合并、分立、解散、被宣告破产等原因需要转移个人信息的, 我们会向终端用户告知接收方的名称或者姓名和联系方式, 并要求接收方继续履行个人信息处理者的义务。接收方变更原先的处理目的、处理方式的, 我们会要求接收方重新取得终端用户的同意。 + +我们不会公开披露终端用户的个人信息, 但以下情况除外: + +1. 告知终端用户公开披露的个人信息的种类、目的、方式和范围并征得终端用户的单独同意后; + +2. 在法律法规、法律程序、诉讼或政府主管部门强制要求的情况下。 + +## 三、终端用户如何管理自己的信息 + +我们非常重视终端用户对其个人信息管理的权利, 并竭力帮助终端用户管理个人信息,包括个人信息查阅、复制、删除、注销账号以及设置隐私功能等, 以保障终端用户的权利。 + +如您是开发者,您应当为终端用户提供实现查阅、复制、修改、删除个人信息、撤回同意和注销账号的方式。 + +开发者可以通过本规则第八条提供的方式联系我们,以便开发者帮助终端用户管理自己的信息。 + +如您是终端用户,由于我们与您无直接的交互对话界面, 您可以直接联系开发者管理您的个人信息,也可通过本规则第八条提供的方式与我们联系。请您理解,特定的业务功能或服务需要您提供服务所需的信息才能得以完成,当您撤回同意后,我们无法继续为您提供对应的功能或服务,也不再处理您相应的个人信息。您撤回同意的决定,不会影响我们此前基于您的授权而开展的个人信息处理。 + +## 四、信息的存储 + +(一) 存储信息的地点 + +我们遵守法律法规的规定,将在中华人民共和国境内收集和产生的个人信息存储在境内。 + +(二) 存储信息的期限 + +一般而言,我们仅在为实现目的所必需的最短时间内保留终端用户的个人信息,但下列情况除外: + +* 为遵守适用的法律法规等有关规定; +* 为遵守法院判决、裁定或其他法律程序的规定; +* 为遵守相关政府机关执法的要求。 + +## 五、信息安全 + +我们为终端用户的个人信息提供相应的安全保障,以防止信息的丢失、不当使用、未经授权访问或披露。 + +我们严格遵守法律法规保护终端用户的个人信息。 + +我们将在合理的安全水平内使用各种安全保护措施以保障信息的安全。例如,我们使用加密技术、匿名化处理等手段来保护终端用户的个人信息。 + +我们建立严谨的管理制度、流程和组织确保信息安全。例如,我们严格限制访问信息的人员范围,要求他们遵守保密义务,并进行审查。 + +若发生个人信息泄露等安全事件,我们会启动应急预案,阻止安全事件扩大,并以推送通知、公告等形式告知开发者。 + +## 六、未成年人保护 + +本SDK产品主要面向成年人。 + +若您是开发者,如果终端用户是未满14周岁的未成年人(“儿童”),您应当向儿童的父母或其他监护人告知本规则,并在征得儿童的父母或其他监护人同意的前提下处理儿童个人信息。如果我们发现开发者未征得儿童监护人同意向我们提供儿童个人信息的,我们将会采取措施尽快删除。 + +若您是儿童监护人,当您对您所监护儿童个人信息保护有相关疑问或权利请求时,您可以联系开发者, 或通过本规则第八条提供的方式与我们联系。 + +## 七、变更 + +我们会适时修订本规则的内容。 + +如本规则的修订会导致终端用户在本规则项下权利的实质减损,我们将在变更生效前,通过网站公告等方式进行告知。如您是开发者,当更新后的本规则对处理终端用户的个人信息情况有变动的,您应当适时更新隐私政策,并以弹框形式通知终端用户并且征得其同意,如果终端用户不同意接受本规则, 请停止集成SDK产品。 + +## 八、联系我们 + +我们设立了专门的个人信息保护团队和个人信息保护负责人, 如果开发者和/或终端用户对本规则或个人信息保护相关事宜有任何疑问或投诉、建议时, 可以通过以下方式与我们联系: (i)通过 https://kf.qq.com/ 与我们联系;(ii)将问题发送至 Dataprivacy@tencent.com;(iii)邮寄信件至: 中国广东省深圳市南山区海天二路33号腾讯滨海大厦 数据隐私保护部(收) 邮编: 518054。我们将尽快审核所涉问题, 并在15个工作日或法律法规规定的期限内予以反馈。 diff --git a/docs/development/react-vue-3.0-integration-guidelines.md b/docs/development/react-vue-3.0-integration-guidelines.md new file mode 100644 index 00000000000..5ad00db5761 --- /dev/null +++ b/docs/development/react-vue-3.0-integration-guidelines.md @@ -0,0 +1,479 @@ + +# Hippy React&Vue SDK接入指引 + +Hippy 同时支持 React 和 Vue 两种 UI 框架,通过 [@hippy/react](//www.npmjs.com/package/@hippy/react) 和 [@hippy/vue](//www.npmjs.com/package/@hippy/vue) 及 [@hippy/vue-next](//www.npmjs.com/package/@hippy/vue-next) 三个包提供实现。 + +# hippy-react + +[[hippy-react 介绍]](api/hippy-react/introduction.md) [[范例工程]](https://github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) + +hippy-react 工程暂时只能通过手工配置初始化,建议直接 clone 范例工程并基于它进行修改。 + +当然,也可以从头开始进行配置。 + +## 准备 hippy-react 运行时依赖 + +请使用 `npm i` 安装以下 npm 包。 + +| 包名 | 说明 | +| ------------------- | -------------------------- | +| @hippy/react | hippy-react 运行时和渲染层 | +| react | react 本体 | +| regenerator-runtime | async/await 转换运行时 | + +## 准备 hippy-react 编译时依赖 + +以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: + +必须的: + +| 包名 | 说明 | +| --------------------------------------- | ---------------------------------------------- | +| @babel/plugin-proposal-class-properties | Babel 插件 - 支持仍在草案的 Class Properties | +| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | +| @babel/preset-react | Babel 插件 - 转译 JSX 到 JS | +| @hippy/debug-server | Hippy 前终端调试服务 | +| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | +| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | +| webpack | Webpack 打包程序 | +| webpack-cli | Webpack 命令行 | + +可选的: + +| 包名 | 说明 | +| ----------------------------------- | ------------------------------------------ | +| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | +| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 +| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | +| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | +| file-loader | 静态文件加载 | +| url-loader | 静态文件以 Base64 形式加载 | + +## hippy-react 编译配置 + +当前 hippy-react 采用 `Webpack 4`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 + +### hippy-react 开发调试编译配置 + +该配置展示了将 Hippy 运行于终端的最小化配置。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ---------- | +| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | + +### hippy-react 生产环境编译配置 + +生产环境和开发调试的包主要有两个区别: + +1. 生产环境开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 +2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减小业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ----------------------------- | +| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | +| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | +| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | +| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | +| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | + +如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 + +!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本。 + +## hippy-react 入口文件 + +入口文件非常简单,只是从 hippy-react 里初始化一个 Hippy 实例。注意,入口文件组件需要通过单节点包裹,如下: + +```js +import { Hippy } from '@hippy/react'; +import App from './app'; + +new Hippy({ + appName: 'Demo', // 终端分配的业务名称 + entryPage: App, // 对应业务启动时的组件 + silent: false, // 设置为 true 可以关闭框架日志输出 +}).start(); + +// P.S. entryPage需要通过单节点包裹,不能用数组的形式,例如 +import React from 'react'; +import { + View, + Text, +} from '@hippy/react'; +export default function app() { + // 入口文件不要使用这种形式,非入口文件可以使用 + return [ + , + test test + ]; + // 修改成通过单节点包裹 + return ( + , + test test + ); +} + +``` + +## hippy-react npm 脚本 + +在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。 + +```json + "scripts": { +"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js", +"hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", +"hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" +} +``` + +## hippy-react 转 Web + +请参考专门的 [hippy-react 转 Web 章节](api/hippy-react/web.md)。 + +# hippy-vue + +>注意:因vue2.x版本将停止更新,建议用户升级至使用vue3.x版本的@hippy/vue-next + +[[hippy-vue 介绍]](api/hippy-vue/introduction.md) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo) + +hippy-vue 相对简单很多,hippy-vue 只是 [Vue](//vuejs.org) 在终端上的渲染层,组件也基本和浏览器保持一致。可以通过 [vue-cli](//cli.vuejs.org/) 先[创建一个 Web 项目](//cli.vuejs.org/zh/guide/creating-a-project.html),然后加上一些 hippy-vue 的内容就可以直接将网页渲染到终端了。 + +## 准备 hippy-vue 运行时依赖 + +请使用 `npm i` 安装以下 npm 包,保证运行时正常。 + +| 包名 | 说明 | +| --------------------------- | -------------------------------- | +| @hippy/vue | hippy-vue 运行时核心 | +| @hippy/vue-native-components | hippy-vue 的扩展终端组件 | +| @hippy/vue-router | vue-router 在 hippy-vue 上的移植 | + +## hippy-vue 编译时依赖 + +以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: + +必须的: + +| 包名 | 说明 | +| -------------------- | ------------------------------------------ | +| @hippy/debug-server | Hippy 前终端调试服务 | +| @hippy/vue-css-loader | hippy-vue 的 CSS 文本到 JS 语法树转换 | +| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | +| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | +| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | +| webpack | Webpack 打包程序 | +| webpack-cli | Webpack 命令行 | + +可选的: + +| 包名 | 说明 | +| ----------------------------------- | ------------------------------------------ | +| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | +| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | +| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 +| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | +| file-loader | 静态文件加载 | +| url-loader | 静态文件以 Base64 形式加载 | + +## hippy-vue 编译配置 + +当前 hippy-vue 采用 `Webpack 4`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 + +### hippy-vue 开发调试编译配置 + +该配置展示了将 Hippy 运行于终端的最小化配置。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ---------- | +| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | + +### hippy-vue 生产环境编译配置 + +线上包和开发调试用包主要有两个区别: + +1. 开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 +2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减小业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ----------------------------- | +| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | +| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | +| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | +| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | +| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | + +如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 + +!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本。 + +## hippy-vue 入口文件 + +hippy-cli 初始化的项目自带了一个 [Web 端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/main.js),可以保留着用来启动 Web 端网页,但是因为 hippy-vue 的启动参数不一样,需要专门的 [终端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/main-native.js)来加载一些终端上用到的模块。 + +```js +import Vue from 'vue'; +import VueRouter from 'vue-router'; +import HippyVueNativeComponents from '@hippy/vue-native-components'; +import App from './app.vue'; +import routes from './routes'; +import { setApp } from './util'; + +// 禁止框架调试信息输出,取消注释即可使用。 +// Vue.config.silent = true; + +Vue.config.productionTip = false; + +// Hippy 终端组件扩展中间件,可以使用 modal、view-pager、tab-host、ul-refresh 等终端扩展组件了。 +Vue.use(HippyVueNativeComponents); +Vue.use(VueRouter); + +const router = new VueRouter(routes); + +/** + * 声明一个 app,这是同步生成的 + */ +const app = new Vue({ + // 终端指定的 App 名称 + appName: 'Demo', + // 根节点,必须是 Id,当根节点挂载时才会触发上屏 + rootView: '#root', + // 渲染自己 + render: h => h(App), + // iPhone 下的状态栏配置 + iPhone: { + // 状态栏配置 + statusBar: { + // 禁用状态栏自动填充 + // disabled: true, + + // 状态栏背景色,如果不配的话,会用 4282431619,也就是 #40b883 - Vue 的绿色 + // 因为运行时只支持样式和属性的实际转换,所以需要用下面的转换器将颜色值提前转换,可以在 Node 中直接运行。 + // hippy-vue-css-loader/src/compiler/style/color-parser.js + backgroundColor: 4283416717, + + // 状态栏背景图,要注意这个会根据容器尺寸拉伸。 + // backgroundImage: '//mat1.gtimg.com/www/qq2018/imgs/qq_logo_2018x2.png', + }, + }, + // 路由 + router, +}); + +/** + * $start 是 Hippy 启动完以后触发的回调 + * Vue 会在 Hippy 启动之前完成首屏 VDOM 的渲染,所以首屏性能非常高 + * 在 $start 里可以通知终端说已经启动完成,可以开始给前端发消息了。 + */ +app.$start((/* app */) => { + // 这里干一点 Hippy 启动后的需要干的事情,比如通知终端前端已经准备完毕,可以开始发消息了。 + // setApp(app); +}); + +/** + * 保存 app 供后面通过 app 接受来自终端的事件。 + * + * 之前是放到 $start 里的,但是有个问题时因为 $start 执行太慢,如果首页就 getApp() 的话可能会 + * 导致获得了 undefined,然后监听失败。所以挪出来了。 + * + * 但是终端事件依然要等到 $start 也就是 Hippy 启动之后再发,因为之前桥尚未建立,终端发消息前端也 + * 接受不到。 + */ +setApp(app); +``` + +## hippy-vue npm 脚本 + +在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。 + +```json + "scripts": { +"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js", +"hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", +"hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" +}, +``` + +## hippy-vue 路由 + +`@hippy/vue-router` 完整支持 vue-router 中的跳转功能,具体请参考 [hippy-vue-router](api/hippy-vue/router.md) 文档。 + +# hippy-vue-next + +[[hippy-vue-next 介绍]](api/hippy-vue/vue3) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo) + +hippy-vue-next 是 [Vue](//cn.vuejs.org) 在终端上的渲染层,组件也基本和浏览器保持一致。可以通过脚手架 [vue-cli](//github.com/vuejs/vue-cli) 先[创建一个 Web 项目](//cli.vuejs.org/zh/guide/creating-a-project.html#vue-create),然后加上一些 hippy-vue-next 的内容就可以直接将网页渲染到终端了。也可以参考我们的范例项目来初始化你的项目。 +>注意这里使用vue-cli创建项目时构建工具要选择webpack,并且Router和Typescript需要勾选,我们的hippy-vue-next默认都是基于Typescript开发的 + +## 准备 hippy-vue-next 运行时依赖 + +请使用 `npm i` 安装以下 npm 包,保证运行时正常。 + +| 包名 | 说明 | +|---------------|-------------------------------------| +| @hippy/vue-next | hippy-vue-next 运行时核心 | + +## hippy-vue-next 编译时依赖 + +以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: + +必须的: + +| 包名 | 说明 | +|------------------------------|------------------------------------| +| @hippy/debug-server-next | Hippy 前终端调试服务 | +| @hippy/vue-css-loader | hippy-vue-next 的 CSS 文本到 JS 语法树转换 | +| @hippy/vue-next-style-parser | hippy-vue-next 的样式 parser | +| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | +| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | +| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | +| webpack | Webpack 打包程序 | +| webpack-cli | Webpack 命令行 | + +可选的: + +| 包名 | 说明 | +|-------------------------------------|-----------------------------------------------------------------------| +| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | +| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | +| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 | +| @hippy/vue-router-next-history | 支持按安卓物理返回键回退路由 | +| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | +| file-loader | 静态文件加载 | +| url-loader | 静态文件以 Base64 形式加载 | +| esbuild & esbuild-loader | 开发环境webpack支持使用esbuild构建,性能比babel更好 | + +## hippy-vue-next 编译配置 + +当前 hippy-vue-next 支持 `Webpack 4 或 Webpack 5`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 + +### hippy-vue-next 开发调试编译配置 + +该配置展示了将 Hippy 运行于终端的最小化配置。 + +| 配置文件 | 说明 | +|--------------------------------------------------------------------------------------------------------------------------| ---------- | +| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | + +### hippy-vue-next 生产环境编译配置 + +线上包和开发调试用包主要有两个区别: + +1. 开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 +2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减小业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。 + +| 配置文件 | 说明 | +|-------------------------------------------------------------------------------------------------------------------------------------------| ----------------------------- | +| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | +| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | +| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | +| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | +| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | + +如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 + +!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本,而hippy-vue-next是基于vue-next的,因此使用hippy-vue-next iOS版本必须要10及以上。 + +## hippy-vue-next 入口文件 + +因为 hippy-vue-next 的启动参数与 web 页面不一样,所以我们需要专门的 [终端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/src/main-native.ts)来加载一些终端上用到的模块,并作为项目的入口文件 + +```ts +// 首先导入所需模块 +import { + createApp, + type HippyApp, + EventBus, + setScreenSize, + BackAndroid, +} from '@hippy/vue-next'; + +import App from './app.vue'; +import { createRouter } from './routes'; +import { setGlobalInitProps } from './util'; + +// 创建 hippy app 实例 +const app: HippyApp = createApp(App, { + // hippy native module name + appName: 'Demo', + iPhone: { + // config of statusBar + statusBar: { + // disable status bar autofill + // disabled: true, + + // Status bar background color, if not set, it will use 4282431619, as #40b883, Vue default green + // hippy-vue-css-loader/src/compiler/style/color-parser.js + backgroundColor: 4283416717, + + // 状态栏背景图,要注意这个会根据容器尺寸拉伸。 + // backgroundImage: 'https://user-images.githubusercontent.com/12878546/148737148-d0b227cb-69c8-4b21-bf92-739fb0c3f3aa.png', + }, + }, + // do not print trace info when set to true + // silent: true, + /** + * whether to trim whitespace on text element, + * default is true, if set false, it will follow vue-loader compilerOptions whitespace setting + */ + trimWhitespace: true, +}); +// create router +const router = createRouter(); +app.use(router); + +// init callback +const initCallback = ({ superProps, rootViewId }) => { + setGlobalInitProps({ + superProps, + rootViewId, + }); + /** + * Because the memory history of vue-router is now used, + * the initial position needs to be pushed manually, otherwise the router will not be ready. + * On the browser, it is matched by vue-router according to location.href, and the default push root path '/' + */ + router.push('/'); + + // listen android native back press, must before router back press inject + BackAndroid.addListener(() => { + console.log('backAndroid'); + // set true interrupts native back + return true; + }); + + // mount first, you can do something before mount + app.mount('#root'); + + /** + * You can also mount the app after the route is ready, However, + * it is recommended to mount first, because it can render content on the screen as soon as possible + */ + // router.isReady().then(() => { + // // mount app + // app.mount('#root'); + // }); +}; + +// start hippy app +app.$start().then(initCallback); + +// you can also use callback to start app like @hippy/vue before +// app.$start(initCallback); +``` + +## hippy-vue-next npm 脚本 + +在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。 + +```json + "scripts": { + "hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js", + "hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", + "hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" + }, +``` + +## hippy-vue-next 路由 + +`@hippy/vue-next` 无需侵入式修改vue-router,直接使用官方 vue-router 即可,如果需要支持安卓物理健回退时路由历史回退,则可以安装@hippy/vue-router-next-history模块。 diff --git a/docs/development/react-vue-3.0-upgrade-guidelines.md b/docs/development/react-vue-3.0-upgrade-guidelines.md new file mode 100644 index 00000000000..7e5c7b1d447 --- /dev/null +++ b/docs/development/react-vue-3.0-upgrade-guidelines.md @@ -0,0 +1,164 @@ +# Hippy React&Vue 3.x SDK升级指引 + +> 这篇教程,主要介绍 Hippy React&Vue&Vue-next 如何升级3.0版本以及升级后的相关验证关注点。 + +--- + +# 升级依赖项变更 + +## hippy-react + +>如果业务目前使用 React 来开发 Hippy,可以参考当前章节升级指引。 +
    + +如果当前 @hippy/react 版本小于 2.12.0, 且 React 使用的 16 的版本,则需要升级如下版本: + +``` javascript +(1)删除 react-reconciler 依赖 +(2)@hippy/react 升级到 3.3.0 及以上 +(3)新增 @hippy/react-reconciler 依赖,使用react17的tag,即 @hippy/react-reconciler: "react17" +(4)React 版本升级到 17,即 react: "^17.0.2" +(5)如果使用了 @hippy/react-web 包做h5同构,则需要升级 @hippy/react-web 到 3.3.0 及以上 +``` + +如果当前 @hippy/react 版本大于 2.12.0, 且 React 使用的 17 的版本,则需要升级如下版本: + +``` javascript +(1)@hippy/react 升级到 3.3.0 及以上 +(2)升级 @hippy/react-reconciler 依赖,使用react17的tag,即 @hippy/react-reconciler: "react17" +(3)如果使用了 @hippy/react-web 包做h5同构,则需要升级 @hippy/react-web 到 3.3.0 及以上 +``` + +需要业务使用新的 hippy-react 重编 js common包 + +## hippy-vue + +>如果业务目前使用 Vue 2.x 来开发 Hippy,可以参考当前章节升级指引。 +
    + +需要升级如下版本依赖: + +``` javascript +(1)@hippy/vue 升级到 3.3.1-rc.1 及以上 +(2)@hippy/vue-native-components 升级到 3.3.0 及以上 +(3)@hippy/vue-router 升级到 3.3.0 及以上 +(4)@hippy/vue-css-loader 升级到 3.3.0 及以上 +(5)@hippy/vue-loader 升级到 3.3.0 及以上 +(6)vue 和 vue-router 等vue相关依赖无需升级 +``` + +需要业务使用新的 hippy-vue 重编 js common包 + +## hippy-vue-next + +>如果业务目前使用 Vue 3.x 来开发 Hippy,可以参考当前章节升级指引。 +
    + +需要升级如下版本依赖: + +``` javascript +(1)@hippy/vue-next 升级到 3.3.0 及以上 +(2)@hippy/vue-css-loader 升级到 3.3.0 及以上 +(3)@hippy/vue-router-next-history 升级到 0.0.1 +(4)vue 和 vue-router 等vue相关依赖无需升级 +``` + +需要业务使用新的 hippy-vue-next 重编 js common包 + +
    +
    + +# 接入与使用方式变更 + +接入 Hippy-React、Hippy-Vue、Hippy-Vue-Next SDK 代码无变化,可参考 [前端集成指引](development/react-vue-3.0-integration-guidelines.md) + +具体变化点如下: + +1. iOS 新增节点层级优化算法,Android 优化了现有的层级优化算法: +该算法会将仅参与布局的View节点优化去除,从而提升渲染效率。请注意 !!!由于该算法的存在,可能导致依赖特定UI层级结构的native组件发生找不到特定View的异常。 +此时,可以通过前端代码中给特定 View 增加 collapsable: 'false' 属性来禁止该节点被优化算法去除。 + + +# 组件变更 + +1. dialog 组件的第一个子元素不能设置 { position: absolute } 样式,如果想将 dialog 内容铺满全屏,可以给第一个子元素设置 { flex: 1 } 样式或者显式设置 width 和 height 数值 + +2. Image 组件废弃了 source、 sources、srcs 字段,建议使用 src 字段代表图片 url + +3. iOS Image 组件默认没有实现图片缓存 (由于实现机制的变化),需要业务 iOS端自行实现缓存管理,详细可参考 [iOS 升级指引](development/ios-3.0-upgrade-guidelines.md) + +4. hippy-vue 2.15以前的版本不支持 scoped 样式隔离,2.15-2.17的版本,如果没有开启 Vue.config.scoped = true; 也不支持 scoped 样式隔离。 +Vue3.0 默认开启 scoped 无需设置开关 + +5. hippy-vue 布局属性如 height、width 在 3.0 的版本将不支持放在自定义属性里,如: + +``` javascript +
    +``` + +需要放在style属性中,如: + +``` javascript +
    +``` + +# 接口定义变更 + +1. hippy-react 不再导出RNfqb、RNfqbRegister、RNfqbEventEmitter、RNfqbEventListener 方法 + +2. hippy-react animation 模块不再有 destory() 方法的错误写法兼容,统一用 destroy() + +3. hippy-react animation 事件监听不再支持 onRNfqbAnimationXX 兼容写法,统一用 onHippyAnimationXX 或者 onAnimationXX + +4. hippy-react 初始化动画对象(new Animation),需要在根节点渲染之后,否则会因为 Dom Manager未创建提示报错 + hippy-vue/hippy-vue-next 初始化动画对象(new Animation),需要在 Vue.start 回调之后,否则会因为 Dom Manager未创建提示报错 + +5. hippy-react/hippy-vue/hippy-vue-next 如果使用了颜色属性的渐变动画,需要显示指定 color 单位,添加 valueType:'color' 字段,例如: + +``` javascript + animation: new Animation({ + startValue: 'red', + toValue: 'yellow', + valueType: 'color', // 颜色动画需显式指定color单位 + duration: 1000, + delay: 0, + mode: 'timing', + timingFunction: 'linear', + }), +``` + + +# 验证关注点 + +一、Hippy 3.0 前端架构升级主要有如下改动点: +
    + +1. JS 驱动上屏的方式由 UIManagerModule 变为了 SceneBuilder。 +2. Node API 重新实现了 Move 计算逻辑。 +3. Event 由前端分发变为 DOM 分发。 +4. 动画由 bridge 模块变为 C++ DOM 模块实现。 + +二、需要验证关注点: +
    + +1. 界面的UI视图渲染正常 (UI结构、样式属性等),特别关注 Hippy-React/Vue 中因为条件渲染语句,产生的节点`Move`操作,表现是否正常。 +2. UI事件(点击、滑动)等表现正常,特别关注事件`冒泡`、`捕获`等表现是否正常。 +3. 关注`动画`表现是否正常。 + +
    +
    + +# 新特性 + +## Performance API + +Hippy 3.0 我们实现了基于前端规范设计的性能 API,接入方式可参考 [Performance](feature/feature3.0/performance.md)。 + +## Layout 引擎支持切换 + +Hippy 3.0 我们支持了 Layout 引擎的无缝切换,项目可保持`Yoga`引擎,也可以选择Hippy自研的`Taitank`引擎。详情可参考 [Layout](feature/feature3.0/layout.md) diff --git a/docs/development/report.md b/docs/development/report.md new file mode 100644 index 00000000000..cb3dbc81ebf --- /dev/null +++ b/docs/development/report.md @@ -0,0 +1,21 @@ +# 曝光上报 + +--- + +# 大同 + +目前 Hippy 还没有对外的曝光上报方案,腾讯内部的业务,可以使用大同来做曝光上报 + +## 方案 + +hippy本质上使用的还是客户端原生组件 以及一部分自绘组件。客户端已集成的的大同sdk能够对原生组件、Activity等做检测上报,自然也可以对hippy的组件做检测上报。重点处理上报id绑定到组件的逻辑就可以。 + +## 接入指引 + +[Hippy Android 曝光上报指引](https://iwiki.woa.com/p/956352478) + +[Hippy iOS 曝光上报指引](https://iwiki.woa.com/p/589637144) + +腾讯内部有疑问可以咨询企业微信 小助手 + + diff --git a/docs/development/support.md b/docs/development/support.md new file mode 100644 index 00000000000..5aa3bca6cc6 --- /dev/null +++ b/docs/development/support.md @@ -0,0 +1,14 @@ +# 技术支持 + +--- + +# Github + +我们鼓励在 [Issue](//github.com/Tencent/Hippy/issues) 里汇报使用问题。 +或者在提交 [Pull Request](//github.com/Tencent/Hippy/pulls),一起来建设Hippy。 + +# 企业微信群 + +使用微信或者企业微信扫描加入 + +![企业微信群二维码](../assets/img/wechat-group.jpeg) diff --git a/docs/development/type-mapping.md b/docs/development/type-mapping.md new file mode 100644 index 00000000000..e4418d59f86 --- /dev/null +++ b/docs/development/type-mapping.md @@ -0,0 +1,117 @@ +# ECMAScript 与 Java 类型映射 + +当通过 Bridge 进行调用时,Bridge 编解码器会自动将【源类型】转换成为【目标类型】供业务模块使用。 + +> 如 JS 调用 Java 时,会将传入的 ECMAScript 对象转换成为 Java 的对应类型,反之亦然。 + +Hippy 在 Java 中提供了两套类型系统: + +* Recommend Type System: 全新设计的类型系统,可以双向表达所有[HTML structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) 中支持的类型(推荐)。 +* Compatible Type System: 旧类型系统,结构简单但无法完整(双向)表达类型,仅存量代码使用(不推荐)。 + +--- + +# 类型映射关系 + +| ECMAScript Type Category | ECMAScript Type | Recommend(New) Type in Java | Compatible(Old) Type in Java | +|---------------------------|------------------------------|-----------------------------------|----------------------------------------| +| Primitives | true | true | true | +| | false | false | false | +| | null | (#1).JSOddball#Null | null | +| | undefined | (#1).JSOddball#Undefined | (#2).ConstantValue#Undefined | +| | number | int | int | +| | | double | double | +| | bigint | java.math.BigInteger | java.math.BigInteger | +| | string | java.lang.String | java.lang.String | +| Primitive wrapper objects | Boolean | (#1).objects.JSBooleanObject#True | true | +| | | (#1).objects.JSBooleanObject#False | false | +| | Number | (#1).objects.JSNumberObject | double | +| | BigInt | (#1).objects.JSBigintObject | java.math.BigInteger | +| | String | (#1).objects.JSStringObject | java.lang.String | +| Fundamental objects | Object | (#1).JSObject | (#2).HippyMap | +| Indexed collections | Array(dense) | (#1).JSDenseArray | (#2).HippyArray (Not fully supported) | +| | Array(sparse) | (#1).JSSparseArray | N/A | +| Keyed collections | Map | (#1).JSMap | (#2).HippyMap (Not fully supported) | +| | Set | (#1).JSSet | (#2).HippyArray (Not fully supported) | +| Structured data | ArrayBuffer | (#1).JSArrayBuffer | N/A | +| | SharedArrayBuffer | (#1).JSSharedArrayBuffer | N/A | +| | ArrayBufferView | (#1).JSDataView | N/A | +| Dates | Date | java.util.Date | java.util.Date | +| Error objects | Error | (#1).JSError | N/A | +| | EvalError | | | +| | RangeError | | | +| | ReferenceError | | | +| | SyntaxError | | | +| | TypeError | | | +| | URIError | | | +| Text processing | RegExp | (#1).JSRegExp | N/A | +| Array Holes | undefined(hole) | (#1).JSOddball#Hole | (#2).ConstantValue#Hole | +| Host Object | Object(with internal fields) | java.lang.Object | N/A | +| WebAssembly | WebAssembly.Module | (#1).wasm.WasmModule | N/A | +| | WebAssembly.Memory | (#1).wasm.WasmMemory | N/A | + +1. com.tencent.mtt.hippy.runtime.builtins +2. com.tencent.mtt.hippy.common + +# 类型纠正 + +由于 ECMAScript 标准未定义 [number](https://262.ecma-international.org/#sec-ecmascript-language-types-number-type) 类型在 VM 内的存储(表达)方式,不同 VM 引擎实现对于相同值的存储实现有可能不同,从而引发类型偏差。 + +> 例如: +> 在 ECMAScript 的实现 v8 内,如整型值超过 Smi 可表达的最大大小,会使用 Heap Number 进行存储,导致其表达为 `double` 类型。 + +类型系统会自动完成类型纠正,还原用户原始类型。 + +> 例如: +> 当 `double` 类型可以表达为 `int` 类型时,系统会自动转换为 `int` 类型 + +# 新旧类型互转 + +新旧类型系统间的类型互转可通过调用下述方法实现: + +* Recommend(New) ---> Compatible(Old): `com.tencent.mtt.hippy.runtime.utils.ValueConverter#toHippyValue` +* Compatible(Old) ---> Recommend(New): `com.tencent.mtt.hippy.runtime.utils.ValueConverter#toJSValue` + +> 由于新类型系统所能表达的 ECMAScript 类型更加精细, +> 故从新类型系统(Recommend)转换到旧类型系统(Compatible)时,可能会造成类型丢失 + +一般情况下,用户无需进行新旧类型系统间的互转。模块在注册到 Bridge 时,可以指定所需使用的类型系统。 + +# Java 中的推荐类型 + +所有新类型系统中的类型,均定义在 `com.tencent.mtt.hippy.runtime.builtins` 这个包中。 + +## JSValue + +所有类型均派生于 `JSValue` 基类,主要提供了: + +* 对象实例类型判定:可调用 `is##Name()` 方法来确认实际类型。 +* 原始对象取值:可调用 `to##Name()` 方法得到 (wrapped)Primitives 的实际值。 + +## JSArray + +所有类型数组(包括密集 `JSDenseArray` 与稀疏 `JSSparseArray` 数组)均派生于 `JSAbstractArray`。 + +根据 ECMAScript 规范的定义,`JSAbstractArray` 重写了由父类 `JSObject` 继承的方法(包含:`entries()`、`keys()`、`values()`): + +1. 会优先枚举数组内值。 +2. 再枚举其属性值。 + +如您仅想遍历获取数组内的值,可调用 `items()` 方法。 + +## JSRegExp + +由于 `java.util.regex.Pattern` 与 ECMAScript `RegExp` 对象的差异,故不支持全局(`g`)标志位与粘性匹配(`y`)标志位,而 Unicode 字符(`u`)标志位则始终启用。 + +# 使用 Demo + +以传输给前端 `ArrayBuffer` 为例: + +```java + JSObject jsObject = new JSObject(); + JSArrayBuffer jsArrayBuffer = new JSArrayBuffer(ByteBuffer.wrap(data)); + jsObject.set("body", jsArrayBuffer); + Promise.resolve(jsObject); +``` + + diff --git a/docs/development/use-hermes-engine.md b/docs/development/use-hermes-engine.md new file mode 100644 index 00000000000..c488fe01ff6 --- /dev/null +++ b/docs/development/use-hermes-engine.md @@ -0,0 +1,278 @@ +# Hippy Hermes JS引擎切换指引(Beta) + +## 概述 + +[Hermes](https://github.com/facebook/hermes) 是 Meta 开发的 JavaScript 引擎,旨在提供更快的执行速度和更小的内存占用,它的主要特点是能够将 JavaScript 代码编译成字节码(Bytecode),从而提高运行时执行效率。在 Hippy 项目中,你可以选择使用 JSC/V8 或 Hermes 作为 JavaScript 引擎。 + +Hippy 从 `3.4.0` 版本开始支持 Hermes 引擎。本文档将指导你如何在开发过程中切换到 Hermes 引擎。 + +具体支持状态: + +- **iOS 平台**:支持 Hermes 引擎, 支持与 JSC 引擎并行使用。 +- **Android 平台**:支持 Hermes 引擎(Alpha版), 支持与 V8 引擎并行使用。 +- **鸿蒙平台**:暂不支持 Hermes 引擎。 + +切换过程概览: + +1. 终端升级 Hippy SDK 版本到 `3.4.0` 及以上版本,并确保正确集成和开启了Hermes 引擎。 +2. 前端项目配置或代码调整,确保前端产物与 Hermes 引擎兼容,并编译为 `HBC (Hermes Bytecode)` 文件。 +3. 调整资源下发与加载配置,确保终端能够正确加载和执行 `HBC` 文件。 +4. 测试验证,确保应用在不同平台和设备上都能正常运行,并且性能达到预期。 + +性能参考预期(仅iOS平台): + +- **启动时间**:首帧耗时(FP指标)减少约 50% ~ 60% +- **内存占用**:一般场景内存降低约 20% ~ 40% + +> 其他平台性能参考数据将在 Beta 版发布后提供。 + +## 终端切换步骤 + +### iOS 平台 + +1. **修改 `Podfile`**: + + 打开你的项目目录下的 `Podfile` 文件,添加环境变量以指定使用 Hermes 引擎: + + ```ruby + ENV['js_engine'] = 'hermes' # js engine configuration for hippy, options are: 'jsc'/'hermes'. + ``` + + 同时,在 `Podfile` 文件中添加 Hermes 依赖: + + ```ruby + # hippy_hermes_full 为带调试能力的 Hermes 库,Hippy 的 podspec 默认依赖该库。 + + # Tips 1:可替换为自行编译的 Hermes 库 + # Hippy 基于 Hermes 仓库下的 'facebook/rn/0.76-stable' 分支构建该库 + if ENV['js_engine'] == 'hermes' + pod 'hippy_hermes_full', :git => 'https://github.com/hippy-contrib/hippy-hermes-bin.git', :tag => '1.0.3' + end + + # Tips 2:如需进一步裁减App安装包,可在发布版本使用不带调试能力的 Hermes 库,替换如下: + # 需注意,使用不带调试能力的 Hermes 库时,Hippy SDK 不能集成 hippy/Devtools 模块。 + if ENV['js_engine'] == 'hermes' + pod 'hippy_hermes_full', :git => 'https://github.com/hippy-contrib/hippy-hermes-bin.git', :tag => '1.0.3', :configurations => ['Debug'] + pod 'hippy_hermes', :git => 'https://github.com/hippy-contrib/hippy-hermes-bin.git', :tag => '1.0.3', :configurations => ['Release'] + end + ``` + + 最终,修改后的Podfile如下所示: + + ```ruby + platform :ios, '12.0' + use_frameworks! + ENV['js_engine'] = 'hermes' # Hippy设置为使用 Hermes 引擎 + + target 'YourTargetName' do + pod 'Hippy', path: '../path/to/hippy' + + # Add hippy_hermes_full when using hermes engine + if ENV['js_engine'] == 'hermes' + pod 'hippy_hermes_full', :git => 'https://github.com/hippy-contrib/hippy-hermes-bin.git', :tag => '1.0.3' + end + end + ``` + +2. **安装依赖**: + + 在项目根目录下运行以下命令以安装所需的依赖: + + ```bash + pod install + ``` + +3. **在Hippy SDK初始化时配置启用Hermes引擎**: + + 调整Hippy SDK的初始化代码,确保在创建实例时启用Hermes引擎。例如,在Objective-C中: + + ```objectivec + @import hippy; + + @implementation MyHippyViewController + + // 省略一些其他代码... + + // 创建Hippy实例 + - (void)runHippyDemo { + // Necessary configuration: + NSString *moduleName = @"Demo"; + + // Set launch options for hippy bridge + HippyLaunchOptions *launchOptions = [HippyLaunchOptions new]; + launchOptions.debugMode = _debugMode; + launchOptions.useHermesEngine = _useHermesEngine; + + // Prepare initial properties for js side + NSDictionary *initialProperties = @{ @"isSimulator": @(TARGET_OS_SIMULATOR) }; + + // Initialize hippy bridge using the above options. + NSURL *vendorBundleURL = [self vendorBundleURL]; + NSURL *indexBundleURL = [self indexBundleURL]; + HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:vendorBundleURL + moduleProvider:nil + launchOptions:launchOptions + executorKey:moduleName]; + + // Create and configure the root view + HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:bridge + businessURL:indexBundleURL + moduleName:moduleName + initialProperties:initialProperties + delegate:self]; + + // 省略一些其他代码... + } + + @end + ``` + + 至此,你已在 iOS 平台上成功地将一个 Hippy 项目中的 JavaScript 运行环境从默认的 JSC 引擎切换至了 Hermes 引擎。此时你可以尝试编译运行项目,但可能会遇到一些兼容性报错提示,因为 Hermes 引擎与 JSC 引擎在某些方面存在差异。解决这些问题通常需要对JS代码进行适当的调整,我们将在后续章节中详细介绍如何解决这些问题。 + + > Tips 1: Hippy 在 iOS 平台支持 JSC 引擎与 Hermes 引擎并行使用,并且支持在运行时根据不同的条件选择使用哪个引擎,即`支持引擎热切换`。 + > + > Tips 2: `HippyLaunchOptions` 中 `useHermesEngine` 的默认值为 `NO`,因此如果需要启用 Hermes 引擎,则必须显式地将其设置为 `YES`,否则项目将继续使用 JSC 引擎。 + +### Android 平台 (Alpha版本) + +由于 Android 平台的 Hermes 引擎切换目前处于 Alpha 阶段,我们将在未来版本中提供详细指引,请关注后续更新。 + +## 前端切换步骤 + +前端切换到 Hermes 引擎要做的主要工作包括: + +1. 调整语法或项目打包配置,确保生成兼容 Hermes 的JS代码。 + + > Hermes 引擎的目标是支持 ECMAScript 2015 (ES6),但有一些例外(比如不支持 `with` 语句、不支持 Local mode `eval()` 函数等),因此有可能需要对现有代码进行调整以适应 Hermes 引擎的要求。 + > + > 更多语法说明请参考: [Hermes语法支持特性](https://github.com/facebook/hermes/blob/rn/0.76-stable/doc/Features.md) + + 推荐使用以下 Babel 预设和插件,以确保项目能够兼容 Hermes 引擎,以 Babel 为例:: + + ```js + module.exports = { + presets : [ + ['module:metro-react-native-babel-preset'], + ], + plugins : [ + ['@babel/plugin-proposal-class-properties'], + ], + }; + ``` + + > 具体需使用的插件和预设可能因项目而异,请根据实际情况进行调整,并做好相应的测试。 + + ⚠️ 特别注意,如果你使用的是 Hippy-Vue2 框架,由于 Hippy-Vue2 在处理组件模版时依赖 Hermes 不支持的 `with` 语法 ,因此必须调整你的组件源码,以确保在 Hermes 引擎中能够正常运行。举个例子,有如下 Vue2 定义的自定义组件: + + ```js + Vue.component('my-view', { + data: function () { + return { + count: 0 + } + }, + template: ' +
    +

    You clicked me {{ count }} times.

    +
    + ' + }) + ``` + + 上述 Vue2 代码需修改为使用 render 函数来代替 template: + + ```js + Vue.component('my-view', { + data: function () { + return { + count: 0 + } + }, + // 由于 Hermes 引擎不支持 template,因此需要使用 render 函数 + // render 函数接收一个 h 函数作为参数,用于创建虚拟 DOM 节点 + render(h) { + return h('div', [ + h('p', `You clicked me ${this.count} times.`) + ]) + } + }) + ``` + + > Tips:使用 Hippy-Vue3 或 Hippy-React 框架时无需进行上述修改。 + +2. 使用Hermes编译器,生成 Hermes 字节码(HBC)。 + + Hermes 编译器可以将 JavaScript 代码转换为 Hermes 字节码(HBC),以便在 Hermes 引擎中运行。可以通过命令行工具或集成到构建系统中来使用 Hermes 编译器。 + + Hippy提供了一个编译好的 Hermes compiler npm 包,可以方便地在项目中使用 Hermes 编译器(支持Linux、macOS 和 Windows 系统)。以下是使用步骤: + + - 安装 Hermes compiler npm 包: + + ```bash + npm install @hippy/hermesc --save-dev + ``` + + - 使用 Hermes compiler 编译 JavaScript 代码: + + ```javascript + // 1. 获取 Hermes compiler 路径 + const getHippyHermescPath = () => { + // 请确保在执行此代码之前,已经安装了 Hermes compiler,并且 hermesc 路径正确 + const hermesPath = path.resolve(__dirname, '../node_modules/@hippy/hermesc'); + console.log('hermes package path:', hermesPath); + let hermesc = `${hermesPath}/%OS%-bin/hermesc`; + switch (process.platform) { + case 'win32': + hermesc = hermesc.replace('%OS%', 'win64'); + break; + case 'darwin': + hermesc = hermesc.replace('%OS%', 'osx'); + break; + default: + hermesc.replace('%OS%', 'linux64'); + break; + } + console.log('hermesc path:', hermesc); + return hermesc; + }; + + // 2. 调用Hermes compiler生成HBC文件 + const { exec } = require('child_process'); + + const compileJSToHBC(inputJSPath, outputHBCPath) => { + let hermesc = getHippyHermescPath(); + exec(`${hermesc} -emit-binary -O -g0 -out ${outputHBCPath} ${inputJSPath}`, (error, stdout, stderr) => { + if (error) { + console.error(`执行出错: ${error.message}`); + return; + } + if (stderr) { + console.error(`错误输出: ${stderr}`); + return; + } + console.log(`成功生成 HBC 文件: ${stdout}`); + }); + }; + + // 调用示例: + compileJSToHBC('path/to/input.js', 'path/to/output.hbc'); + ``` + + > 如需在命令行使用自行编译的Hermes compiler,可以使用以下命令: + > + > ```bash + > hermesc -emit-binary -O -g0 -out output.hbc input.js + > # 更多参数请查阅 Hermes 官方文档 + > ``` + +3. 在应用中加载和运行 Hermes 字节码(HBC)。 + + 至此,你已经成功地将 JavaScript 代码编译为 Hermes 字节码,并在应用中加载和运行。 + +## 注意事项 + +- 确保您的项目中正确配置了 Hermes 引擎。 +- 根据需要调整编译选项以优化性能。 +- 在生产环境中使用时,确保对 Hermes 字节码进行充分的测试。 +- 查阅 Hermes 官方文档获取更多详细信息和最佳实践。 diff --git a/docs/development/v8-api.md b/docs/development/v8-api.md new file mode 100755 index 00000000000..838435fc8e1 --- /dev/null +++ b/docs/development/v8-api.md @@ -0,0 +1,128 @@ +# V8 相关初始化参数 + +在HippyEngine初始化的时候,EngineInitParams属性里有以下v8相关的属性参数。 + +## codeCacheTag + +code cache 是V8中的一个特性,简单说就是JavaScript代码在执行前,需要进行解析和编译,才能正确执行,解析编译过程是耗时的,V8 暴露了一个方法,可以将编译产物序列化存储下来,下次再执行相同一段代码时,就可以用之前缓存的内容,节省了解析编译的时间,codeCacheTag作为编译内容缓存的key,设置后便会开启v8 code cache能力,建议开发者对该初始化参数进行设置,可以有效降低非首次启动js bundle加载运行耗时。 + +## v8InitParams + +- initialHeapSize代表v8初始Heap size +- maximumHeapSize代表v8最大Heap size + +由于v8的内存是自己管理的,使用策略是尽可能使用更多的内存,只有在达到maximumHeapSize 80%左右的时候才会触发gc,未达到之前会一直增长,达到80%触发gc的同时会回调near_heap_limit_callback接口获取内存增量,这里内存增量通过sdk内部接口V8VMInitParam::HeapLimitSlowGrowthStrategy返回,默认内存增长策略是当前max值*2,如果前端申请大内存,扩容后还不满足内存分配就会产生OOM. + +在无限滚动列表场景,设置maximumHeapSize可以有效降低v8内存增加速率。 + +修改v8初始内存参数虽然能减少内存增量,但频繁的内存申请和gc,可能引入以下2个负面影响: + +- 首屏性能下降 +- OOM率升高 + +所以v8初始化内存参数的设置需要跟进具体的业务场景设置合适的值,并做完整的测试验证,如果不是内存占用有严格要的求场景不建议设置该初始化参数。 + +# V8 API + +获取 V8 JS 引擎对象,并操作相关方法。 + +--- + +## GetHeapStatistics + +获取 js 堆内存信息。 + +> 最低支持版本 `2.15.0` + +``` java +V8 v8 = mHippyEngine.getV8(); +if (v8 != null) { + boolean success = v8.getHeapStatistics(new Callback() { + @Override + public void callback(V8HeapStatistics param, Throwable e) { + if (param != null) { + // success + } else { + // error + } + } + }); + if (!success) { + // error + } +} +``` + +## GetHeapCodeStatistics + +获取js堆中代码及其元数据的统计信息。 +> 最低支持版本 `2.15.0` + +``` java +V8 v8 = mHippyEngine.getV8(); +if (v8 != null) { + boolean success = v8.getHeapCodeStatistics(new Callback() { + @Override + public void callback(V8HeapCodeStatistics param, Throwable e) { + if (param != null) { + // success + } else { + // error + } + } + }); + if (!success) { + // error + } +} +``` + +## GetHeapSpaceStatistics + +返回堆各个空间的统计信息。 +> 最低支持版本 `2.15.0` + +``` java +V8 v8 = mHippyEngine.getV8(); +if (v8 != null) { + boolean success = v8.getHeapSpaceStatistics(new Callback() { + @Override + public void callback(V8HeapSpaceStatistics param, Throwable e) { + if (param != null) { + // success + } else { + // error + } + } + }); + if (!success) { + // error + } +} +``` + +## WriteHeapSnapshot + +生成一个堆快照(可导入Chrome浏览器开发者工具分析)。 +> 最低支持版本 `2.15.0` + +``` java +V8 v8 = mHippyEngine.getV8(); +if (v8 != null) { + File hippyFile = FileUtils.getHippyFile(mHippyEngine.getEngineContext().getGlobalConfigs().getContext()); + String snapshotPath = hippyFile.getAbsolutePath() + File.separator + "snapshot" + File.separator + "1.heapsnapshot"; + boolean success = v8.writeHeapSnapshot(snapshotPath, new Callback() { + @Override + public void callback(Integer param, Throwable e) { + if (param == 0) { + // success + } else { + // error + } + } + }); + if (!success) { + // error + } +} +``` diff --git a/docs/development/voltron-flutter-integration-guidelines.md b/docs/development/voltron-flutter-integration-guidelines.md new file mode 100644 index 00000000000..c2b5b0ff5d8 --- /dev/null +++ b/docs/development/voltron-flutter-integration-guidelines.md @@ -0,0 +1,78 @@ +# Voltron Flutter 集成指引 + +这篇教程,讲述了如何将 Hippy 3.x SDK 集成到 Flutter 工程。 + +> 注:以下文档都是假设您已经具备一定的 Flutter 开发经验。 + +--- + +## 前期准备 + +- 已经安装了 Flutter version>=3.0 并配置了环境变量 + +## Demo 体验 + +若想快速体验,可以直接基于我们的 `Voltron Demo` 来开发,我们提供以下两种 `Demo` + +- 如果您的应用完全通过 `Flutter` 进行开发,可以参考[flutter_proj](https://github.com/Tencent/Hippy/tree/master/framework/example/voltron-demo/flutter_proj),3.0正式发布前,请使用 [flutter_proj](https://github.com/Tencent/Hippy/tree/v3.0-dev/framework/example/voltron-demo/flutter_proj) + +- 如果您希望将 `Voltron` 集成进您的原生 `IOS` 或 `Android` 应用,可以使用 `flutter module` 进行集成 + + - `Android` 应用请参考[android-proj](https://github.com/Tencent/Hippy/tree/master/framework/example/voltron-demo/android-proj),3.0正式发布前,请使用 [flutter_proj](https://github.com/Tencent/Hippy/tree/v3.0-dev/framework/example/voltron-demo/android-proj) + - `IOS` 应用请参考[IOSProj](https://github.com/Tencent/Hippy/tree/master/framework/example/voltron-demo/IOSProj),3.0正式发布前,请使用 [flutter_proj](https://github.com/Tencent/Hippy/tree/v3.0-dev/framework/example/voltron-demo/IOSProj) + +> 注意,使用 `flutter_module` 方式进行开发时,原生工程和 `Flutter` 工程在两个目录,上面所提到的 `android-proj` 和 `IOSProj` 均需要配合 [flutter_module](https://github.com/Tencent/Hippy/tree/master/framework/example/voltron-demo/flutter_module)进行使用,3.0正式发布前,请使用 [flutter_proj](https://github.com/Tencent/Hippy/tree/v3.0-dev/framework/example/voltron-demo/flutter_module) + +## 快速接入 + +### 如果您的应用完全通过 `Flutter` 进行开发 + +1. 创建一个 Flutter 工程 + +2. Pub 集成 + + 在 `pubspec.yaml` 中添加 `Voltron` 依赖 + + ```yaml + dependencies: + voltron: ^0.0.1 + ``` + +3. 本地集成(可选) + + 1. 克隆 Hippy 源码 + + ```shell + git clone https://github.com/Tencent/Hippy.git + ``` + + > 注意使用相应的分支及tag,未合入主干前,请使用v3.0-dev分支 + + 2. 打开 Flutter 工程根目录下的 `pubspec.yaml` + + 在 `dependencies` 下添加 `voltron` 依赖 + + ```yaml + voltron: + path: Hippy路径/framework/voltron + ``` + +4. 安装依赖 + + ```shell + flutter pub get + ``` + +5. 使用 `Voltron` + + 建议参考[flutter_proj](https://github.com/Tencent/Hippy/tree/master/framework/example/voltron-demo/flutter_proj),3.0正式发布前,请使用 [flutter_proj](https://github.com/Tencent/Hippy/tree/v3.0-dev/framework/example/voltron-demo/flutter_proj) + + > Pub 集成方式在 Android 平台默认支持 `arm64-v8a` 和 `armeabi-v7a`,如需支持 `x86` 和 `x86_64`,请使用本地集成,iOS 无影响。 + + > 需要注意,如果 **debugMode** 为YES的情况下,会忽略所有参数,直接使用 npm 本地服务加载测试 bundle, + +### 如果您希望将 `Voltron` 集成进您的原生 `IOS` 或 `Android` 应用 + +1. 使用该方式进行集成时,要首先集成 Flutter Module,该部分可直接参考官网[Add Flutter to an existing app](https://docs.flutter.dev/add-to-app) + +2. 后续流程与完全通过 `Flutter` 进行开发保持一致即可。也可直接参考我们的[Demo](#demo-体验-1)工程 diff --git a/docs/development/web-integration-guidelines.md b/docs/development/web-integration-guidelines.md new file mode 100644 index 00000000000..6c2bf0812fa --- /dev/null +++ b/docs/development/web-integration-guidelines.md @@ -0,0 +1,151 @@ +# Web同构指引 + +这篇教程,讲述了如何将 Hippy 集成到 Web 页面中。 + +> 不同于 @hippy/react-web 和 @hippy/vue-web 方案,本方案(Web Renderer)不会替换 @hippy/react 和 @hippy/vue,而是将运行在原生环境下的 bundle 原封不动运行到 Web 上,与转译 Web 的方案各有利弊,业务可根据具体场景采用合适的方案 + +--- + +## 前期准备 + +- 模板文件:Web 运行需要一个 HTML 文件作为入口 +- 入口文件:WebRenderer 是作为 Hippy bundle 的一个运行环境,因此不共享入口 JS 文件,应为其创建独立的入口文件 + +### npm script + +在 demo 项目中,通过 `web:dev` 命令启动 WebRenderer 调试服务,通过 `web:build` 打包编译。 + +```json + "scripts": { + "web:dev": "npm run hippy:dev & node ./scripts/env-polyfill.js webpack serve --config ./scripts/hippy-webpack.web-renderer.dev.js", + "web:build": "node ./scripts/env-polyfill.js +webpack --config ./scripts/hippy-webpack.web-renderer.js" + } +``` + +### 启动调试 + +执行 `npm run web:dev` 启动 WebRenderer 调试,根据 demo 的 webpack 配置,WebRenderer 的 web 服务运行在`3000`端口,浏览器通过 `http://localhost:3000` 访问页面。 + +## 快速接入 + +WebRenderer 的执行应符合以下流程: + +1. 导入 WebRenderer:该阶段会初始化 Hippy 代码运行的环境 +2. 加载业务 bundle:这个 bundle 与 Native 侧运行的 bundle 包保持一致 +3. 启动 WebRenderer:该阶段会加载 Hippy 内置组件和模块,也可以加载自定义组件和模块 + +### 导入 WebRenderer + +#### 以 CDN 方式使用 + +在模板文件内添加: + +```html + + + + + + Example + + +
    + + + + + + +``` + +#### 以 NPM 包方式使用 + +```shell +npm install -S @hippy/web-renderer +``` + +在入口文件内添加: + +```javascript +// 1. 导入 web renderer +import { HippyWebEngine, HippyWebModule } from '@hippy/web-renderer'; + +// 2. 导入业务 bundle 的入口文件,需放在 web renderer 导入之后 + +// 3. 创建 web engine,如果有业务自定义模块和组件,从此处传入 +``` + +### 加载业务 Bundle + +加载 bundle 包有多种方式,可根据业务需要灵活选择,只需要确保引入顺序在 WebRenderer 之后即可 + +#### 在模板文件内引用加载 + +```html + + + + + +``` + +#### 在入口文件内动态加载 + +```javascript +import { HippyWebEngine } from '@hippy/web-renderer'; + +const engine = HippyWebEngine.create(); + + engine.load('https://xxxx.com/hippy-bundle/index.bundle.js').then(() => { + engine.start({ + id: 'root', + name: 'example', + }); +}); +``` + +#### 业务源码直接引用 + +```javascript +import { HippyCallBack, HippyWebEngine, HippyWebModule, View } from '@hippy/web-renderer'; +// 导入业务 bundle 的入口文件,需放在 web renderer 导入之后 +import './main'; + + +const engine = HippyWebEngine.create(); +``` + +### 启动 WebRenderer + +加载完业务 bundle 后,调用相关 API 创建并启动 WebRenderer + +```js +// 创建 web engine,如果有业务自定义模块和组件,从此处传入 +// 如果只使用官方模块和组件,则直接使用 const engine = HippyWebEngine.create() 即可 +const engine = HippyWebEngine.create({ + modules: { + CustomCommonModule, + }, + components: { + CustomPageView, + }, +}); + +// 启动 web renderer +engine.start({ + // 挂载的 dom id + id: 'root', + // 模块名 + name: 'module-name', + // 模块启动参数,业务自定义, + // hippy-react 可以从 入口文件props里获取,hippy-vue可以从 app.$options.$superProps 里获取 + params: { + path: '/home', + singleModule: true, + isSingleMode: true, + business: '', + data: { }, + }, +}); +``` diff --git a/docs/development/web-integration.md b/docs/development/web-integration.md new file mode 100644 index 00000000000..3d77a392597 --- /dev/null +++ b/docs/development/web-integration.md @@ -0,0 +1,479 @@ + +# 前端接入 + +Hippy 同时支持 React 和 Vue 两种 UI 框架,通过 [@hippy/react](//www.npmjs.com/package/@hippy/react) 和 [@hippy/vue](//www.npmjs.com/package/@hippy/vue) 及 [@hippy/vue-next](//www.npmjs.com/package/@hippy/vue-next) 三个包提供实现。 + +# hippy-react + +[[hippy-react 介绍]](api/hippy-react/introduction.md) [[范例工程]](https://github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) + +hippy-react 工程暂时只能通过手工配置初始化,建议直接 clone 范例工程并基于它进行修改。 + +当然,也可以从头开始进行配置。 + +## 准备 hippy-react 运行时依赖 + +请使用 `npm i` 安装以下 npm 包。 + +| 包名 | 说明 | +| ------------------- | -------------------------- | +| @hippy/react | hippy-react 运行时和渲染层 | +| react | react 本体 | +| regenerator-runtime | async/await 转换运行时 | + +## 准备 hippy-react 编译时依赖 + +以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: + +必须的: + +| 包名 | 说明 | +| --------------------------------------- | ---------------------------------------------- | +| @babel/plugin-proposal-class-properties | Babel 插件 - 支持仍在草案的 Class Properties | +| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | +| @babel/preset-react | Babel 插件 - 转译 JSX 到 JS | +| @hippy/debug-server | Hippy 前终端调试服务 | +| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | +| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | +| webpack | Webpack 打包程序 | +| webpack-cli | Webpack 命令行 | + +可选的: + +| 包名 | 说明 | +| ----------------------------------- | ------------------------------------------ | +| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | +| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 +| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | +| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | +| file-loader | 静态文件加载 | +| url-loader | 静态文件以 Base64 形式加载 | + +## hippy-react 编译配置 + +当前 hippy-react 采用 `Webpack 4`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 + +### hippy-react 开发调试编译配置 + +该配置展示了将 Hippy 运行于终端的最小化配置。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ---------- | +| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | + +### hippy-react 生产环境编译配置 + +生产环境和开发调试的包主要有两个区别: + +1. 生产环境开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 +2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减小业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ----------------------------- | +| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | +| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | +| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | +| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | +| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | + +如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 + +!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本。 + +## hippy-react 入口文件 + +入口文件非常简单,只是从 hippy-react 里初始化一个 Hippy 实例。注意,入口文件组件需要通过单节点包裹,如下: + +```js +import { Hippy } from '@hippy/react'; +import App from './app'; + +new Hippy({ + appName: 'Demo', // 终端分配的业务名称 + entryPage: App, // 对应业务启动时的组件 + silent: false, // 设置为 true 可以关闭框架日志输出 +}).start(); + +// P.S. entryPage需要通过单节点包裹,不能用数组的形式,例如 +import React from 'react'; +import { + View, + Text, +} from '@hippy/react'; +export default function app() { + // 入口文件不要使用这种形式,非入口文件可以使用 + return [ + , + test test + ]; + // 修改成通过单节点包裹 + return ( + , + test test + ); +} + +``` + +## hippy-react npm 脚本 + +在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。 + +```json + "scripts": { +"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js", +"hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", +"hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" +} +``` + +## hippy-react 转 Web + +请参考专门的 [hippy-react 转 Web 章节](api/hippy-react/web.md)。 + +# hippy-vue + +>注意:因vue2.x版本将于年底停止更新,建议用户升级至使用vue3.x版本的@hippy/vue-next + +[[hippy-vue 介绍]](api/hippy-vue/introduction.md) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo) + +hippy-vue 相对简单很多,hippy-vue 只是 [Vue](//vuejs.org) 在终端上的渲染层,组件也基本和浏览器保持一致。可以通过 [vue-cli](//cli.vuejs.org/) 先[创建一个 Web 项目](//cli.vuejs.org/zh/guide/creating-a-project.html),然后加上一些 hippy-vue 的内容就可以直接将网页渲染到终端了。 + +## 准备 hippy-vue 运行时依赖 + +请使用 `npm i` 安装以下 npm 包,保证运行时正常。 + +| 包名 | 说明 | +| --------------------------- | -------------------------------- | +| @hippy/vue | hippy-vue 运行时核心 | +| @hippy/vue-native-components | hippy-vue 的扩展终端组件 | +| @hippy/vue-router | vue-router 在 hippy-vue 上的移植 | + +## hippy-vue 编译时依赖 + +以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: + +必须的: + +| 包名 | 说明 | +| -------------------- | ------------------------------------------ | +| @hippy/debug-server | Hippy 前终端调试服务 | +| @hippy/vue-css-loader | hippy-vue 的 CSS 文本到 JS 语法树转换 | +| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | +| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | +| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | +| webpack | Webpack 打包程序 | +| webpack-cli | Webpack 命令行 | + +可选的: + +| 包名 | 说明 | +| ----------------------------------- | ------------------------------------------ | +| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | +| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | +| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 +| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | +| file-loader | 静态文件加载 | +| url-loader | 静态文件以 Base64 形式加载 | + +## hippy-vue 编译配置 + +当前 hippy-vue 采用 `Webpack 4`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 + +### hippy-vue 开发调试编译配置 + +该配置展示了将 Hippy 运行于终端的最小化配置。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ---------- | +| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | + +### hippy-vue 生产环境编译配置 + +线上包和开发调试用包主要有两个区别: + +1. 开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 +2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减小业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。 + +| 配置文件 | 说明 | +| ------------------------------------------------------------ | ----------------------------- | +| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | +| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | +| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | +| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | +| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | + +如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 + +!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本。 + +## hippy-vue 入口文件 + +hippy-cli 初始化的项目自带了一个 [Web 端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/main.js),可以保留着用来启动 Web 端网页,但是因为 hippy-vue 的启动参数不一样,需要专门的 [终端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/main-native.js)来加载一些终端上用到的模块。 + +```js +import Vue from 'vue'; +import VueRouter from 'vue-router'; +import HippyVueNativeComponents from '@hippy/vue-native-components'; +import App from './app.vue'; +import routes from './routes'; +import { setApp } from './util'; + +// 禁止框架调试信息输出,取消注释即可使用。 +// Vue.config.silent = true; + +Vue.config.productionTip = false; + +// Hippy 终端组件扩展中间件,可以使用 modal、view-pager、tab-host、ul-refresh 等终端扩展组件了。 +Vue.use(HippyVueNativeComponents); +Vue.use(VueRouter); + +const router = new VueRouter(routes); + +/** + * 声明一个 app,这是同步生成的 + */ +const app = new Vue({ + // 终端指定的 App 名称 + appName: 'Demo', + // 根节点,必须是 Id,当根节点挂载时才会触发上屏 + rootView: '#root', + // 渲染自己 + render: h => h(App), + // iPhone 下的状态栏配置 + iPhone: { + // 状态栏配置 + statusBar: { + // 禁用状态栏自动填充 + // disabled: true, + + // 状态栏背景色,如果不配的话,会用 4282431619,也就是 #40b883 - Vue 的绿色 + // 因为运行时只支持样式和属性的实际转换,所以需要用下面的转换器将颜色值提前转换,可以在 Node 中直接运行。 + // hippy-vue-css-loader/src/compiler/style/color-parser.js + backgroundColor: 4283416717, + + // 状态栏背景图,要注意这个会根据容器尺寸拉伸。 + // backgroundImage: '//mat1.gtimg.com/www/qq2018/imgs/qq_logo_2018x2.png', + }, + }, + // 路由 + router, +}); + +/** + * $start 是 Hippy 启动完以后触发的回调 + * Vue 会在 Hippy 启动之前完成首屏 VDOM 的渲染,所以首屏性能非常高 + * 在 $start 里可以通知终端说已经启动完成,可以开始给前端发消息了。 + */ +app.$start((/* app */) => { + // 这里干一点 Hippy 启动后的需要干的事情,比如通知终端前端已经准备完毕,可以开始发消息了。 + // setApp(app); +}); + +/** + * 保存 app 供后面通过 app 接受来自终端的事件。 + * + * 之前是放到 $start 里的,但是有个问题时因为 $start 执行太慢,如果首页就 getApp() 的话可能会 + * 导致获得了 undefined,然后监听失败。所以挪出来了。 + * + * 但是终端事件依然要等到 $start 也就是 Hippy 启动之后再发,因为之前桥尚未建立,终端发消息前端也 + * 接受不到。 + */ +setApp(app); +``` + +## hippy-vue npm 脚本 + +在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。 + +```json + "scripts": { +"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js", +"hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", +"hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" +}, +``` + +## 路由 + +`@hippy/vue-router` 完整支持 vue-router 中的跳转功能,具体请参考 [hippy-vue-router](api/hippy-vue/router.md) 文档。 + +# hippy-vue-next + +[[hippy-vue-next 介绍]](api/hippy-vue/vue3) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo) + +hippy-vue-next 是 [Vue](//cn.vuejs.org) 在终端上的渲染层,组件也基本和浏览器保持一致。可以通过脚手架 [vue-cli](//github.com/vuejs/vue-cli) 先[创建一个 Web 项目](//cli.vuejs.org/zh/guide/creating-a-project.html#vue-create),然后加上一些 hippy-vue-next 的内容就可以直接将网页渲染到终端了。也可以参考我们的范例项目来初始化你的项目。 +>注意这里使用vue-cli创建项目时构建工具要选择webpack,并且Router和Typescript需要勾选,我们的hippy-vue-next默认都是基于Typescript开发的 + +## 准备 hippy-vue-next 运行时依赖 + +请使用 `npm i` 安装以下 npm 包,保证运行时正常。 + +| 包名 | 说明 | +|---------------|-------------------------------------| +| @hippy/vue-next | hippy-vue-next 运行时核心 | + +## hippy-vue-next 编译时依赖 + +以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: + +必须的: + +| 包名 | 说明 | +|------------------------------|------------------------------------| +| @hippy/debug-server-next | Hippy 前终端调试服务 | +| @hippy/vue-css-loader | hippy-vue-next 的 CSS 文本到 JS 语法树转换 | +| @hippy/vue-next-style-parser | hippy-vue-next 的样式 parser | +| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | +| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | +| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | +| webpack | Webpack 打包程序 | +| webpack-cli | Webpack 命令行 | + +可选的: + +| 包名 | 说明 | +|-------------------------------------|-----------------------------------------------------------------------| +| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | +| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | +| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 | +| @hippy/vue-router-next-history | 支持按安卓物理返回键回退路由 | +| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | +| file-loader | 静态文件加载 | +| url-loader | 静态文件以 Base64 形式加载 | +| esbuild & esbuild-loader | 开发环境webpack支持使用esbuild构建,性能比babel更好 | + +## hippy-vue-next 编译配置 + +当前 hippy-vue-next 支持 `Webpack 4 或 Webpack 5`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-next-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 + +### hippy-vue-next 开发调试编译配置 + +该配置展示了将 Hippy 运行于终端的最小化配置。 + +| 配置文件 | 说明 | +|--------------------------------------------------------------------------------------------------------------------------| ---------- | +| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | + +### hippy-vue-next 生产环境编译配置 + +线上包和开发调试用包主要有两个区别: + +1. 开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 +2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减小业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。 + +| 配置文件 | 说明 | +|-------------------------------------------------------------------------------------------------------------------------------------------| ----------------------------- | +| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | +| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | +| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | +| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | +| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | + +如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 + +!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本,而hippy-vue-next是基于vue-next的,因此使用hippy-vue-next iOS版本必须要10及以上。 + +## hippy-vue-next 入口文件 + +因为 hippy-vue-next 的启动参数与 web 页面不一样,所以我们需要专门的 [终端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/src/main-native.ts)来加载一些终端上用到的模块,并作为项目的入口文件 + +```ts +// 首先导入所需模块 +import { + createApp, + type HippyApp, + EventBus, + setScreenSize, + BackAndroid, +} from '@hippy/vue-next'; + +import App from './app.vue'; +import { createRouter } from './routes'; +import { setGlobalInitProps } from './util'; + +// 创建 hippy app 实例 +const app: HippyApp = createApp(App, { + // hippy native module name + appName: 'Demo', + iPhone: { + // config of statusBar + statusBar: { + // disable status bar autofill + // disabled: true, + + // Status bar background color, if not set, it will use 4282431619, as #40b883, Vue default green + // hippy-vue-css-loader/src/compiler/style/color-parser.js + backgroundColor: 4283416717, + + // 状态栏背景图,要注意这个会根据容器尺寸拉伸。 + // backgroundImage: 'https://user-images.githubusercontent.com/12878546/148737148-d0b227cb-69c8-4b21-bf92-739fb0c3f3aa.png', + }, + }, + // do not print trace info when set to true + // silent: true, + /** + * whether to trim whitespace on text element, + * default is true, if set false, it will follow vue-loader compilerOptions whitespace setting + */ + trimWhitespace: true, +}); +// create router +const router = createRouter(); +app.use(router); + +// init callback +const initCallback = ({ superProps, rootViewId }) => { + setGlobalInitProps({ + superProps, + rootViewId, + }); + /** + * Because the memory history of vue-router is now used, + * the initial position needs to be pushed manually, otherwise the router will not be ready. + * On the browser, it is matched by vue-router according to location.href, and the default push root path '/' + */ + router.push('/'); + + // listen android native back press, must before router back press inject + BackAndroid.addListener(() => { + console.log('backAndroid'); + // set true interrupts native back + return true; + }); + + // mount first, you can do something before mount + app.mount('#root'); + + /** + * You can also mount the app after the route is ready, However, + * it is recommended to mount first, because it can render content on the screen as soon as possible + */ + // router.isReady().then(() => { + // // mount app + // app.mount('#root'); + // }); +}; + +// start hippy app +app.$start().then(initCallback); + +// you can also use callback to start app like @hippy/vue before +// app.$start(initCallback); +``` + +## hippy-vue-next npm 脚本 + +在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-next-demo/package.json#L13) 中提供了几个以 `hippy:`开头的 npm 脚本,可用来启动 [@hippy/debug-server-next](//www.npmjs.com/package/@hippy/debug-server-next) 等调试工具。 + +```json + "scripts": { + "hippy:dev": "node ./scripts/env-polyfill.js hippy-dev --config ./scripts/hippy-webpack.dev.js", + "hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", + "hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" + }, +``` + +## 路由 + +`@hippy/vue-next` 无需侵入式修改vue-router,直接使用官方 vue-router 即可,如果需要支持安卓物理健回退时路由历史回退,则可以安装@hippy/vue-router-next-history模块。 diff --git a/docs/feature/_sidebar.md b/docs/feature/_sidebar.md new file mode 100644 index 00000000000..a2369a7d15f --- /dev/null +++ b/docs/feature/_sidebar.md @@ -0,0 +1,15 @@ +- 3.x + - [VFS](feature/feature3.0/vfs.md) + - [Layout 引擎切换](feature/feature3.0/layout.md) + - [Snapshot](feature/feature3.0/render-node-snapshot.md) + - [双端一致性](feature/feature3.0/cross-platform-consistency.md) + - [Performance API](feature/feature3.0/performance.md) +- 2.x + - [动画](feature/feature2.0/animation.md) + - [日志](feature/feature2.0/console.md) + - [自定义字体](feature/feature2.0/custom-font.md) + - [动态加载](feature/feature2.0/dynamic-import.md) + - [异常捕获](feature/feature2.0/exception.md) + - [JSI 模式](feature/feature2.0/jsi.md) + - [节点缓存](feature/feature2.0/dom-cache.md) + \ No newline at end of file diff --git a/docs/feature/feature2.0/_sidebar.md b/docs/feature/feature2.0/_sidebar.md new file mode 100644 index 00000000000..f33183333e4 --- /dev/null +++ b/docs/feature/feature2.0/_sidebar.md @@ -0,0 +1,17 @@ +- 3.0+ + - [VFS](feature/feature3.0/vfs.md) + - [Layout 引擎切换](feature/feature3.0/layout.md) + - [Snapshot](feature/feature3.0/render-node-snapshot.md) + - [双端一致性](feature/feature3.0/cross-platform-consistency.md) + - [Performance API](feature/feature3.0/performance.md) + - [Screenshot](feature/feature3.0/screenshot.md) + - [自定义字体](feature/feature3.0/custom-font.md) +- 2.0+ + - [动画](feature/feature2.0/animation.md) + - [日志](feature/feature2.0/console.md) + - [自定义字体](feature/feature2.0/custom-font.md) + - [动态加载](feature/feature2.0/dynamic-import.md) + - [异常捕获](feature/feature2.0/exception.md) + - [JSI 模式](feature/feature2.0/jsi.md) + - [节点缓存](feature/feature2.0/dom-cache.md) + diff --git a/docs/feature/feature2.0/animation.md b/docs/feature/feature2.0/animation.md new file mode 100644 index 00000000000..727f6e0c921 --- /dev/null +++ b/docs/feature/feature2.0/animation.md @@ -0,0 +1,149 @@ +# 动画方案 + +--- + +# 原理 + +Hippy 的动画则是完全由前端传入动画参数,由终端控制每一帧的计算和排版更新,减少了前端与终端的通信次数,因此也大大减少动画的卡顿。 + +# 酷炫效果 + +* 关注动画 + +关注动画 + +* 点赞微笑动画 + +点赞微笑 + +* 进度条动画 + +PK进度条动画 + +# 如何使用 + +以 `Hippy-React` 为例,在 Hippy 上实现一个动画分为三个步骤: + +1. 通过 Animation 或 AnimationSet 定义动画 +2. 在 render() 时,将动画设置到需要产生动画效果的控件属性上 +3. 通过 Animation 的 start 方法启动动画,与通过 destroy 方法停止并销毁动画; + +## 示例代码 + +```js +import { Animation, StyleSheet } from "@hippy/react"; +import React, { Component } from "react"; + +export default class AnimationExample extends Component { + componentDidMount() { + // 动画参数的设置 + this.verticalAnimation = new Animation({ + startValue: 0, // 动画开始值 + toValue: 100, // 动画结束值 + duration: 500, // 动画持续时长 + delay: 360, // 至动画真正开始的延迟时间 + mode: "timing", // 动画模式,现在只支持timing + timingFunction: "linear", // 动画缓动函数 + }); + this.horizonAnimation = new Animation({ + startValue: 0, // 开始值 + toValue: 100, // 动画结束值 + duration: 500, // 动画持续时长 + delay: 360, // 至动画真正开始的延迟时间 + mode: "timing", // 动画模式,现在只支持timing + timingFunction: "linear", // 动画缓动函数 + }); + this.scaleAnimationSet = new AnimationSet({ + children: [ + { + animation: new Animation({ + startValue: 1, + toValue: 1.4, + duration: 200, + delay: 0, + mode: "timing", + timingFunction: "linear", + }), + follow: false, // 配置子动画的执行是否跟随执行 + }, + { + animation: new Animation({ + startValue: 1.4, + toValue: 0.2, + duration: 210, + delay: 200, + mode: "timing", + timingFunction: "linear", + }), + follow: true, + }, + ], + }); + } + + componentWillUnmount() { + // 如果动画没有销毁,需要在此处保证销毁动画,以免动画后台运行耗电 + this.scaleAnimationSet && this.scaleAnimationSet.destroy(); + this.horizonAnimation && this.horizonAnimation.destroy(); + this.verticalAnimation && this.verticalAnimation.destroy(); + } + + render() { + return ( + + + + + + { + this.verticalAnimation.start(); + }} + > + 水平位移动画 + + { + this.horizonAnimation.start(); + }} + > + 垂直位移动画 + + { + this.scaleAnimationSet.start(); + }} + > + 图形形变动画 + + + + ); + } +} + +// 样式代码省略 +``` + +## 更多使用说明 + +详细使用,可以参考 + +* [HippyReact Animation 模块](api/hippy-react/modules.md?id=animation) +* [HippyVue Animation 模块](api/hippy-vue/external-components?id=animation) diff --git a/docs/guide/console.md b/docs/feature/feature2.0/console.md similarity index 87% rename from docs/guide/console.md rename to docs/feature/feature2.0/console.md index 84db9ec3676..4c2a53299e9 100644 --- a/docs/guide/console.md +++ b/docs/feature/feature2.0/console.md @@ -2,5 +2,5 @@ Hippy 2.10.0 之前,前端的 `console` 模块实现了基本的日志输出。 同时 `console` 与能够将前端日志输出到终端的 `ConsoleModule` 模块进行融合, 当调用 `console` 的 `log()`、`info()`、`warn()`、`error()` 四个方法时会将日志输出到 iOS 终端日志和 [Android logcat](//developer.android.com/studio/command-line/logcat),这样跟终端日志一起输出有助于解决线上一些难以发现的问题,但要注意在线上包中屏蔽掉正常的信息日志输出。 -Hippy 2.10.0 之后,为了修正 `console` 的调用栈定位问题,将 `console` 方法与 `ConsoleModule` 模块进行分离,调用 `console` 的 `log()`、`info()`、`warn()`、`error()` 方法不再将日志输出到终端,若需要将前端日志输出到终端,请直接使用 [HippyReact ConsoleModule](hippy-react/modules?id=consolemodule) 和 [HippyVue ConsoleModule](hippy-vue/vue-native?id=consolemodule) 说明。 +Hippy 2.10.0 之后,为了修正 `console` 的调用栈定位问题,将 `console` 方法与 `ConsoleModule` 模块进行分离,调用 `console` 的 `log()`、`info()`、`warn()`、`error()` 方法不再将日志输出到终端,若需要将前端日志输出到终端,请直接使用 [HippyReact ConsoleModule](api/hippy-react/modules?id=consolemodule) 和 [HippyVue ConsoleModule](api/hippy-vue/vue-native?id=consolemodule) 说明。 diff --git a/docs/feature/feature2.0/custom-font.md b/docs/feature/feature2.0/custom-font.md new file mode 100644 index 00000000000..5c5433c09ed --- /dev/null +++ b/docs/feature/feature2.0/custom-font.md @@ -0,0 +1,68 @@ + + +# 自定义字体 + +--- + +# 前端 + +前端使用自定义字体非常简单,和浏览器一样,使用 [font-family](https://www.w3schools.com/cssref/pr_font_font-family.asp) 样式即可。 + +有两个范例:[hippy-react-demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx#L49)、[hippy-vue-demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue#L41) + +但是如果要使用操作系统自带以外的字体,需要单独整合一下,继续阅读下面内容。 + +# iOS + +## 整合字体文件 + +打开 iOS 工程,新建一个 `fonts` 目录,并将字体文件拖动到该目录中。按照截图,建立字体引用即可,确保 Target 正确。 + +![拷贝字体](../../assets/img/copy-font.png) + +然后点击项目中的字体文件,并再次确认 Target 正确。 + +![确认字体](../../assets/img/confirm-font.png) + +## 检查项目配置 + +确认项目的设置的 `Build Phases` 里字体文件正确整合。 + +![项目设置](../../assets/img/font-project-setup.png) + +## 将字体添加到 Info.plist + +将准确的字体文件名加入 `Info.plist` 的 `Fonts provided by application` 字段,如果没有这行的话,需要手工 `Add row` 添加一行。 + +![Info.plist](../../assets/img/info-plist.png) + +## 验证字体正确性 + +如果一切都正确,前端应该已经能正常显示自定义字体了,不过有的时候还是显示不了,其中最常见的,就是 Font Family 参数值不对,因为**字体文件名 !== Font Family**。 + +有个简单办法可以进行校验,将 Font Family 全部列出来检查。 + +在 `AppDelegate.m` 的 `application didFinishLaunchingWithOptions` 方法中加上以下代码,在 `Debug` 菜单中打开 `Debug Area` 下 `Active Console`(按下 Command + Shift +C 可以快速打开)即可打印所有 Font Family。 + +```objectivec +for (NSString* family in [UIFont familyNames]) +{ + NSLog(@"%@", family); + for (NSString* name in [UIFont fontNamesForFamilyName: family]) + { + NSLog(@" %@", name); + } +} +``` + +![检查字体](../../assets/img/check-font.png) + +# Android + +## 整合字体文件 + +Android 只需要在静态资源 `assets` 目录中建立 `fonts` 目录,然后把字体文件拷贝进去即可。 + +需要注意的是,字体文件名需要和 FontFamily 一致,因为 Android 虽然也可以做字体文件名映射,但是字体和文件名一致无疑是最简单的办法。 + +> 官方 demo 的字体放在 [res/fonts](https://github.com/Tencent/Hippy/tree/master/examples/android-demo/res) 目录下,是因为编译脚本[将 `res` 目录下的文件直接拷贝到 `assets` 目录](https://github.com/Tencent/Hippy/blob/master/examples/android-demo/build.gradle#L35)下了,所以 `res/assets` 就变成 `assets/assets` 目录,为了让字体目录正确拷贝进 `assets` 静态资源目录,只能让它放在 `res` 下。 diff --git a/docs/feature/feature2.0/dom-cache.md b/docs/feature/feature2.0/dom-cache.md new file mode 100755 index 00000000000..fbf19d69e71 --- /dev/null +++ b/docs/feature/feature2.0/dom-cache.md @@ -0,0 +1,37 @@ +# 节点缓存 + +缓存上一次页面打开 DOM Node 节点的数据,序列化保存至本地,当下次打开页面时反序列化本地节点数据,调用 SDK create node 接口创建节点完成上屏。SDK统一提供对外接口,由接入方完成节点数据的存储与读取(序列化,反序列化),同样数据的缓存有效期也是由接入方自行决定,SDK 负责首屏节点数据的获取与首屏界面的创建还原。 + +--- + +# 接口 + +## HippyThirdPartyAdapter 新增接口 + ++ `public void saveInstanceState(ArrayList recordList)` + + 这个接口由接入方实现,通过根节点遍历获取每个节点数据,序列化并保存,获取节点数据可以调用 `node.getDomainData()` 接口返回 `DomDomainData` 对象。 + +## HippyEngine 新增接口 + ++ `public void saveInstanceState()` + + 该接口会转发消息到 dom 线程,最终获取 root dom node 节点并调用 `ThirdPartyAdapter` 的 `saveInstanceState`。 + ++ `public void HippyRootView restoreInstanceState(ArrayList domNodeRecordList, HippyEngine.ModuleLoadParams loadParams, Callback callback)` + + 接入方提前读取好本地节点数据,并反序列化为 `DomNodeRecord` list 输入参数,**转换时需要注意把 node id 都转成负数**,不然会和正式JS页面节点有冲突。 + ++ `public void destroyInstanceState(HippyRootView rootView)` + + 最终真实JS页面显示后,需要销毁首屏页面释放内存。 + +# 使用方式 + ++ `saveInstanceState` 调用时机 + + 可以由接入方决定,比如在页面退出调用引擎 `destroy` 方法前。 + ++ `restoreInstanceState` 调用时机 + + 按正常初始化引擎流程,在 Hippy engine 初始化完成后调用 `rootView = mHippyEngine.restoreInstanceState(recordList, loadParams);` diff --git a/docs/guide/dynamic-import.md b/docs/feature/feature2.0/dynamic-import.md similarity index 77% rename from docs/guide/dynamic-import.md rename to docs/feature/feature2.0/dynamic-import.md index a9fd3913b60..2f3721898cb 100644 --- a/docs/guide/dynamic-import.md +++ b/docs/feature/feature2.0/dynamic-import.md @@ -1,33 +1,32 @@ - - - # 动态加载 -## 介绍 +--- + +# 介绍 Hippy 2.2 版本之前只支持加载单个 js bundle 文件。随着业务越来越复杂,单个 js 文件体积愈发增加的体积会影响首屏启动速度。为了解决这个问题,Hippy 在 2.2 版本增添了动态加载能力,开发人员可以按需来动态引入子 js bundle 文件。 `Hippy 最低版本支持 2.2` -## 原理架构 +# 原理架构 -![Communication Info](//m4.publicimg.browser.qq.com/publicimg/nav/hippydoc/dynamic_import.png) +![Communication Info](../../assets/img/dynamic_import.png) -## 范例 +# 范例 [[React 范例]](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/externals/DyanmicImport/index.jsx) [[Vue 范例]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-dynamicimport.vue) -## 使用方法 +# 使用方法 -### 安装 +## 安装 `npm install -D @hippy/hippy-dynamic-import-plugin` -### 使用 +## 使用 -在 [webpack 打包脚本](https://github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/scripts) 中引入插件 +在 [Webpack 打包脚本](https://github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/scripts) 中引入插件 ```javascript const HippyDynamicImportPlugin = require('@hippy/hippy-dynamic-import-plugin'); @@ -48,7 +47,7 @@ module.exports = { }; ``` -### 降级方案 +## 降级方案 在终端 SDK 不支持 dynamic import 的版本,可以使用以下两种方法阻止分包。 @@ -74,7 +73,7 @@ plugins: [ ], ``` -## 支持同时配置本地/网络加载分包 +# 可同时配置本地/网络加载分包 `网络加载 hippy sdk 最低支持版本 2.5.5` @@ -82,11 +81,11 @@ plugins: [ 提供以下几种模式 -### 业务只加载 [本地] js bundle +## 业务只加载 [本地] js bundle 与原有动态加载能力一样,直接使用 `import()` 语法即可 -### 业务只加载 [远程] js bundle +## 业务只加载 [远程] js bundle + webpack打包脚本配置全局 `publicPath`(可选) @@ -94,22 +93,22 @@ plugins: [ // webpack output 配置 output: { ... - publicPath: 'https://static.res.qq.com/hippy/hippyVueDemo/', + publicPath: 'https://xxxx/hippy/hippyVueDemo/', }, ``` -+ 在业务代码引用分包的入口配置 `magic comment`的 `webpackChunkName`(必须) 和 `customChunkPath`(可选),如果没有配置`customChunkPath`,会默认使用全局 `publicPath`; ++ 在业务代码引用分包的入口配置 `magic comment`的 `webpackChunkName`(必须) 和 `customChunkPath`(可选),如果没有配置`customChunkPath`,会默认使用全局 `publicPath`; 以 Hippy-Vue 为例: ```javascript // Hippy-Vue 配置, - AsyncComponentFromHttp: () => import(/* customChunkPath: "https://static.res.qq.com/hippy/hippyVueDemo/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue') + AsyncComponentFromHttp: () => import(/* customChunkPath: "https://xxx/hippy/hippyVueDemo/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue') .then(res => res) .catch(err => console.error('import async remote component error', err)) ``` -### 业务同时加载 [本地 + 远程] js bundle +## 业务同时加载 [本地 + 远程] js bundle + 去除 webpack 全局配置的 `publicPath`(publicPath 会强制在所有 bundle 前加上配置的路径,影响本地 bundle 加载) @@ -117,7 +116,7 @@ plugins: [ ```javascript // Hippy-Vue 配置 - AsyncComponentFromHttp: () => import(/* customChunkPath: "https://static.res.qq.com/hippy/hippyVueDemo/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue') + AsyncComponentFromHttp: () => import(/* customChunkPath: "https://xxx/hippy/hippyVueDemo/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue') .then(res => res) .catch(err => console.error('import async remote component error', err)) diff --git a/docs/feature/feature2.0/exception.md b/docs/feature/feature2.0/exception.md new file mode 100644 index 00000000000..6656a93f280 --- /dev/null +++ b/docs/feature/feature2.0/exception.md @@ -0,0 +1,60 @@ +# 异常捕获 + +--- + +# uncaughtException + +Hippy 对于 JS 代码里没有处理的异常错误,可以通过监听 `uncaughtException` 事件进行捕获。 + +```javascript + global.Hippy.on('uncaughtException', (...args) => { + // 此处可以做错误上报 + report('[uncaughtException]', ...args); + }); +``` + +# unhandledRejection + +当 Promise 被 reject 且没有 reject 处理器的时候,会触发 `unhandledRejection` 事件 + +!> 当前只能通过 js polyfill 的方式捕获 iOS(JSCore) Promise 的 `unhandledRejection` 错误,Android(V8) 暂不支持。 + +## iOS + +iOS 的 Promise 目前是采用 polyfill 的方式实现的,因此可以对 `unhandledRejection` 异常直接进行捕获。 + +由于 `rejection-tracking` 有一定的性能损耗,业务在有需要的时候才引入该插件。 + +> 最低支持版本 `2.14.1` + ++ `npm install -D @hippy/rejection-tracking-polyfill` + ++ 引入 `polyfill` + +```javascript + +// 可以在 iOS webpack config 配置 +module.exports = { + entry: { + // 注入 polyfill 代码 + index: ['@hippy/rejection-tracking-polyfill', 'dist/dev/index.js'] + }, +} + +// 也可以在业务代码里直接引入,以 hippy-react 举例 +import { Hippy } from '@hippy/react'; +import '@hippy/rejection-tracking-polyfill'; + +new Hippy({ + appName: 'Demo', + entryPage: App, +}).start(); +``` + ++ 监听错误 + +```javascript +global.Hippy.on('unhandledRejection', (reason) => { + console.error('unhandledRejection', reason); +}); +``` diff --git a/docs/feature/feature2.0/jsi.md b/docs/feature/feature2.0/jsi.md new file mode 100644 index 00000000000..5c478ac738e --- /dev/null +++ b/docs/feature/feature2.0/jsi.md @@ -0,0 +1,266 @@ +# JSI 模式 + +> 最低支持版本 2.11.0 + +JavaScript Interface(JSI) 模式提供了一种无需经历编解码(序列化)过程的跨 VM (同步)互调用解决方案,使得 js 可以和 native 直接通信。传统互调用所传递的对象会全部序列化,但并非所有成员都被访问,在特定场景下导致了不必要的开销与冗余。通过 JSI,js 侧可以获取 C++ 定义的对象(HostObject),并调用该对象上的方法。 + +--- + +# 架构图 + +
    +jsi架构图 +
    +
    + +# 不适用场景 + +JSI 并非适用于所有场景: + +* 所需读取的成员占比越少,JSI 表现出的性能越优异。 +* 随着所需读取的成员占比上升,JNI 调用次数的增加,所累计的耗时也随之上涨,反而不如编解码实现性能优异。 +* 同步调用简化了编码,耗时更稳定,但会阻塞 JS 执行,不适用于复杂逻辑。 + +# 接入说明 + +## Android + +* 通过设置引擎初始化参数开启JSI能力 + +```kotlin +val initParams = HippyEngine.EngineInitParams() +initParams.enableTurbo = true +``` + +* 定义Module + +> 跟普通NativeModule类似,区别在于需要添加以下注解表明是同步调用 `@HippyMethod(isSync = true)` + +```kotlin +@HippyNativeModule(name = "demoTurbo") +class DemoTurboModule(context: HippyEngineContext?) : HippyNativeModuleBase(context) { + ... + @HippyMethod(isSync = true) + fun getNum(num: Double): Double = num + ... +} +``` + +> 支持的数据类型说明: + +
    +数据类型 +
    +
    + +更多示例可参考类[DemoTurboModule](https://github.com/Tencent/Hippy/blob/v3.0-dev/framework/examples/android-demo/src/main/java/com/openhippy/example/turbo/DemoTurboModule.kt) + +* 注册TurboModule模块,跟NativeModule注册方法完全一致 + +```kotlin +class ExampleAPIProvider : HippyAPIProvider { + + override fun getNativeModules(context: HippyEngineContext): Map, Provider> { + return mapOf( + ... + DemoTurboModule::class.java to Provider { DemoTurboModule(context) } + ) + } + ... +} +``` + +## iOS + +* 通过设置引擎初始化参数开启JSI能力 +iOS有两种方式去打开关闭enableTurbo能力,如下: + +```objc +// 方式一:bridge初始化时通过配置参数设置生效 +NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO)}; +HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:[NSURL fileURLWithPath:commonBundlePath] + moduleProvider:nil + launchOptions:launchOptions + executorKey:@"Demo"]; + +// 方式二:bridge初始化完成后,设置属性生效 +HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:nil + businessURL:nil + moduleName:@"Demo" + initialProperties:@{@"isSimulator": @(isSimulator)} + launchOptions:nil + shareOptions:nil + debugMode:YES + delegate:nil]; +rootView.bridge.enableTurbo = YES; + +``` + +* 定义Module + +> 继承HippyOCTurboModule,实现协议HippyTurboModule。 + +目前iOS端仅支持继承关系来实现JSI能力,后续会考虑升级,只需实现协议`HippyTurboModule`就能实现能力。 + +具体使用与实现协议如下: + +```obj + +@implementation TurboConfig + +... + +// 注册模块 +HIPPY_EXPORT_TURBO_MODULE(TurboConfig) + +// 注册交互函数 +HIPPY_EXPORT_TURBO_METHOD(getInfo) { + return self.strInfo; +} +HIPPY_EXPORT_TURBO_METHOD(setInfo:(NSString *)string) { + self.strInfo = string; + return @(YES); +} + +... + +@end + +``` + +> 支持的数据类型说明: + +| Objec类型 | Js类型 | +|:----------|:----------| +| BOOL | Bool | +| NSInteger | Number | +| NSUInteger | Number | +| CGDouble | Number | +| CGFloat | Number | +| NSString | String | +| NSArray | Array | +| NSDictionary | Object | +| Promise | Function | +| NULL | null | + + + +更多示例可参考类[DemoIOSTurboModule](https://github.com/Tencent/Hippy/blob/master/examples/ios-demo/HippyDemo/turbomodule/TurboBaseModule.mm) + +## 鸿蒙 + +* 通过设置引擎初始化参数开启JSI能力 + +```typescript +initParams.enableTurbo = true +``` + +* 定义Module + +> 跟普通NativeModule类似,区别在于需要设置 isTurbo 为 true + +```typescript +export class ExampleNativeTurboModule extends HippyNativeModuleBase { + public static readonly NAME = 'demoTurbo' + + constructor(ctx: HippyEngineContext) { + super(ctx) + } + + isTurbo(): boolean { + return true + } + + public getString(info: string): string { + return 'demoTurbo' + info; + } + + public getNum(num: number): number { + return num; + } + + public getBoolean(b: boolean): boolean { + return b; + } + + public getMap(map: HippyMap): HippyMap { + return map + } + + public getArray(array: HippyArray): HippyArray { + return array + } + + public getObject(obj: HippyAny): HippyAny { + return obj + } + + public getTurboConfig(): TurboConfig { + return new TurboConfig(); + } + + public printTurboConfig(turboConfig: TurboConfig): string { + return turboConfig.info; + } +} +``` + +> 嵌套 turbo 对象需要设置注解@HippyTurboObject, 否则会当作普通对象解析 + +``` typescript +@HippyTurboObject() +export class TurboConfig { + public static readonly NAME = 'turboConfig' + public info = "info from turboConfig" + private static instance: TurboConfig; + + public static getInstance() { + if (!TurboConfig.instance) { + TurboConfig.instance = new TurboConfig(); + } + return TurboConfig.instance; + } + + public toString() { + return this.info; + } + + public getTestString() { + return 'test' + this.info; + } +} +``` + +> 支持的数据类型说明: + +| Objec类型 | Js类型 | +|:----------|:----------| +| napi_boolean | Bool | +| napi_number | Number | +| napi_bigint | Number | +| napi_string | String | +| napi_object | Array | +| napi_object | Object | +| NULL | null | + +更多示例可参考类[DemoTurboModule](https://github.com/Tencent/Hippy/blob/main/framework/examples/ohos-demo/src/main/ets/hippy_extend/ExampleNativeTurboModule.ets) + +* 注册TurboModule模块,跟NativeModule注册方法完全一致 + + + +# 使用例子 + +[Android Demo](https://github.com/Tencent/Hippy/blob/master/examples/android-demo) + +[iOS Demo](https://github.com/Tencent/Hippy/blob/master/examples/ios-demo) + +[HippyReact Demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/externals/Turbo/index.jsx) + +[HippyVue Demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-turbo.vue) + + + + + diff --git a/docs/feature/feature3.0/_sidebar.md b/docs/feature/feature3.0/_sidebar.md new file mode 100755 index 00000000000..f33183333e4 --- /dev/null +++ b/docs/feature/feature3.0/_sidebar.md @@ -0,0 +1,17 @@ +- 3.0+ + - [VFS](feature/feature3.0/vfs.md) + - [Layout 引擎切换](feature/feature3.0/layout.md) + - [Snapshot](feature/feature3.0/render-node-snapshot.md) + - [双端一致性](feature/feature3.0/cross-platform-consistency.md) + - [Performance API](feature/feature3.0/performance.md) + - [Screenshot](feature/feature3.0/screenshot.md) + - [自定义字体](feature/feature3.0/custom-font.md) +- 2.0+ + - [动画](feature/feature2.0/animation.md) + - [日志](feature/feature2.0/console.md) + - [自定义字体](feature/feature2.0/custom-font.md) + - [动态加载](feature/feature2.0/dynamic-import.md) + - [异常捕获](feature/feature2.0/exception.md) + - [JSI 模式](feature/feature2.0/jsi.md) + - [节点缓存](feature/feature2.0/dom-cache.md) + diff --git a/docs/feature/feature3.0/cross-platform-consistency.md b/docs/feature/feature3.0/cross-platform-consistency.md new file mode 100644 index 00000000000..c1853b676b4 --- /dev/null +++ b/docs/feature/feature3.0/cross-platform-consistency.md @@ -0,0 +1,37 @@ +# 双端一致性 + +## 改进背景 + +在之前的Hippy版本中,存在一些双端不一致的问题,比如某些属性在双端有不同的默认值、动画效果双端有差异等。这些问题不仅会增加开发成本,甚至可能影响到用户体验。因此,我们在Hippy 3.0对此重点进行了优化,以确保Hippy能够在不同平台上提供一致的开发体验和运行效果。 + +## 已修复的问题 + +以下列举部分重要且已经修复的一致性问题及其修改说明: + +> 注意:部分改变属于breaking change,升级时可能需要对代码进行一些调整。 + +| 模块 | Hippy 2.0存在的问题 | Hippy 3.0的解决方案 | +|------|------|---------| +| 动画模块 | 在不同平台上,动画渲染效果不一致,主要表现为iOS动画存在较多问题。 | 优化动画渲染机制,iOS动画由CAAnimation驱动调整为DOM层驱动。 | +| 布局样式 | overflow属性在Android端默认值与iOS不同,且属性设置语法有差异。 | 调整Android端实现方式,对齐iOS。 | +| 布局样式 | backgroundImage的默认位置存在差异 | 统一默认值,对齐双端显示效果 | +| 文本组件 | Text组件嵌套Text或Image时双端显示效果不一致,且Android不支持tintColor、backgroundColor等样式设置 | 对齐双端显示效果,同时新增verticalAlign属性,支持更加灵活的文本排版控制 | +| 列表组件 | iOS端ListView组件不支持horizontal属性 | iOS端增加横向列表的支持,对齐Android。 | +| NetworkModule | fetch接口回调headers字段参数等不一致 | 统一双端回调参数及接口表现。 | + +> 具体变更细节请参考对应组件或模块的接口说明。 + +## 即将解决的问题 + +我们还会在Hippy 3.0后续版本中逐步解决以下双端一致性问题: + +- [ ] 阴影样式问题:阴影样式双端写法不同,显示效果略有差异; +- [ ] 文本样式问题:部分字体样式,如textDecorationColor、textDecorationStyle属性等双端支持存在差异,部分能力仅一端支持; +- [ ] onLayout回调问题:Android中onLayout事件默认从子组件向父组件冒泡,而iOS不冒泡; +- [ ] 部分手势事件回调时机不一致:onClick与onLongClick触发条件存在轻微差异; +- [ ] ListView组件部分回调时机不一致问题:onAppear/onDisappear/onEndReached等回调时机存在轻微差异; +- [ ] Image组件部分样式问题:resizeMode、capInsets等属性存在用法和效果差异; + +> 以上仅列举部分差异,除此之外,部分UI组件和模块也存在轻微的不一致问题,我们将在Hippy 3.0中持续优化和改进。 + +如果您有任何问题或意见,欢迎随时发起Issue或提交PR,我们将第一时间跟进。 diff --git a/docs/feature/feature3.0/custom-font.md b/docs/feature/feature3.0/custom-font.md new file mode 100644 index 00000000000..a62a5a8c684 --- /dev/null +++ b/docs/feature/feature3.0/custom-font.md @@ -0,0 +1,62 @@ + + +# 自定义字体 + +--- + +# 前端 + +前端使用自定义字体非常简单,和浏览器一样,使用 [font-family](https://www.w3schools.com/cssref/pr_font_font-family.asp) 样式即可。 + +有两个范例:[hippy-react-demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx#L49)、[hippy-vue-demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue#L41) + +但是如果要使用操作系统自带以外的字体,需要单独整合一下,继续阅读下面内容。 + +# Ohos + +## 整合字体文件 + +Ohos 只需要在静态资源 `resfile` 目录中建立 `fonts` 目录,然后把字体文件拷贝进去即可。 +当然其它目录也可以,也可以下载字体文件到某个目录。 + +> 对于 `rawfile` 目录里的字体文件,因为鸿蒙提供的rawfile操作是一套非路径Api,无法获取文件路径,所以为了使用路径需要拷贝字体文件到一个临时目录,示例代码参考[EntryAbility.ets](https://github.com/Tencent/Hippy/blob/main/framework/examples/ohos-demo/src/main/ets/entryability/EntryAbility.ets)里。 + +需要注意的是,字体文件名需要和 FontFamily 一致,因为虽然也可以做字体文件名映射,但是字体和文件名一致无疑是最简单的办法。 + +> 官方 demo 的字体目录参考 [resfile/fonts](https://github.com/Tencent/Hippy/tree/main/framework/examples/ohos-demo/src/main/resources/resfile/fonts) + +## 注册字体 + +```typescript +let fontPath = `${getContext().resourceDir}/fonts/TTTGB.otf`; +font.registerFont({ + familyName: 'TTTGB', + familySrc: `file://${fontPath}` +}) +``` + +具体代码可参考 Demo 里 [EntryAbility.ets](https://github.com/Tencent/Hippy/blob/main/framework/examples/ohos-demo/src/main/ets/entryability/EntryAbility.ets) + +## 配置字体路径到 C 层 + +继承 `HippyFontAdapter` 接口并配置自定义字体 familyName 和文件路径: + +```typescript +export class ExampleFontAdapter implements HippyFontAdapter { + // 注册字体路径至hippy测量函数 + getCustomFontPathMap(): Map | null { + let map = new Map(); + const fontFile = `${getContext().resourceDir}/fonts/TTTGB.otf`; + map.set("TTTGB", fontFile); + return map; + } +} +``` + +具体代码可参考 Demo 里 [ExampleFontAdapter.ets](https://github.com/Tencent/Hippy/blob/main/framework/examples/ohos-demo/src/main/ets/hippy_extend/ExampleFontAdapter.ets) + +配置 `ExampleFontAdapter` 到 `EngineInitParams` 参数: + +```typescript +params.fontAdapter = new ExampleFontAdapter() +``` diff --git a/docs/feature/feature3.0/image-decoder-adapter.md b/docs/feature/feature3.0/image-decoder-adapter.md new file mode 100644 index 00000000000..988c67dd144 --- /dev/null +++ b/docs/feature/feature3.0/image-decoder-adapter.md @@ -0,0 +1,35 @@ +# ImageDecoderAdapter + +--- + +## 背景 + +3.0我们在HippyEngine引擎初始化参数中增加了ImageDecoderAdapter的设置,如果有开发者业务中有使用到特殊格式的图片,如SharpP、avif等,可以通过设置ImageDecoderAdapter来对接你的自定义图片解码器,具体接口描述如下: + +## 3.0 图片解码Adapter接口定义 + +### ImageDecoderAdapter Public methods + + ```java + boolean preDecode(@NonNull byte[] data, + @Nullable Map initProps, + @NonNull ImageDataHolder imageHolder, + @NonNull BitmapFactory.Options options); + ``` + + 该接口在拉取到图片原始数据的时候会调用,解码的结果可以通过image data holder提供的setBitmap或者setDrawable接口设置到holder中,并且返回true,表示不需要sdk再做解码操作,如果返回false表示需要sdk做默认的解码操作。 + + ```java + void afterDecode(@Nullable Map initProps, + @NonNull ImageDataHolder imageHolder, + @NonNull BitmapFactory.Options options); + ``` + + + 该接口在解码结束后会调用,为开发者提供二次处理bitmap的机会, 比如要对bitmap做高斯模糊。 + + ```java + void destroyIfNeeded(); + ``` + + 引擎退出销毁时调用,释放adapter可能占用的资源 diff --git a/docs/feature/feature3.0/js-engine.md b/docs/feature/feature3.0/js-engine.md new file mode 100644 index 00000000000..0cdad39d462 --- /dev/null +++ b/docs/feature/feature3.0/js-engine.md @@ -0,0 +1 @@ +# JS引擎切换 diff --git a/docs/feature/feature3.0/layout.md b/docs/feature/feature3.0/layout.md new file mode 100644 index 00000000000..06044067d5a --- /dev/null +++ b/docs/feature/feature3.0/layout.md @@ -0,0 +1,27 @@ +# Layout引擎 + +--- + +Hippy 3.0 默认采用 [Taitank](https://taitank.dev/) 布局引擎,提供轻量、高效、跨平台的布局能力。同时 Hippy 3.0 也支持 [Yoga](https://yogalayout.com/)。 + +## 布局引擎切换 + +1. `cd` to `dom/`. + +2. 修改 CMakeLists.txt 文件 + + ```camke + if (NOT DEFINED LAYOUT_ENGINE) + set(LAYOUT_ENGINE "Taitank") + endif () + ``` + + 修改为 + + ```cmake + if (NOT DEFINED LAYOUT_ENGINE) + set(LAYOUT_ENGINE "Yoga") + endif () + ``` + +3. 重新编译工程 diff --git a/docs/feature/feature3.0/performance.md b/docs/feature/feature3.0/performance.md new file mode 100644 index 00000000000..5778a9a682e --- /dev/null +++ b/docs/feature/feature3.0/performance.md @@ -0,0 +1,90 @@ +# Performance API + +## 背景 + +过去 Hippy SDK 缺乏对关键性能指标的获取和监控机制,各个业务都需自行打点或者魔改 SDK 进行统计,导致 Hippy 团队和接入业务均没有一个针对性能指标的统一基准,数据解读混乱,因此由 SDK 统一提供标准化的性能监控和指标显得非常有必要。 + +## 指标 + +### 2\.1 启动耗时 + +Web 设计了 Performance API ,其中包含了 PerformanceResourceTiming 和 PerformanceNavigationTiming 接口,用于检索和分析有关加载应用程序资源的详细网络计时数据和首屏加载耗时数据 + +0 +1 + +Hippy 3\.0 新架构参考 Web 标准设计了新的性能 API: + +start + +性能数据获取示例: + +global\.performance\.getEntries\(\): 获取所有的性能指标对象 (PerformanceResource、PerformanceNavigation等) + +global\.performance\.getEntriesByType\('navigation'\): 获取启动加载性能指标对象 + +global\.performance\.getEntriesByType\('resource'\): 获取资源加载性能指标对象 + +2 + +>PerformanceNavigationTiming: + +| 指标 | 对应 Key | +|----------------|---------------------| +| Hippy 引擎加载开始 | hippyNativeInitStart | +| JS 引擎加载开始 | hippyJsEngineInitStart | +| JS 引擎加载结束 | hippyJsEngineInitEnd | +| Hippy 引擎加载结束 | hippyNativeInitEnd | +| JS Bundle 自执行耗时 | bundleInfo[] | +| 业务入口执行开始 | hippyRunApplicationStart | +| 业务入口执行结束 | hippyRunApplicationEnd | +| 首帧绘制开始 | hippyFirstFrameStart | +| 首帧绘制结束 | hippyFirstFrameEnd | +| 启动耗时 | duration | +| 指标名称 | name | +| 指标类型 | entryType | + +>bundleInfo: + +| 指标 | 对应 Key | +|----------------|---------------------| +| 主包/分包地址 | url | +| 执行js包开始时间 | executeSourceStart | +| 执行js包结束时间 | executeSourceEnd | + +>PerformanceResourceTiming: + +| 指标 | 对应 Key | +|----------------|---------------------| +| 资源地址 | name | +| 请求资源开始时间 | loadSourceStart | +| 请求资源结束时间 | loadSourceEnd | +| 请求耗时 | duration | +| 指标类型 | entryType | + + +- 适用版本:3\.1 + +### 2\.2 内存 + +- 现状:2\.0 已支持 JS 层通过 Performance\.memory 获取到 V8 引擎的内存数据(Hermes 待定) + +memory + +- 适用版本:2\.0、3\.1 + +### 2\.3 流畅度 + +流畅度可通过 FPS 和 Janky Frame 指标来衡量 + +浏览器里提供了 requestAnimationFrame API,浏览器会在屏幕刷新(一帧)时机调用回调函数,JS 可在回调函数中执行动画等逻辑,也可用来计算 FPS 和 janky frame。Hippy 由于 JS 线程与 UI 线程独立,渲染异步执行,若通过终端实现 requestAnimationFrame 无法做到与浏览器一致的数据精确度(JS 层获取到的帧率会小于终端的真实帧率),但也可作为一个通用能力提供给业务作为参考。 + +fps + +- Hippy 3\.0 基于vsync信号重新实现了 requestAnimationFrame API +- 适用版本:3\.1 + +## 三、Aegis\-Hippy 接入 + +aegis\-sdk:1\.42\.4 + diff --git a/docs/feature/feature3.0/render-node-snapshot.md b/docs/feature/feature3.0/render-node-snapshot.md new file mode 100644 index 00000000000..fa2347b7e24 --- /dev/null +++ b/docs/feature/feature3.0/render-node-snapshot.md @@ -0,0 +1,63 @@ +# RenderNode Snapshot + +--- + +## 2.0 dom node缓存存在的问题 + +2.0上我们支持了dom节点的缓存,但这套方案存在一些性能上的瓶颈,只在少量的业务上应用: + +- 全量节点缓存,在一些类似长列表节点较多的复杂页面恢复耗时比较大(首屏恢复耗时=dom节点恢复+render节点恢复+layout+view恢复); +- 恢复过程存在线程切换,同步恢复dom节点会卡住UI线程,异步恢复dom节点不能在同一个渲染周期去渲染首屏,还是有可能出现短暂白屏; +- 存在一定接入成本,dom tree的遍历与序列化数据需要宿主自己完成。 + +## 3.0 render node缓存解决方案 + +3.0上我们支持了render node节点的缓存方案,很好的解决了之前缓存dom node存在的问题: + +- 由于不再需要创建dom节点和layout,大大减少了首屏恢复耗时,而且整个还原过程不再需要线程切换; +- 由于render节点本身带有排版后的layout信息,节点遍历的时候增加了节点显示区域的判断逻辑,只保存首屏显示区域内的节点,解决长列表节点多的问题; +- 使用Native renderer新dom value编解码能力,在SDK内部完成了节点数据的序列化与反序列化操作,进一步降低了开发者的接入成本。 + +## 3.0 render node缓存接口定义 + +### HippyEngine Public methods + +```java +public void recordSnapshot(@NonNull View rootView, @NonNull final Callback callback) +``` + + 记录指定root view的节点缓存,SDK内部会完成节点遍历,序列化相关的任务,最终通过Callback返回节点序列化后的buffer,节点数据存储,生命周期管理由宿主自行完成 + +```java +public View replaySnapshot(@NonNull Context context, byte[] buffer, String bundlePath) +``` + + 传入之前record的buffer回放节点数据,这个接口调用将同步返回还原的view,bundlePath为js bundle包的绝对路径,用与replay加载本地图片用 + +```java +public View replaySnapshot(@NonNull Context context, @NonNull Map snapshotMap, String bundlePath) +``` + + 传入decode后的节点Map数据,同步返回还原的view,bundlePath为js bundle包的绝对路径,用与replay加载本地图片用 + +```java +public View removeSnapshotView() +``` + + 从view tree中移除snapshot view及其子view,同时删除所有对应的render node节点,调用该接口的时机需要根据不同的业务场景做调整,保证真正页面完整显示后再移除snapshot view,不会产生页面的跳变视觉体验 + +### NativeRenderer Public static methods + +```java +public static Map decodeSnapshot(@NonNull byte[] buffer) +``` + + NativeRenderer静态方法,对节点数据进行decode操作,支持子线程异步调用,返回的Map可以直接用作 replaySnapshot接口的输入参数 + + > 注意:replaySnapshot接口调用必须在Hippy engine初始化完成以后,可以在引擎回调的子线程中执行,也可以在UI主线程执行,但必须在replay调用结束后再调用loadModule,否则有可能会有多线程的问题,在子线程执行好处就是不卡UI线程,但需要post到UI线程挂载到父容器,中间还是会有短暂白屏过程,在主线程直接replay并挂载到父容器,虽然会卡UI,但可以保证页面切换无白屏效果 + +## Performance + +在中低端机型华为M10上对比demo首屏还原耗时:3.0 replay耗时47.8ms,2.0 relplay耗时146.9ms,优化后耗时下降67.5% + +![render node replay与dom node replay性能对比](../../assets/img/render-snapshot-performance.png) diff --git a/docs/feature/feature3.0/screenshot.md b/docs/feature/feature3.0/screenshot.md new file mode 100644 index 00000000000..3b5c59d7e01 --- /dev/null +++ b/docs/feature/feature3.0/screenshot.md @@ -0,0 +1,42 @@ +# Screenshot for specific views + +--- + +## 背景 + +过去在一些业务的使用场景中需要针对指定的Hippy view进行截图并做分享,之前截图逻辑都是由开发者自己实现,在3.0中我们针对图片解码使用了Android高版本的api,导致部分开发者自己创建canvas和bitmap,并用draw方法截图的方式无法正常截取图片,为了进一步降低开发者的适配成本,我们把截图能力下沉到了SDK,为开发者提供更为便捷的使用方式。 + +## 3.0 Screenshot接口定义 + +### HippyEngine Public methods + +```java +/** + * @throws IllegalArgumentException + */ +public abstract void getScreenshotBitmapForView(@Nullable Context context, + int id, @NonNull ScreenshotBuildCallback callback); +``` + + 针对指定id的View进行截图,context非空情况下需要是HippyRootView挂载容器所属的Activity + +```java +/** + * @throws IllegalArgumentException + */ +public abstract void getScreenshotBitmapForView(@Nullable Context context, + @NonNull View view, @NonNull ScreenshotBuildCallback callback); +``` + + 针对指定的View进行截图,context非空情况下需要是HippyRootView挂载容器所属的Activity + + > 注意:以上2个接口中的context参数如果传入null,会默认使用view的context,view设置的context是loadModule时候在ModuleLoadParams中传入的context,针对一些预加载场景,开发者有可能设置的是app的context,当context不是Activiy的时候会抛出IllegalArgumentException异常导致截图失败。除了context不满足条件,还有其它view不存在或者执行PixelCopy.request都有可能抛出IllegalArgumentException类型异常,需要开发者自行捕获处理。 + +```java +public interface ScreenshotBuildCallback { + + void onScreenshotBuildCompleted(Bitmap bitmap, int result); +} +``` + + 返回截图结果的回调,result为0代表截图成功,非0代表截图失败,失败错误值可以参考系统PixelCopy类中定义的错误码 diff --git a/docs/feature/feature3.0/vfs.md b/docs/feature/feature3.0/vfs.md new file mode 100644 index 00000000000..3e65cd17458 --- /dev/null +++ b/docs/feature/feature3.0/vfs.md @@ -0,0 +1,95 @@ +# VFS + +--- + +当前SDK内部发起资源请求的类型主要分为以下几种: + +- debug模式下jsbundle请求 +- 动态加载资源请求 +- Image view url资源请求 +- Text中嵌套image url资源请求 +- Network module fetch请求 +- Image module 图片预拉取请求 +- Font-face 字体资源请求 + +在2.0中对于以上IO资源的请求缺少一套统一管理机制和处理流程,导致很难去全局添加一些监控分析,拦截过滤的处理逻辑,同时由于存在多条资源请求处理分支也会使代码维护成本很高,所以我们在3.0中新增了VFS独立模块,主要模拟类似Virtual file system的机制,对所有IO资源的请求进行统一的管理并提供统一的处理机制,目前3.0所有IO资源的请求已经全部对接到VFS模块。 + +## VFS链式访问机制 + +1. 什么是链式访问 + + VFS内部实际管理了一个链表,链表中的每个元素是引擎启动时候就注册好的processor,当请求发起者调用VFS接口发起请求后,VFS会遍历这个链表,让processor对request进行处理,request处理完成后,VFS会反向遍历链表,让每个processor对response进行处理,最终返回给请求发起者。 + +2. 对称链表结构定义 + + 2.0中所以的资源请求都是从JAVA层发起,但3.0由于接入了自绘内核以及dev tools对接C++ dom以后,资源请求有可能从C++层发起,所以JAVA层和C++层各维护了一条VFS链表,形成对称结构: + + ![render node replay与dom node replay性能对比](../../assets/img/vfs-chain.png) + +3. 链表遍历访问规则 + +- 当请求发起者调用VFS接口以后,默认从链首第一个processor开始访问; +对于request的处理是否需要递交给下一个processor处理,由当前processor决定,也就是说不是所有的processor都会获得request的处理机会; +- 当request处理完成后,会反向遍历链表,把response递交给上一级processor的处理,反方向上的每一级processor都会获得response处理机会,直到最开始的请求发起者; +- SDK内部会在链表尾端插入Default processor,只有当Default processor无法识别的scheme才会传递给Native C++的链表继续处理,识别的scheme无论处理成功或失败都会原路返回,不会再递交给Native C++去处理; +- Native C++链表与JAVA对称,同样遵守以上4条规则; + +## Processor介绍 + +### Processor接口定义 + +所有custom processor都需要extends base processor,base processor定义位于3.0 VFS子工程中 - com.tencent.vfs.Processor,也可以参照同目录下DefaultProcessor的定义 - com.tencent.vfs.DefaultProcessor。 + +### Processor Public methods + +```java +public void handleRequestAsync(@NonNull ResourceDataHolder holder, @NonNull ProcessorCallback callback) +``` + + 异步处理request,基类默认什么都不处理调用callback.next传递给下一个processor + +```java +public boolean handleRequestSync(@NonNull ResourceDataHolder holder) +``` + + 同步处理request,返回true表示这个请求处理完成不需要再传递给下一个processor,返回false,表示需要递交给下一个processor继续处理 + +```java +public void handleResponseAsync(@NonNull ResourceDataHolder holder,@NonNull ProcessorCallback callback) +``` + + 异步处理response,基类默认不对response做任何处理,直接调用callback.onHandleCompleted()递交给上一个processor + +```java +public void handleResponseSync(@NonNull ResourceDataHolder holder) +``` + + 同步处理response,基类默认不做任何处理 + +### ProcessorCallback Public methods + +```java +public void goNext() +``` + + VFS链表正向遍历处理request的时候,当前processor调用该接口表示需要递交给下一个processor继续处理在反向遍历处理response的时候,由于默认会原路返回并传递给请求发起者,所以processor在handleResponse相关接口的重载逻辑中不需要调用该接口,也就是说该接口仅在handleRequest相关接口的重载逻辑中调用才有效 + +```java +public void onHandleCompleted() +``` + + VFS链表正向遍历处理request的时候,当前processor调用该接口表示不在需要递交给下一个processor处理,直接将当前处理结果原路返回给请求发起者。在反向遍历处理response的时候,当前processor调用该接口表示已经完成处理,可以遍历到上一级processor继续处理 + +### Processor的注册 + +在HippyEngine的EngineInitParams初始化参数中增加了设置选项 + +```java + public List processors +``` + +引擎初始化阶段会将开发者自定义的processor设置到VFS链表中 + +![render node replay与dom node replay性能对比](../../assets/img/vfs-processor.png) + +关于Devtools processor和Default processor是SDK内部默认添加的,其存放位置不可以更改 diff --git a/docs/guide/_sidebar.md b/docs/guide/_sidebar.md deleted file mode 100644 index 2157d3bc46d..00000000000 --- a/docs/guide/_sidebar.md +++ /dev/null @@ -1,14 +0,0 @@ - - -* [开始接入](guide/integration.md) -* [Android集成](android/integration.md) -* [iOS集成](ios/integration.md) -* [前端调试](guide/debug.md) -* [Core C++ 架构](core/introduction.md) -* [布局与单位](guide/layout.md) -* [网络请求](guide/network-request.md) -* [定时器](guide/timer.md) -* [日志](guide/console.md) -* [自定义字体](guide/custom-font.md) -* [动态加载](guide/dynamic-import.md) -* [技术支持](guide/support.md) diff --git a/docs/guide/custom-font.md b/docs/guide/custom-font.md deleted file mode 100644 index 2e67ee2e018..00000000000 --- a/docs/guide/custom-font.md +++ /dev/null @@ -1,66 +0,0 @@ - - -# 自定义字体 - -# 前端 - -前端使用自定义字体非常简单,和浏览器一样,使用 [font-family](https://www.w3schools.com/cssref/pr_font_font-family.asp) 样式即可。 - -有两个范例:[hippy-react-demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/components/Text/index.jsx#L49)、[hippy-vue-demo](https://github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-p.vue#L41) - -但是如果要使用操作系统自带以外的字体,需要单独整合一下,继续阅读下面内容。 - -# iOS - -## 整合字体文件 - -打开 iOS 工程,新建一个 `fonts` 目录,并将字体文件拖动到该目录中。按照截图,建立字体引用即可,确保 Target 正确。 - -![拷贝字体](https://puui.qpic.cn/vupload/0/1581839496811_kt5r2ikktko.png/0) - -然后点击项目中的字体文件,并再次确认 Target 正确。 - -![确认字体](https://puui.qpic.cn/vupload/0/1581839940042_5lhnniq1lxw.png/0) - -## 检查项目配置 - -确认项目的设置的 `Build Phases` 里字体文件正确整合。 - -![项目设置](https://puui.qpic.cn/vupload/0/1581840059761_c4iuwaq27co.png/0) - -## 将字体添加到 Info.plist - -将准确的字体文件名加入 `Info.plist` 的 `Fonts provided by application` 字段,如果没有这行的话,需要手工 `Add row` 添加一行。 - -![Info.plist](https://puui.qpic.cn/vupload/0/1581840249218_6ltk8mud643.png/0) - -## 验证字体正确性 - -如果一切都正确,前端应该已经能正常显示自定义字体了,不过有的时候还是显示不了,其中最常见的,就是 Font Family 参数值不对,因为**字体文件名 !== Font Family**。 - -有个简单办法可以进行校验,将 Font Family 全部列出来检查。 - -在 `AppDelegate.m` 的 `application didFinishLaunchingWithOptions` 方法中加上以下代码,在 `Debug` 菜单中打开 `Debug Area` 下 `Active Console`(按下 Command + Shift +C 可以快速打开)即可打印所有 Font Family。 - -```objectivec -for (NSString* family in [UIFont familyNames]) -{ - NSLog(@"%@", family); - for (NSString* name in [UIFont fontNamesForFamilyName: family]) - { - NSLog(@" %@", name); - } -} -``` - -![检查字体](https://puui.qpic.cn/vupload/0/1581840956463_08b8j5p8cp9.png/0) - -# Android - -## 整合字体文件 - -Android 只需要在静态资源 `assets` 目录中建立 `fonts` 目录,然后把字体文件拷贝进去即可。 - -需要注意的是,字体文件名需要和 FontFamily 一致,因为 Android 虽然也可以做字体文件名映射,但是字体和文件名一致无疑是最简单的办法。 - -> 官方 demo 的字体放在 [res/fonts](https://github.com/Tencent/Hippy/tree/master/examples/android-demo/res) 目录下,是因为编译脚本[将 `res` 目录下的文件直接拷贝到 `assets` 目录](https://github.com/Tencent/Hippy/blob/master/examples/android-demo/build.gradle#L35)下了,所以 `res/assets` 就变成 `assets/assets` 目录,为了让字体目录正确拷贝进 `assets` 静态资源目录,只能让它放在 `res` 下。 diff --git a/docs/guide/debug.md b/docs/guide/debug.md deleted file mode 100644 index a7cd860ffe3..00000000000 --- a/docs/guide/debug.md +++ /dev/null @@ -1,135 +0,0 @@ -# 前端调试 - -# Hippy 调试原理 - -Hippy 是直接运行于手机的 JS 引擎中的,在 Android 上使用 WebSocket 通过 [Chrome DevTools Protocol](//chromedevtools.github.io/devtools-protocol/) 与电脑上的 Chrome 进行通讯调试,而 iOS 上使用内置 的 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore) 与 [Safari](//www.apple.com.cn/cn/safari/) 连接进行调试。 - -Hippy中运行的JS代码可以来源于本地文件(local file),或者远程服务地址(server)。 - -[hippy-debug-server](//www.npmjs.com/package/hippy-debug-server) 就是为了解决调试模式下终端模式获取调试用 JS 文件,以及将 [Chrome DevTools Protocol](//chromedevtools.github.io/devtools-protocol/) 传输回调试器而诞生。 - -# 项目初始化 - -1. 运行 `git clone https://github.com/Tencent/Hippy.git` - - !> Hippy 仓库使用 [git-lfs](https://git-lfs.github.com/) 来管理 so,gz,otf,png,jpg 文件, 请确保你已经安装 [git-lfs](https://git-lfs.github.com/)。 - -2. 项目根目录运行命令 `npm install` 安装前端依赖。 -3. 项目根目录运行命令 `lerna bootstrap` 安装前端每一个 package 依赖。(Hippy 采用 [Lerna](https://lerna.js.org/) 管理多JS仓库,如果出现 `lerna command is not found`, 先执行 `npm install lerna -g`) -4. 项目根目录运行命令 `npm run build` 编译前端 SDK 包。 -5. 选择一个前端范例项目来进行编译,项目根目录运行 `npm run buildexample -- [hippy-react-demo|hippy-vue-demo]`。 - -# 终端环境准备 - -我们推荐在终端代码中留一个后门,通过一定条件触发后进入调试模式,具体代码可以参考 [iOS](//github.com/Tencent/Hippy/blob/master/examples/ios-demo/HippyDemo/TestModule.m#L36) 和 [Android](//github.com/Tencent/Hippy/blob/master/examples/android-demo/example/src/main/java/com/tencent/mtt/hippy/example/module/TestModule.java#L31),这里实现了一个 `TestModule`,当前端调用它的 `debug` 方法时就会进入调试模式,而终端可以通过其它方式进入。 - -# 调试 Javascript - -尽管 Hippy 是前端框架,但依然运行在终端中,如果终端提供了后门可以直接链接调试服务,那可以直接用终端后门连接终端进行调试。 - -这里仅以官方范例为准,讲述如何进行调试。 - -!> 需要注意的是:官方范例为测试最新功能,将 `@hippy/react` 和 `@hippy/vue` 做了个 [alias 到 packages 目录](https://github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.dev.js#L76),如果调试官方范例,需要先在 Hippy 项目根目录下使用 ```npm run build``` 编译前端 SDK;或者删除范例的 `scripts` 目录中对 packages 的 alias,Hippy-Vue 范例则需要将 `vue` 和 `vue-router` 分别映射到 `@hippy/vue` 和 `@hippy/vue-router` - -## iOS - -因为 Hippy 需要经过网络传输调试协议,我们建议使用 iOS 模拟器进行调试,真机上虽然也可以但会要求手机和开发机在同一个网络内,并且需要在手机中配置连接获取开发机上的调试服务。 - -同时,本方法也可以用 Safari 进行内置包(不连接开发机上的调试 JS 包)的调试。 - -具体流程: - -1. 点击 [Xcode on Mac AppStore](//apps.apple.com/cn/app/xcode/id497799835?l=en&mt=12) 下载安装 Xcode。 -2. 使用 Xcode 打开[Hippy iOS 范例工程](//github.com/Tencent/Hippy/tree/master/examples/ios-demo) 中的 `HippyDemo.xcodeproj` 工程文件,并点击运行,正常情况下应该可以启动模拟器,并运行之前内置的 Hippy 前端代码。 -3. 打开 `examples` 下的前端范例工程 [hippy-react-demo](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) 或者 [hippy-vue-demo](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo),通过 `npm i` 安装完依赖之后,使用 `npm run hippy:dev` 启动编译,并另开一个终端窗口,运行 `npm run hippy:debug` 启动调试服务。 -4. 回到模拟器,点击前端工程中的调试按钮,即可进入调试状态。hippy-react 有一个单独的页面,hippy-vue 在右上角。以 hippy-react 为例: - - ![iOS 模拟器](//puui.qpic.cn/vupload/0/1577796352672_tmjp70r3bma.png/0) - -5. 打开 Safari,首先确保 `预置` -> `高级` -> `显示开发菜单` 正常勾上。 -6. 然后按图打开 Safari 调试器即可开始调试工作。 - - Safari 调试器 - -7. 当 JS 文件发生改动时,自动编译会执行,但是终端却无法获知 JS 文件已经发生改变,需要通过按 `Command + R`刷新 或者 `Command + D` 键调起 Reload 面板刷新 - -> 如果 `Command + D` 无法调起面板,可以点击 `Device` -> `Shake` 强制调起 Reload 面板 - -### 远程调试 - -默认情况下,iOS使用本地服务地址进行代码调试。Hippy客户端从服务器地址获取JS代码并运行Hippy业务。但是用户可能遇到真机调试的问题,这就需要真机连接远程地址。 -在`TestModuel.m`文件中,打开`REMOTEDEBUG`宏,并填入Hippy服务地址与业务名称,即可实现远程调试。 - -## Android - -Android 使用了 [adb](//developer.android.com/studio/command-line/adb) 的端口映射功能,解决了真机到开发机通讯问题,反而因为 ARM 模拟器运行效率问题,更加推荐使用真机进行调试。 - -具体流程: - -1. 下载安装 [Android Studio](//developer.android.com/studio) (可能需要翻墙,也可以通过其它途径下载)。 -2. 通过 Android Studio 打开[Hippy Android 范例工程](//github.com/Tencent/Hippy/tree/master/examples/android-demo),当提示 ToolChain 需要更新时全部选择拒绝,安装好 SDK、NDK、和 cmake 3.6.4。 -3. 通过数据线插上 Android 手机,并在 Android Studio 中点击运行,正常情况下手机应该已经运行起 `Hippy Demo` app。*编译如果出现问题请参考 [#39](//github.com/Tencent/Hippy/issues/39)*。 -4. 回到手机上,首先确保手机的 `USB 调试模式` 已经打开 -- 一般在关于手机页面里连续点击 `Build` 可以进入`开发者模式`,再进入`开发者模式`界面后打开 `USB 调试模式`。 -5. 执行 `adb reverse --remove-all && adb reverse tcp:38989 tcp:38989` 确保 38389 端口不被占用。 -6. 打开前端范例工程 [hippy-react-demo](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) 或者 [hippy-vue-demo](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo),通过 `npm i` 安装完依赖之后,使用 `npm run hippy:dev` 启动编译,并另开一个终端窗口,运行 `npm run hippy:debug` 启动调试服务。 -7. 回到手机上,点击前端工程中的调试按钮,即可进入调试状态。hippy-react 有一个单独的页面,hippy-vue 在右上角。以 hippy-react 为例: - - Android 调试 - -8. 然后打开 [Chrome](//www.google.com/chrome/),输入 `chrome://inspect`,首先确保 `Discover USB devices` 的复选框呈未选中状态,然后确保 `Discover network targets` 选中,并在右侧 `Configure` 按钮的弹窗中包含了 `localhost:38989` 调试服务地址,下方的 `Remote Target` 中应该会出现 `Hippy debug tools for V8` 字样,点击下方的 `inspect` 链接即可打开 Chrome 调试器。 - - ![Chrome inspect](//puui.qpic.cn/vupload/0/1577798490075_9tezu60gzzo.png/0) - -9. 当 JS 文件发生改动时,自动编译会执行,但是终端却无法获知 JS 文件已经发生改变,点击界面上的`小圆点`,选择弹出菜单中的 `Reload` 重新加载 JS 代码。 - -# Elements 可视化审查 - -> Android 最低支持版本 2.9.0 - -Hippy 实现了节点和属性从前端到终端的映射,可以在 Chrome Inspector 上进行 Elements 的可视化检查。 - -Inspect Elements -
    -
    - -# Live-Reload 能力 - -> 最低支持版本 2.9.0 - -当开发者修改了前端代码后,我们可以通过 `live-reload` 能力帮助我们在代码变更时自动重载业务实例,步骤如下: - -+ webpack 配置文件在 entry 末端引入 `@hippy/hippy-live-reload-polyfill` - -```javascript -module.exports = { - mode: 'development', - entry: { - index: ['regenerator-runtime', 'index.js', '@hippy/hippy-live-reload-polyfill'], - } -} -``` - -+ 启动调试 server 增加 `--live` 参数,这时候会启动一个 `38999` 端口的 Websocket - -```json -{ - "scripts": { - "hippy:debug": "hippy-debug --live" - } -} -``` - -+ 对于 Android 调试,打开 `Enable Live Reload` 开关,(`2.9.1` 版本后业务代码启动后会自动监听,无需再用该开关) - -Android Debug -
    - -+ 对于 iOS 调试,业务代码启动后会自动监听 - -# 框架日志输出 - -无论是 hippy-react 还是 hippy-vue 都将和终端通讯的信息进行输出,包含了前终端的节点操作、事件收发。这些日志对于业务调试其实很有帮助,可以让开发了解到前端框架是如何将代码转译成终端可以理解的语法,当遇到问题时应先检查框架通信日志,基本可以定位到大部分问题。 - -如果需要关闭日志,可以在 hippy-react 的 new Hippy 启动参数中增加 `silent: true`,或者 hippy-vue 项目的入口文件中,开启 `Vue.config.silent = true;`。 - -Communication Info diff --git a/docs/guide/integration.md b/docs/guide/integration.md deleted file mode 100644 index df9f5aa8691..00000000000 --- a/docs/guide/integration.md +++ /dev/null @@ -1,314 +0,0 @@ -# 开始接入 - -Hippy 已经提供了完整的[前端和终端范例](//github.com/Tencent/Hippy/tree/master/examples),可直接基于我们现有的范例开始 App 开发。若想快速体验 Hippy,可按照 [README 步骤](https://github.com/Tencent/Hippy/blob/master/README.zh_CN.md#-%E5%BC%80%E5%A7%8B) 将 DEMO 运行起来 。 - -如果要在已有的 App 里整合 Hippy,请继续阅读下面的`终端集成`章节。需要提醒的是,在 Hippy 体系下,终端开发转变为`平台开发`,前端开发变成`业务开发`,`平台开发`提供通用的能力,供`业务开发`完成实际交互。 - -# 终端集成 - -如果要接入 Hippy 到现有终端项目,请参考 [Android](android/integration.md) 和 [iOS](ios/integration.md) 集成教程。 - -# 前端接入 - -Hippy 同时支持 React 和 Vue 两种语法框架,通过 [@hippy/react](//www.npmjs.com/package/@hippy/react) 和 [@hippy/vue](//www.npmjs.com/package/@hippy/vue) 两个包提供实现。 - -> 从工程上我们依然称呼它们为 `hippy-react` 和 `hippy-vue`。 - -## hippy-react - -[[hippy-react 介绍]](hippy-react/introduction.md) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) - -hippy-react 工程暂时只能通过手工配置初始化(后期会提供基于 [yeoman](//yeoman.io/) 的脚手架),建议直接 clone 范例工程并基于它进行修改。 - -当然,也可以从头开始进行配置。 - -### 准备 hippy-react 运行时依赖 - -请使用 `npm i` 安装以下 npm 包。 - -| 包名 | 说明 | -| ------------------- | -------------------------- | -| @hippy/react | hippy-react 运行时和渲染层 | -| react | react 本体 | -| regenerator-runtime | async/await 转换运行时 | - -### 准备 hippy-react 编译时依赖 - -以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: - -必须的: - -| 包名 | 说明 | -| --------------------------------------- | ---------------------------------------------- | -| @babel/plugin-proposal-class-properties | Babel 插件 - 支持仍在草案的 Class Properties | -| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | -| @babel/preset-react | Babel 插件 - 转译 JSX 到 JS | -| @hippy/debug-server | Hippy 前终端调试服务 | -| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | -| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | -| webpack | Webpack 打包程序 | -| webpack-cli | Webpack 命令行 | - -可选的: - -| 包名 | 说明 | -| ----------------------------------- | ------------------------------------------ | -| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | -| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 -| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | -| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | -| file-loader | 静态文件加载 | -| url-loader | 静态文件以 Base64 形式加载 | - -### hippy-react 编译配置 - -当前 hippy-react 采用 `Webpack 4`构建,配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 - -#### hippy-react 终端开发调试用编译配置 - -该配置展示了将 Hippy 运行于终端的最小化配置。 - -| 配置文件 | 说明 | -| ------------------------------------------------------------ | ---------- | -| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | - -#### 终端线上包配置 - -线上包和开发调试用包主要有两个区别: - -1. 开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 -2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减少业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。需要说明的是生成的 `vendor` 包正常情况下是不需要特别更新的,但是如果更新了也要注意一下向上兼容性,不要因为分包导致业务崩溃。 - -| 配置文件 | 说明 | -| ------------------------------------------------------------ | ----------------------------- | -| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | -| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | -| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | -| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | -| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | - -如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 - -!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本。 - -### hippy-react 入口文件 - -入口文件非常简单,只是从 hippy-react 里初始化一个 Hippy 实例。注意,入口文件组件需要通过单节点包裹,如下: - -```js -import { Hippy } from '@hippy/react'; -import App from './app'; - -new Hippy({ - appName: 'Demo', // 终端分配的业务名称 - entryPage: App, // 对应业务启动时的组件 - silent: false, // 设置为 true 可以关闭框架日志输出 -}).start(); - -// P.S. entryPage需要通过单节点包裹,不能用数组的形式,例如 -import React from 'react'; -import { - View, - Text, -} from '@hippy/react'; -export default function app() { - // 入口文件不要使用这种形式,非入口文件可以使用 - return [ - , - test test - ]; - // 修改成通过单节点包裹 - return ( - , - test test - ); -} - -``` - -### hippy-react npm 脚本 - -最后在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/package.json#L13) 中补上几个快速的 npm 脚本就可以了,这里以 `hippy:`开头做好了范例,这里顺道做了一个到 [hippy-debug-server](//www.npmjs.com/package/hippy-debug-server) 的快速启动命令。 - -```json - "scripts": { - "hippy:debug": "hippy-debug --live", // live 参数会开启 live-reload 监听 - "hippy:dev": "webpack --config ./scripts/hippy-webpack.dev.js", - "hippy:vendor": "webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", - "hippy:build": "webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" - } -``` - -### hippy-react 转 Web - -请参考专门的 [hippy-react 转 Web 章节](hippy-react/web.md)。 - -## hippy-vue - -[[hippy-vue 介绍]](hippy-vue/introduction.md) [[范例工程]](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo) - -hippy-vue 相对简单很多,hippy-vue 只是 [Vue](//vuejs.org) 在终端上的渲染层,组件也基本和浏览器保持一致。可以通过 [vue-cli](//cli.vuejs.org/) 先[创建一个 Web 项目](//cli.vuejs.org/zh/guide/creating-a-project.html),然后加上一些 hippy-vue 的内容就可以直接将网页渲染到终端了。 - -### 准备 hippy-vue 运行时依赖 - -请使用 `npm i` 安装以下 npm 包,保证运行时正常。 - -| 包名 | 说明 | -| --------------------------- | -------------------------------- | -| @hippy/vue | hippy-vue 运行时核心 | -| @hippy/vue-native-components | hippy-vue 的扩展终端组件 | -| @hippy/vue-router | vue-router 在 hippy-vue 上的移植 | - -### hippy-vue 编译时依赖 - -以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: - -必须的: - -| 包名 | 说明 | -| -------------------- | ------------------------------------------ | -| @hippy/debug-server | Hippy 前终端调试服务 | -| @hippy/vue-css-loader | hippy-vue 的 CSS 文本到 JS 语法树转换 | -| @babel/preset-env | Babel 插件 - 根据所设置的环境选择 polyfill | -| @babel/core | Babel - 高版本 ES 转换为 ES6 和 ES5 的转译程序 | -| babel-loader | Webpack 插件 - 加载 Babel 转译后的代码 | -| webpack | Webpack 打包程序 | -| webpack-cli | Webpack 命令行 | - -可选的: - -| 包名 | 说明 | -| ----------------------------------- | ------------------------------------------ | -| case-sensitive-paths-webpack-plugin | Webpack 插件,对 import 文件进行大小写检查 | -| @hippy/hippy-live-reload-polyfill | live-reload 必备脚本 - 会在调试模式编译时注入代码到工程里 | -| @hippy/hippy-dynamic-import-plugin | 动态加载插件 - 拆分出子包用于按需加载 -| @babel/plugin-x | Babel 其余相关插件,如 `@babel/plugin-proposal-nullish-coalescing-operator` 等 | -| file-loader | 静态文件加载 | -| url-loader | 静态文件以 Base64 形式加载 | - -### hippy-vue 编译配置 - -当前 hippy-vue 采用 `Webpack 4`构建(暂时不建议升级到`Weppack 5`),配置全部放置于 [scripts](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/scripts) 目录下,其实只是 [webpack](//webpack.js.org/) 的配置文件,建议先阅读 [webpack](//webpack.js.org/) 官网内容,具备一定基础后再进行修改。 - -#### hippy-vue 终端开发调试用编译配置 - -该配置展示了将 Hippy 运行于终端的最小化配置。 - -| 配置文件 | 说明 | -| ------------------------------------------------------------ | ---------- | -| [hippy-webpack.dev.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.dev.js) | 调试用配置 | - -#### hippy-vue 终端线上包配置 - -线上包和开发调试用包主要有两个区别: - -1. 开启了 production 模式,去掉调试信息,关闭了 `watch`(watch 模式下会监听文件变动并重新打包)。 -2. 终端内很可能不止运行一个 Hippy 业务,所以将共享的部分单独拆出来做成了 `vendor` 包,这样可以有效减少业务包体积,这里使用了 [DllPlugin](//webpack.js.org/plugins/dll-plugin/) 和 [DllReferencePlugin](//webpack.js.org/plugins/dll-plugin/#dllreferenceplugin) 来实现。需要说明的是生成的 `vendor` 包正常情况下是不需要特别更新的,但是如果更新了也要注意一下向上兼容性,不要因为分包导致业务崩溃。 - -| 配置文件 | 说明 | -| ------------------------------------------------------------ | ----------------------------- | -| [vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/vendor.js) | vendor 包中需要包含的共享部分 | -| [hippy-webpack.ios.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.ios.js) | iOS 业务包配置 | -| [hippy-webpack.ios-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.ios-vendor.js) | iOS Vendor 包配置 | -| [hippy-webpack.android.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.android.js) | Android 业务包配置 | -| [hippy-webpack.android-vendor.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/scripts/hippy-webpack.android-vendor.js) | Android Vendor 包配置 | - -如果仔细观察 webpack 配置,可以看出 iOS 和 Android 配置相差不大,但因为 iOS 上受苹果政策影响只能使用 [JavaScriptCore](//developer.apple.com/documentation/javascriptcore)(以下简称 JSC)作为运行环境,而 JSC 是跟随 iOS 操作系统的,无法进行独立升级,低版本 iOS 带的 JSC 甚至无法完整支持 ES6,所以需要输出一份 ES5 版本的 JS 代码。而 Android 下可以使用独立升级的 [X5](//x5.tencent.com/) 中的 V8 作为运行环境,就可以直接使用 ES6 代码了。 - -!> **特别说明:** JS 可以使用的语法受到 iOS 覆盖的最低版本的影响,绝大多数能力可以通过 `@babel/preset-env` 自动安装 polyfill,但是部分特性不行,例如要使用 [Proxy](//caniuse.com/#feat=proxy),就无法覆盖 iOS 10 以下版本。 - -### hippy-vue 入口文件 - -hippy-cli 初始化的项目自带了一个 [Web 端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/main.js),可以保留着用来启动 Web 端网页,但是因为 hippy-vue 的启动参数不一样,需要专门的 [终端入口文件](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/main-native.js)来加载一些终端上用到的模块。 - -```js -import Vue from 'vue'; -import VueRouter from 'vue-router'; -import HippyVueNativeComponents from '@hippy/vue-native-components'; -import App from './app.vue'; -import routes from './routes'; -import { setApp } from './util'; - -// 禁止框架调试信息输出,取消注释即可使用。 -// Vue.config.silent = true; - -Vue.config.productionTip = false; - -// Hippy 终端组件扩展中间件,可以使用 modal、view-pager、tab-host、ul-refresh 等终端扩展组件了。 -Vue.use(HippyVueNativeComponents); -Vue.use(VueRouter); - -const router = new VueRouter(routes); - -/** - * 声明一个 app,这是同步生成的 - */ -const app = new Vue({ - // 终端指定的 App 名称 - appName: 'Demo', - // 根节点,必须是 Id,当根节点挂载时才会触发上屏 - rootView: '#root', - // 渲染自己 - render: h => h(App), - // iPhone 下的状态栏配置 - iPhone: { - // 状态栏配置 - statusBar: { - // 禁用状态栏自动填充 - // disabled: true, - - // 状态栏背景色,如果不配的话,会用 4282431619,也就是 #40b883 - Vue 的绿色 - // 因为运行时只支持样式和属性的实际转换,所以需要用下面的转换器将颜色值提前转换,可以在 Node 中直接运行。 - // hippy-vue-css-loader/src/compiler/style/color-parser.js - backgroundColor: 4283416717, - - // 状态栏背景图,要注意这个会根据容器尺寸拉伸。 - // backgroundImage: '//mat1.gtimg.com/www/qq2018/imgs/qq_logo_2018x2.png', - }, - }, - // 路由 - router, -}); - -/** - * $start 是 Hippy 启动完以后触发的回调 - * Vue 会在 Hippy 启动之前完成首屏 VDOM 的渲染,所以首屏性能非常高 - * 在 $start 里可以通知终端说已经启动完成,可以开始给前端发消息了。 - */ -app.$start((/* app */) => { - // 这里干一点 Hippy 启动后的需要干的事情,比如通知终端前端已经准备完毕,可以开始发消息了。 - // setApp(app); -}); - -/** - * 保存 app 供后面通过 app 接受来自终端的事件。 - * - * 之前是放到 $start 里的,但是有个问题时因为 $start 执行太慢,如果首页就 getApp() 的话可能会 - * 导致获得了 undefined,然后监听失败。所以挪出来了。 - * - * 但是终端事件依然要等到 $start 也就是 Hippy 启动之后再发,因为之前桥尚未建立,终端发消息前端也 - * 接受不到。 - */ -setApp(app); -``` - -### hippy-vue npm script - -最后在 [package.json](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/package.json#L13) 中补上几个快速的 npm 脚本就可以了,这里以 `hippy:`开头做好了范例,这里顺道做了一个到 [hippy-debug-server](//www.npmjs.com/package/hippy-debug-server) 的快速启动命令。 - -```json - "scripts": { - "hippy:debug": "hippy-debug --live", // live 参数会开启 live-reload 监听 - "hippy:dev": "webpack --config ./scripts/hippy-webpack.dev.js", - "hippy:vendor": "webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js", - "hippy:build": "webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js" - }, -``` - -### 路由 - -`@hippy/vue-router` 完整支持 vue-router 中的跳转功能,具体请参考 [hippy-vue-router](hippy-vue/router.md) 文档。 - -### hippy-vue 转 Web - -hippy-vue 项目基于 vue-cli 生成的 Web 项目,之前的 Web 能力可以直接使用,对于使用 vue-cli 生产的项目,可以参考[官方文档](//cli.vuejs.org/zh/guide/build-targets.html)。 diff --git a/docs/guide/layout.md b/docs/guide/layout.md deleted file mode 100644 index ab7dcc787cc..00000000000 --- a/docs/guide/layout.md +++ /dev/null @@ -1,118 +0,0 @@ -# 盒模型 - -Hippy 为了方便前端开发便于理解,样式也采用了 CSS 的盒模型构建。当 Hippy 在进行布局的时候,渲染引擎会根据 CSS-Box 模型将所有元素表示为一个矩形盒子,样式配置决定这些盒子的大小,位置以及属性(颜色,背景,边框尺寸...). - -在 Hippy 中,使用标准盒模型描述这些矩形盒子中的每一个。这个模型描述了元素所占空间的内容。每个盒子有四个边:外边距边, 边框边, 内填充边 与 内容边。 - -> PS: Hippy 的盒模型布局对应的是CSS的 `box-sizing` 属性的 `border-box` 类型,具体表现与宽高边距计算可参考[MDN文档 box-sizing](//developer.mozilla.org/zh-CN/docs/Web/CSS/box-sizing)。 - -![盒模型](//res.imtt.qq.com/hippydoc/img/border-box.png) - -* [width](style/layout.md?id=width) -* [height](style/layout.md?id=height) -* [padding](style/layout.md?id=padding) -* [margin](style/layout.md?id=margin) -* [border](style/layout.md?id=borderWidth) - -# 布局(Flex) - -Hippy 中,为了方便移动端编写布局,所以默认支持了现在移动端最流行的 `Flex` 布局。同时,因为仅支持 `Flex` 布局,所以不需要手写 `display: flex` 即可使用 -Flex 布局与 Web 的 Flex 类似,它们都旨在提供一个更加有效的方式制定、调整和分布一个容器里的项目布局,即使他们的大小是未知或者是动态的。Flex 规定了弹性元素如何伸长或缩短以适应flex容器中的可用空间。CSS 版教程文档可以参考[这篇](http://www.w3cplus.com/css3/a-visual-guide-to-css3-flexbox-properties.html) - -## flexDirection - -flexDirection 属性指定了内部元素是如何在 flex 容器中布局的,定义了主轴的方向(水平或垂直)。 - -> 注意:Hippy 的 flexDirection 与 Web的 flex-direction Web 默认为 `row`, Hippy 默认为 `column`。 - -flexDirection -
    -
    - -| 类型 | 必需 |默认| -| ------ | -------- |---| -| enum('column', 'row') | 否 |'column'| - -## alignItems - -alignItems 定义了伸缩项目可以在伸缩容器的当前行的侧轴上对齐方式 - -* flex-start(默认值):伸缩项目在侧轴起点边的外边距紧靠住该行在侧轴起始的边。 -* flex-end:伸缩项目在侧轴终点边的外边距靠住该行在侧轴终点的边 。 -* center:伸缩项目的外边距盒在该行的侧轴上居中放置。 -* baseline:伸缩项目根据他们的基线对齐。 -* stretch:伸缩项目拉伸填充整个伸缩容器。此值会使项目的外边距盒的尺寸在遵照「min/max-width/height」属性的限制下尽可能接近所在行的尺寸。 - -| 类型 | 必需 |默认| -| ------ | -------- |---| -| enum('flex-start', 'flex-end', 'center', 'baseline', 'stretch') | 否 |'flex-start'| - -## justifyContent - -justifyContent 定义了伸缩项目沿着主轴线的对齐方式。 - -* flex-start(默认值):伸缩项目向一行的起始位置靠齐。 -* flex-end:伸缩项目向一行的结束位置靠齐。 -* center:伸缩项目向一行的中间位置靠齐。 -* space-between:伸缩项目会平均地分布在行里。第一个伸缩项目一行中的最开始位置,最后一个伸缩项目在一行中最终点位置。 -* space-around:伸缩项目会平均地分布在行里,两端保留一半的空间。 - -| 类型 | 必需 |默认| -| ------ | -------- |---| -| enum('flex-start', 'flex-end', 'center', 'baseline', 'stretch') | 否 |'flex-start'| - -## flex - -flex 属性数值, 定义了 flex 容器的子节点项可以占用容器中剩余空间的大小。默认值为0,即不占用剩余空间。如果定义了 flex 数字且为正数的时候,则 - -```text -每个元素占用的剩余空间=自己的 flex 数值 / 所有同一级子容器的 flex 数字之和 -``` - -当 flex 设置为-1的时候,默认情况会显示正常宽高。然而, 如果剩余空间不足的话,此设置了`flex: -1`的容器将会收缩到其 minWidth 的宽度与 minHeight 的高度来显示。 - -| 类型 | 必需 |默认| -| ------ | -------- |---| -| number| 否 |0| - -## flexBasis - -flexBasis 设置伸缩基准值,剩余的空间按比率进行伸缩,负值无效,只能为 0 或正数。 - -| 类型 | 必需 |默认| -| ------ | -------- |---| -| number, string| 否 |auto| - -## flexGrow - -flexGrow 定义伸缩项目的扩展能力。它接受一个不带单位的值做为一个比例。主要用来决定伸缩容器剩余空间按比例应扩展多少空间。 - -如果所有伸缩项目的 flex-grow 设置了 1,那么每个伸缩项目将设置为一个大小相等的剩余空间。如果你给其中一个伸缩项目设置了 flex-grow 值为 2,那么这个伸缩项目所占的剩余空间是其他伸缩项目所占剩余空间的两倍。 - -| 类型 | 必需 |默认| -| ------ | -------- |---| -| number| 否 |0| - -## flexShrink - -flexShrink 定义伸缩项目收缩的能力。 - -> 注意:Hippy 中 flexShrink 默认值为 0,与Web标准有差异 - -| 类型 | 必需 |默认| -| ------ | -------- |---| -| number| 否 |0| - -# 长度单位 - -Hippy 现在暂时不支持百分比的长度值,只支持具体数值(number)。单位为 dp,具体换算公式为: - -```text -实际真机长度值 = 屏幕缩放比例 * Hippy 样式长度值 -``` - -屏幕缩放比例 可以通过 `PixelRatio.get()`(hippy-react) 或 `Vue.Native.PixelRatio`(hippy-vue) 获取,如 iPhone 8 为 2,iPhone X 为 3,以 iPhone 8 为例: - -* 屏幕真实宽度为 750px -* PixelRatio 为 2 -* 所以 Hippy 的全屏宽度为`750/2 = 375` diff --git a/docs/guide/support.md b/docs/guide/support.md deleted file mode 100644 index 94341f20778..00000000000 --- a/docs/guide/support.md +++ /dev/null @@ -1,12 +0,0 @@ -# 技术支持 - -# Github - -我们鼓励在 [Issue](//github.com/Tencent/Hippy/issues) 里汇报使用问题。 -或者在提交 [Pull Request](//github.com/Tencent/Hippy/pulls),一起来建设Hippy。 - -# QQ 群 - -也可以加入 QQ 群 [784894901](//shang.qq.com/wpa/qunwpa?idkey=ce9cd2eb06fd6da26a1a63b70da82edd132964d22998e5154e533822f7b757cc) - -[![QQ群](//puui.qpic.cn/vupload/0/1577700402806_3qd3bjxmlq7.png/0)](//shang.qq.com/wpa/qunwpa?idkey=ce9cd2eb06fd6da26a1a63b70da82edd132964d22998e5154e533822f7b757cc) diff --git a/docs/hippy-react/_sidebar.md b/docs/hippy-react/_sidebar.md deleted file mode 100644 index 18163a7e3b5..00000000000 --- a/docs/hippy-react/_sidebar.md +++ /dev/null @@ -1,12 +0,0 @@ - - -* [介绍](hippy-react/introduction.md) -* [组件](hippy-react/components.md) -* [模块](hippy-react/modules.md) -* [样式](hippy-react/style.md) -* [终端事件](hippy-react/native-event.md) -* [动画方案](hippy-react/animation.md) -* [手势系统](hippy-react/gesture.md) -* [自定义组件和模块](hippy-react/customize.md) -* [转 Web](hippy-react/web.md) -* [从 React Native 迁移](hippy-react/migrate-from-rn.md) diff --git a/docs/hippy-react/animation.md b/docs/hippy-react/animation.md deleted file mode 100644 index a281ff95723..00000000000 --- a/docs/hippy-react/animation.md +++ /dev/null @@ -1,194 +0,0 @@ -# 动画方案 - -## 原理 - -Hippy 的动画则是完全由前端传入动画参数,由终端控制每一帧的计算和排版更新,减少了前端端与终端的通信次数,因此也大大减少动画的卡顿。 - -## 酷炫的效果 - -* 关注动画 - -关注动画 - -* 点赞微笑动画 - -点赞微笑 - -* 进度条动画 - -PK进度条动画 - -## 让我们开始吧 - -在 Hippy 上实现一个动画分为三个步骤: - -1. 通过 Animation 或 AnimationSet 定义动画 -2. 在 render() 时,将动画设置到需要产生动画效果的控件属性上 -3. 通过 Animation 的 start 方法启动动画,与通过 destroy 方法停止并销毁动画; - -## 示例代码 - -```js -import { Animation, StyleSheet } from "@hippy/react"; -import React, { Component } from "react"; - -export default class AnimationExample extends Component { - componentDidMount() { - // 动画参数的设置 - this.verticalAnimation = new Animation({ - startValue: 0, // 动画开始值 - toValue: 100, // 动画结束值 - duration: 500, // 动画持续时长 - delay: 360, // 至动画真正开始的延迟时间 - mode: "timing", // 动画模式,现在只支持timing - timingFunction: "linear", // 动画缓动函数 - }); - this.horizonAnimation = new Animation({ - startValue: 0, // 开始值 - toValue: 100, // 动画结束值 - duration: 500, // 动画持续时长 - delay: 360, // 至动画真正开始的延迟时间 - mode: "timing", // 动画模式,现在只支持timing - timingFunction: "linear", // 动画缓动函数 - }); - this.scaleAnimationSet = new AnimationSet({ - children: [ - { - animation: new Animation({ - startValue: 1, - toValue: 1.4, - duration: 200, - delay: 0, - mode: "timing", - timingFunction: "linear", - }), - follow: false, // 配置子动画的执行是否跟随执行 - }, - { - animation: new Animation({ - startValue: 1.4, - toValue: 0.2, - duration: 210, - delay: 200, - mode: "timing", - timingFunction: "linear", - }), - follow: true, - }, - ], - }); - } - - componentWillUnmount() { - // 如果动画没有销毁,需要在此处保证销毁动画,以免动画后台运行耗电 - this.scaleAnimationSet && this.scaleAnimationSet.destroy(); - this.horizonAnimation && this.horizonAnimation.destroy(); - this.verticalAnimation && this.verticalAnimation.destroy(); - } - - render() { - return ( - - - - - - { - this.verticalAnimation.start(); - }} - > - 水平位移动画 - - { - this.horizonAnimation.start(); - }} - > - 垂直位移动画 - - { - this.scaleAnimationSet.start(); - }} - > - 图形形变动画 - - - - ); - } -} - -// 样式代码省略 -``` - -`Animation` 和 `AnimationSet` 都是赋予 hippy 组件的单个样式属性(如 width,height,left,right)动画能力的模块。 - -`Animation`与`AnimationSet`的不同点在于`Animation`只是单个动画模块,`AnimationSet`为多个`Animation`的动画模块组合,支持同步执行或顺序执行多个`Animation`动画 - -Hippy 的动画能力支持位移,变形,旋转等功能,且因为动画对应的是样式属性,与支持动画集合`AnimationSet`,所以可以更加灵活地制作出炫丽的动画效果~ - -## 属性 - -Animation 支持的动画配置包括: - -* mode :动画模式,当前仅支持“timing”模式,即随时间改变控件的属性,默认配置即为"timing"; -* delay :动画延迟开始的时间,单位为毫秒,默认为 0,即动画 start 之后立即执行; -* startValue :动画开始时的值,可为 Number 类型或一个 Animation 的对象,如果指定为一个 Animation 时,代表本动画的初始值为其指定的动画结束或中途 cancel 后的所处的动画值(这种场景通常用于 AnimationSet 中实现多个连续变化的动画); -* toValue :动画结束时候的值,类型只能为 Number; -* valueType :动画的开始和结束值的单位类型,默认为空,代表动画起止的单位是普通数值,另外可取值有: - - * “rad” :代表动画参数的起止值为弧度; - * “deg” :代表动画参数的起止值为度数; - * “color” :代表动画参数的起止值为颜色; - -* duration :动画的持续时间,单位为毫秒,默认为 0; - -* timingFunction :动画插值器类型,默认为“linear”,可选值包括: - - * “linear”:使用线性插值器,动画将匀速进行; - * “ease-in”:使用加速插值器,动画速度将随时间逐渐增加; - * “ease-out”:使用减速插值器,动画速度将随时间逐渐减小; - * “ease-in-out”:使用加减速插值器,动画速度前半段先随时间逐渐增加,后半段速度将逐渐减小; - * “cubic-bezier”:(最低支持版本 2.9.0)使用自定义贝塞尔曲线,与 [css transition-timing-function 的 cubic-bezier](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function) 一致; - -* repeatCount :动画的重复次数,默认为 0,即不重复播放,为"loop"时代表无限循环播放; - -AnimationSet 为实现动画集合添加了 3 个属性 - -* children :接收一个 Array,用于指定子动画,该 Array 的每个元素包括: - * animation:子动画对应的 Animation 对象; - * follow:配置子动画的执行是否跟随执行,为 true,代表该子动画会等待上一个子动画执行完成后在开始,为 false 则代表和上一个子动画同时开始,默认为 false; - -## 方法 - -除了动画配置,Animation 与 AnimationSet 都提供了一系列控制和监听动画过程的方法: - -* start() :启动动画,注意,如果调用该方法前,动画尚未经过 render 赋值给相应控件或者该动画已经 destroy,那 start 将不会生效; -* destroy():停止并销毁一个动画; -* updateAnimation( newConfig ) :修改动画的配置参数,注意,如果动画已经 start 或 destroy,更新操作将不会生效,该方法接收的 newConfig 参数结构与 Animation 构造函数中动画配置参数一致; -* removeEventListener():撤销所有注册的动画监听; - -## 回调 - -* onAnimationStart(callback):注册一个动画的监听回调,在动画开始时将会回调 callback; -* onAnimationEnd(callback):注册一个动画的监听回调,在动画结束时将会回调 callback; -* onAnimationCancel(callback):注册一个动画的监听回调,在动画被取消时将会回调 callback,取消的情况包括:尚未 start 或尚未结束的动画被 destroy 时; -* onAnimationRepeat(callback):注册一个动画的监听回调,当动画开始下一次重复播放时 callback 将被回调; diff --git a/docs/hippy-react/components.md b/docs/hippy-react/components.md deleted file mode 100644 index 808d81358e1..00000000000 --- a/docs/hippy-react/components.md +++ /dev/null @@ -1,532 +0,0 @@ - - -# 组件 - -hippy-react 的组件接近终端,语法上接近 React Native。 - ---- - -# Image - -[[Image 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/Image) - -图片组件,用于显示单张图片。 - -> * 注意: 必须指定样式中的宽度和高度,否则无法工作。 -> * 注意: Android 端默认会带上灰底色用于图片占位,可以加上 `backgroundColor: transparent` 样式改为透明背景。 - -## 基本用法 - -直接加载远程图片: - -```jsx -; -``` - -或者使用本地图片加载能力: - -```jsx -import icon from './qb_icon_new.png'; - - -``` - ->* 本地图片可通过[加载时定义 Loader](//webpack.js.org/concepts/loaders/#inline),或者 webpack 配置 `url-loader` 转换成 base64 加载。 ->* `2.8.1` 版本后支持终端本地图片能力,可通过配置 webpack `file-loader` 加载。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | -| onLayout | 当元素挂载或者布局改变的时候调用,参数为: `{ nativeEvent: { layout: { x, y, width, height } } }`。 | `Function` | `ALL` | -| onLoad | 加载成功完成时调用此回调函数。 | `Function` | `ALL` | -| onLoadStart | 加载开始时调用。 例如, `onLoadStart={() => this.setState({ loading: true })}` | `Function` | `ALL` | -| onLoadEnd | 加载结束后,不论成功还是失败,调用此回调函数。 | `Function` | `ALL` | -| resizeMode | 决定当组件尺寸和图片尺寸不成比例的时候如何调整图片的大小。 | `enum`(cover, contain, stretch, repeat, center) | `ALL` | -| source | uri是一个表示图片的资源标识的字符串,需要用http路径。 现在支持的图片格式有 `png` , `jpg` , `jpeg` , `bmp` , `gif` 。 | `{ uri: string }` | `ALL` | -| defaultSource | 指定当 `Image` 组件还没加载出来 `source` 属性指定的图片的占位符图片,当 `source` 属性指定的图片加载失败时, `Image` 组件会显示 `defaultSource` 属性指定的图片 | `string`:图片 base64 字符串 | `ALL` | -| onError | 当加载错误的时候调用此回调函数,参数为 `{ nativeEvent: { error } }` | `Function` | `ALL` | -| capInsets | 当调整 `Image` 大小的时候,由 `capInsets` 指定的边角尺寸会被固定而不进行缩放,而中间和边上其他的部分则会被拉伸。这在制作一些可变大小的圆角按钮、阴影、以及其它资源的时候非常有用。 | `{ top: number, left: number, bottom: number, right: number }` | `ALL` | -| onProgress | 在加载过程中不断调用,参数为 `{ nativeEvent: { loaded, total } }` | `Function` | `ALL` | -| onTouchDown | 当用户开始触屏控件时(即用户在该控件上按下手指时),将回调此函数,并将触屏点信息作为参数传递进来; 参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchMove | 当用户在控件移动手指时,此函数会持续收到回调,并通过event参数告知控件的触屏点信息;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchEnd | 当触屏操作结束,用户在该控件上抬起手指时,此函数将被回调,event参数也会通知当前的触屏点信息;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchCancel | 当用户触屏过程中,某个系统事件中断了触屏,例如电话呼入、组件变化(如设置为hidden),此函数会收到回调,触屏点信息也会通过event参数告知前端;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | - -## 方法 - -### getSize - -`(uri: string, success: (width: number, height: number) => void, failure?: ErrorFunction) => void` 在显示图片前获取图片的宽高(以像素为单位)。如果图片地址不正确或下载失败, 此方法也会失败。 - -要获取图片的尺寸, 首先需要加载或下载图片(同时会被缓存起来)。这意味着理论上你可以用这个方法来预加载图片,虽然此方法并没有针对这一用法进行优化,而且将来可能会换一些实现方案使得并不需要完整下载图片即可获取尺寸。所以更好的预加载方案是使用下面那个专门的预加载方法。 - -*不适用于静态图片资源。* - -> * `uri`: string - 图片的地址 -> * `success`: (width: number, height: number) => void - 此函数会在获取图片与其宽高成功后被回调 -> * `failure`: ErrorFunction - 此函数会在如获取图片失败等异常情况被回调 - -### prefetch - -`(url: string) => void` 预加载一个远程图片,将其下载到本地磁盘缓存。 - -> * `uri`: string - 图片的地址 - ---- - -# ListView - -[[ListView 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/ListView) - -可复用垂直列表功能,尤其适合大量条目的数据渲染。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- | -------- | -| horizontal | 指定 `ListView` 是否采用横向布局。`default: undefined` | `any` | `Android` | -| initialListSize | 指定在组件刚挂载的时候渲染多少行数据。用这个属性来确保首屏显示合适数量的数据,而不是花费太多帧时间逐步显示出来。 | `number` | `ALL` | -| initialContentOffset | 初始位移值 -- 在列表初始化时即可指定滚动距离,避免初始化后再通过 scrollTo 系列方法产生的闪动。Android 在 `2.8.0` 版本后支持 | `number` | `ALL` | -| bounces | 是否开启回弹效果,默认 `true` | `boolean` | `iOS` | -| overScrollEnabled | 是否开启回弹效果,默认 `true` | `boolean` | `Android` | -| renderRow | 这里的入参是当前row 的index,在这里可以凭借index 获取到具体这一行单元格的数据,从而决定如何渲染这个单元格。 | `(index: number) => Node` | `ALL` | -| getRowStyle | 设置`ListViewItem`容器的样式。当设置了 `horizontal=true` 启用横向 `ListView` 时,需显式设置 `ListViewItem` 宽度 | `(index: number) => styleObject` | `ALL` | -| getRowType | 指定一个函数,在其中返回对应条目的类型(返回Number类型的自然数,默认是0),List 将对同类型条目进行复用,所以合理的类型拆分,可以很好地提升list 性能。 | `(index: number) => number` | `ALL` | -| getRowKey | 指定一个函数,在其中返回对应条目的 Key 值,详见 [React 官文](//reactjs.org/docs/lists-and-keys.html) | `(index: number) => any` | `ALL` | -| preloadItemNumber | 指定当列表滚动至倒数第几行时触发 `onEndReached` 回调。 | `number` | `ALL` | -| onAppear | 当有`ListViewItem`滑动进入屏幕时(曝光)触发,入参返回曝光的`ListViewItem`对应索引值。 | `(index) => any` | `ALL` | -| onDisappear | 当有`ListViewItem`滑动离开屏幕时触发,入参返回离开的`ListViewItem`对应索引值。 | `(index) => any` | `ALL` | -| onWillAppear | 当有`ListViewItem`至少一个像素进入屏幕时(曝光)触发,入参返回曝光的`ListViewItem`对应索引值。 `最低支持版本2.3.0` | `(index) => any` | `ALL` | -| onWillDisappear | 当有`ListViewItem`至少一个像素滑动离开屏幕时触发,入参返回离开的`ListViewItem`对应索引值。 `最低支持版本2.3.0`| `(index) => any` | `ALL` | -| onEndReached | 当所有的数据都已经渲染过,并且列表被滚动到最后一条时,将触发 `onEndReached` 回调。 | `Function` | `ALL` | -| onMomentumScrollBegin | 在 `ListView` 开始滑动的时候调起 | `Function` | `ALL` | -| onMomentumScrollEnd | 在 `ListView` 结束滑动的时候调起 | `Function` | `ALL` | -| onScroll | 当触发 `ListView` 的滑动事件时回调,在 `ListView` 滑动时回调,因此调用会非常频繁,请使用 `scrollEventThrottle` 进行频率控制。 注意:ListView 在滚动时会进行组件回收,不要在滚动时对 renderRow() 生成的 ListItemView 做任何 ref 节点级的操作(例如:所有 callUIFunction 和 measureInAppWindow 方法),回收后的节点将无法再进行操作而报错。横向ListView时,Android在 `2.8.0` 版本后支持 | `(obj: { contentOffset: { x: number, y: number } }) => any` | `ALL` | -| onScrollBeginDrag | 当用户开始拖拽 `ListView` 时调用。 | `Function` | `ALL` | -| onScrollEndDrag | 当用户停止拖拽 `ListView` 或者放手让 `ListView` 开始滑动的时候调用 | `Function` | `ALL` | -| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onScroll` 回调事件 | `number` | `ALL` | -| rowShouldSticky | 在回调函数,根据传入参数index(ListView单元格的index)返回true或false指定对应的item是否需要使用悬停效果(滚动到顶部时,会悬停在List顶部,不会滚出屏幕)。 | `(index: number) => boolean` | `ALL` | -| showScrollIndicator | 是否显示垂直滚动条。 因为目前 ListView 其实仅有垂直滚动一种方向,水平滚动会导致 `onEndReached` 等一堆问题暂不建议使用,所以 `showScrollIndicator` 也仅用来控制是否显示垂直滚动条。 | `boolean` | `ALL` | -| renderPullHeader | 设置列表下拉头部(刷新条),配合`onHeaderReleased`、`onHeaderPulling` 和 `collapsePullHeader`使用, 参考 [DEMO](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/PullHeader/index.jsx)。 | `() => View` | `ALL` | -| onHeaderPulling | 下拉过程中触发, 事件会通过 contentOffset 参数返回拖拽高度,可以根据下拉偏移量做相应的逻辑。 | `(obj: { contentOffset: number }) => any` | `ALL` | -| onHeaderReleased | 下拉超过内容高度,松手后触发。 | `() => any` | `ALL` | -| editable | 是否可编辑,开启侧滑删除时需要设置为 `true`。`最低支持版本2.9.0` | `boolean` | `iOS` | -| delText | 侧滑删除文本。`最低支持版本2.9.0` | `string` | `iOS` | -| onDelete | 在列表项侧滑删除时调起。`最低支持版本2.9.0` | `( nativeEvent: { index: number} ) => void` | `iOS` | - -## 方法 - -### scrollToContentOffset - -`(xOffset: number, yOffset: number: animated: boolean) => void` 通知 ListView 滑动到某个具体坐标偏移值(offset)的位置。 - -> * `xOffset`: number - 滑动到 X 方向的 offset -> * `yOffset`: number - 滑动到 Y 方向的 offset -> * `animated`: boolean - 滑动过程是否使用动画 - -### scrollToIndex - -`(xIndex: number, yIndex: number: animated: boolean) => void` 通知 ListView 滑动到第几个 item。 - -> * `xIndex`: number - 滑动到 X 方向的第 xIndex 个 item -> * `yIndex`: number - 滑动到 Y 方向的 yIndex 个 item -> * `animated`: boolean - 滑动过程是否使用动画 - -### collapsePullHeader - -`() => void` 收起刷新条 PullHeader。当设置了`renderPullHeader`后,每当下拉刷新结束需要主动调用该方法收回 PullHeader。 - ---- - -# Modal - -[[Modal 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/Modal) - -模态弹窗组件。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | -| animated | 弹出时是否需要带动画 | `boolean` | `ALL` | -| animationType | 动画效果 | `enum`(none, slide, fade, slide_fade) | `ALL` | -| supportedOrientations | 支持屏幕翻转方向 | `enum`(portrait, portrait-upside-down, landscape, landscape-left, landscape-right)[] | `ALL` | -| immersionStatusBar | 是否是沉浸式状态栏。 | `boolean` | `ALL` | -| darkStatusBarText | 是否是亮色主体文字,默认字体是黑色的,改成 true 后会认为 Modal 背景为暗色调,字体就会改成白色。 | `boolean` | `ALL` | -| onShow | 在`Modal`显示时会执行此回调函数。 | `Function` | `ALL` | -| onOrientationChange | 屏幕旋转方向改变时执行会回调 | `Function` | `ALL` | -| onRequestClose | 在`Modal`请求关闭时会执行此回调函数,一般时在 Android 系统里按下硬件返回按钮时触发,一般要在里面处理关闭弹窗。 | `Function` | `ALL` | -| primaryKey | - | `string` | `iOS` | -| onDismiss | - | `Function` | `iOS` | -| transparent | 背景是否是透明的 | `boolean` | `ALL` | -| visible | 是否显示 | `boolean` | `ALL` | - ---- - -# RefreshWrapper - -[[RefreshWrapper 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/RefreshWrapper) - -包裹住 `ListView` 提供下滑刷新功能的组件. - -> `RefreshWrapper` 现在只支持包裹一个 `ListView` 组件,暂不支持别的组件的下滑刷新功能。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| ---------- | ---------------------------------------------------- | ---------- | -------- | -| onRefresh | 当`RefreshWrapper`执行刷新操作时,会触发到此回调函数 | `Function` | `ALL` | -| getRefresh | 定义刷新栏的视图表现,返回 `View`, `Text` 等组件。 | `Function` | `ALL` | -| bounceTime | 指定刷新条收回动画的时长,单位为ms | `number` | `ALL` | - -## 方法 - -### refreshCompleted - -`() => void` 调用此方法,告知 RefreshWrapper 已经刷新完毕,RefreshWrapper 将会收起刷新栏。 - -### startRefresh - -`() => void` 调用此方法,手工告知 RefreshWrapper 开始刷新,展开刷新栏。 - ---- - -# ScrollView - -[[Scroll 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/ScrollView) - -滚动视图组件,用于展示不确定高度的内容,它可以将一系列不确定高度的子组件装到一个确定高度的容器中,使用者可通过上下或左右滚动操作查看组件宽高之外的内容。 - -一个包装了平台的 `ScrollView`(滚动视图)的组件,同时还集成了触摸锁定的“响应者”系统。 - -> * 注意:记住 ScrollView 必须有一个确定的高度才能正常工作,因为它实际上所做的就是将一系列不确定高度的子组件装进一个确定高度的容器(通过滚动操作)。要给一个 ScrollView 确定一个高度的话,要么直接给它设置高度(不建议),要么确定所有的父容器都有确定的高度。一般来说我们会给 ScrollView 设置 `flex: 1` 以使其自动填充父容器的空余空间,但前提条件是所有的父容器本身也设置了flex或者指定了高度,否则就会导致无法正常滚动,你可以使用元素查看器来查找问题的原因。 -> * 注意: ScrollView 无法使用 onTouch 系列事件监听触屏行为,但可以用 onScroll 监听滚动行为。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- | -| bounces | 是否开启回弹效果,默认 `true` | `boolean` | `iOS` | -| contentContainerStyle | 这些样式会应用到一个内层的内容容器上,所有的子视图都会包裹在内容容器内。 | `StyleSheet` | `ALL` | -| onMomentumScrollBegin | 在 `ScrollView` 滑动开始的时候调起。 | `Function` | `ALL` | -| onMomentumScrollEnd | 在 `ScrollView` 滑动结束的时候调起。 | `Function` | `ALL` | -| onScroll | 在滚动的过程中,每帧最多调用一次此回调函数。 | `Function` | `ALL` | -| onScrollBeginDrag | 当用户开始拖拽 `ScrollView` 时调用。 | `Function` | `ALL` | -| onScrollEndDrag | 当用户停止拖拽 `ScrollView` 或者放手让 `ScrollView` 开始滑动的时候调用。 | `Function` | `ALL` | -| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onScroll` 回调事件。 | `number` | `ALL` | -| scrollIndicatorInsets | 决定滚动条距离视图边缘的坐标。这个值应该和contentInset一样。 | `{ top: number, left: number, bottom: number, right: number }` | `ALL` | -| pagingEnabled | 当值为 `true` 时,滚动条会停在滚动视图的尺寸的整数倍位置。这个可以用在水平分页上。`default: false` | `boolean` | `ALL` | -| scrollEnabled | 当值为 `false` 的时候,内容不能滚动。`default: true` | `boolean` | `ALL` | -| horizontal | 当此属性为 `true` 的时候,所有的子视图会在水平方向上排成一行,而不是默认的在垂直方向上排成一列 | `boolean` | `ALL` | -| showsHorizontalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏水平的滚动条。`default: true` | `boolean` | `iOS` | -| showsVerticalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏垂直的滚动条。 `default: true` | `boolean` | `iOS` | - -## 方法 - -### scrollTo - -`(x: number, y: number, animated: boolean) => void` 滚动到指定的 X,Y 偏移值,第三个参数为是否启用平滑滚动动画。 - -> * x: number - X 偏移值 -> * y: number - Y 偏移值 -> * animated: boolean - 是否启用平滑滚动动画。 - -### scrollToWithDuration - -`(x: number, y: number, duration: number) => void` 经过指定的时间平滑滚动到 X、Y 偏移值。 - -> * x: number - X 偏移值 -> * y: number - Y 偏移值 -> * duration: number - 毫秒为单位的滚动时间 - ---- - -# TextInput - -[[TextInput 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/TextInput) - -输入文本的基本组件。 - -本组件的属性提供了多种特性的配置,譬如自动完成、自动大小写、占位文字,以及多种不同的键盘类型(如纯数字键盘)等等。 - -## 差异性 - -由于系统组件层的差异,如果 TextInput 处于会被键盘遮住的位置,在呼出键盘后: - -* iOS 则是正常的遮住 -* Android 的表现为页面会被键盘顶起,顶起的幅度取决于 TextInput 的 Y 轴位置决定 - -关于解决此间的平台差异性,我们仍在讨论。 - -若有 iOS 对齐 Android 的键盘顶起的需求,建议参考 [StackOverflow](//stackoverflow.com/questions/32382892/ios-xcode-how-to-move-view-up-when-keyboard-appears),在业务层解决。 - -### Android 弹出后盖住界面的解决办法 - -在部分 Android 机型上,键盘弹出后也可能会产生盖住界面的情况,一般情况下可以通过修改 `AndroidMainfest.xml` 文件,在 activity 上增加 android:windowSoftInputMode="adjustPan" 解决。 - -```xml - - - - - - - -``` - -该参数的意义是: - -* adjustResize: resize the page content -* adjustPan: move page content without resizing page content - -详情请参考 Android 开发文档。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | --------- | -| defaultValue | 提供一个文本框中的初始值。当用户开始输入的时候,值就可以改变。 在一些简单的使用情形下,如果你不想用监听消息然后更新 value 属性的方法来保持属性和状态同步的时候,就可以用 defaultValue 来代替。 | `string` | `ALL` | -| editable | 如果为 false,文本框是不可编辑的。 | `boolean` | `ALL` | -| keyboardType | 决定弹出的何种软键盘的。 注意,`password`仅在属性 `multiline=false` 单行文本框时生效。 | `enum`(default, numeric, password, email, phone-pad) | `ALL` | -| maxLength | 限制文本框中最多的字符数。使用这个属性而不用JS 逻辑去实现,可以避免闪烁的现象。 | `numbers` | `ALL` | -| multiline | 如果为 `true` ,文本框中可以输入多行文字。 由于终端特性。 | `boolean` | `ALL` | -| numberOfLines | 设置 `TextInput` 的最大行数,在使用的时候必需同时设置 `multiline` 参数为 `true`。 | `number` | `ALL` | -| onBlur | 当文本框失去焦点的时候调用此回调函数。 | `Function` | `ALL` | -| onChangeText | 当文本框内容变化时调用此回调函数。改变后的文字内容会作为参数传递。 | `Function` | `ALL` | -| onKeyboardWillShow | 在弹出输入法键盘时候会触发此回调函数,返回值包含键盘高度 `keyboardHeight`,样式如 `{ keyboardHeight: 260}`。仅在 `iOS` 可用,`Android` 输入法不会遮挡App画面 | `Function` | `iOS` | -| onEndEditing | 当文本输入结束后调用此回调函数。 | `Function` | `ALL` | -| onLayout | 当组件挂载或者布局变化的时候调用,参数为`{ x, y, width, height }`。 | `Function` | `ALL` | -| onSelectionChange | 当输入框选择文字的范围被改变时调用。返回参数的样式如 `{ nativeEvent: { selection: { start, end } } }`。 | `Function` | `ALL` | -| placeholder | 如果没有任何文字输入,会显示此字符串。 | `string` | `ALL` | -| placeholderTextColor | 占位字符串显示的文字颜色。 | [`color`](style/color.md) | `ALL` | -| placeholderTextColors | - | [`color`](style/color.md) | `ALL` | -| returnKeyType | 指定软键盘的回车键显示的样式。 | `enum`(done, go, next, search, send) | `ALL` | -| underlineColorAndroid | `TextInput` 下底线的颜色。 可以设置为'transparent'来去掉下底线。 | `string` | `Android` | -| value | 指定 `TextInput` 组件的值。 | `string` | `ALL` | -| autoFocus | 组件渲染时自动获得焦点。 | `boolean` | `ALL` | - -## 方法 - -### blur - -`() => void` 让指定的 input 或 View 组件失去光标焦点,与 focus() 的作用相反。 - -### clear - -`() => void` 清空输入框的内容。 - -### focus - -`() => void` 指派 TextInput 获得焦点。 - -### getValue - -`() => Promise` 获得文本框中的内容。 - -### hideInputMethod - -`() => void` 隐藏软键盘。 - -### setValue - -`(value: string) => void` 设置文本框内容。 - -> * value: string - 文本框内容 - -### showInputMethod - -`() => void` 显示软键盘。 - ---- - -# Text - -[[Text 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/Text) - -文本组件。 - -## 注意事项 - -需要注意的是,在 `` 中拼接字符串时,推荐使用 ES6 的[模板字符串](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals): - -```jsx -{ `现在时间是 ${new Date().toString()}` } // ✅ -``` - -而不是 - -```jsx -现在时间是 { new Date().toString() } // ❌ -``` - -后者有可能在数据更新时不会更新界面。 - -## 属性 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | -| numberOfLines | 用来当文本过长的时候裁剪文本。包括折叠产生的换行在内,总的行数不会超过这个属性的限制。 | `number` | `ALL` | -| opacity | 配置 `View` 的透明度,同时会影响子节点的透明度。 | `number` | `ALL` | -| onLayout | 当元素挂载或者布局改变的时候调用,参数为: `{ nativeEvent: { layout: { x, y, width, height } } }`。 | `Function` | `ALL` | -| onClick | 当文本被点击以后调用此回调函数。 例如, `onClick={() => console.log('onClick') }` | `Function` | `ALL` | -| ellipsizeMode* | 当设定了 `numberOfLines` 值后,这个参数指定了字符串如何被截断。所以在使用 `ellipsizeMode` 时,必须得同时指定 `numberOfLines` 数值。 | `enum`(head, middle, tail, clip)| `Android 仅支持 tail 属性,iOS 全支持` | -| onTouchDown | 当用户开始触屏控件时(即用户在该控件上按下手指时),将回调此函数,并将触屏点信息作为参数传递进来; 参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchMove | 当用户在控件移动手指时,此函数会持续收到回调,并通过event参数告知控件的触屏点信息;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchEnd | 当触屏操作结束,用户在该控件上抬起手指时,此函数将被回调,event参数也会通知当前的触屏点信息;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchCancel | 当用户触屏过程中,某个系统事件中断了触屏,例如电话呼入、组件变化(如设置为hidden),此函数会收到回调,触屏点信息也会通过event参数告知前端;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | - -* ellipsizeMode 的参数含义: - * `clip` - 超过指定行数的文字会被直接截断,不显示“...”;(仅iOS支持) - * `head` - 文字将会从头开始截断,保证字符串的最后的文字可以正常显示在 `Text` 组件的最后,而从开头给截断的文字,将以 “...” 代替,例如 “...wxyz”;(仅iOS支持) - * `middle` - "文字将会从中间开始截断,保证字符串的最后与最前的文字可以正常显示在Text组件的响应位置,而中间给截断的文字,将以 “...” 代替,例如 “ab...yz”;(仅iOS支持) - * `tail` - 文字将会从最后开始截断,保证字符串的最前的文字可以正常显示在 Text 组件的最前,而从最后给截断的文字,将以 “...” 代替,例如 “abcd...”; - ---- - -# View - -[[View 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/View) - -最基础的容器组件,它是一个支持Flexbox布局、样式、一些触摸处理、和一些无障碍功能的容器,并且它可以放到其它的视图里,也可以有任意多个任意类型的子视图。不论在什么平台上,`View` 都会直接对应一个平台的原生视图。 - -## 属性 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------------ | ------------------------------------------------------------ | ------------------------------------ | --------- | -| accessible | 当此属性为 `true` 时,表示此视图时一个启用了无障碍功能的元素。启用无障碍的其他属性时,必须优先设置 `accessible` 为 `true`。 | `boolean` | `ALL` | -| accessibilityLabel | 设置当用户与此元素交互时,“读屏器”(对视力障碍人士的辅助功能)阅读的文字。默认情况下,这个文字会通过遍历所有的子元素并累加所有的文本标签来构建。 | `node` | `ALL` | -| style | - | [`View Styles`](style/layout.md) | `ALL` | -| opacity | 配置 `View` 的透明度,同时会影响子节点的透明度 | `number` | `ALL` | -| overflow | 指定当子节点内容溢出其父级 `View` 容器时, 是否剪辑内容 | `enum`(visible, hidden) | `ALL` | -| onLayout | 这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。 | `Function` | `ALL` | -| onAttachedToWindow | 这个事件会在节点已经渲染并且添加到容器组件中触发,因为 Hippy 的渲染是异步的,这是很稳妥的执行后续操作的事件。 | `Function` | `ALL` | -| onTouchDown | 当用户开始触屏控件时(即用户在该控件上按下手指时),将回调此函数,并将触屏点信息作为参数传递进来; 参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchMove | 当用户在控件移动手指时,此函数会持续收到回调,并通过event参数告知控件的触屏点信息;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchEnd | 当触屏操作结束,用户在该控件上抬起手指时,此函数将被回调,event参数也会通知当前的触屏点信息;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | -| onTouchCancel | 当用户触屏过程中,某个系统事件中断了触屏,例如电话呼入、组件变化(如设置为hidden),此函数会收到回调,触屏点信息也会通过event参数告知前端;参数为 `{ nativeEvent: { name, page_x, page_y, id } }` | `Function` | `ALL` | - -## 样式内特殊属性 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------------ | ------------------------------------------------------------ | ------------------------------------ | --------- | -| collapsable | Android 里如果一个 `View` 只用于布局它的子组件,则它可能会为了优化而从原生布局树中移除,因此该节点 DOM 的引用会丢失。 把此属性设为 `false` 可以禁用这个优化,以确保对应视图在原生结构中存在。 | `boolean` | `Android` | - ---- - -# ViewPager - -[[ViewPager 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/ViewPager) - -支持横滑翻页的容器,它的每一个子容器组件会被视作一个单独的页面,并且会被拉伸宽度至 `ViewPager` 本身宽度。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------------------ | ------------------------------------------------------------ | -------------------------------------------- | -------- | -| initialPage | 指定一个数字,用于决定初始化后默认显示的页面index,默认不指定的时候是0 | `number` | `ALL` | -| scrollEnabled | 指定ViewPager是否可以滑动,默认为true | `boolean` | `ALL` | -| onPageSelected | 指定一个函数,当page被选中时进行回调,回调参数是一个对象event,包括position值 回调参数: `position`: number -被选中即将滑到的目标page的index | `(obj: {position: number}) => void` | `ALL` | -| onPageScroll | 指定一个函数,当page被滑动时进行回调,回调参数是一个对象event,包括position值与offset值 回调参数: `position`: number -即将滑到的目标page的index `offset`: number -当前被选中的page的相对位移,取值范围-1到1 | `(obj: {position: number, offset: number}) => void` | `ALL` | -| onPageScrollStateChanged | 指定一个函数,当page的滑动状态改变时进行回调 回调参数: `pageScrollState`: string -改变后的状态,idle表示停止,dragging表示用户用手拖拽,settling表示page正在滑动 | `(pageScrollState: string) => void` | `ALL` | -| direction | 设置viewPager滚动方向,不设置默认横向滚动,设置 `vertical` 为竖向滚动 | `string` | `Android` | - -## 方法 - -### setPage - -`(index: number) => void` 通过传入一个index 值(数字),滑动到第 index 个页面(有动画) - -> * index: number - 指定滑动页面 - -### setPageWithoutAnimation - -`(index: number) => void` 通过传入一个index 值(数字),滑动到第 index 个页面(无动画) - -> * index: number - 指定滑动页面 - ---- - -# WaterfallView - -> 最低支持版本 2.9.0 - -[[WaterfallView 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/WaterfallView) - -瀑布流组件。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- | -------- | -| numberOfColumns | 瀑布流列数量 , Default: 2 | `number` | `ALL` | -| numberOfItems | 瀑布流 item 总个数 | `number` | `ALL`| -| columnSpacing | 瀑布流每列之前的水平间距 | `number` | `ALL` | -| interItemSpacing | item 间的垂直间距 | `number` | `ALL` | -| contentInset | 内容缩进 ,默认值 `{ top:0, left:0, bottom:0, right:0 }` | `Object` | `ALL` | -| renderItem | 这里的入参是当前 item 的 index,在这里可以凭借 index 获取到瀑布流一个具体单元格的数据,从而决定如何渲染这个单元格。 | `(index: number) => React.ReactElement` | `ALL` | -| renderBanner | 如何渲染 Banner。 | `() => React.ReactElement` | `iOS` -| getItemStyle | 设置`WaterfallItem`容器的样式。 | `(index: number) => styleObject` | `ALL` | -| getItemType | 指定一个函数,在其中返回对应条目的类型(返回Number类型的自然数,默认是0),List 将对同类型条目进行复用,所以合理的类型拆分,可以很好地提升list 性能。 | `(index: number) => number` | `ALL` | -| getItemKey | 指定一个函数,在其中返回对应条目的 Key 值,详见 [React 官文](//reactjs.org/docs/lists-and-keys.html) | `(index: number) => any` | `ALL` | -| preloadItemNumber | 滑动到瀑布流底部前提前预加载的 item 数量 | `number` | `ALL` | -| onEndReached | 当所有的数据都已经渲染过,并且列表被滚动到最后一条时,将触发 `onEndReached` 回调。 | `Function` | `ALL` | -| containPullHeader | 是否包含`PullHeader`组件,默认 `false` ;`Android` 暂不支持,可暂时用 `RefreshWrapper` 组件替代 | `boolean` | `iOS` | -| renderPullHeader | 如何渲染 `PullHeader`,此时 `containPullHeader` 默认设置成 `true` | `() => React.ReactElement` | `iOS` | -| containPullFooter | 是否包含`PullFooter`组件,默认 `false` | `boolean` | `ALL` | -| renderPullFooter | 如何渲染 `PullFooter`,此时 `containPullFooter` 默认设置成 `true` | `() => React.ReactElement` | `ALL` | -| onScroll | 当触发 `WaterFall` 的滑动事件时回调。`startEdgePos`表示距离 List 顶部边缘滚动偏移量;`endEdgePos`表示距离 List 底部边缘滚动偏移量;`firstVisibleRowIndex`表示当前可见区域内第一个元素的索引;`lastVisibleRowIndex`表示当前可见区域内最后一个元素的索引;`visibleRowFrames`表示当前可见区域内所有 item 的信息(x,y,width,height) | `{ nativeEvent: { startEdgePos: number, endEdgePos: number, firstVisibleRowIndex: number, lastVisibleRowIndex: number, visibleRowFrames: Object[] } }` | `ALL` - -## 方法 - -### scrollToIndex - -`(obj: { index: number, animated: boolean }) => void` 通知 Waterfall 滑动到第几个 item。 - -> * `index`: number - 滑动到的第 index 个 item -> * `animated`: boolean - 滑动过程是否使用动画, 默认 `true` - -### scrollToContentOffset - -`(obj: { xOffset: number, yOffset: number, animated: boolean }) => void` 通知 Waterfall 滑动到某个具体坐标偏移值(offset)的位置。 - -> * `xOffset`: number - 滑动到 X 方向的 offset -> * `yOffset`: number - 滑动到 Y 方向的 offset -> * `animated`: boolean - 滑动过程是否使用动画,默认 `true` - ---- - -# WebView - -[[WebView 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/WebView/index.jsx) - -WebView组件。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- | -------- | -| source | Webview 内嵌地址 | `{ uri: string }` | `ALL` | -| userAgent | Webview userAgent | `string` | `ALL`| -| method | 请求方式, `get`、`post` | `string` | `ALL` | -| onLoadStart | 网页开始加载时触发 | `(object: { url:string }) => void` | `ALL` | -| onLoad | 网页加载时触发 | `(object: { url:string }) => void` | `ALL` | -| onLoadEnd | 网页加载结束时触发 | `(object: { url:string }) => void` | `ALL` | -| style | Webview 容器样式 | `Object` | `ALL` | diff --git a/docs/hippy-react/customize.md b/docs/hippy-react/customize.md deleted file mode 100644 index b84f4e882f7..00000000000 --- a/docs/hippy-react/customize.md +++ /dev/null @@ -1,98 +0,0 @@ -# 自定义组件和模块 - -# 自定义组件 - -写个 React 组件,在需要渲染的地方通过 `nativeName` 指定到终端组件名称即可,以终端范例中的 `MyView` 为例: - -```javascript -import React from "react"; -import { UIManagerModule } from "@hippy/react" - -export class MyView extends React.Component { - constructor(props) { - super(props); - this.state = {}; - this.changeColor = this.changeColor.bind(this); - } - - changeColor(color) { - // callUIFunction 只能接收一个实际渲染的终端节点 - UIManagerModule.callUIFunction(this.instance, "changeColor", [color]); - } - - render() { - return ( -
    this.instance = ref} // 设置 ref 方便 changeColor 获取 - nativeName="MyView" // **必须:**将前端组件与终端组件进行绑定 - {...this.props} - >
    - ) - } -} -``` - -# 自定义模块 - -> 该范例仅可以在 Android 下运行。 - -前端扩展模块分为三步: - -1. 第一步导入 callNative 或者 callNativeWithPromise 接口 -2. 封装调用接口 -3. 导出模块 - -```javascript -// TestModule.js -import { callNative, callNativeWithPromise } from "@hippy/react" - -/* - 自定义module - */ -const TestModule = { - log(msg) { - callNative("TestModule", "log", msg) - }, - helloNative(msg) { - callNative("TestModule", "helloNative", msg) - }, - //这个是需要终端回调的 - helloNativeWithPromise(msg) { - return callNativeWithPromise("TestModule", "helloNativeWithPromise", msg); - } -} - -export { TestModule } -``` - -## 使用 - -```jsx -import React from "react"; -import { Text } from "@hippy/react" -import { TestModule } from "./TestModule" - -//展示自定义Module的使用 -export default class TestModuleDemo extends React.Component { - static defaultProps = {}; - - constructor(props) { - super(props); - this.state = { hello: "TestModule log" } - //调用 - TestModule.log("hello I am from js"); - TestModule.helloNative({ hello: "I am from js" }) - TestModule.helloNativeWithPromise({ hello: "I am from js" }) - .then(rsp => this.setState({ hello: JSON.stringify(rsp) })); - } - - render() { - const { hello } = this.state; - return ( - - {hello} - - ) - } -} -``` diff --git a/docs/hippy-react/gesture.md b/docs/hippy-react/gesture.md deleted file mode 100644 index 8ee2ab4707f..00000000000 --- a/docs/hippy-react/gesture.md +++ /dev/null @@ -1,156 +0,0 @@ -# 手势系统 - -Hippy 的手势系统使用起来相对更加便捷,主要区别就在不需要再依赖其它事件组件,所有组件,包括 View、Text、Image 或各种自定义控件等都可以设置点击、触屏事件监听; - -## 点击事件 - -点击事件包括长按、点击、按下、抬手 4 种类型,分别由以下 4 种接口通知: - -1. onClick:当控件被点击时,会回调此函数; -2. onPressIn:在长按或点击时,用户开始触屏(即用户按下手指时)该控件时,此函数会被调用; -3. onPressOut:在长按或点击时,用户结束触屏(即用户抬起手指时)该控件时,此函数会被调用; -4. onLongClick:当控件被长按时,此函数会被调用; - -### 范例 - -通过配合使用 onPressIn 和 onPressOut 可以实现点击态的效果,例如下面的示例代码,实现了点击时背景变色的功能: - -```jsx -render() { - let bgColor = "#FFFFFF"; //非点击状态下背景为白色 - if (this.state.pressedIn) { - bgColor = "#000000"; //点击状态下背景为黑色 - } - - return ( - { this.setState({pressedIn: true}) }} - onPressOut={() => { this.setState({pressedIn: false}) }} - > - 点击按钮 - - ); -} -``` - -## 触屏事件 - -触屏事件的处理与点击事件类似,可以再任何 React 组件上使用,touch 事件主要由以下几个回调函数组成: - -1. onTouchDown(event):当用户开始触屏控件时(即用户在该控件上按下手指时),将回调此函数,并将触屏点信息作为参数传递进来; -2. onTouchMove(event):当用户在控件移动手指时,此函数会持续收到回调,并通过 event 参数告知控件的触屏点信息; -3. onTouchEnd(event):当触屏操作结束,用户在该控件上抬起手指时,此函数将被回调,event 参数也会通知当前的触屏点信息; -4. onTouchCancel(event):当用户触屏过程中,某个系统事件中断了触屏,例如电话呼入、组件变化(如设置为 hidden),此函数会收到回调,触屏点信息也会通过 event 参数告知前端; - -注意:若 onTouchCancel 被触发,则 onTouchEnd 不会被触发 - -以上回调函数均带有一个参数 event,该数据包含以下结构: - -- name:该触屏事件的名称,分别对应为“onTouchDown“、“onTouchMove”、"onTouchEnd"、“onTouchCancel”; -- id:接收触屏事件的目标控件的 id,即触屏点所在控件的 id; -- page_x:触屏点相对于根元素的横坐标; -- page_y:触屏点相对于根元素的纵坐标; - -以上结构中的 x 和 y 坐标已经经过转换,与屏幕分辨率无关的单位,例如 onTouchDonw 回调的 event 参数结构如下: - -```json -{ - "name": "onTouchDown", - "page_y": 172.27392578125, - "id": 6574, - "page_x": 532.6397094726562 -} -``` - -## 事件冒泡 - -点击事件和触屏事件均可以在回调函数中定义是否需要冒泡该事件到上层组件,点击或触屏事件发生时,终端会寻找该触屏点下声明了要处理该事件的最小控件: - -!> HippyReact 默认不冒泡 - -1. 返回 true 或没有返回值:控件处理完事件后,将不再继续冒泡,整个手势事件处理结束; -2. 返回 false:控件处理完事件后,事件将继续往上一层冒泡,如果找到某个父控件也设置了对应事件处理函数,则会调用改该回调函数,并再次根据其返回值决定是否继续冒泡。如果再向上冒泡的过程中达到了根节点,则事件冒泡结束; - -我们通过以下示例进一步说明事件冒泡的机制: - -```js -render() { - return ( - { console.log("根节点 点击"); }} - > - console.log("点击按钮1 点击")} - > - 点击按钮1 - - { - console.log("父控件 点击"); - return true; - }} - > - { - console.log("点击按钮2 点击"); - return false; - }} - > - 点击按钮2 - - - - ); -} -``` - -> 2.10.1 版本开始支持在 Hippy 初始化时通过 `bubbles` 参数设置默认冒泡(即事件处理return没有返回值,也会向上传递事件),默认 `false` - -```js -new Hippy({ - appName: 'Demo', - entryPage: App, - // set bubbles, default is false - bubbles: true, -}).start(); -```` - -## 事件的拦截 - -某些场景下,父控件又需要优先拦截到子控件的手势事件,因此 Hippy 也提供了手势事件拦截机制,手势拦截由父控件的两个属性控制 `onInterceptTouchEvent` 和`onInterceptPullUpEvent`,这两个属性仅对能容纳子控件的组件生效,如 `` 这种控件就不支持这两个属性: - -- onInterceptTouchEvent:父控件是否拦截所有子控件的手势事件,true 为拦截,false 为不拦截(默认为 false)。当父控件设置该属性为 true 时,所有其子控件将无法收到任何 touch 事件和点击事件的回调,不管是否有设置事件处理函数,在该父控件区域内按下、移动、抬起手指以及点击和长按发生时,终端将默认把事件发送给该父控件进行处理。如果父控件在设置 onInterceptTouchEvent 为 true 之前,子控件已经在处理 touch 事件,那么子控件将收到一次 onTouchCancel 回调(如果子控件有注册该函数); -- onInterceptPullUpEvent:该属性的作用与 onInterceptTouchEvent 类似,只是决定父控件是否拦截的条件稍有不同。为 true 时,如果用户在当前父控件区域内发生了手指上滑的动作,后续所有的触屏事件将被该父控件拦截处理,所有其子控件将无法收到任何 touch 事件回调,不管是否有设置 touch 事件处理函数;如果拦截生效之前子控件已经在处理 touch 事件,子控件将收到一次 onTouchCancel 回调。为 false 时,父控件将不会拦截事件,默认为 false; - -注意,由于这两种标记拦截条件不同,onInterceptTouchEvent 标记设置为 true 之后,子控件的所有触屏事件都将失效,而 onInterceptPullUpEvent 则不会影响子控件的点击事件。 - -还是以代码为例: - -```js -render() { - return ( - { console.log("根节点 TouchMove:" + JSON.stringify(event)); }} - > - console.log("红色区域 TouchMove:" + JSON.stringify(event)) } - onTouchDown={(event) => { - console.log("红色区域 onTouchDown:" + JSON.stringify(event)); - }}/> - { - console.log("绿色区域 TouchMove:" + JSON.stringify(event)); - return false; - }} - onInterceptTouchEvent={true} - > - { - console.log("蓝色区域 TouchMove:" + JSON.stringify(event)); - return false; - }}/> - - - ); -} -``` diff --git a/docs/hippy-react/introduction.md b/docs/hippy-react/introduction.md deleted file mode 100644 index 482f77011ca..00000000000 --- a/docs/hippy-react/introduction.md +++ /dev/null @@ -1,11 +0,0 @@ -# hippy-react 介绍 - -hippy-react 是基于 Facebook React 的官方自定义渲染器 [react-reconciler](//www.npmjs.com/package/react-reconciler) 重新开发的 React 到终端的渲染层,可以使用 React 的全部特性。 - -在语法上 hippy-react 更加接近底层终端,使用了类似 [React Native](//facebook.github.io/react-native/) 的语法。 - -# 架构图 - -hippy-react 架构图 -
    -
    diff --git a/docs/hippy-react/migrate-from-rn.md b/docs/hippy-react/migrate-from-rn.md deleted file mode 100644 index d2081ca6d71..00000000000 --- a/docs/hippy-react/migrate-from-rn.md +++ /dev/null @@ -1,40 +0,0 @@ -# 从 React Native 迁移 - -Hippy React 基本兼容 React Native 语法,但相对 React Native 提供的组件,Hippy 更加内聚,除了部分组件可能需要通过前端重新实现,主要还有以下三个区别: - -# 触屏 Touchable 系列组件 - -Hippy 的触屏系列事件可以直接绑定到 View 上,之前 RN 上的 `Touchable` 系列组件其实可以简单迁移过来。以 `TouchableWithoutFeedback` 为例: - -```jsx -import React from 'react'; - -function TouchableWithoutFeedback(props) { - const child = React.Children.only(props.children); - const { onClick, onPressIn, onPressOut } = props; - const { children, ...nativeProps } = child.props; - // 透传事件 - if (typeof onClick === 'function') { - nativeProps.onClick = onClick; - } - if (typeof onPressIn === 'function') { - nativeProps.onPressIn = onPressIn; - } - if (typeof onPressOut === 'function') { - nativeProps.onPressOut = onPressOut; - } - return React.cloneElement(child, nativeProps, children); -} -``` - -# 动画系统 - -Hippy 的动画机制和 React Native 机制有所不同,React Native 的动画模块其实是由前端通过定时器驱动,存在大量前终端通讯,而 Hippy 通过将动画方案一次性下发给终端实现了更好的动画性能。 - -请参考 [动画方案的最佳实践](hippy-react/animation.md)。 - -# 手势系统 - -和 React Native 的 PanResponder 不同,Hippy 的手势事件可以应用于任何一个组件上,更加接近浏览器的实现。 - -请参考 [手势系统的最佳实践](hippy-react/gesture.md)。 diff --git a/docs/hippy-react/modules.md b/docs/hippy-react/modules.md deleted file mode 100644 index 1df441cdb90..00000000000 --- a/docs/hippy-react/modules.md +++ /dev/null @@ -1,463 +0,0 @@ - - - -# 模块 - ---- - -# Animation - -[[Animation 范例]](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/modules/Animation/index.jsx) - -`Animation` 是 Hippy 提供的动画组件,可以支持传入动画配置,以及手动控制开始与结束。在 Hippy 上实现一个动画分为三个步骤: - -- 通过 Animation 定义动画; -- 在 render 时,将动画设置到需要产生动画效果的控件属性上; -- 通过 Animation 的 start 接口启动动画,或是通过 destroy 停止并销毁动画。 - -> 注意,转 Web 需要用 setRef 方法手动传入 ref 才可以正常运行动画 - -## 构造参数 - -| 参数 | 类型 | 必需 | 默认值 | 描述 | -| ---------------- | ------------------ | ---- | ------ | ------------------------------------------------------------------------------------------------------------------------- | -| mode | `string` | 是 | timing | 动画时间轴模式 | -| delay | `number` | 是 | - | 动画延迟开始的时间,单位为毫秒,默认为 0,即动画 start 之后立即执行;指定列表的行数,一般直接传入数据源条数 `length` 即可 | -| startValue | `number`, `string` | 是 | - | 动画开始时的值,可为 Number 类型 String 类型,如果为颜色值参考 [color](style/color.md) | -| toValue | `number`, `string` | 是 | - | 动画结束时候的值;如果为颜色值参考 [color](style/color.md) | -| valueType\* | `number`, `string` | 否 | null | 动画的开始和结束值的类型,默认为空,代表动画起止的单位是普通 Number。 PS: Web 平台此接口只支持 number 类型传参 | -| duration | `number` | 否 | - | 动画时长,单位为毫秒(ms) | -| timingFunction\* | `string` | 否 | linear | 动画插值器类型, 支持 `linear`,`ease-in`, `ease-out`,`ease-in-out`,`cubic-bezier` | -| repeatCount | `number`, `loop` | 否 | - | 动画的重复次数,默认为 0,即只播放一次,为"loop"时代表无限循环播放; repeatCount 设为 n 时,则动画会播放 n 次 | - -- valueType 的参数选项: - - - `rad`:代表动画参数的起止值为弧度; - - `deg`:代表动画参数的起止值为度数; - - `color`:代表动画参数的起止值为颜色值,可修饰背景色 `backgroundColor` 和文字颜色 `color`(仅 Android 支持),参考 [例子](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/modules/Animation/index.jsx) `最低支持版本2.6.0` - -- timingFunction 的参数选项: - - `linear`:使用线性插值器,动画将匀速进行; - - `ease-in`:使用加速插值器,动画速度将随时间逐渐增加; - - `ease-out`:使用减速插值器,动画速度将随时间逐渐减小; - - `ease-in-out`:使用加减速插值器,动画速度前半段先随时间逐渐增加,后半段速度将逐渐减小; - - `cubic-bezier`:(最低支持版本 2.9.0)使用自定义贝塞尔曲线,与 [css transition-timing-function 的 cubic-bezier](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function) 一致; - -## 方法 - -### destroy - -`() => void` 停止并销毁一个动画集。建议在组件销毁的生命周期执行此方法,避免动画在后台运行耗。 - -### onAnimationEnd - -`(callback: () => void) => void` 注册一个动画的监听回调,在动画结束时将会回调 callback。 - -### onAnimationRepeat(仅 Android 支持) - -`(callback: () => void) => void` 注册一个动画的监听回调,当动画开始下一次重复播放时 callback 将被回调。 - -### onAnimationStart - -`(callback: () => void) => void` 注册一个动画的监听回调,在动画开始时将会回调 callback。 - -### pause - -`() => void` 暂停运行中的动画。 - -### resume - -`() => void` 继续播放暂停了的动画。 - -### start - -`() => void` 启动动画。注意:如果调用该方法前,动画尚未经过 render 赋值给相应控件, 或该动画已经 destroy 的话,那 start 将不会生效; - -### updateAnimation - -`(options: Object) => void` 修改动画的配置参数,只需要填入需要修改的配置项即可,不需要重复填入所有的动画参数 - -> - options: Object: 实例化参数 - ---- - -# AnimationSet - -[[AnimationSet 范例]](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/modules/Animation) - -`AnimationSet` 与 `Animation` 类似,都是赋予 hippy 组件的单个样式属性(如 width、height、left、right)动画能力的模块。 - -`Animation` 与 `AnimationSet` 的不同点在于 `Animation` 只是单个动画模块,`AnimationSet` 为多个 `Animation` 的动画模块组合,支持同步执行或顺序执行多个 `Animation` 动画。 - -> 注意,转 Web 需要用 setRef 方法手动传入 ref 才可以正常运行动画。 - -## 构造参数 - -| 参数 | 类型 | 必需 | 默认值 | 描述 | -| ----------- | ------------------------------------------- | ---- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| children | `{ children: Animation, follow = false }[]` | 是 | - | 接收一个 Array,用于指定子动画,该 Array 的每个元素包括: + animation:子动画对应的 Animation 对象; + follow:配置子动画的执行是否跟随执行,为 true,代表该子动画会等待上一个子动画执行完成后在开始,为 false 则代表和上一个子动画同时开始,默认为 false。 | -| repeatCount | `number` | 否 | - | 动画 Set 的重复次数,默认为 0,即不重复播放,为'loop'时代表无限循环播放; `repeatCount` 设为 n 时,则动画会播放 n 次。 | - -## 方法 - -### destroy - -`() => void` 停止并销毁一个动画集。建议在组件销毁的生命周期执行此方法,避免动画在后台运行耗。 - -### onAnimationEnd - -`(callback: () => void) => void` 注册一个动画的监听回调,在动画结束时将会回调 callback。 - -### onAnimationRepeat - -`(callback: () => void) => void` 注册一个动画的监听回调,当动画开始下一次重复播放时 callback 将被回调。 - -### onAnimationStart - -`(callback: () => void) => void` 注册一个动画的监听回调,在动画开始时将会回调 callback。 - -### pause - -`() => void` 暂停运行中的动画。 - -### resume - -`() => void` 继续播放暂停了的动画。 - -### start - -`() => void` 启动动画。注意:如果调用该方法前,动画尚未经过 render 赋值给相应控件, 或该动画已经 destroy 的话,那 start 将不会生效; - -### updateAnimation - -`(options: Object) => void` 修改动画的配置参数,只需要填入需要修改的配置项即可,不需要重复填入所有的动画参数 - ---- - -# AsyncStorage - -[[AsyncStorage 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/modules/AsyncStorage/index.jsx) - -AsyncStorage 是一个简单的、异步的、持久化的 Key-Value 存储系统,它对于 App 来说是全局性的。 - -> 也可以直接使用 localStorage 对象使用,方法跟 Web 版 localStorage 接口一致,不同的是:因为都是异步方法,需要在方法前面前面加上 `await`。 - -## 方法 - -### AsyncStorage.getAllKeys - -`() => Promise` 获取 AsyncStorage 所有的 key。 - -### AsyncStorage.getItem - -`(key: string) => Promise` 根据 key 值获取对应数据。 - -> - key: string - 需要获取值的目标 key - -### AsyncStorage.multiGet - -`(key: string[]) => Promise<[key: string, value: value][]>` 一次性用多个 key 值的数组去批量请求缓存数据,返回值将在回调函数以键值对的二维数组形式返回。 - -> - key: string[] - 需要获取值的目标 key 数组 - -### AsyncStorage.multiRemove - -`(key: string[]) => void` 调用此函数批量删除 AsyncStorage 里面在传入的 keys 数组存在的 key 值。 - -> - key: string[] - 需要删除的目标 key 数组 - -### AsyncStorage.multiSet - -`(keyValuePairs: [key: string, value: value][]) => void` 调用这个函数可以批量存储键值对对象。 - -> - keyValuePairs: [key: string, value: value][] - 需要设置的储键值二维数组 - -### AsyncStorage.removeItem - -`(key: string) => void` 根据 key 值删除对应数据。 - -> - key: string - 需要删除的目标 key - -### AsyncStorage.setItem - -`(key: string, value: string) => void` 根据 key 和 value 设置保存键值对。 - -> - key: string - 需要获取值的目标 key -> - value: string - 需要获取值的目标值 - ---- - -# BackAndroid - -[[BackAndroid 范例]](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/src/pages/gallery.jsx#L171) - -可以监听 Android 实体键的回退,在退出前做操作或拦截实体键的回退。 - -> 注意:该方法需要终端拦截实体返回按钮的事件,可以参考 [android-demo 的 onBackPressed 方法](//github.com/Tencent/Hippy/blob/master/examples/android-demo/example/src/main/java/com/tencent/mtt/hippy/example/MyActivity.java) - -## 方法 - -### BackAndroid.addListener - -`(handler: () => boolean) => { remove: Function }` 监听 Android 实体健回退,触发时执行 handler 回调函数。回调函数返回 true 时,拦截终端的回退操作。回调函数返回 false 时, 就不会拦截回退。该函数返回包含 `remove()` 方法的对象,可通过调用 `remove()` 方法移除监听,同 `BackAndroid.removeListener`。 - -> - handler: Function - 实体键回退时触发的回调函数 - -### BackAndroid.exitApp - -`() => void`直接执行终端的退出 App 逻辑。 - -### BackAndroid.removeListener - -`(handler: () => boolean) => void` 移除 BackAndroid 关于 Android 实体健回退事件的监听器。 - -- handler: Function - 建议使用 `addListener` 返回的包含 `remove()` 方法的对象,也可以是之前 BackAndroid 的回调函数。 - ---- - -# Clipboard - -[[Clipboard 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/modules/Clipboard) - -模块提供了 iOS/Android 双端的剪贴板能力,开发者可使用其来读取或写入剪贴板,目前仅支持字符串作为存取类型。 - -## 方法 - -### Clipboard.getString - -`() => string` 获取剪贴板的内容 - -### Clipboard.setString - -`(value: string) => void` 设置剪贴板的内容 - -> - value: string - 需要设置到剪贴板中的内容。 - ---- - -# ConsoleModule - -提供了将前端日志输出到 iOS 终端日志和 [Android logcat](//developer.android.com/studio/command-line/logcat) 的能力 - -## 方法 - -### ConsoleModule.log - -`(...value: string) => void` - -### ConsoleModule.info - -`(...value: string) => void` - -### ConsoleModule.warn - -`(...value: string) => void` - -### ConsoleModule.error - -`(...value: string) => void` - -> - `log` 和 `info` 默认都输出为终端 INFO 级别日志。 -> - Hippy 2.10.0 版本之后将原始 js 的 `console` 方法与 `ConsoleModule` 方法进行分离,`console` 不再输出日志到终端。 - ---- - -# Dimensions - -用于获取当前设备的宽高。 - -## 方法 - -### Dimensions.get - -`(target: 'window' | 'screen') => { height: number, width: number, scale: number, statusBarHeight, navigatorBarHeight }` Hippy Root View 尺寸或者屏幕尺寸。 - -> - target: 'window' | 'screen' - 指定丈量 Hippy Root View 或者屏幕尺寸。 -> - Android 特别说明:因为历史遗留问题,screen 下的 statusBarHeight 是按实际像素算的,window 下经过修正已经是 dp 单位。 -> - navigatorBarHeight: Android 底部 navigatorBar 高度;最低支持版本 2.3.4 - ---- - -# ImageLoaderModule - -通过该模块可以对远程图片进行相应操作 - -## 方法 - -### ImageLoaderModule.getSize - -`(url: string) => Promise<{width, height}>` 获取图片大小(会同时预加载图片)。 - -> - url - 图片地址 - -### ImageLoaderModule.prefetch - -`(url: string) => void` 用于预加载图片。 - -> - url - 图片地址 - ---- - -# NetInfo - -[[NetInfo 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/modules/NetInfo) - -通过该接口可以获得当前设备的网络状态,也可以注册一个监听器,当系统网络切换的时候,得到一个通知。 - -安卓的开发者,在请求网络状态之前,你需要在 app 的 `AndroidManifest.xml` 加入以下配置 : - -```xml - -``` - -## 网络状态 - -以异步的方式判断设备是否联网,以及是否使用了移动数据网络。 - -- `NONE` - 设备处于离线状态。 -- `WIFI` - 设备通过 wifi 联网 -- `CELL` - 设备通过移动网络联网 -- `UNKNOWN` - 出现异常或联网状态不可知 - -## 方法 - -### NetInfo.addEventListener - -`(eventName: string, handler: Function) => NetInfoRevoker` 添加一个网络变化监听器。 - -> - eventName: 'change' - 事件名称 -> - handler: ({ network_info:string }) => any - 网络发生变化时触发的回调函数 - -### NetInfo.fetch - -`() => Promise` 用于获取当前的网络状态。 - -### NetInfo.removeEventListener - -`(eventName: string, handler: NetInfoRevoker | Function) => void` 移除事件监听器 - -> - eventName: 'change' - 事件名称 -> - handler: Function - 需要删除的对应事件监听。 - -# NetworkModule - -主要包含了网络相关的模块,目前主要是操作 Cookie。 - -普通的网络请求请参考: [起步 - 网络请求](guide/network-request.md) - -## 方法 - -### NetworkModule.getCookies - -`(url: string) => Promise` 获取指定 url 的所有 cookie - -> - url: string - 需要获取 cookie 的目标 url - -### NetworkModule.setCookie - -`(url: string, keyValue: string, expires?: string) => Promise` 设置 Cookie - -> - url: string - 需要获取 cookie 的目标 url -> - keyValue: string - 需要设置的键值对 -> - expires?: string - 设置 Cookie 的超市时间 - ---- - -# PixelRatio - -用于获取当前设备的像素密度(pixel density)。 - -## 方法 - -### PixelRatio.get - -`() => number` 返回当前设备的像素密度。 - -## 范例 - -- PixelRatio.get() === 1 - - [mdpi Android 设备](//material.io/tools/devices/) -- PixelRatio.get() === 1.5 - - [hdpi Android 设备](//material.io/tools/devices/) -- PixelRatio.get() === 2 - - iPhone 4, iPhone 4S - - iPhone 5, iPhone 5c, iPhone 5s - - iPhone 6, iPhone 7, iPhone 8 - - [xhdpi Android 设备](//material.io/tools/devices/) -- PixelRatio.get() === 3 - - iPhone 6 Plus, iPhone 7 Plus, iPhone 8 Plus - - iPhone X - - Pixel, Pixel 2 - - [xxhdpi Android 设备](//material.io/tools/devices/) -- PixelRatio.get() === 3.5 - - Nexus 6 - - Pixel XL, Pixel 2 XL - - [xxxhdpi Android 设备](//material.io/tools/devices/) - ---- - -# Platform - -用于书写平台区分代码的一个组件。开发者使用时,根据 `Platform.OS` 输出值开发分平台业务逻辑分支。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------ | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------- | -| OS | 用来判断是在 iOS 或者 Android 下 | `string` | `ALL` | -| Localization | 输出国际化相关信息, `最低支持版本 2.8.0` | `object: { country: string , language: string, direction: number }`, 其中 `direction` 为 0 表示 LTR 方向,1 表示 RTL 方向 | `ALL` | - ---- - -# Stylesheet - -提供了一种类似 CSS 样式表的抽象。 - -## 参数 - -| 参数 | 描述 | 类型 | 支持平台 | -| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------- | -| hairlineWidth | 这一常量定义了当前平台上的最细的宽度。可以用作边框或是两个元素间的分隔线。然而,你不应该信任它作为一个衡量长度的单位,因为在不同机器与不同分辨率,hairlineWidth 可能会表现不同。 | `number` | `ALL` | - -## 方法 - -### StyleSheet.create - -`(styleObj: Object) => styleObj` - -> - styleObj: Object - 样式对象 - ---- - -# UIManagerModule - -提供了操作 UI 相关的能力。 - -## 方法 - -### UIManagerModule.callUIFunction - -调用组件定义的终端方法 - -`callUIFunction(instance: ref, method: string, options: Array)` - -> - instance: 组件的引用 Ref -> - method:方法名称,如 ListView 的 `scrollToIndex` -> - options: 需传递的数据,如 ListView 的 `[xIndex, yIndex, animated]`,空时显式写 `[]` - -### UIManagerModule.getElementFromFiberRef - -获取元素 Ref 对应的 Element(类似DOM) - -`getElementFromFiberRef(instance: ref): ElementNode` - -> - instance: 组件的引用 Ref -> - ElementNode:类似DOM,可以调用 setNativeProps 等方法 - -### UIManagerModule.measureInAppWindow - -测量在 App 窗口范围内某个组件的尺寸和位置,如果出错 callback 参数可能为字符串或者 -1 - -`(ref, callback: Function) => Promise` - -> - callback: ({ x, y, width, height } | string | -1) => void - 回调函数, 参数可以获取到引用组件在 App 窗口范围内的坐标值和宽高,如果出错可能返回 -1 或者 `this view is null` 字符串 diff --git a/docs/hippy-react/native-event.md b/docs/hippy-react/native-event.md deleted file mode 100644 index 7dc1c1fd05f..00000000000 --- a/docs/hippy-react/native-event.md +++ /dev/null @@ -1,49 +0,0 @@ -# 终端事件 - -有一些事件不是发给单个 UI,而是发给整个业务的,例如屏幕的翻转、网络的变化等等,我们称之它为 `终端事件`。 - -# 事件监听器 - -这里是向前端发送一个名叫 rotate 的事件,里面有个参数是 result,这样就发送到前端去了。 - -```jsx -import { HippyEventEmitter } from '@hippy/react'; - -const hippyEventEmitter = new HippyEventEmitter(); -this.call = hippyEventEmitter.addListener('rotate', evt => console.log(evt.result)); -``` - -# 事件卸载 - -如果不需要使用的时候记得调用一下移除监听的方法,一般放在组件的卸载生命周期中执行。 - -```jsx -this.call.remove() -``` - -# 实例销毁事件 - -`最低支持版本 2.3.4` - -当 hippy js 引擎或者 context 被销毁时会触发该事件,hippy业务可以通过监听 `destroyInstance` 事件做一些离开时的操作,但回调函数不能使用 `async` - -```jsx -Hippy.on('destroyInstance', () => { - // do something -}); -``` - -# 容器大小改变事件 - -`只有 Android 支持` - -当容器大小改变时,如屏幕旋转、折叠屏切换等,会触发该事件 - -```jsx -import { HippyEventEmitter } from '@hippy/react'; -const hippyEventEmitter = new HippyEventEmitter(); -hippyEventEmitter.addListener('onSizeChanged', ({ oldWidth, oldHeight, width, height }) => { - // oldWidth: 旧的宽度;oldHeight: 旧的高度;width: 新的宽度; height: 新的高度 - console.log('size', oldWidth, oldHeight, width, height); -}); -``` diff --git a/docs/hippy-react/style.md b/docs/hippy-react/style.md deleted file mode 100644 index 2557098ddbc..00000000000 --- a/docs/hippy-react/style.md +++ /dev/null @@ -1,55 +0,0 @@ -# 样式 - -Hippy 的所有样式支持由终端直接提供,基本和浏览器一致,但暂不支持百分比布局,但可以使用最新的 Flex 弹性布局。 - -# 内联样式 - -最简单的方式,我们可以用内联样式,直接定义容器如`View`,`Text`等的样式,用双括号包裹,示例代码如下: - -```jsx -import React from 'react'; -import { View } from '@hippy/react'; - -function InlineStyleDemo() { - return ( - // 显示一个宽为100pt,高为100pt,背景颜色为红色的正方形在屏幕上 - return ; - ) -} -``` - -# 外部样式 - -当然,为了代码的整洁,我们更加推荐将样式用 [StyleSheet](hippy-react/modules.md?id=stylesheet) 统一管理,类似 HTML 编程指定 DOM 的 Class 后,再统一在 CSS 书写 Class 对应的样式,示例代码如下: - -```jsx -import React from 'react'; -import { View, StyleSheet, Text } from '@hippy/react'; - -class StyleSheetDemo extends React.Component { - render() { - // 显示一个红色背景色,字体为白色的按钮 - return ( - - - - ); - } -} - -const styles = StyleSheet.create({ - buttonContainer: { - paddingHorizontal: 20, - backgroundColor: 'red', - borderRadius: 4, - height: 60, - alignItems: 'center', - justifyContent: 'center', - }, - buttonText:{ - fontSize: 24, - color: 'white', - } -}); -``` - diff --git a/docs/hippy-react/web.md b/docs/hippy-react/web.md deleted file mode 100644 index 432493e83c1..00000000000 --- a/docs/hippy-react/web.md +++ /dev/null @@ -1,57 +0,0 @@ -# 转 Web - -hippy-react 通过 [@hippy/react-web](//www.npmjs.com/package/@hippy/react-web) 库来将 Hippy 应用转译、运行在浏览器中。 - -> 该项目仍在开发中,有不完善的地方,欢迎 PR。 - -# 安装运行时依赖 - -请使用 `npm i` 安装以下 npm 包,保证转 Web 运行时正常。 - -| 包名 | 说明 | -| --------------- | --------------------------------- | -| bezier-easing | hippy-react 动画在 Web 运行时需要 | -| hippy-react-web | hippy-react 转 Web 适配器 | -| react-dom | react 的 Web 的渲染器 | - -# 编译时依赖 - -以官方提供的 [范例工程](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo) 范例工程为例,需要使用 `npm i -D` 准备好以下依赖,当然开发者可以根据需要自行选择: - -| 包名 | 说明 | -| ------------------- | ----------------------------- | -| css-loader | Webpack 插件 - 内联样式转 CSS | -| html-webpack-plugin | Webpack 插件 - 生成首页 html | -| style-loader | Webpack 插件 - 内联样式 | -| webpack-dev-server | Webpack 网页端调试服务 | - -# 终端开发调试用编译配置 - -该配置展示了将 Hippy 运行于 Web 的最小化配置,并未包含分包等内容,开发者可以自行扩展。 - -和 hippy-react 的主要区别在于做了一个 hippy-react 到 hippy-react-web 的 [alias](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.web.js#L80),使之可以不用修改代码直接运行。 - -| 配置文件 | 说明 | -| ------------------------------------------------------------ | ---------- | -| [hippy-webpack.web.js](//github.com/Tencent/Hippy/blob/master/examples/hippy-react-demo/scripts/hippy-webpack.web.js) | 调试用配置 | - -# 入口文件 - -hippy-react-web 和 hippy-react 的启动参数一致,可以共享同一个 `main.js` 入口文件。 - -# npm script - -hippy-react-web 使用了 [webpack-dev-server](//webpack.js.org/configuration/dev-server/) 来启动调试,可以支持全部的 Web 调试特性,而同时使用同一份配置文件换而使用 webpack 进行打包。 - -这里的命令其实参考了 vue-cli 生成的 Vue 项目,通过 `serve` 启动调试服务,通过 `build` 编译出 JS 包。 - -```json - "scripts": { - "serve": "webpack-dev-server --config ./scripts/hippy-webpack.web.js", - "build": "webpack --config ./scripts/hippy-webpack.web.js", - } -``` - -# 启动调试 - -执行 `npm run serve` 后就会启动 Web 调试,但要注意默认生成的 HTML 文件名是从 `package.json` 的 `name` 字段定义,而不是默认的 `index.html`,所以对于官方范例,需要使用 `http://localhost:8080/hippy-react-demo.html` 来访问调试用页面。 diff --git a/docs/hippy-vue/_sidebar.md b/docs/hippy-vue/_sidebar.md deleted file mode 100644 index 5e4aab0d3eb..00000000000 --- a/docs/hippy-vue/_sidebar.md +++ /dev/null @@ -1,10 +0,0 @@ - - -* Hippy-Vue - * [介绍](hippy-vue/introduction.md) - * [核心组件](hippy-vue/components.md) - * [扩展组件](hippy-vue/external-components.md) - * [终端能力](hippy-vue/vue-native.md) - * [终端事件](hippy-vue/native-event.md) - * [自定义组件和模块](hippy-vue/customize.md) - * [路由](hippy-vue/router.md) diff --git a/docs/hippy-vue/components.md b/docs/hippy-vue/components.md deleted file mode 100644 index b65fa01ce58..00000000000 --- a/docs/hippy-vue/components.md +++ /dev/null @@ -1,432 +0,0 @@ - - -# 核心组件 - -核心组件的定义是跟浏览器、Vue 中保持一致,如果只使用这些组件的话,可以直接跨浏览器。 - ---- - -# a - -该组件目前映射到 Text,目前主要用于在 hippy-vue-router 中进行页面跳转。 一切同 [p](hippy-vue/components.md?id=p)。 - -## 事件 - -| 事件名称 | 描述 | 类型 | 支持平台 | -| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- | -| touchstart | 触屏开始事件,最低支持版本 2.6.2 | `Function` | `ALL` | -| touchmove | 触屏移动事件,最低支持版本 2.6.2 | `Function` | `ALL` | -| touchend | 触屏结束事件,最低支持版本 2.6.2 | `Function` | `ALL` | -| touchcancel | 触屏取消事件,最低支持版本 2.6.2 | `Function` | `ALL` | - ---- - -# button - -[[范例:demo-button.vue]](//github.com/Tencent/Hippy/blob/master/examples/hippy-vue-demo/src/components/demos/demo-button.vue) - -该组件映射到 View 上是因为它是一个可点击的容器,容器里面可以放图片、也可以放文本。但是因为 View 不能包裹文本,所以需要在 `