Compare commits

..

13 Commits

Author SHA1 Message Date
Aaron van Meerten 20b597abda Merge branch 'analytics_include_region_info' of github.com:jitsi/jitsi-meet into analytics_include_region_info 2017-05-23 15:01:18 -05:00
Aaron van Meerten e68be6fa84 assign isn’t supported, so do a for loop 2017-05-23 15:00:42 -05:00
Aaron van Meerten 44d75b5253 add new local file for inclusion via ssi, intended for local variables describing the server
change analytics to pull from new collection jitsiAnalyticsPermanentProperties, which is to be user-defined via javascript in local.html
2017-05-23 15:00:42 -05:00
Aaron van Meerten 440865f3ca missing assignments
lots of line breaks for coding style
2017-05-23 15:00:42 -05:00
Aaron van Meerten e91c62142d fixed trailing comma 2017-05-23 15:00:42 -05:00
Aaron van Meerten 1a892a689e moved to explicit assignment of properties from jitsiRegionInfo
removed no longer needed jshint ignore statement
2017-05-23 15:00:42 -05:00
Aaron van Meerten 04851b4baa add jitsi regional information to all analytics events via permanent properties if available
ignore listing on modules/analytics/analytics.js to avoid es6 linting errors
2017-05-23 15:00:42 -05:00
Aaron van Meerten beec60be47 assign isn’t supported, so do a for loop 2017-05-23 14:59:02 -05:00
Aaron van Meerten 36d40cdec9 add new local file for inclusion via ssi, intended for local variables describing the server
change analytics to pull from new collection jitsiAnalyticsPermanentProperties, which is to be user-defined via javascript in local.html
2017-05-23 14:49:34 -05:00
Aaron van Meerten 5be3504fad missing assignments
lots of line breaks for coding style
2017-05-23 09:50:14 -05:00
Aaron van Meerten bc9ef4421a fixed trailing comma 2017-05-23 09:37:06 -05:00
Aaron van Meerten 4ffe668dd2 moved to explicit assignment of properties from jitsiRegionInfo
removed no longer needed jshint ignore statement
2017-05-23 09:26:49 -05:00
Aaron van Meerten 3cc4d44376 add jitsi regional information to all analytics events via permanent properties if available
ignore listing on modules/analytics/analytics.js to avoid es6 linting errors
2017-05-22 14:40:18 -05:00
3174 changed files with 64325 additions and 318720 deletions

View File

@ -1,15 +0,0 @@
{
"name": "Jitsi Meet Dev Container",
"image": "mcr.microsoft.com/devcontainers/universal:2",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "16"
}
},
"hostRequirements": {
"cpus": 4,
"memory": "8gb",
"storage": "32gb"
},
"postCreateCommand": "bash -i -c 'nvm use && npm install && cp tsconfig.web.json tsconfig.json'"
}

View File

@ -3,15 +3,10 @@ build/*
# Third-party source code which we (1) do not want to modify or (2) try to
# modify as little as possible.
flow-typed/*
libs/*
resources/*
react/features/stream-effects/virtual-background/vendor/*
react/features/face-landmarks/resources/*
# ESLint will by default ignore its own configuration file. However, there does
# not seem to be a reason why we will want to risk being inconsistent with our
# remaining JavaScript source code.
!.eslintrc.js
# Not worth it.
actionTypes.ts

View File

@ -1,6 +1,44 @@
module.exports = {
'env': {
'browser': true,
'commonjs': true,
'es6': true
},
'extends': [
'@jitsi/eslint-config'
'eslint:recommended',
'plugin:flowtype/recommended'
],
'ignorePatterns': [ '*.d.ts' ]
'globals': {
// The globals that (1) are accessed but not defined within many of our
// files, (2) are certainly defined, and (3) we would like to use
// without explicitly specifying them (using a comment) inside of our
// files.
'__filename': false
},
'parser': 'babel-eslint',
'parserOptions': {
'ecmaFeatures': {
'experimentalObjectRestSpread': true
},
'sourceType': 'module'
},
'plugins': [
'flowtype'
],
'rules': {
'new-cap': [
'error',
{
'capIsNew': false // Behave like JSHint's newcap.
}
],
// While it is considered a best practice to avoid using methods on
// console in JavaScript that is designed to be executed in the browser
// and ESLint includes the rule among its set of recommended rules, (1)
// the general practice is to strip such calls before pushing to
// production and (2) we prefer to utilize console in lib-jitsi-meet
// (and jitsi-meet).
'no-console': 'off',
'semi': 'error'
}
};

71
.flowconfig Normal file
View File

@ -0,0 +1,71 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
.*/Libraries/react-native/ReactNative.js
; Ignore packages in node_modules which we (i.e. the jitsi-meet project) have
; seen to cause errors and we have chosen not to fix.
.*/node_modules/babel-core/.*
.*/node_modules/bower/.*
.*/node_modules/jsonlint/.*
.*/node_modules/styled-components/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow
flow/
[options]
emoji=true
module.system=haste
experimental.strict_type_args=true
; FIXME: munge_underscores should be false but right now there are some errors
; if we change the value to false
; Treats class properties with underscore as private. Disabled because currently
; for us "_" can mean protected too.
; munge_underscores=false
munge_underscores=true
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowDisableNextLine
unsafe.enable_getters_and_setters=true
; We (i.e. the jitsi-meet project) are using the haste module system on Web as
; well, not only on React Native. Unfortunately, Flow does not support .web.js
; by default. Override Flow's defaults to include .web.js as well. Technically,
; we have .native.js as well so the choice of .web.js may lead to errors.
; Practically though, it is a potential future problem that we do not have at
; the time of this writing.
module.file_ext=.web.js
; Flow's defaults:
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
[version]
^0.38.0

View File

@ -1,48 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
<!--
This issue tracker is only for reporting bugs and tracking issues related to the source code.
Before posting, please make sure to check if the same or similar bugs have already been discussed: https://github.com/jitsi/jitsi-meet/issues
General questions regarding usage, installation, etc. should be posted at https://community.jitsi.org. They will be closed if posted here.
-->
### Description:
<!-- Please describe the bug clearly and concisely. -->
### Steps to reproduce:
1. <!-- Open '...' -->
2. <!-- Click on '...' -->
3. <!-- and so on... -->
### Expected behavior:
<!-- Please describe what should happen. -->
### Actual behavior:
<!-- Please describe what actually happens. -->
<!-- Please attach screenshot if possible. -->
### Server information:
- Jitsi Meet version:
- Operating System:
### Client information:
- Browser / app version:
- Operating System:
### Additional information:
<!-- Please provide additional information about the bug, if any. -->

View File

@ -1,25 +0,0 @@
---
name: "Feature request"
about: Suggest an idea for this project
title: ''
labels: 'feature-request'
assignees: ''
---
<!--
Thank you for suggesting an idea to make Jitsi Meet better.
Please fill in as much of the template below as you're able.
Note that the ultimate decision for implementing features lies on the Jitsi team, not all feature requests shall be accepted.
-->
**Is your feature request related to a problem you are facing?**
Please describe the problem you are trying to solve.
**Describe the solution you'd like**
Please describe the desired behavior.
**Describe alternatives you've considered**
Please describe alternative solutions or features you have considered.

View File

@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Need help with Jitsi Meet?
url: https://community.jitsi.org
about: Please ask it in our community.

View File

@ -1,5 +0,0 @@
<!--
Thank you for your pull request. Please provide a thorough description below.
Contributors guide: https://github.com/jitsi/jitsi-meet/blob/master/CONTRIBUTING.md
-->

16
.github/stale.yml vendored
View File

@ -1,16 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- confirmed
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -1,25 +0,0 @@
name: Lua CI
on: [pull_request]
jobs:
luacheck:
name: Luacheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install luarocks
run: sudo apt-get --install-recommends -y install luarocks
- name: Install luacheck
run: sudo luarocks install luacheck
- name: Check lua codes
run: |
set -o pipefail && luacheck . | awk -F: '
{
print $0
printf "::warning file=%s,line=%s,col=%s::%s\n", $1, $2, $3, $4
}
'

View File

@ -1,44 +0,0 @@
name: Simple CI
on: [pull_request]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
- run: npm install
- name: Check git status
run: git status
- name: Normalize lang files to ensure sorted
run: npm run lang-sort
- name: Check if the git repository is clean
run: $(exit $(git status --porcelain --untracked-files=no | head -255 | wc -l)) || (echo "Dirty git tree"; git diff; exit 1)
- run: npm run lint:ci
linux-build:
name: Build Frontend (Linux)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
- run: npm install
- run: make
macos-ci:
name: Build Frontend (macOS)
runs-on: macOS-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
- run: npm install
- run: make

44
.gitignore vendored
View File

@ -7,9 +7,6 @@ all.css
.remote-sync.json
.sync-config.cson
# CocoaPods
Pods/
# The following are automatically generated by the react-native command line
# utility (either with the init or upgrade option which pull in the latest
# template files recommended by Facebook for React Native).
@ -35,7 +32,6 @@ xcuserdata
DerivedData
*.hmap
*.ipa
*.dSYM.zip
*.xcuserstate
project.xcworkspace
@ -61,35 +57,11 @@ buck-out/
# fastlane
#
*/fastlane/report.xml
*/fastlane/Preview.html
# Build artifacts
*.jsbundle
*.framework
android/app/debug
android/app/release
ios/sdk/out
# precommit-hook
.jshintignore
.jshintrc
# VSCode files
android/.project
android/.settings/org.eclipse.buildship.core.prefs
# Secrets
android/app/dropbox.key
android/app/google-services.json
ios/app/dropbox.key
ios/app/GoogleService-Info.plist
.vscode
# TWA
twa/*.apk
twa/*.aab
twa/assetlinks.json
tsconfig.json
# It is recommended to not store the screenshots in the git repo. Instead, use
# fastlane to re-generate the screenshots whenever they are needed. For more
# information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
#
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots

21
.jshintignore Normal file
View File

@ -0,0 +1,21 @@
# The following do not need to be checked because they do not represent JS
# source code.
build/
debian/
libs/
node_modules/
# The following are checked by ESLint with the maximum configuration which
# supersedes JSHint.
flow-typed/
modules/API/
modules/remotecontrol/
modules/transport/
react/
# The following are checked by ESLint with the minimum configuration which does
# not supersede JSHint but take advantage of advanced language features such as
# Facebook Flow which are not supported by JSHint.
modules/translation/translation.js
analytics.js

20
.jshintrc Normal file
View File

@ -0,0 +1,20 @@
{
// Refer to http://jshint.com/docs/options/ for an exhaustive list of options
"asi": false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
"expr": true, // true: Tolerate `ExpressionStatement` as Programs
"loopfunc": true, // true: Tolerate functions being defined in loops
"curly": false, // true: Require {} for every new block or scope
"evil": true, // true: Tolerate use of `eval` and `new Function()`
"white": true,
"undef": true, // true: Require all non-global variables to be declared (prevents global leaks)
"browser": true, // Web Browser (window, document, etc)
"node": true, // Node.js
"trailing": true,
"indent": 4, // {int} Number of spaces to use for indentation
"latedef": true, // true: Require variables/functions to be defined before being used
"newcap": true, // true: Require capitalization of all constructor functions e.g. `new F()`
"maxlen": 80, // {int} Max number of characters per line
"latedef": false, //This option prohibits the use of a variable before it was defined
"laxbreak": true, //Ignore line breaks around "=", "==", "&&", etc.
"esnext": true //support ES2015
}

View File

@ -1,8 +0,0 @@
global = false
unused = false
redefined = false
ignore = { "581" }
max_line_length = false
color = false
formatter = "plain"
quiet = 1

3
.npmrc
View File

@ -1,3 +0,0 @@
package-lock=true
; FIXME Set legacy-peer-deps=false when we upgrade RN.
legacy-peer-deps=true

1
.nvmrc
View File

@ -1 +0,0 @@
16

View File

@ -1,6 +0,0 @@
osx_image: xcode11.1
language: objective-c
script:
- "./ios/travis-ci/build-ipa.sh"
after_script:
- sleep 10

View File

@ -3,8 +3,8 @@ We would love to have your help. Before you start working however, please read
and follow this short guide.
# Reporting Issues
Provide as much information as possible. Mention the version of Jitsi Meet,
Jicofo and JVB you are using, and explain (as detailed as you can) how the
Provide as much information as possible. Mention the version of Jitsi Meet,
Jicofo and JVB you are using, and explain (as detailed as you can) how the
problem can be reproduced.
# Code contributions
@ -13,7 +13,7 @@ Found a bug and know how to fix it? Great! Please read on.
## Contributor License Agreement
While the Jitsi projects are released under the
[Apache License 2.0](https://github.com/jitsi/jitsi-meet/blob/master/LICENSE), the copyright
holder and principal creator is [8x8](https://www.8x8.com/). To
holder and principal creator is [Atlassian](https://www.atlassian.com/). To
ensure that we can continue making these projects available under an Open Source license,
we need you to sign our Apache-based contributor
license agreement as either a [corporation](https://jitsi.org/ccla) or an
@ -21,151 +21,9 @@ license agreement as either a [corporation](https://jitsi.org/ccla) or an
in the agreement, unfortunately, we cannot accept your contribution.
## Creating Pull Requests
- Make sure your code passes the linter rules beforehand. The linter is executed
- Make sure your code passes the linter rules beforehand. The linter is exeuted
automatically when committing code.
- Perform **one** logical change per pull request.
- Maintain a clean list of commits, squash them if necessary.
- Rebase your topic branch on top of the master branch before creating the pull
request.
## Coding style
### Comments
* Comments documenting the source code are required.
* Comments from which documentation is automatically generated are **not**
subject to case-by-case decisions. Such comments are used, for example, on
types and their members. Examples of tools which automatically generate
documentation from such comments include JSDoc, Javadoc, Doxygen.
* Comments which are not automatically processed are strongly encouraged. They
are subject to case-by-case decisions. Such comments are often observed in
function bodies.
* Comments should be formatted as proper English sentences. Such formatting pays
attention to, for example, capitalization and punctuation.
### Duplication
* Don't copy-paste source code. Reuse it.
### Formatting
* Line length is limited to 120 characters.
* Sort by alphabetical order in order to make the addition of new entities as
easy as looking a word up in a dictionary. Otherwise, one risks duplicate
entries (with conflicting values in the cases of key-value pairs). For
example:
* Within an `import` of multiple names from a module, sort the names in
alphabetical order. (Of course, the default name stays first as required by
the `import` syntax.)
````javascript
import {
DOMINANT_SPEAKER_CHANGED,
JITSI_CLIENT_CONNECTED,
JITSI_CLIENT_CREATED,
JITSI_CLIENT_DISCONNECTED,
JITSI_CLIENT_ERROR,
JITSI_CONFERENCE_JOINED,
MODERATOR_CHANGED,
PEER_JOINED,
PEER_LEFT,
RTC_ERROR
} from './actionTypes';
````
* Within a group of imports (e.g. groups of imports delimited by an empty line
may be: third-party modules, then project modules, and eventually the
private files of a module), sort the module names in alphabetical order.
````javascript
import React, { Component } from 'react';
import { connect } from 'react-redux';
````
### Indentation
* Align `switch` and `case`/`default`. Don't indent the `case`/`default` more
than its `switch`.
````javascript
switch (i) {
case 0:
...
break;
default:
...
}
````
### Naming
* An abstraction should have one name within the project and across multiple
projects. For example:
* The instance of lib-jitsi-meet's `JitsiConnection` type should be named
`connection` or `jitsiConnection` in jitsi-meet, not `client`.
* The class `ReducerRegistry` should be defined in ReducerRegistry.js and its
imports in other files should use the same name. Don't define the class
`Registry` in ReducerRegistry.js and then import it as `Reducers` in other
files.
* The names of global constants (including ES6 module-global constants) should
be written in uppercase with underscores to separate words. For example,
`BACKGROUND_COLOR`.
* The underscore character at the beginning of a name signals that the
respective variable, function, property is non-public i.e. private, protected,
or internal. In contrast, the lack of an underscore at the beginning of a name
signals public API.
### Feature layout
When adding a new feature, this would be the usual layout.
```
react/features/sample/
├── actionTypes.ts
├── actions.js
├── components
│   ├── AnotherComponent.js
│   ├── OneComponent.js
│   └── index.js
├── middleware.js
└── reducer.js
```
The middleware must be imported in `react/features/app/` specifically
in `middlewares.any.ts`, `middlewares.native.ts` or `middlewares.web.ts` where appropriate.
Likewise for the reducer.
An `index.js` file must not be provided for exporting actions, action types and
component. Features / files requiring those must import them explicitly.
This has not always been the case and the entire codebase hasn't been migrated to
this model but new features should follow this new layout.
When working on an old feature, adding the necessary changes to migrate to the new
model is encouraged.
### Avoiding bundle bloat
When adding a new feature it's possible that it triggers a build failure due to the increased bundle size. We have safeguards inplace to avoid bundles growing disproportionatelly. While there are legit reasons for increasing the limits, please analyze the bundle first to make sure no unintended dependencies have been included, causing the increase in size.
First, make a production build with bundle-analysis enabled:
```
npx webpack -p --analyze-bundle
```
Then open the interactive bundle analyzer tool:
```
npx webpack-bundle-analyzer build/app-stats.json
```

11
ConferenceEvents.js Normal file
View File

@ -0,0 +1,11 @@
/**
* Notifies interested parties that hangup procedure will start.
*/
export const BEFORE_HANGUP = "conference.before_hangup";
/**
* Notifies interested parties that desktop sharing enable/disable state is
* changed.
*/
export const DESKTOP_SHARING_ENABLED_CHANGED
= "conference.desktop_sharing_enabled_changed";

105
Makefile
View File

@ -1,132 +1,57 @@
BUILD_DIR = build
CLEANCSS = ./node_modules/.bin/cleancss
DEPLOY_DIR = libs
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet
OLM_DIR = node_modules/@matrix-org/olm
TF_WASM_DIR = node_modules/@tensorflow/tfjs-backend-wasm/dist/
RNNOISE_WASM_DIR = node_modules/@jitsi/rnnoise-wasm/dist
EXCALIDRAW_DIR = node_modules/@jitsi/excalidraw/dist/excalidraw-assets
EXCALIDRAW_DIR_DEV = node_modules/@jitsi/excalidraw/dist/excalidraw-assets-dev
TFLITE_WASM = react/features/stream-effects/virtual-background/vendor/tflite
MEET_MODELS_DIR = react/features/stream-effects/virtual-background/vendor/models
FACE_MODELS_DIR = node_modules/@vladmandic/human-models/models
NODE_SASS = ./node_modules/.bin/sass
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
NODE_SASS = ./node_modules/.bin/node-sass
NPM = npm
OUTPUT_DIR = .
STYLES_BUNDLE = css/all.bundle.css
STYLES_DESTINATION = css/all.css
STYLES_MAIN = css/main.scss
ifeq ($(OS),Windows_NT)
WEBPACK = .\node_modules\.bin\webpack
WEBPACK_DEV_SERVER = .\node_modules\.bin\webpack serve --mode development
else
WEBPACK = ./node_modules/.bin/webpack
WEBPACK_DEV_SERVER = ./node_modules/.bin/webpack serve --mode development
endif
WEBPACK = ./node_modules/.bin/webpack
all: compile deploy clean
compile:
NODE_OPTIONS=--max-old-space-size=8192 \
$(WEBPACK)
$(WEBPACK) -p
clean:
rm -fr $(BUILD_DIR)
.NOTPARALLEL:
deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-excalidraw deploy-tflite deploy-meet-models deploy-lib-jitsi-meet deploy-olm deploy-tf-wasm deploy-css deploy-local deploy-face-landmarks
deploy: deploy-init deploy-appbundle deploy-lib-jitsi-meet deploy-css deploy-local
deploy-init:
rm -fr $(DEPLOY_DIR)
mkdir -p $(DEPLOY_DIR)
deploy-appbundle:
cp \
$(BUILD_DIR)/app.bundle.min.js \
$(BUILD_DIR)/app.bundle.min.js.map \
$(BUILD_DIR)/app.bundle.min.map \
$(BUILD_DIR)/do_external_connect.min.js \
$(BUILD_DIR)/do_external_connect.min.map \
$(BUILD_DIR)/external_api.min.js \
$(BUILD_DIR)/external_api.min.js.map \
$(BUILD_DIR)/alwaysontop.min.js \
$(BUILD_DIR)/alwaysontop.min.js.map \
$(OUTPUT_DIR)/analytics-ga.js \
$(BUILD_DIR)/analytics-ga.min.js \
$(BUILD_DIR)/analytics-ga.min.js.map \
$(BUILD_DIR)/face-landmarks-worker.min.js \
$(BUILD_DIR)/face-landmarks-worker.min.js.map \
$(BUILD_DIR)/noise-suppressor-worklet.min.js \
$(BUILD_DIR)/noise-suppressor-worklet.min.js.map \
$(BUILD_DIR)/external_api.min.map \
$(OUTPUT_DIR)/analytics.js \
$(DEPLOY_DIR)
cp \
$(BUILD_DIR)/close3.min.js \
$(BUILD_DIR)/close3.min.js.map \
$(DEPLOY_DIR) || true
deploy-lib-jitsi-meet:
cp \
$(LIBJITSIMEET_DIR)/dist/umd/lib-jitsi-meet.min.js \
$(LIBJITSIMEET_DIR)/dist/umd/lib-jitsi-meet.min.map \
$(LIBJITSIMEET_DIR)/dist/umd/lib-jitsi-meet.e2ee-worker.js \
$(LIBJITSIMEET_DIR)/modules/browser/capabilities.json \
$(DEPLOY_DIR)
deploy-olm:
cp \
$(OLM_DIR)/olm.wasm \
$(DEPLOY_DIR)
deploy-tf-wasm:
cp \
$(TF_WASM_DIR)/*.wasm \
$(DEPLOY_DIR)
deploy-rnnoise-binary:
cp \
$(RNNOISE_WASM_DIR)/rnnoise.wasm \
$(DEPLOY_DIR)
deploy-tflite:
cp \
$(TFLITE_WASM)/*.wasm \
$(DEPLOY_DIR)
deploy-excalidraw:
cp -R \
$(EXCALIDRAW_DIR) \
$(DEPLOY_DIR)/
deploy-excalidraw-dev:
cp -R \
$(EXCALIDRAW_DIR_DEV) \
$(DEPLOY_DIR)/
deploy-meet-models:
cp \
$(MEET_MODELS_DIR)/*.tflite \
$(DEPLOY_DIR)
deploy-face-landmarks:
cp \
$(FACE_MODELS_DIR)/blazeface-front.bin \
$(FACE_MODELS_DIR)/blazeface-front.json \
$(FACE_MODELS_DIR)/emotion.bin \
$(FACE_MODELS_DIR)/emotion.json \
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.js \
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.map \
$(LIBJITSIMEET_DIR)/connection_optimization/external_connect.js \
$(DEPLOY_DIR)
deploy-css:
$(NODE_SASS) $(STYLES_MAIN) $(STYLES_BUNDLE) && \
$(CLEANCSS) --skip-rebase $(STYLES_BUNDLE) > $(STYLES_DESTINATION) && \
$(CLEANCSS) $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
rm $(STYLES_BUNDLE)
deploy-local:
([ ! -x deploy-local.sh ] || ./deploy-local.sh)
.NOTPARALLEL:
dev: deploy-init deploy-css deploy-rnnoise-binary deploy-tflite deploy-meet-models deploy-lib-jitsi-meet deploy-olm deploy-tf-wasm deploy-excalidraw-dev deploy-face-landmarks
$(WEBPACK_DEV_SERVER)
source-package:
mkdir -p source_package/jitsi-meet/css && \
cp -r *.js *.html resources/*.txt favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp -r *.js *.html connection_optimization favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp css/all.css source_package/jitsi-meet/css && \
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
rm -rf source_package

128
README.md
View File

@ -1,87 +1,105 @@
# <p align="center">Jitsi Meet</p>
# Jitsi Meet - Secure, Simple and Scalable Video Conferences
Jitsi Meet is a set of Open Source projects which empower users to use and deploy
video conferencing platforms with state-of-the-art video quality and features.
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, scalable video conferences. You can see [Jitsi Meet in action](http://youtu.be/7vFUVClsNh0) here at the session #482 of the VoIP Users Conference.
<hr />
You can also try it out yourself at https://meet.jit.si .
<p align="center">
<img src="https://raw.githubusercontent.com/jitsi/jitsi-meet/master/readme-img1.png" width="900" />
</p>
Jitsi Meet allows for very efficient collaboration. It allows users to stream their desktop or only some windows. It also supports shared document editing with Etherpad.
<hr />
## Installation
Amongst others here are the main features Jitsi Meet offers:
Installing Jitsi Meet is quite a simple experience. For Debian-based systems, we recommend following the [quick-install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md) document, which uses the package system.
* Support for all current browsers
* Mobile applications
* Web and native SDKs for integration
* HD audio and video
* Content sharing
* Raise hand and reactions
* Chat with private conversations
* Polls
* Virtual backgrounds
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md).
And many more!
## Download
## Using Jitsi Meet
You can download Debian/Ubuntu binaries:
* [stable](https://download.jitsi.org/stable/) ([instructions](https://jitsi.org/Main/InstallJitsiMeetDebianStableRepository))
* [testing](https://download.jitsi.org/testing/) ([instructions](https://jitsi.org/Main/InstallJitsiMeetDebianTestingRepository))
* [nightly](https://download.jitsi.org/unstable/) ([instructions](https://jitsi.org/Main/InstallJitsiMeetDebianNightlyRepository))
Using Jitsi Meet is straightforward, as it's browser based. Head over to [meet.jit.si](https://meet.jit.si) and give it a try. It's anonymous, scalable and free to use. All browsers are supported!
You can download source archives (produced by ```make source-package```):
* [source builds](https://download.jitsi.org/jitsi-meet/src/)
Using mobile? No problem, you can either use your mobile web browser or our fully-featured
mobile apps:
You can get our mobile versions from here:
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
| Android | Android (F-Droid) | iOS |
|:-:|:-:|:-:|
| [<img src="resources/img/google-play-badge.png" height="50">](https://play.google.com/store/apps/details?id=org.jitsi.meet) | [<img src="resources/img/f-droid-badge.png" height="50">](https://f-droid.org/en/packages/org.jitsi.meet/) | [<img src="resources/img/appstore-badge.png" height="50">](https://itunes.apple.com/us/app/jitsi-meet/id1165103905) |
## Building the sources
If you are feeling adventurous and want to get an early scoop of the features as they are being
developed you can also sign up for our open beta testing here:
On Debian/Ubuntu systems, the required packages can be installed with:
```
sudo apt-get install npm nodejs-legacy
cd jitsi-meet
npm install
```
* [Android](https://play.google.com/apps/testing/org.jitsi.meet)
* [iOS](https://testflight.apple.com/join/isy6ja7S)
To build the Jitsi Meet application, just type
```
make
```
## Running your own instance
## Working with the library sources (lib-jitsi-meet)
If you'd like to run your own Jitsi Meet installation head over to the [handbook](https://jitsi.github.io/handbook/docs/devops-guide/) to get started.
By default the library is build from its git repository sources. The default dependency path in package.json is :
```json
"lib-jitsi-meet": "jitsi/lib-jitsi-meet",
```
We provide Debian packages and a comprehensive Docker setup to make deployments as simple as possible.
Advanced users also have the possibility of building all the components from source.
To work with local copy you must change the path to:
```json
"lib-jitsi-meet": "file:///Users/name/local-lib-jitsi-meet-copy",
```
You can check the latest releases [here](https://jitsi.github.io/handbook/docs/releases).
To make the project you must force it to take the sources as 'npm update' will not do it.
```
npm install lib-jitsi-meet --force && make
```
## Jitsi as a Service
Or if you are making only changes to the library:
```
npm install lib-jitsi-meet --force && make deploy-lib-jitsi-meet
```
If you like the branding capabilities of running your own instance but you'd like
to avoid dealing with the complexity of monitoring, scaling and updates, JaaS might be
for you.
Alternative way is to use [npm link](https://docs.npmjs.com/cli/link).
It allows to link `lib-jitsi-meet` dependency to local source in few steps:
[8x8 Jitsi as a Service (JaaS)](https://jaas.8x8.vc) is an enterprise-ready video meeting platform that allows developers, organizations and businesses to easily build and deploy video solutions. With Jitsi as a Service we now give you all the power of Jitsi running on our global platform so you can focus on building secure and branded video experiences.
```bash
cd lib-jitsi-meet
## Documentation
# create global symlink for lib-jitsi-meet package
npm link
All the Jitsi Meet documentation is available in [the handbook](https://jitsi.github.io/handbook/).
cd ../jitsi-meet
## Security
# create symlink from the local node_modules folder to the global lib-jitsi-meet symlink
npm link lib-jitsi-meet
```
For a comprehensive description of all Jitsi Meet's security aspects, please check [this link](https://jitsi.org/security).
So now after changes in local `lib-jitsi-meet` repository you can rebuild it with `npm run install` and your `jitsi-meet` repository will use that modified library.
Note: when using node version 4.x, the make file of jitsi-meet do npm update which will delete the link, no longer the case with version 6.x.
For a detailed description of Jitsi Meet's End-to-End Encryption (E2EE) implementation,
please check [this link](https://jitsi.org/e2ee-whitepaper/).
For information on reporting security vulnerabilities in Jitsi Meet, see [SECURITY.md](./SECURITY.md).
If you do not want to use local repository anymore you should run
```bash
cd jitsi-meet
npm unlink lib-jitsi-meet
npm install
```
## Contributing
If you are looking to contribute to Jitsi Meet, first of all, thank you! Please
see our [guidelines for contributing](CONTRIBUTING.md).
<br />
<br />
## Embedding in external applications
<footer>
<p align="center" style="font-size: smaller;">
Built with ❤️ by the Jitsi team at <a href="https://8x8.com" target="_blank">8x8</a> and our community.
</p>
</footer>
Jitsi Meet provides a very flexible way of embedding it in external applications by using the [Jitsi Meet API](doc/api.md).
## Mobile app
Jitsi Meet is also available as a React Native application for Android and iOS.
Instructions on how to build it can be found [here](doc/mobile.md).
## Acknowledgements
Jitsi Meet started out as a sample conferencing application using Jitsi Videobridge. It was originally developed by then ESTOS' developer Philipp Hancke who then contributed it to the community where development continues with joint forces!

View File

@ -1,9 +0,0 @@
# Security
## Reporting security issues
We take security very seriously and develop all Jitsi projects to be secure and safe.
If you find (or simply suspect) a security issue in any of the Jitsi projects, please report it to us via [HackerOne](https://hackerone.com/8x8) or send us an email to security@jitsi.org.
**We encourage responsible disclosure for the sake of our users, so please reach out before posting in a public space.**

View File

@ -1,163 +0,0 @@
/* global ga */
(function(ctx) {
/**
*
*/
function Analytics(options) {
/* eslint-disable */
if (!options.googleAnalyticsTrackingId) {
console.log(
'Failed to initialize Google Analytics handler, no tracking ID');
return;
}
/**
* Google Analytics
* TODO: Keep this local, there's no need to add it to window.
*/
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', options.googleAnalyticsTrackingId, 'auto');
ga('send', 'pageview');
/* eslint-enable */
}
/**
* Extracts the integer to use for a Google Analytics event's value field
* from a lib-jitsi-meet analytics event.
* @param {Object} event - The lib-jitsi-meet analytics event.
* @returns {Object} - The integer to use for the 'value' of a Google
* Analytics event.
* @private
*/
Analytics.prototype._extractAction = function(event) {
// Page events have a single 'name' field.
if (event.type === 'page') {
return event.name;
}
// All other events have action, actionSubject, and source fields. All
// three fields are required, and the often jitsi-meet and
// lib-jitsi-meet use the same value when separate values are not
// necessary (i.e. event.action == event.actionSubject).
// Here we concatenate these three fields, but avoid adding the same
// value twice, because it would only make the GA event's action harder
// to read.
let action = event.action;
if (event.actionSubject && event.actionSubject !== event.action) {
// Intentionally use string concatenation as analytics needs to
// work on IE but this file does not go through babel. For some
// reason disabling this globally for the file does not have an
// effect.
// eslint-disable-next-line prefer-template
action = event.actionSubject + '.' + action;
}
if (event.source && event.source !== event.action
&& event.source !== event.action) {
// eslint-disable-next-line prefer-template
action = event.source + '.' + action;
}
return action;
};
/**
* Extracts the integer to use for a Google Analytics event's value field
* from a lib-jitsi-meet analytics event.
* @param {Object} event - The lib-jitsi-meet analytics event.
* @returns {Object} - The integer to use for the 'value' of a Google
* Analytics event, or NaN if the lib-jitsi-meet event doesn't contain a
* suitable value.
* @private
*/
Analytics.prototype._extractValue = function(event) {
let value = event && event.attributes && event.attributes.value;
// Try to extract an integer from the "value" attribute.
value = Math.round(parseFloat(value));
return value;
};
/**
* Extracts the string to use for a Google Analytics event's label field
* from a lib-jitsi-meet analytics event.
* @param {Object} event - The lib-jitsi-meet analytics event.
* @returns {string} - The string to use for the 'label' of a Google
* Analytics event.
* @private
*/
Analytics.prototype._extractLabel = function(event) {
let label = '';
// The label field is limited to 500B. We will concatenate all
// attributes of the event, except the user agent because it may be
// lengthy and is probably included from elsewhere.
for (const property in event.attributes) {
if (property !== 'permanent_user_agent'
&& property !== 'permanent_callstats_name'
&& event.attributes.hasOwnProperty(property)) {
// eslint-disable-next-line prefer-template
label += property + '=' + event.attributes[property] + '&';
}
}
if (label.length > 0) {
label = label.slice(0, -1);
}
return label;
};
/**
* This is the entry point of the API. The function sends an event to
* google analytics. The format of the event is described in
* AnalyticsAdapter in lib-jitsi-meet.
* @param {Object} event - the event in the format specified by
* lib-jitsi-meet.
*/
Analytics.prototype.sendEvent = function(event) {
if (!event || !ga) {
return;
}
const ignoredEvents
= [ 'e2e_rtt', 'rtp.stats', 'rtt.by.region', 'available.device',
'stream.switch.delay', 'ice.state.changed', 'ice.duration' ];
// Temporary removing some of the events that are too noisy.
if (ignoredEvents.indexOf(event.action) !== -1) {
return;
}
const gaEvent = {
'eventCategory': 'jitsi-meet',
'eventAction': this._extractAction(event),
'eventLabel': this._extractLabel(event)
};
const value = this._extractValue(event);
if (!isNaN(value)) {
gaEvent.eventValue = value;
}
ga('send', 'event', gaEvent);
};
if (typeof ctx.JitsiMeetJS === 'undefined') {
ctx.JitsiMeetJS = {};
}
if (typeof ctx.JitsiMeetJS.app === 'undefined') {
ctx.JitsiMeetJS.app = {};
}
if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === 'undefined') {
ctx.JitsiMeetJS.app.analyticsHandlers = [];
}
ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
})(window);
/* eslint-enable prefer-template */

33
analytics.js Normal file
View File

@ -0,0 +1,33 @@
/* global ga */
(function (ctx) {
function Analytics() {
/* eslint-disable */
/**
* Google Analytics
*/
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-319188-14', 'jit.si');
ga('send', 'pageview');
/* eslint-enable */
}
Analytics.prototype.sendEvent = function (action, data) {
// empty label if missing value for it and add the value,
// the value should be integer or null
var value = data.value;
value = value? Math.round(parseFloat(value)) : null;
var label = data.label || "";
ga('send', 'event', 'jit.si',
action + '.' + data.browserName, label, value);
};
if(typeof ctx.analyticsHandlers === "undefined")
ctx.analyticsHandlers = [];
ctx.analyticsHandlers.push(Analytics);
}(window));

View File

@ -1,3 +0,0 @@
# Jitsi Meet SDK for Android
This document has been moved to [The Handbook](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk).

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@ -1,2 +0,0 @@
connection.project.dir=..
eclipse.preferences.version=1

66
android/app/BUCK Normal file
View File

@ -0,0 +1,66 @@
import re
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
lib_deps = []
for jarfile in glob(['libs/*.jar']):
name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile)
lib_deps.append(':' + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)
for aarfile in glob(['libs/*.aar']):
name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile)
lib_deps.append(':' + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
android_library(
name = 'all-libs',
exported_deps = lib_deps
)
android_library(
name = 'app-code',
srcs = glob([
'src/main/java/**/*.java',
]),
deps = [
':all-libs',
':build_config',
':res',
],
)
android_build_config(
name = 'build_config',
package = 'org.jitsi.meet',
)
android_resource(
name = 'res',
res = 'src/main/res',
package = 'org.jitsi.meet',
)
android_binary(
name = 'app',
package_type = 'debug',
manifest = 'src/main/AndroidManifest.xml',
keystore = '//android/keystores:debug',
deps = [
':app-code',
],
)

View File

@ -1,176 +1,159 @@
apply plugin: 'com.android.application'
// Crashlytics integration is done as part of Firebase now, so it gets
// automagically activated with google-services.json
if (googleServicesEnabled) {
apply plugin: 'com.google.firebase.crashlytics'
}
import com.android.build.OutputFile
// Use the number of seconds/10 since Jan 1 2019 as the versionCode.
// This lets us upload a new build at most every 10 seconds for the
// next ~680 years.
// https://stackoverflow.com/a/38643838
def vcode = (int) (((new Date().getTime() / 1000) - 1546297200) / 10)
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.android.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"]
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
apply from: '../../node_modules/react-native/react.gradle'
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
packagingOptions {
exclude 'lib/*/libhermes*.so'
}
compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
applicationId 'org.jitsi.meet'
versionCode vcode
versionName project.appVersion
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
minSdkVersion 16
targetSdkVersion 22
versionCode Integer.parseInt("${version}")
versionName "1.4.${version}"
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
abiFilters 'armeabi-v7a', 'x86'
}
packagingOptions {
// The project react-native does not provide 64-bit binaries at the
// time of this writing. Unfortunately, packaging any 64-bit
// binaries into the .apk will crash the app at runtime on 64-bit
// platforms.
exclude 'lib/x86_64/libjingle_peerconnection_so.so'
exclude 'lib/arm64-v8a/libjingle_peerconnection_so.so'
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include 'armeabi-v7a', 'x86'
}
}
buildTypes {
debug {
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
}
release {
// Uncomment the following line for singing a test release build.
//signingConfig signingConfigs.debug
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-release.pro'
buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
java {
if (rootProject.ext.libreBuild) {
srcDir "src"
exclude "**/GoogleServicesHelper.java"
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ['armeabi-v7a':1, 'x86':2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
if (project.hasProperty('JITSI_SIGNING')
&& new File(project.property('JITSI_SIGNING')).exists()) {
apply from: project.property('JITSI_SIGNING');
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.5.1'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
if (!rootProject.ext.libreBuild) {
implementation 'com.google.android.gms:play-services-auth:16.0.1'
// Firebase
// - Crashlytics
// - Dynamic Links
implementation 'com.google.firebase:firebase-analytics:17.5.0'
implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
implementation 'com.google.firebase:firebase-dynamic-links:19.1.0'
}
implementation project(':sdk')
compile project(':react-native-background-timer')
compile project(':react-native-immersive')
compile project(':react-native-keep-awake')
compile project(':react-native-vector-icons')
compile project(':react-native-webrtc')
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.facebook.react:react-native:+' // From node_modules
}
gradle.projectsEvaluated {
// Dropbox integration
//
def dropboxAppKey
if (project.file('dropbox.key').exists()) {
dropboxAppKey = project.file('dropbox.key').text.trim() - 'db-'
}
if (dropboxAppKey) {
android.defaultConfig.resValue('string', 'dropbox_app_key', "${dropboxAppKey}")
def dropboxActivity = """
<activity
android:configChanges="keyboard|orientation"
android:exported="true"
android:launchMode="singleTask"
android:name="com.dropbox.core.android.AuthActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="db-${dropboxAppKey}" />
</intent-filter>
</activity>"""
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
output.getProcessManifestProvider().get().doLast {
def outputDir = multiApkManifestOutputDirectory.get().asFile
def manifestPath = new File(outputDir, 'AndroidManifest.xml')
def charset = 'UTF-8'
def text
text = manifestPath.getText(charset)
text = text.replace('</application>', "${dropboxActivity}</application>")
manifestPath.write(text, charset)
}
}
}
}
// Run React packager
android.applicationVariants.all { variant ->
def targetName = variant.name.capitalize()
def currentRunPackagerTask = tasks.create(
name: "run${targetName}ReactPackager",
type: Exec) {
group = "react"
description = "Run the React packager."
doFirst {
println "Starting the React packager..."
def androidRoot = file("${projectDir}/../")
// Set up the call to the script
workingDir androidRoot
// Run the packager
commandLine("scripts/run-packager.sh")
}
// Set up dev mode
def devEnabled = !targetName.toLowerCase().contains("release")
// Only enable for dev builds
enabled devEnabled
}
def packageTask = variant.packageApplicationProvider.get()
packageTask.dependsOn(currentRunPackagerTask)
}
apply from: '../../node_modules/react-native-vector-icons/fonts.gradle'
}
if (googleServicesEnabled) {
apply plugin: 'com.google.gms.google-services'
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}

Binary file not shown.

View File

@ -1,6 +0,0 @@
-include proguard-rules.pro
# Crashlytics
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception

View File

@ -9,6 +9,17 @@
# 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 *;
#}
# Disabling obfuscation is useful if you collect stack traces from production crashes
# (unless you are using a system that supports de-obfuscate the stack traces).
-dontobfuscate
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
@ -38,7 +49,6 @@
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
-keep,includedescriptorclasses class com.facebook.react.bridge.** { *; }
# okhttp
@ -53,41 +63,4 @@
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-keep class okio.** { *; }
-dontwarn okio.**
# WebRTC
-keep class org.webrtc.** { *; }
-dontwarn org.chromium.build.BuildHooksAndroid
# Jisti Meet SDK
-keep class org.jitsi.meet.** { *; }
-keep class org.jitsi.meet.sdk.** { *; }
# We added the following when we switched minifyEnabled on. Probably because we
# ran the app and hit problems...
-keep class com.facebook.react.bridge.CatalystInstanceImpl { *; }
-keep class com.facebook.react.bridge.ExecutorToken { *; }
-keep class com.facebook.react.bridge.JavaScriptExecutor { *; }
-keep class com.facebook.react.bridge.ModuleRegistryHolder { *; }
-keep class com.facebook.react.bridge.ReadableType { *; }
-keep class com.facebook.react.bridge.queue.NativeRunnable { *; }
-keep class com.facebook.react.devsupport.** { *; }
-dontwarn com.facebook.react.devsupport.**
-dontwarn com.google.appengine.**
-dontwarn com.squareup.okhttp.**
-dontwarn javax.servlet.**
# ^^^ We added the above when we switched minifyEnabled on.
# Rule to avoid build errors related to SVGs.
-keep public class com.horcrux.svg.** {*;}
# https://github.com/facebook/fresco/issues/2638
-keep public class com.facebook.imageutils.** {
public *;
}

View File

@ -1,46 +1,60 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jitsi.meet"
android:installLocation="auto">
<application
android:versionCode="1"
android:versionName="1.0">
<!-- XXX: ACCESS_NETWORK_STATE is required by WebRTC. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="23" />
<application
android:allowBackup="true"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".MainApplication"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
<meta-data
android:name="android.content.APP_RESTRICTIONS"
android:resource="@xml/app_restrictions" />
<activity
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:exported="true"
<activity
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTask"
android:name=".MainActivity"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:windowSoftInputMode="adjustResize">
<meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="alpha.jitsi.net" android:scheme="https" />
<data android:host="beta.meet.jit.si" android:scheme="https" />
<data android:host="meet.jit.si" android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="org.jitsi.meet" />
</intent-filter>
</activity>
</application>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:host="beta.hipchat.me" android:scheme="https" />
<data android:host="beta.meet.jit.si" android:scheme="https" />
<data android:host="chaos.hipchat.me" android:scheme="https" />
<data android:host="enso.me" android:scheme="https" />
<data android:host="hipchat.me" android:scheme="https" />
<data android:host="meet.jit.si" android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="org.jitsi.meet" />
</intent-filter>
</activity>
<activity
android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

Binary file not shown.

View File

@ -1,39 +0,0 @@
package org.jitsi.meet;
import android.net.Uri;
import android.util.Log;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity;
/**
* Helper class to initialize Google related services and functionality.
* This functionality is compiled conditionally and called via reflection, that's why it was
* extracted here.
*
* "Libre builds" (builds with the LIBRE_BUILD flag set) will not include this file.
*/
final class GoogleServicesHelper {
public static void initialize(JitsiMeetActivity activity) {
if (BuildConfig.GOOGLE_SERVICES_ENABLED) {
Log.d(activity.getClass().getSimpleName(), "Initializing Google Services");
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(!JitsiMeet.isCrashReportingDisabled(activity));
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent())
.addOnSuccessListener(activity, pendingDynamicLinkData -> {
Uri dynamicLink = null;
if (pendingDynamicLinkData != null) {
dynamicLink = pendingDynamicLinkData.getLink();
}
if (dynamicLink != null) {
activity.join(dynamicLink.toString());
}
});
}
}
}

View File

@ -1,235 +1,46 @@
/*
* Copyright @ 2017-present 8x8, 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 org.jitsi.meet;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.RestrictionEntry;
import android.content.RestrictionsManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import androidx.annotation.Nullable;
import org.jitsi.meet.sdk.JitsiMeet;
import org.jitsi.meet.sdk.JitsiMeetActivity;
import org.jitsi.meet.sdk.JitsiMeetConferenceOptions;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
/**
* The one and only Activity that the Jitsi Meet app needs. The
* {@code Activity} is launched in {@code singleTask} mode, so it will be
* created upon application initialization and there will be a single instance
* of it. Further attempts at launching the application once it was already
* launched will result in {@link MainActivity#onNewIntent(Intent)} being called.
*/
public class MainActivity extends JitsiMeetActivity {
public class MainActivity extends ReactActivity {
/**
* The request code identifying requests for the permission to draw on top
* of other apps. The value must be 16-bit and is arbitrarily chosen here.
* {@inheritDoc}
*
* Overrides {@link ReactActivity#createRootActivityDelegate()} to customize
* the {@link ReactRootView} with a background color that is in accord with
* the JavaScript and iOS parts of the application and causes less perceived
* visual flicker than the default background color.
*/
private static final int OVERLAY_PERMISSION_REQUEST_CODE
= (int) (Math.random() * Short.MAX_VALUE);
/**
* ServerURL configuration key for restriction configuration using {@link android.content.RestrictionsManager}
*/
public static final String RESTRICTION_SERVER_URL = "SERVER_URL";
/**
* Broadcast receiver for restrictions handling
*/
private BroadcastReceiver broadcastReceiver;
/**
* Flag if configuration is provided by RestrictionManager
*/
private boolean configurationByRestrictions = false;
/**
* Default URL as could be obtained from RestrictionManager
*/
private String defaultURL;
// JitsiMeetActivity overrides
//
@Override
protected void onCreate(Bundle savedInstanceState) {
JitsiMeet.showSplashScreen(this);
super.onCreate(null);
}
@Override
protected boolean extraInitialize() {
Log.d(this.getClass().getSimpleName(), "LIBRE_BUILD="+BuildConfig.LIBRE_BUILD);
// Setup Crashlytics and Firebase Dynamic Links
// Here we are using reflection since it may have been disabled at compile time.
try {
Class<?> cls = Class.forName("org.jitsi.meet.GoogleServicesHelper");
Method m = cls.getMethod("initialize", JitsiMeetActivity.class);
m.invoke(null, this);
} catch (Exception e) {
// Ignore any error, the module is not compiled when LIBRE_BUILD is enabled.
}
// In Debug builds React needs permission to write over other apps in
// order to display the warning and error overlays.
if (BuildConfig.DEBUG) {
if (!Settings.canDrawOverlays(this)) {
Intent intent
= new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
return true;
}
}
return false;
}
@Override
protected void initialize() {
broadcastReceiver = new BroadcastReceiver() {
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
/**
* {@inheritDoc}
*
* Overrides {@link ReactActivityDelegate#createRootView()} to
* customize the {@link ReactRootView} with a background color that
* is in accord with the JavaScript and iOS parts of the application
* and causes less perceived visual flicker than the default
* background color.
*/
@Override
public void onReceive(Context context, Intent intent) {
// As new restrictions including server URL are received,
// conference should be restarted with new configuration.
leave();
recreate();
protected ReactRootView createRootView() {
ReactRootView rootView = super.createRootView();
rootView.setBackgroundColor(0xFF111111);
return rootView;
}
};
registerReceiver(broadcastReceiver,
new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED));
resolveRestrictions();
setJitsiMeetConferenceDefaultOptions();
super.initialize();
}
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
public void onDestroy() {
if (broadcastReceiver != null) {
unregisterReceiver(broadcastReceiver);
broadcastReceiver = null;
}
super.onDestroy();
}
private void setJitsiMeetConferenceDefaultOptions() {
// Set default options
JitsiMeetConferenceOptions defaultOptions
= new JitsiMeetConferenceOptions.Builder()
.setServerURL(buildURL(defaultURL))
.setFeatureFlag("welcomepage.enabled", true)
.setFeatureFlag("call-integration.enabled", false)
.setFeatureFlag("resolution", 360)
.setFeatureFlag("server-url-change.enabled", !configurationByRestrictions)
.build();
JitsiMeet.setDefaultConferenceOptions(defaultOptions);
}
private void resolveRestrictions() {
RestrictionsManager manager =
(RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
Bundle restrictions = manager.getApplicationRestrictions();
Collection<RestrictionEntry> entries = manager.getManifestRestrictions(
getApplicationContext().getPackageName());
for (RestrictionEntry restrictionEntry : entries) {
String key = restrictionEntry.getKey();
if (RESTRICTION_SERVER_URL.equals(key)) {
// If restrictions are passed to the application.
if (restrictions != null &&
restrictions.containsKey(RESTRICTION_SERVER_URL)) {
defaultURL = restrictions.getString(RESTRICTION_SERVER_URL);
configurationByRestrictions = true;
// Otherwise use default URL from app-restrictions.xml.
} else {
defaultURL = restrictionEntry.getSelectedString();
configurationByRestrictions = false;
}
}
}
}
// Activity lifecycle method overrides
//
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE) {
if (Settings.canDrawOverlays(this)) {
initialize();
return;
}
throw new RuntimeException("Overlay permission is required when running in Debug mode.");
}
super.onActivityResult(requestCode, resultCode, data);
}
// ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (BuildConfig.DEBUG && keyCode == KeyEvent.KEYCODE_MENU) {
JitsiMeet.showDevOptions();
return true;
}
return super.onKeyUp(keyCode, event);
}
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
Log.d(TAG, "Is in picture-in-picture mode: " + isInPictureInPictureMode);
if (!isInPictureInPictureMode) {
this.startActivity(new Intent(this, getClass())
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
}
}
// Helper methods
//
private @Nullable URL buildURL(String urlStr) {
try {
return new URL(urlStr);
} catch (MalformedURLException e) {
return null;
}
protected String getMainComponentName() {
return "App";
}
}

View File

@ -1,47 +1,65 @@
/*
* Copyright @ 2022-present 8x8, 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 org.jitsi.meet;
import android.app.Application;
import android.util.Log;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import org.jitsi.meet.sdk.JitsiReactNativeHost;
import java.util.Arrays;
import java.util.List;
/**
* Application class for Jitsi Meet. The only reason why this exists is for Detox
* to believe our app is a "greenfield" app. SDK users need not use this.
*/
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new JitsiReactNativeHost(this);
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
/**
* {@inheritDoc}
*/
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
/**
* {@inheritDoc}
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new com.corbt.keepawake.KCKeepAwakePackage(),
new com.facebook.react.shell.MainReactPackage(),
new com.oblador.vectoricons.VectorIconsPackage(),
new com.ocetnik.timer.BackgroundTimerPackage(),
new com.oney.WebRTCModule.WebRTCModulePackage(),
new com.rnimmersive.RNImmersivePackage(),
new org.jitsi.meet.audiomode.AudioModePackage(),
new org.jitsi.meet.proximity.ProximityPackage()
);
}
};
/**
* {@inheritDoc}
*/
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
/**
* {@inheritDoc}
*/
@Override
public void onCreate() {
super.onCreate();
// Initialize RN
Log.d(this.getClass().getCanonicalName(), "app onCreate");
getReactNativeHost().getReactInstanceManager();
SoLoader.init(this, /* native exopackage */ false);
if (!getReactNativeHost()
.getReactInstanceManager()
.getDevSupportManager()
.getDevSupportEnabled()) {
// TODO Auto-generated method stub
}
}
}

View File

@ -0,0 +1,333 @@
package org.jitsi.meet.audiomode;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.HashMap;
import java.util.Map;
/**
* Module implementing a simple API to select the appropriate audio device for a
* conference call.
*
* Audio calls should use <tt>AudioModeModule.AUDIO_CALL</tt>, which uses the
* builtin earpiece, wired headset or bluetooth headset. The builtin earpiece is
* the default audio device.
*
* Video calls should should use <tt>AudioModeModule.VIDEO_CALL</tt>, which uses
* the builtin speaker, earpiece, wired headset or bluetooth headset. The
* builtin speaker is the default audio device.
*
* Before a call has started and after it has ended the
* <tt>AudioModeModule.DEFAULT</tt> mode should be used.
*/
public class AudioModeModule extends ReactContextBaseJavaModule {
/**
* Constants representing the audio mode.
* - DEFAULT: Used before and after every call. It represents the default
* audio routing scheme.
* - AUDIO_CALL: Used for audio only calls. It will use the earpiece by
* default, unless a wired or Bluetooth headset is connected.
* - VIDEO_CALL: Used for video calls. It will use the speaker by default,
* unless a wired or Bluetooth headset is connected.
*/
private static final int DEFAULT = 0;
private static final int AUDIO_CALL = 1;
private static final int VIDEO_CALL = 2;
/**
*
*/
private static final String ACTION_HEADSET_PLUG
= (Build.VERSION.SDK_INT >= 21)
? AudioManager.ACTION_HEADSET_PLUG
: Intent.ACTION_HEADSET_PLUG;
/**
* React Native module name.
*/
private static final String MODULE_NAME = "AudioMode";
/**
* Tag used when logging messages.
*/
static final String TAG = MODULE_NAME;
/**
* {@link AudioManager} instance used to interact with the Android audio
* subsystem.
*/
private final AudioManager audioManager;
/**
* {@link BluetoothHeadsetMonitor} for detecting Bluetooth device changes in
* old (< M) Android versions.
*/
private BluetoothHeadsetMonitor bluetoothHeadsetMonitor;
/**
* {@link Handler} for running all operations on the main thread.
*/
private final Handler mainThreadHandler
= new Handler(Looper.getMainLooper());
/**
* {@link Runnable} for running update operation on the main thread.
*/
private final Runnable mainThreadRunner
= new Runnable() {
@Override
public void run() {
if (mode != -1) {
updateAudioRoute(mode);
}
}
};
/**
* Audio mode currently in use.
*/
private int mode = -1;
/**
* Initializes a new module instance. There shall be a single instance of
* this module throughout the lifetime of the application.
*
* @param reactContext the {@link ReactApplicationContext} where this module
* is created.
*/
public AudioModeModule(ReactApplicationContext reactContext) {
super(reactContext);
audioManager
= (AudioManager)
reactContext.getSystemService(Context.AUDIO_SERVICE);
// Setup runtime device change detection.
setupAudioRouteChangeDetection();
}
/**
* Gets a mapping with the constants this module is exporting.
*
* @return a {@link Map} mapping the constants to be exported with their
* values.
*/
@Override
public Map<String, Object> getConstants() {
Map<String, Object> constants = new HashMap<>();
constants.put("AUDIO_CALL", AUDIO_CALL);
constants.put("DEFAULT", DEFAULT);
constants.put("VIDEO_CALL", VIDEO_CALL);
return constants;
}
/**
* Gets the name for this module, to be used in the React Native bridge.
*
* @return a string with the module name.
*/
@Override
public String getName() {
return MODULE_NAME;
}
/**
* Helper method to trigger an audio route update when devices change. It
* makes sure the operation is performed on the main thread.
*/
void onAudioDeviceChange() {
mainThreadHandler.post(mainThreadRunner);
}
/**
* Helper method to set the output route to a Bluetooth device.
*
* @param enabled true if Bluetooth should use used, false otherwise.
*/
private void setBluetoothAudioRoute(boolean enabled) {
if (enabled) {
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);
} else {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
}
}
/**
* Public method to set the current audio mode.
*
* @param mode the desired audio mode.
* @param promise a {@link Promise} which will be resolved if the audio mode
* could be updated successfully, and it will be rejected otherwise.
*/
@ReactMethod
public void setMode(final int mode, final Promise promise) {
if (mode != DEFAULT && mode != AUDIO_CALL && mode != VIDEO_CALL) {
promise.reject("setMode", "Invalid audio mode " + mode);
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
boolean success;
try {
success = updateAudioRoute(mode);
} catch (Throwable e) {
success = false;
Log.e(
TAG,
"Failed to update audio route for mode: " + mode,
e);
}
if (success) {
AudioModeModule.this.mode = mode;
promise.resolve(null);
} else {
promise.reject(
"setMode",
"Failed to set audio mode to " + mode);
}
}
};
mainThreadHandler.post(r);
}
/**
* Setup the audio route change detection mechanism. We use the
* {@link android.media.AudioDeviceCallback} API on Android >= 23 only.
*/
private void setupAudioRouteChangeDetection() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setupAudioRouteChangeDetectionM();
} else {
setupAudioRouteChangeDetectionPreM();
}
}
/**
* Audio route change detection mechanism for Android API >= 23.
*/
@TargetApi(Build.VERSION_CODES.M)
private void setupAudioRouteChangeDetectionM() {
android.media.AudioDeviceCallback audioDeviceCallback =
new android.media.AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(
AudioDeviceInfo[] addedDevices) {
Log.d(TAG, "Audio devices added");
onAudioDeviceChange();
}
@Override
public void onAudioDevicesRemoved(
AudioDeviceInfo[] removedDevices) {
Log.d(TAG, "Audio devices removed");
onAudioDeviceChange();
}
};
audioManager.registerAudioDeviceCallback(audioDeviceCallback, null);
}
/**
* Audio route change detection mechanism for Android API < 23.
*/
private void setupAudioRouteChangeDetectionPreM() {
Context context = getReactApplicationContext();
// Detect changes in wired headset connections.
IntentFilter wiredHeadSetFilter = new IntentFilter(ACTION_HEADSET_PLUG);
BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Wired headset added / removed");
onAudioDeviceChange();
}
};
context.registerReceiver(wiredHeadsetReceiver, wiredHeadSetFilter);
// Detect Bluetooth device changes.
bluetoothHeadsetMonitor = new BluetoothHeadsetMonitor(this, context);
}
/**
* Updates the audio route for the given mode.
*
* @param mode the audio mode to be used when computing the audio route.
* @return true if the audio route was updated successfully, false
* otherwise.
*/
private boolean updateAudioRoute(int mode) {
Log.d(TAG, "Update audio route for mode: " + mode);
if (mode == DEFAULT) {
audioManager.setMode(AudioManager.MODE_NORMAL);
audioManager.abandonAudioFocus(null);
audioManager.setSpeakerphoneOn(false);
audioManager.setMicrophoneMute(true);
setBluetoothAudioRoute(false);
return true;
}
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.setMicrophoneMute(false);
if (audioManager.requestAudioFocus(
null,
AudioManager.STREAM_VOICE_CALL,
AudioManager.AUDIOFOCUS_GAIN)
== AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
Log.d(TAG, "Audio focus request failed");
return false;
}
boolean useSpeaker = (mode == VIDEO_CALL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// On Android >= M we use the AudioDeviceCallback API, so turn on
// Bluetooth SCO from the start.
if (audioManager.isBluetoothScoAvailableOffCall()) {
audioManager.startBluetoothSco();
}
} else {
// On older Android versions we must set the Bluetooth route
// manually. Also disable the speaker in that case.
setBluetoothAudioRoute(
bluetoothHeadsetMonitor.isHeadsetAvailable());
if (bluetoothHeadsetMonitor.isHeadsetAvailable()) {
useSpeaker = false;
}
}
// XXX: isWiredHeadsetOn is not deprecated when used just for knowing if
// there is a wired headset connected, regardless of audio being routed
// to it.
audioManager.setSpeakerphoneOn(
useSpeaker
&& !(audioManager.isWiredHeadsetOn()
|| audioManager.isBluetoothScoOn()));
return true;
}
}

View File

@ -0,0 +1,48 @@
package org.jitsi.meet.audiomode;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Implements {@link ReactPackage} for {@link AudioModeModule}.
*/
public class AudioModePackage implements ReactPackage {
/**
* {@inheritDoc}
*/
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
/**
* {@inheritDoc}
*
* @return List of native modules to be exposed by React Native.
*/
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AudioModeModule(reactContext));
return modules;
}
/**
* {@inheritDoc}
*/
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@ -0,0 +1,189 @@
package org.jitsi.meet.audiomode;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
/**
* Helper class to detect and handle Bluetooth device changes. It monitors
* Bluetooth headsets being connected / disconnected and notifies the module
* about device changes when this occurs.
*/
public class BluetoothHeadsetMonitor {
/**
* {@link AudioModeModule} where this monitor reports.
*/
private final AudioModeModule audioModeModule;
/**
* The {@link Context} in which {@link #audioModeModule} executes.
*/
private final Context context;
/**
* Reference to a proxy object which allows us to query connected devices.
*/
private BluetoothHeadset headset;
/**
* Flag indicating if there are any Bluetooth headset devices currently
* available.
*/
private boolean headsetAvailable = false;
/**
* {@link Handler} for running all operations on the main thread.
*/
private final Handler mainThreadHandler
= new Handler(Looper.getMainLooper());
/**
* Helper for running Bluetooth operations on the main thread.
*/
private final Runnable updateDevicesRunnable
= new Runnable() {
@Override
public void run() {
headsetAvailable
= (headset != null)
&& !headset.getConnectedDevices().isEmpty();
audioModeModule.onAudioDeviceChange();
}
};
public BluetoothHeadsetMonitor(
AudioModeModule audioModeModule,
Context context) {
this.audioModeModule = audioModeModule;
this.context = context;
AudioManager audioManager
= (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (!audioManager.isBluetoothScoAvailableOffCall()) {
Log.w(AudioModeModule.TAG, "Bluetooth SCO is not available");
return;
}
if (getBluetoothHeadsetProfileProxy()) {
registerBluetoothReceiver();
// Initial detection.
updateDevices();
}
}
private boolean getBluetoothHeadsetProfileProxy() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter == null) {
Log.w(AudioModeModule.TAG, "Device doesn't support Bluetooth");
return false;
}
// XXX: The profile listener listens for system services of the given
// type being available to the application. That is, if our Bluetooth
// adapter has the "headset" profile.
BluetoothProfile.ServiceListener listener
= new BluetoothProfile.ServiceListener() {
@Override
public void onServiceConnected(
int profile,
BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
headset = (BluetoothHeadset) proxy;
updateDevices();
}
}
@Override
public void onServiceDisconnected(int profile) {
// The logic is the same as the logic of onServiceConnected.
onServiceConnected(profile, /* proxy */ null);
}
};
return
adapter.getProfileProxy(
context,
listener,
BluetoothProfile.HEADSET);
}
/**
* Returns the current headset availability.
*
* @return true if there is a Bluetooth headset connected, false otherwise.
*/
public boolean isHeadsetAvailable() {
return headsetAvailable;
}
private void onBluetoothReceiverReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
// XXX: This action will be fired when a Bluetooth headset is
// connected or disconnected to the system. This is not related to
// audio routing.
int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -99);
switch (state) {
case BluetoothHeadset.STATE_CONNECTED:
case BluetoothHeadset.STATE_DISCONNECTED:
Log.d(
AudioModeModule.TAG,
"BT headset connection state changed: " + state);
updateDevices();
break;
}
} else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
// XXX: This action will be fired when the connection established
// with a Bluetooth headset (called a SCO connection) changes state.
// When the SCO connection is active we route audio to it.
int state
= intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99);
switch (state) {
case AudioManager.SCO_AUDIO_STATE_CONNECTED:
case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
Log.d(
AudioModeModule.TAG,
"BT SCO connection state changed: " + state);
updateDevices();
break;
}
}
}
private void registerBluetoothReceiver() {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
onBluetoothReceiverReceive(context, intent);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
context.registerReceiver(receiver, filter);
}
/**
* Detects if there are new devices connected / disconnected and fires the
* {@link AudioModeModule#onAudioDeviceChange()} callback.
*/
private void updateDevices() {
mainThreadHandler.post(updateDevicesRunnable);
}
}

View File

@ -0,0 +1,101 @@
package org.jitsi.meet.proximity;
import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.UiThreadUtil;
/**
* Module implementing a simple API to enable a proximity sensor-controlled
* wake lock. When the lock is held, if the proximity sensor detects a nearby
* object it will dim the screen and disable touch controls. The functionality
* is used with the conference audio-only mode.
*/
public class ProximityModule extends ReactContextBaseJavaModule {
/**
* React Native module name.
*/
private static final String MODULE_NAME = "Proximity";
/**
* This type of wake lock (the one activated by the proximity sensor) has
* been available for a while, but the constant was only exported in API
* level 21 (Android Marshmallow) so make no assumptions and use its value
* directly.
*
* TODO: Remove when we bump the API level to 21.
*/
private static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
/**
* {@link WakeLock} instance.
*/
private final WakeLock wakeLock;
/**
* Initializes a new module instance. There shall be a single instance of
* this module throughout the lifetime of the application.
*
* @param reactContext The {@link ReactApplicationContext} where this module
* is created.
*/
public ProximityModule(ReactApplicationContext reactContext) {
super(reactContext);
WakeLock wakeLock;
PowerManager powerManager
= (PowerManager)
reactContext.getSystemService(Context.POWER_SERVICE);
try {
wakeLock
= powerManager.newWakeLock(
PROXIMITY_SCREEN_OFF_WAKE_LOCK,
MODULE_NAME);
} catch (Throwable ignored) {
wakeLock = null;
}
this.wakeLock = wakeLock;
}
/**
* Gets the name of this module to be used in the React Native bridge.
*
* @return The name of this module to be used in the React Native bridge.
*/
@Override
public String getName() {
return MODULE_NAME;
}
/**
* Acquires / releases the proximity sensor wake lock.
*
* @param enabled {@code true} to enable the proximity sensor; otherwise,
* {@code false}.
*/
@ReactMethod
public void setEnabled(final boolean enabled) {
if (wakeLock == null) {
return;
}
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
if (enabled) {
if (!wakeLock.isHeld()) {
wakeLock.acquire();
}
} else if (wakeLock.isHeld()) {
wakeLock.release();
}
}
});
}
}

View File

@ -0,0 +1,48 @@
package org.jitsi.meet.proximity;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Implements {@link ReactPackage} for {@link ProximityModule}.
*/
public class ProximityPackage implements ReactPackage {
/**
* {@inheritDoc}
*/
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
/**
* {@inheritDoc}
*
* @return List of native modules to be exposed by React Native.
*/
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ProximityModule(reactContext));
return modules;
}
/**
* {@inheritDoc}
*/
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@ -1,70 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="262.91376dp"
android:height="262.91376dp"
android:viewportWidth="262.91376"
android:viewportHeight="262.91376">
<group>
<clip-path
android:pathData="m0,0 l262.914,-0L262.914,262.914 0,262.914 0,0Z"/>
<path
android:pathData="m142.646,105.099c0.117,0.026 0.255,0.036 0.406,0.036 3.186,-0 10.297,-4.615 11.617,-6.721l0.1,-0.17 0.153,-0.135c0.451,-0.441 1.746,-2.773 2.374,-4.17 -6.751,-2.023 -7.49,-5.677 -8.153,-8.919 -0.069,-0.376 -0.138,-0.717 -0.204,-1.019 -0.074,-0.397 -0.153,-0.8 -0.226,-1.112C138.668,86.221 135.593,88.094 133.921,89.483 133.056,90.201 132.542,92.251 135.042,97.926 136.323,100.816 140.727,104.733 142.646,105.099"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m115.413,146.042c5.934,-0 18.464,-3.543 26.748,-5.887 1.21,-0.336 2.33,-0.66 3.351,-0.944 0.166,-0.046 0.321,-0.091 0.472,-0.124 -0.463,-0.461 -1.239,-1.159 -2.497,-2.216 -5.521,-3.741 -10.736,-5.484 -16.403,-5.484 -1.237,-0 -2.522,0.071 -3.923,0.231 -4.801,0.55 -8.8,1.69 -10.722,2.237 -0.967,0.284 -1.263,0.366 -1.567,0.366 -0.58,-0 -1.079,-0.341 -1.273,-0.878 -0.194,-0.534 -0.027,-1.121 0.425,-1.507l0.024,-0.011c3.316,-2.784 9.489,-7.951 21.198,-10.256 2.027,-0.401 4.202,-0.605 6.454,-0.605 5.242,-0 10.67,1.086 16.125,3.219 7.436,2.899 12.521,6.625 16.602,9.62 2.199,1.609 4.105,3.007 5.755,3.771 0.421,0.2 0.637,0.255 0.746,0.265 0.074,-0.095 0.23,-0.365 0.474,-1.069 0.066,-0.185 0.529,-2.161 -2.806,-13.374 -1.931,-6.51 -4.264,-13.156 -5.479,-16.104 -2.356,-5.711 -1.778,-9.76 -1.051,-12.125 -1.999,0.735 -4.033,1.87 -6.174,3.446L161.758,98.711C160.694,99.506 159.599,100.404 158.426,101.454 151.517,107.64 146.344,110.864 143.035,111.04l-0.093,0.004 -0.093,-0.009c-2.912,-0.245 -7.324,-4.489 -9.133,-6.634 -0.373,-0.251 -0.8,-0.366 -1.366,-0.366 -0.564,-0 -1.202,0.116 -1.82,0.235C130.086,104.354 129.623,104.441 129.167,104.489 127.708,104.632 125.668,105.106 123.694,105.561 122.746,105.777 121.762,106.005 120.864,106.189 120.851,106.19 120.463,106.272 119.774,106.454 114.903,107.891 111.228,109.55 109.432,111.111 109.414,111.127 109.352,111.174 109.266,111.242 108.048,112.105 105.124,114.567 104.248,118.762L104.237,118.795C102.398,126.516 105.187,136.087 108.892,141.554 110.636,144.125 112.513,145.727 114.048,145.959 114.437,146.015 114.891,146.042 115.413,146.042"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m90.093,173.175c-1.252,-1.472 -1.783,-3.324 -1.574,-5.521 0.884,-10.642 -0.329,-13.215 -0.891,-13.829 -0.131,-0.144 -0.207,-0.144 -0.265,-0.144 -0.022,-0 -0.041,0.003 -0.064,0.003 -1.044,0.248 -8.066,5.002 -9.615,19.171 -0.749,6.845 0.561,15.63 1.679,20.974 0.897,-3.155 2.314,-6.624 5.057,-10.204 2.556,-3.326 5.345,-5.955 8.801,-8.253C92.143,174.93 90.991,174.235 90.093,173.175"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m94.906,156.389c-0.03,2.229 -0.326,4.36 -0.61,6.445 -0.151,1.119 -0.314,2.286 -0.434,3.46 -0.161,2.341 0.346,3.166 0.571,3.406 0.127,0.136 0.326,0.287 0.76,0.287 0.339,-0 0.741,-0.091 1.161,-0.268 4.202,-1.756 8.195,-4.815 10.115,-6.515C103.522,161.892 98.995,159.058 94.906,156.389"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m154.002,81.595c-0.031,0.074 -0.065,0.148 -0.101,0.216 -0.821,2.403 0.306,5.664 2.419,6.898 0.561,0.327 1.106,0.526 1.624,0.596 0.072,0.006 0.148,0.009 0.219,0.009 1.645,-0 2.971,-1.199 3.961,-3.561C162.752,83.959 162.836,81.827 162.37,79.904 162.003,78.409 161.057,76.627 160.453,75.738 159.332,76.509 157.111,78.207 155.585,79.553 154.518,80.582 154.136,81.229 154.002,81.595"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="M148.97,77.699C153.957,73.194 156.988,65.754 158.253,61.334 153.915,65.513 148.633,67.758 145.25,69.198 144.084,69.695 143.08,70.124 142.477,70.476 142.224,70.623 141.965,70.77 141.708,70.919 139.654,72.109 136.55,73.905 136.1,75.011l-0.012,0.036 -0.012,0.034c-1.406,2.956 -2.199,7.401 -2.457,9.95 3.266,-1.99 6.625,-3.322 9.416,-4.42C145.628,79.585 147.863,78.703 148.97,77.699"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m164.464,51.921c-0.84,5.539 -2.205,10.799 -4.751,16.347 2.781,-3.144 4.396,-6.568 4.941,-10.401C164.886,56.275 165.097,54.756 164.464,51.921"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="M148.749,142.639C148.718,142.598 148.684,142.56 148.658,142.519 148.523,142.539 148.307,142.584 147.972,142.683l-0.14,0.04c-1.726,0.644 -4.899,1.708 -8.556,2.946 -4.396,1.479 -9.365,3.154 -13.526,4.649 -5.297,1.975 -7.021,2.755 -7.557,3.024 -0.098,0.266 -0.203,0.599 -0.327,0.965 -1.254,3.816 -4.125,12.541 -18.276,18.653 2.928,2.956 9.289,8.27 21.809,8.27 1.082,-0 2.21,-0.036 3.341,-0.12 9.451,-0.666 18.342,-4.855 25.026,-11.78 6.087,-6.291 9.538,-14.136 9.585,-21.7C157.876,147.509 155.367,147.135 153.043,146.033 153.014,146.02 150.361,144.745 148.749,142.639"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m189.478,117.853c-0.523,9.749 -2.122,18.424 -4.744,25.8 -2.128,5.988 -4.94,11.134 -8.356,15.316 -5.676,6.931 -11.555,9.256 -12.804,9.304 -0.866,-0 -1.313,-0.309 -3.046,-1.528 -0.17,-0.114 -0.37,-0.252 -0.581,-0.4 -3.313,5.953 -8.505,11.097 -15.065,14.959 -7.079,4.144 -15.297,6.423 -23.157,6.423 -9.078,-0 -17.13,-2.924 -23.341,-8.456 -7.467,4.799 -12.31,9.074 -16.267,27.005l-1.363,6.17 -2.971,-5.564c-0.424,-0.786 -1.929,-3.731 -3.332,-8.887 -1.934,-7.104 -2.86,-15.181 -2.758,-24.01 0.117,-10.049 3.154,-16.526 5.68,-20.186 2.98,-4.314 6.837,-6.994 10.076,-6.994 0.216,-0 0.428,0.006 0.616,0.035 5.159,0.575 8.435,2.75 14.396,6.686l1.899,1.252c2.059,1.344 4.481,2.7 5.259,2.989 0.54,-0.284 1.749,-2.3 2.155,-5.271l0.069,-0.451c0.005,-0.045 0.009,-0.091 0.014,-0.131 -0.036,-0.02 -0.065,-0.029 -0.094,-0.041 -4.008,-1.375 -9.539,-7.7 -12.364,-17.134 -2.684,-9.382 -2.129,-17.185 1.644,-23.193 6.12,-9.736 19.198,-11.974 23.466,-12.702 1.331,-0.266 2.716,-0.511 4.041,-0.717 0.255,-0.061 0.469,-0.121 0.642,-0.168 -0.031,-0.126 -0.071,-0.265 -0.114,-0.43 -0.108,-0.417 -0.23,-0.891 -0.354,-1.447 -1.345,-6.035 -0.664,-11.069 0.181,-15.193 0.928,-4.546 1.489,-7.287 3.747,-9.936 3.029,-4.165 8.319,-5.936 11.479,-6.991 0.746,-0.249 1.511,-0.509 1.894,-0.689 8.988,-4.31 11.82,-8.739 12.615,-11.694 0.656,-2.451 1.699,-8.884 1.251,-13.335 -0.085,-0.805 0.129,-1.521 0.621,-2.065 0.45,-0.505 1.101,-0.794 1.778,-0.794 1.515,-0 2.82,-0 7.511,14.598 2.481,7.698 0.645,14.903 -5.45,21.424l-0.226,0.231c0.024,0.044 0.049,0.09 0.08,0.144 2.57,4.236 3.963,9.54 3.553,13.51 -0.099,0.906 -0.265,1.775 -0.419,2.549 -0.003,0.01 -0.003,0.016 -0.004,0.029 0.516,-0.032 1.119,-0.055 1.775,-0.055 3.052,-0 7.435,0.474 10.989,2.735 2.135,1.352 4.845,3.439 6.835,7.615C189.223,102.942 190.076,109.575 189.478,117.853m4.77,-23.191c-2.916,-6.1 -6.989,-9.177 -9.793,-10.96 -2.355,-1.494 -5.064,-2.584 -8.077,-3.24l-0.676,-0.146 -0.111,-0.689c-0.339,-2.119 -0.918,-4.275 -1.715,-6.406l-0.185,-0.49 0.292,-0.434c5.095,-7.594 6.323,-16.17 3.54,-24.802 -2.191,-6.824 -3.895,-11.211 -5.341,-13.799 -2.954,-5.305 -7.006,-6.417 -9.891,-6.417 -2.964,-0 -5.8,1.261 -7.789,3.457 -2.043,2.254 -2.993,5.207 -2.678,8.31 0.316,3.134 -0.494,8.516 -1.014,10.439 -0.04,0.117 -0.975,2.929 -8.201,6.428 -0.162,0.056 -0.512,0.179 -1.053,0.359 -3.729,1.246 -10.666,3.571 -15.258,9.64 -3.465,4.205 -4.332,8.441 -5.338,13.346 -0.586,2.865 -1.236,6.744 -1.079,11.344l0.026,0.841 -0.824,0.188c-11.646,2.585 -20.025,7.835 -24.909,15.605 -5.054,8.04 -5.919,18.055 -2.543,29.853 0.063,0.204 0.126,0.407 0.189,0.615l0.527,1.608 -1.665,-0.286c-0.561,-0.101 -1.135,-0.18 -1.729,-0.241 -0.493,-0.06 -1.001,-0.082 -1.509,-0.082 -5.633,-0 -11.663,3.585 -16.128,9.592 -3.451,4.641 -7.588,12.849 -7.735,25.601 -0.114,9.573 0.906,18.401 3.038,26.228 1.581,5.795 3.326,9.329 4.004,10.577l13.306,24.94 6.096,-27.619c2.454,-11.09 4.864,-15.262 7.725,-18.111l0.561,-0.563 0.679,0.411c6.605,3.977 14.466,6.084 22.73,6.084 9.286,-0 18.965,-2.682 27.259,-7.551 5.38,-3.16 9.974,-7.036 13.649,-11.531l0.45,-0.369 0.85,-0.02c2.156,-0.068 5.16,-1.164 8.222,-3.004 2.6,-1.555 6.543,-4.428 10.501,-9.262 3.997,-4.884 7.274,-10.854 9.716,-17.734 2.876,-8.073 4.625,-17.489 5.204,-28.004 0.689,-9.668 -0.434,-17.641 -3.327,-23.704"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m180.026,98.414c-1.67,-2.596 -3.771,-4.206 -5.475,-4.206 -0.313,-0 -0.613,0.051 -0.895,0.161 -0.911,0.361 -2.356,4.532 -1.714,7.566 0.434,2.066 2.938,9.04 4.151,12.394 0.456,1.281 0.68,1.91 0.754,2.142 0.064,0.183 0.145,0.448 0.256,0.774 0.97,2.971 3.467,10.586 4.206,16.761 1.549,-6.579 2.424,-14.512 2.085,-23.997C183.235,105.662 182.04,101.538 180.026,98.414"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="M168.088,142.604C169.896,142.111 171.33,141.705 172.398,141.395 170.213,139.874 167.689,137.979 164.247,135.304c-8.418,-6.546 -17.449,-9.87 -26.839,-9.87 -5.135,-0 -9.611,0.991 -13.156,2.186 0.882,-0.05 1.779,-0.079 2.7,-0.079 1.1,-0 2.247,0.04 3.411,0.119 3.652,0.246 13.061,1.901 21.565,12.047 1.714,2.039 3.559,3.73 8.794,3.73 1.873,-0 4.051,-0.207 6.662,-0.645C167.544,142.751 167.793,142.678 168.088,142.604"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m164.3,147.583c-0.122,1.563 -0.376,4.509 -0.782,6.76 -0.495,2.719 -1.31,5.02 -1.791,6.226 0.85,0.786 1.694,1.553 2.247,2.043 2.214,-1.447 9.47,-6.96 14.483,-19.474C176.847,144.229 174.59,145.178 171.671,146.018 168.701,146.861 165.82,147.357 164.3,147.583"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
</group>
</vector>

View File

@ -1,70 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="262.91376dp"
android:height="262.91376dp"
android:viewportWidth="262.91376"
android:viewportHeight="262.91376">
<group android:scaleX="0.75" android:scaleY="0.75" android:translateX="35" android:translateY="35">
<clip-path
android:pathData="m0,0 l262.914,-0L262.914,262.914 0,262.914 0,0Z"/>
<path
android:pathData="m142.646,105.099c0.117,0.026 0.255,0.036 0.406,0.036 3.186,-0 10.297,-4.615 11.617,-6.721l0.1,-0.17 0.153,-0.135c0.451,-0.441 1.746,-2.773 2.374,-4.17 -6.751,-2.023 -7.49,-5.677 -8.153,-8.919 -0.069,-0.376 -0.138,-0.717 -0.204,-1.019 -0.074,-0.397 -0.153,-0.8 -0.226,-1.112C138.668,86.221 135.593,88.094 133.921,89.483 133.056,90.201 132.542,92.251 135.042,97.926 136.323,100.816 140.727,104.733 142.646,105.099"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m115.413,146.042c5.934,-0 18.464,-3.543 26.748,-5.887 1.21,-0.336 2.33,-0.66 3.351,-0.944 0.166,-0.046 0.321,-0.091 0.472,-0.124 -0.463,-0.461 -1.239,-1.159 -2.497,-2.216 -5.521,-3.741 -10.736,-5.484 -16.403,-5.484 -1.237,-0 -2.522,0.071 -3.923,0.231 -4.801,0.55 -8.8,1.69 -10.722,2.237 -0.967,0.284 -1.263,0.366 -1.567,0.366 -0.58,-0 -1.079,-0.341 -1.273,-0.878 -0.194,-0.534 -0.027,-1.121 0.425,-1.507l0.024,-0.011c3.316,-2.784 9.489,-7.951 21.198,-10.256 2.027,-0.401 4.202,-0.605 6.454,-0.605 5.242,-0 10.67,1.086 16.125,3.219 7.436,2.899 12.521,6.625 16.602,9.62 2.199,1.609 4.105,3.007 5.755,3.771 0.421,0.2 0.637,0.255 0.746,0.265 0.074,-0.095 0.23,-0.365 0.474,-1.069 0.066,-0.185 0.529,-2.161 -2.806,-13.374 -1.931,-6.51 -4.264,-13.156 -5.479,-16.104 -2.356,-5.711 -1.778,-9.76 -1.051,-12.125 -1.999,0.735 -4.033,1.87 -6.174,3.446L161.758,98.711C160.694,99.506 159.599,100.404 158.426,101.454 151.517,107.64 146.344,110.864 143.035,111.04l-0.093,0.004 -0.093,-0.009c-2.912,-0.245 -7.324,-4.489 -9.133,-6.634 -0.373,-0.251 -0.8,-0.366 -1.366,-0.366 -0.564,-0 -1.202,0.116 -1.82,0.235C130.086,104.354 129.623,104.441 129.167,104.489 127.708,104.632 125.668,105.106 123.694,105.561 122.746,105.777 121.762,106.005 120.864,106.189 120.851,106.19 120.463,106.272 119.774,106.454 114.903,107.891 111.228,109.55 109.432,111.111 109.414,111.127 109.352,111.174 109.266,111.242 108.048,112.105 105.124,114.567 104.248,118.762L104.237,118.795C102.398,126.516 105.187,136.087 108.892,141.554 110.636,144.125 112.513,145.727 114.048,145.959 114.437,146.015 114.891,146.042 115.413,146.042"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m90.093,173.175c-1.252,-1.472 -1.783,-3.324 -1.574,-5.521 0.884,-10.642 -0.329,-13.215 -0.891,-13.829 -0.131,-0.144 -0.207,-0.144 -0.265,-0.144 -0.022,-0 -0.041,0.003 -0.064,0.003 -1.044,0.248 -8.066,5.002 -9.615,19.171 -0.749,6.845 0.561,15.63 1.679,20.974 0.897,-3.155 2.314,-6.624 5.057,-10.204 2.556,-3.326 5.345,-5.955 8.801,-8.253C92.143,174.93 90.991,174.235 90.093,173.175"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m94.906,156.389c-0.03,2.229 -0.326,4.36 -0.61,6.445 -0.151,1.119 -0.314,2.286 -0.434,3.46 -0.161,2.341 0.346,3.166 0.571,3.406 0.127,0.136 0.326,0.287 0.76,0.287 0.339,-0 0.741,-0.091 1.161,-0.268 4.202,-1.756 8.195,-4.815 10.115,-6.515C103.522,161.892 98.995,159.058 94.906,156.389"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m154.002,81.595c-0.031,0.074 -0.065,0.148 -0.101,0.216 -0.821,2.403 0.306,5.664 2.419,6.898 0.561,0.327 1.106,0.526 1.624,0.596 0.072,0.006 0.148,0.009 0.219,0.009 1.645,-0 2.971,-1.199 3.961,-3.561C162.752,83.959 162.836,81.827 162.37,79.904 162.003,78.409 161.057,76.627 160.453,75.738 159.332,76.509 157.111,78.207 155.585,79.553 154.518,80.582 154.136,81.229 154.002,81.595"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="M148.97,77.699C153.957,73.194 156.988,65.754 158.253,61.334 153.915,65.513 148.633,67.758 145.25,69.198 144.084,69.695 143.08,70.124 142.477,70.476 142.224,70.623 141.965,70.77 141.708,70.919 139.654,72.109 136.55,73.905 136.1,75.011l-0.012,0.036 -0.012,0.034c-1.406,2.956 -2.199,7.401 -2.457,9.95 3.266,-1.99 6.625,-3.322 9.416,-4.42C145.628,79.585 147.863,78.703 148.97,77.699"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m164.464,51.921c-0.84,5.539 -2.205,10.799 -4.751,16.347 2.781,-3.144 4.396,-6.568 4.941,-10.401C164.886,56.275 165.097,54.756 164.464,51.921"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="M148.749,142.639C148.718,142.598 148.684,142.56 148.658,142.519 148.523,142.539 148.307,142.584 147.972,142.683l-0.14,0.04c-1.726,0.644 -4.899,1.708 -8.556,2.946 -4.396,1.479 -9.365,3.154 -13.526,4.649 -5.297,1.975 -7.021,2.755 -7.557,3.024 -0.098,0.266 -0.203,0.599 -0.327,0.965 -1.254,3.816 -4.125,12.541 -18.276,18.653 2.928,2.956 9.289,8.27 21.809,8.27 1.082,-0 2.21,-0.036 3.341,-0.12 9.451,-0.666 18.342,-4.855 25.026,-11.78 6.087,-6.291 9.538,-14.136 9.585,-21.7C157.876,147.509 155.367,147.135 153.043,146.033 153.014,146.02 150.361,144.745 148.749,142.639"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m189.478,117.853c-0.523,9.749 -2.122,18.424 -4.744,25.8 -2.128,5.988 -4.94,11.134 -8.356,15.316 -5.676,6.931 -11.555,9.256 -12.804,9.304 -0.866,-0 -1.313,-0.309 -3.046,-1.528 -0.17,-0.114 -0.37,-0.252 -0.581,-0.4 -3.313,5.953 -8.505,11.097 -15.065,14.959 -7.079,4.144 -15.297,6.423 -23.157,6.423 -9.078,-0 -17.13,-2.924 -23.341,-8.456 -7.467,4.799 -12.31,9.074 -16.267,27.005l-1.363,6.17 -2.971,-5.564c-0.424,-0.786 -1.929,-3.731 -3.332,-8.887 -1.934,-7.104 -2.86,-15.181 -2.758,-24.01 0.117,-10.049 3.154,-16.526 5.68,-20.186 2.98,-4.314 6.837,-6.994 10.076,-6.994 0.216,-0 0.428,0.006 0.616,0.035 5.159,0.575 8.435,2.75 14.396,6.686l1.899,1.252c2.059,1.344 4.481,2.7 5.259,2.989 0.54,-0.284 1.749,-2.3 2.155,-5.271l0.069,-0.451c0.005,-0.045 0.009,-0.091 0.014,-0.131 -0.036,-0.02 -0.065,-0.029 -0.094,-0.041 -4.008,-1.375 -9.539,-7.7 -12.364,-17.134 -2.684,-9.382 -2.129,-17.185 1.644,-23.193 6.12,-9.736 19.198,-11.974 23.466,-12.702 1.331,-0.266 2.716,-0.511 4.041,-0.717 0.255,-0.061 0.469,-0.121 0.642,-0.168 -0.031,-0.126 -0.071,-0.265 -0.114,-0.43 -0.108,-0.417 -0.23,-0.891 -0.354,-1.447 -1.345,-6.035 -0.664,-11.069 0.181,-15.193 0.928,-4.546 1.489,-7.287 3.747,-9.936 3.029,-4.165 8.319,-5.936 11.479,-6.991 0.746,-0.249 1.511,-0.509 1.894,-0.689 8.988,-4.31 11.82,-8.739 12.615,-11.694 0.656,-2.451 1.699,-8.884 1.251,-13.335 -0.085,-0.805 0.129,-1.521 0.621,-2.065 0.45,-0.505 1.101,-0.794 1.778,-0.794 1.515,-0 2.82,-0 7.511,14.598 2.481,7.698 0.645,14.903 -5.45,21.424l-0.226,0.231c0.024,0.044 0.049,0.09 0.08,0.144 2.57,4.236 3.963,9.54 3.553,13.51 -0.099,0.906 -0.265,1.775 -0.419,2.549 -0.003,0.01 -0.003,0.016 -0.004,0.029 0.516,-0.032 1.119,-0.055 1.775,-0.055 3.052,-0 7.435,0.474 10.989,2.735 2.135,1.352 4.845,3.439 6.835,7.615C189.223,102.942 190.076,109.575 189.478,117.853m4.77,-23.191c-2.916,-6.1 -6.989,-9.177 -9.793,-10.96 -2.355,-1.494 -5.064,-2.584 -8.077,-3.24l-0.676,-0.146 -0.111,-0.689c-0.339,-2.119 -0.918,-4.275 -1.715,-6.406l-0.185,-0.49 0.292,-0.434c5.095,-7.594 6.323,-16.17 3.54,-24.802 -2.191,-6.824 -3.895,-11.211 -5.341,-13.799 -2.954,-5.305 -7.006,-6.417 -9.891,-6.417 -2.964,-0 -5.8,1.261 -7.789,3.457 -2.043,2.254 -2.993,5.207 -2.678,8.31 0.316,3.134 -0.494,8.516 -1.014,10.439 -0.04,0.117 -0.975,2.929 -8.201,6.428 -0.162,0.056 -0.512,0.179 -1.053,0.359 -3.729,1.246 -10.666,3.571 -15.258,9.64 -3.465,4.205 -4.332,8.441 -5.338,13.346 -0.586,2.865 -1.236,6.744 -1.079,11.344l0.026,0.841 -0.824,0.188c-11.646,2.585 -20.025,7.835 -24.909,15.605 -5.054,8.04 -5.919,18.055 -2.543,29.853 0.063,0.204 0.126,0.407 0.189,0.615l0.527,1.608 -1.665,-0.286c-0.561,-0.101 -1.135,-0.18 -1.729,-0.241 -0.493,-0.06 -1.001,-0.082 -1.509,-0.082 -5.633,-0 -11.663,3.585 -16.128,9.592 -3.451,4.641 -7.588,12.849 -7.735,25.601 -0.114,9.573 0.906,18.401 3.038,26.228 1.581,5.795 3.326,9.329 4.004,10.577l13.306,24.94 6.096,-27.619c2.454,-11.09 4.864,-15.262 7.725,-18.111l0.561,-0.563 0.679,0.411c6.605,3.977 14.466,6.084 22.73,6.084 9.286,-0 18.965,-2.682 27.259,-7.551 5.38,-3.16 9.974,-7.036 13.649,-11.531l0.45,-0.369 0.85,-0.02c2.156,-0.068 5.16,-1.164 8.222,-3.004 2.6,-1.555 6.543,-4.428 10.501,-9.262 3.997,-4.884 7.274,-10.854 9.716,-17.734 2.876,-8.073 4.625,-17.489 5.204,-28.004 0.689,-9.668 -0.434,-17.641 -3.327,-23.704"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m180.026,98.414c-1.67,-2.596 -3.771,-4.206 -5.475,-4.206 -0.313,-0 -0.613,0.051 -0.895,0.161 -0.911,0.361 -2.356,4.532 -1.714,7.566 0.434,2.066 2.938,9.04 4.151,12.394 0.456,1.281 0.68,1.91 0.754,2.142 0.064,0.183 0.145,0.448 0.256,0.774 0.97,2.971 3.467,10.586 4.206,16.761 1.549,-6.579 2.424,-14.512 2.085,-23.997C183.235,105.662 182.04,101.538 180.026,98.414"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="M168.088,142.604C169.896,142.111 171.33,141.705 172.398,141.395 170.213,139.874 167.689,137.979 164.247,135.304c-8.418,-6.546 -17.449,-9.87 -26.839,-9.87 -5.135,-0 -9.611,0.991 -13.156,2.186 0.882,-0.05 1.779,-0.079 2.7,-0.079 1.1,-0 2.247,0.04 3.411,0.119 3.652,0.246 13.061,1.901 21.565,12.047 1.714,2.039 3.559,3.73 8.794,3.73 1.873,-0 4.051,-0.207 6.662,-0.645C167.544,142.751 167.793,142.678 168.088,142.604"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
<path
android:pathData="m164.3,147.583c-0.122,1.563 -0.376,4.509 -0.782,6.76 -0.495,2.719 -1.31,5.02 -1.791,6.226 0.85,0.786 1.694,1.553 2.247,2.043 2.214,-1.447 9.47,-6.96 14.483,-19.474C176.847,144.229 174.59,145.178 171.671,146.018 168.701,146.861 165.82,147.357 164.3,147.583"
android:fillColor="#ffffff"
android:strokeColor="#00000000"
android:fillType="nonZero"/>
</group>
</vector>

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
android:insetTop="@dimen/abc_edit_text_inset_top_material"
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">
<selector>
<!--
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
-->
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
</selector>
</inset>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/ic_jitsi_logosvg"/>
</RelativeLayout>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#17A0DB</color>
<color name="navigationBarColor">#161618</color>
</resources>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#66A8DD</color>
</resources>

View File

@ -1,5 +1,3 @@
<resources>
<string name="app_name">Jitsi Meet</string>
<string name="restriction_server_url_description">URL of Jitsi Meet server instance to connect to</string>
<string name="restriction_server_url_title">Server URL</string>
</resources>

View File

@ -1,8 +1,9 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:navigationBarColor">@color/navigationBarColor</item>
<item name="android:windowDisablePreview">true</item>
</style>
<!-- Customize your theme here. -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Server URL configuration -->
<restriction
android:defaultValue="https://meet.jit.si"
android:description="@string/restriction_server_url_description"
android:key="SERVER_URL"
android:restrictionType="string"
android:title="@string/restriction_server_url_title"/>
</restrictions>

View File

@ -1,12 +0,0 @@
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">localhost</domain>
<domain includeSubdomains="false">10.0.2.2</domain>
</domain-config>
</network-security-config>

View File

@ -1,193 +1,24 @@
import groovy.json.JsonSlurper
import org.gradle.util.VersionNumber
// Top-level build file where you can add configuration options common to all
// sub-projects/modules.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.4'
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
classpath 'com.android.tools.build:gradle:2.2.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
ext {
buildToolsVersion = "31.0.0"
compileSdkVersion = 32
minSdkVersion = 23
targetSdkVersion = 32
supportLibVersion = "28.0.0"
if (System.properties['os.arch'] == "aarch64") {
// For M1 Users we need to use the NDK 24 which added support for aarch64
ndkVersion = "24.0.8215888"
} else {
// Otherwise we default to the side-by-side NDK version from AGP.
ndkVersion = "21.4.7075529"
}
// The Maven artifact groupdId of the third-party react-native modules which
// Jitsi Meet SDK for Android depends on and which are not available in
// third-party Maven repositories so we have to deploy to a Maven repository
// of ours.
moduleGroupId = 'com.facebook.react'
// Maven repo where artifacts will be published
mavenRepo = System.env.MVN_REPO ?: ""
mavenUser = System.env.MVN_USER ?: ""
mavenPassword = System.env.MVN_PASSWORD ?: ""
// Libre build
libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()
googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
}
allprojects {
repositories {
// React Native (JS, Obj-C sources, Android binaries) is installed from npm.
maven { url "$rootDir/../node_modules/react-native/android" }
// Android JSC is installed from npm.
maven { url("$rootDir/../node_modules/jsc-android/dist") }
mavenCentral {
// We don't want to fetch react-native from Maven Central as there are
// older versions over there.
content {
excludeGroup "com.facebook.react"
}
}
google()
maven { url 'https://www.jitpack.io' }
}
// Make sure we use the react-native version in node_modules and not the one
// published in jcenter / elsewhere.
configurations.all {
resolutionStrategy {
eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'com.facebook.react'
&& details.requested.name == 'react-native') {
def file = new File("$rootDir/../node_modules/react-native/package.json")
def version = new JsonSlurper().parseText(file.text).version
details.useVersion version
}
}
}
}
// Third-party react-native modules which Jitsi Meet SDK for Android depends
// on and which are not available in third-party Maven repositories need to
// be deployed in a Maven repository of ours.
//
if (project.name.startsWith('react-native-')) {
apply plugin: 'maven-publish'
publishing {
publications {}
repositories {
maven {
url rootProject.ext.mavenRepo
if (!rootProject.ext.mavenRepo.startsWith("file")) {
credentials {
username rootProject.ext.mavenUser
password rootProject.ext.mavenPassword
}
}
}
}
}
}
// Use the number of seconds/10 since Jan 1 2019 as the version qualifier number.
// This will last for the next ~680 years.
// https://stackoverflow.com/a/38643838
def versionQualifierNumber = (int)(((new Date().getTime()/1000) - 1546297200) / 10)
afterEvaluate { project ->
if (project.plugins.hasPlugin('android') || project.plugins.hasPlugin('android-library')) {
project.android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
}
if (project.name.startsWith('react-native-')) {
def npmManifest = project.file('../package.json')
def json = new JsonSlurper().parseText(npmManifest.text)
// Release every dependency the SDK has with a -jitsi-XXX qualified version. This allows
// us to pin the dependencies and make sure they are always updated, no matter what.
project.version = "${json.version}-jitsi-${versionQualifierNumber}"
task jitsiAndroidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.source
}
publishing.publications {
aarArchive(MavenPublication) {
groupId rootProject.ext.moduleGroupId
artifactId project.name
version project.version
artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
extension "aar"
}
artifact(jitsiAndroidSourcesJar)
pom.withXml {
def pomXml = asNode()
pomXml.appendNode('name', project.name)
pomXml.appendNode('description', json.description)
pomXml.appendNode('url', json.homepage)
if (json.license) {
def license = pomXml.appendNode('licenses').appendNode('license')
license.appendNode('name', json.license)
license.appendNode('distribution', 'repo')
}
def dependencies = pomXml.appendNode('dependencies')
configurations.getByName('releaseCompileClasspath').getResolvedConfiguration().getFirstLevelModuleDependencies().each {
def artifactId = it.moduleName
def version = it.moduleVersion
// React Native signals breaking changes by
// increasing the minor version number. So the
// (third-party) React Native modules we utilize can
// depend not on a specific react-native release but
// a wider range.
if (artifactId == 'react-native') {
def versionNumber = VersionNumber.parse(version)
version = "${versionNumber.major}.${versionNumber.minor}"
}
def dependency = dependencies.appendNode('dependency')
dependency.appendNode('groupId', it.moduleGroup)
dependency.appendNode('artifactId', artifactId)
dependency.appendNode('version', version)
}
}
}
}
}
}
}
// Force the version of the Android build tools we have chosen on all
// subprojects. The forcing was introduced for react-native and the third-party
// modules that we utilize such as react-native-background-timer.
subprojects { subproject ->
afterEvaluate{
if ((subproject.plugins.hasPlugin('android')
|| subproject.plugins.hasPlugin('android-library'))
&& rootProject.ext.has('buildToolsVersion')) {
android {
buildToolsVersion rootProject.ext.buildToolsVersion
}
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
}

View File

@ -1,2 +0,0 @@
json_key_file("")
package_name("org.jitsi.meet")

View File

@ -1,34 +0,0 @@
ENV["FASTLANE_SKIP_UPDATE_CHECK"] = "1"
opt_out_usage
default_platform(:android)
platform :android do
desc "Deploy a new version to Goolge Play (Closed Beta)"
lane :deploy do
# Cleanup
gradle(task: "clean")
# Build and sign the app
gradle(
task: "assemble",
build_type: "Release",
print_command: false,
properties: {
"android.injected.signing.store.file" => ENV["JITSI_KEYSTORE"],
"android.injected.signing.store.password" => ENV["JITSI_KEYSTORE_PASSWORD"],
"android.injected.signing.key.alias" => ENV["JITSI_KEY_ALIAS"],
"android.injected.signing.key.password" => ENV["JITSI_KEY_PASSWORD"],
}
)
# Upload built artifact to the Closed Beta track
upload_to_play_store(
track: "beta",
json_key: ENV["JITSI_JSON_KEY_FILE"],
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true
)
end
end

View File

@ -1,29 +0,0 @@
fastlane documentation
================
# Installation
Make sure you have the latest version of the Xcode command line tools installed:
```
xcode-select --install
```
Install _fastlane_ using
```
[sudo] gem install fastlane -NV
```
or alternatively using `brew cask install fastlane`
# Available Actions
## Android
### android deploy
```
fastlane android deploy
```
Deploy a new version to Goolge Play (Closed Beta)
----
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 694 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 950 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1000 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -9,22 +9,13 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx1024m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# This one fixes a weird WebRTC runtime problem on some devices.
# https://github.com/jitsi/jitsi-meet/issues/7911#issuecomment-714323255
android.enableDexingArtifactTransform.desugaring=false
android.useAndroidX=true
android.enableJetifier=true
android.bundle.enableUncompressedNativeLibs=false
appVersion=99.0.0
sdkVersion=99.0.0
android.useDeprecatedNdk=true
version=1

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip

298
android/gradlew vendored
View File

@ -1,129 +1,79 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# 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
#
# https://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.
#
#!/usr/bin/env bash
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
MAX_FD="maximum"
warn () {
warn ( ) {
echo "$*"
} >&2
}
die () {
die ( ) {
echo
echo "$*"
echo
exit 1
} >&2
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD=$JAVA_HOME/bin/java
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -132,7 +82,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@ -140,95 +90,75 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
exec "$JAVACMD" "$@"
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

179
android/gradlew.bat vendored
View File

@ -1,89 +1,90 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -1,8 +1,8 @@
keystore(
name = "debug",
properties = "debug.keystore.properties",
store = "debug.keystore",
visibility = [
"PUBLIC",
],
name = 'debug',
store = 'debug.keystore',
properties = 'debug.keystore.properties',
visibility = [
'PUBLIC',
],
)

Some files were not shown because too many files have changed in this diff Show More