diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 3b3ce6bb..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,169 +0,0 @@ -version: 2.1 - -orbs: - android: circleci/android@2.1.2 - -workflows: - test: - jobs: - - package - - unit-tests - - instrumented-tests: - matrix: - parameters: - api-level: - # - 21 - TODO: EasyMock makes our tests fail - - 25 - # - 29 - TODO: offline tests fail -# Contract tests are temporarily disabled for API 31 and API 33 due to a degree of -# test instability that impedes development. Currently there are two common failure -# modes: SDK initialization times out, or SDK initialization completes immediately -# without acquiring any data because the emulator reports no network availability. -# These do not appear correlated to any actual SDK logic flaw. - - contract-tests: - matrix: - parameters: - api-level: - - 21 - - 25 - - 30 -# - 31 - # # "default" images are faster than "google_apis" images, but are otherwise equivalent for our purposes. - # # however, there are no "default" images for Android 32+, so as a workaround we have a separate matrix - # # for Android 32+ - # - contract-tests: - # matrix: - # parameters: - # api-level: - # - 33 - # system-image-type: - # - google_apis - # resource-class: - # - xlarge - -commands: - check-emulator-available: - steps: - # Additional validation that emulator is fully started and will accept adb - # commands - - run: - name: Check emulator is available - command: | - while ! adb shell getprop ro.build.version.sdk; do - sleep 1 - done - -jobs: - package: - docker: - - image: cimg/android:2022.06 - steps: - - checkout - - android/restore-gradle-cache: - cache-prefix: package - - run: - name: Validate package creation - command: ./gradlew packageRelease --console=plain -PdisablePreDex - - run: - name: Validate Javadoc - command: ./gradlew Javadoc - - store_artifacts: - path: ./launchdarkly-android-client-sdk/build/reports/ - - android/save-gradle-cache: - cache-prefix: package - - unit-tests: - docker: - - image: cimg/android:2022.06 - steps: - - checkout - - android/restore-gradle-cache: - cache-prefix: unit - - run: - name: Build unit tests - command: ./gradlew :launchdarkly-android-client-sdk:assembleDebugUnitTest - - run: - name: Run local tests - command: ./gradlew :launchdarkly-android-client-sdk:testDebugUnitTest - - android/save-gradle-cache: - cache-prefix: unit - - store_test_results: - path: ./launchdarkly-android-client-sdk/build/test-results/testDebugUnitTest - - instrumented-tests: - parameters: - api-level: - type: integer - system-image-type: - type: string - default: default - resource-class: - type: string - default: large - - executor: - name: android/android-machine - tag: 2022.07.1 - resource-class: << parameters.resource-class >> - - steps: - - checkout - - android/start-emulator-and-run-tests: - avd-name: ci-android-avd - system-image: system-images;android-<< parameters.api-level >>;<< parameters.system-image-type >>;x86_64 - run-logcat: true - restore-gradle-cache-prefix: instrumented-v1 - post-emulator-launch-assemble-command: ./gradlew :launchdarkly-android-client-sdk:assembleDebugAndroidTest - pre-run-tests-steps: - - check-emulator-available - # Necessary for test mocking to disable network access through WiFi - # configuration, allowing testing of behavior when device is offline - - run: - name: Disable mobile data for network tests - command: adb shell svc data disable - test-command: ./gradlew connectedDebugAndroidTest - max-tries: 1 - post-run-tests-steps: - - store_test_results: - path: ./launchdarkly-android-client-sdk/build/outputs/androidTest-results/ - - store_artifacts: - path: ./launchdarkly-android-client-sdk/build/reports/ - - contract-tests: - parameters: - api-level: - type: integer - system-image-type: - type: string - default: default - resource-class: - type: string - default: large - - executor: - name: android/android-machine - tag: 2022.07.1 - resource-class: << parameters.resource-class >> - - environment: - TEST_HARNESS_PARAMS: -junit /home/circleci/junit/contract-tests-junit.xml - - steps: - - checkout - - android/start-emulator-and-run-tests: - avd-name: ci-android-avd - system-image: system-images;android-<< parameters.api-level >>;<< parameters.system-image-type >>;x86_64 - run-logcat: true - restore-gradle-cache-prefix: contract-v1 - post-emulator-launch-assemble-command: make build-contract-tests - pre-run-tests-steps: - - check-emulator-available - - run: mkdir -p ~/junit - - run: make start-contract-test-service - test-command: make run-contract-tests - max-tries: 1 - post-run-tests-steps: - - store_test_results: - path: ~/junit - - store_artifacts: - path: ./launchdarkly-android-client-sdk/build/reports/ diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a9c8db85..c101d59d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- **Is this a support request?** -This issue tracker is maintained by LaunchDarkly SDK developers and is intended for feedback on the SDK code. If you're not sure whether the problem you are having is specifically related to the SDK, or to the LaunchDarkly service overall, it may be more appropriate to contact the LaunchDarkly support team; they can help to investigate the problem and will consult the SDK team if necessary. You can submit a support request by going [here](https://support.launchdarkly.com/hc/en-us/requests/new) or by emailing support@launchdarkly.com. +This issue tracker is maintained by LaunchDarkly SDK developers and is intended for feedback on the code in this library. If you're not sure whether the problem you are having is specifically related to this library, or to the LaunchDarkly service overall, it may be more appropriate to contact the LaunchDarkly support team; they can help to investigate the problem and will consult the SDK team if necessary. You can submit a support request by going [here](https://support.launchdarkly.com/) and clicking "submit a request", or by emailing support@launchdarkly.com. Note that issues filed on this issue tracker are publicly accessible. Do not provide any private account information on your issues. If your problem is specific to your account, you should submit a support request as described above. diff --git a/.github/actions/build-docs/action.yml b/.github/actions/build-docs/action.yml new file mode 100644 index 00000000..88b665ec --- /dev/null +++ b/.github/actions/build-docs/action.yml @@ -0,0 +1,9 @@ +name: Build Documentation +description: 'Build Documentation.' + +runs: + using: composite + steps: + - name: Build Documentation + shell: bash + run: ./gradlew javadoc diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml new file mode 100644 index 00000000..0e9f6073 --- /dev/null +++ b/.github/actions/ci/action.yml @@ -0,0 +1,59 @@ +name: CI Workflow +description: 'Shared CI workflow.' +inputs: + run_tests: + description: 'If true, run unit tests, otherwise skip them.' + required: false + default: 'true' + android_api_level: + description: 'The Android API level to use.' + required: true + java_version: + description: 'The Java version to use.' + required: true + java_distribution: + description: 'The Java distribution to use.' + required: false + default: 'temurin' + +runs: + using: composite + steps: + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: ${{ inputs.java_distribution }} + java-version: ${{ inputs.java_version }} + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Build + shell: bash + id: build + run: ./gradlew build jar + + - name: Run Unit Tests + if: inputs.run_tests == 'true' + shell: bash + run: ./gradlew test + + - name: Build contract tests + shell: bash + run: make build-contract-tests + + - name: Perform Instrumented Tests + uses: reactivecircus/android-emulator-runner@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2 #2.30.1 + with: + api-level: ${{ inputs.android_api_level }} + target: google_apis + emulator-boot-timeout: 900 + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: | + make start-contract-test-service + make run-contract-tests + ./gradlew connectedDebugAndroidTest + + - name: Build documentation + uses: ./.github/actions/build-docs diff --git a/.github/actions/publish-docs/action.yml b/.github/actions/publish-docs/action.yml new file mode 100644 index 00000000..9c04e47e --- /dev/null +++ b/.github/actions/publish-docs/action.yml @@ -0,0 +1,24 @@ +name: Publish Documentation +description: 'Publish the documentation to Github pages' +inputs: + token: + description: 'Token to use for publishing.' + required: true + dry_run: + description: 'Is this a dry run. If so no docs will be published.' + required: true + +runs: + using: composite + steps: + - uses: launchdarkly/gh-actions/actions/publish-pages@publish-pages-v1.0.1 + name: 'Publish to Github pages' + if: ${{ inputs.dry_run == 'false' }} + with: + docs_path: launchdarkly-android-client-sdk/build/docs/javadoc + github_token: ${{ inputs.token }} # For the shared action the token should be a GITHUB_TOKEN + + - name: Dry Run Publish Docs + shell: bash + if: ${{ inputs.dry_run == 'true' }} + run: echo "Dry run. Not publishing docs." diff --git a/.github/actions/publish/action.yml b/.github/actions/publish/action.yml new file mode 100644 index 00000000..e7d3bec5 --- /dev/null +++ b/.github/actions/publish/action.yml @@ -0,0 +1,28 @@ +name: Publish Package +description: 'Publish the package to Sonatype' +inputs: + code_signing_keyring: + description: 'The path of the code signing keyring.' + required: true + prerelease: + description: 'Is this a prerelease. If so then it will be published to the staging repository only.' + required: true + dry_run: + description: 'Is this a dry run. If so no package will be published.' + required: true + +runs: + using: composite + steps: + - name: Publish Library + shell: bash + if: ${{ inputs.dry_run == 'false' }} + env: + LD_RELEASE_IS_PRERELEASE: ${{ inputs.prerelease }} + SIGNING_SECRET_KEY_RING_FILE: ${{ inputs.code_signing_keyring }} + run: source $GITHUB_ACTION_PATH/publish.sh + + - name: Dry Run Publish Library + shell: bash + if: ${{ inputs.dry_run == 'true' }} + run: echo "Dry run. Not publishing." diff --git a/.github/actions/publish/publish.sh b/.github/actions/publish/publish.sh new file mode 100755 index 00000000..837aaa0c --- /dev/null +++ b/.github/actions/publish/publish.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -ue + +echo "Publishing to Sonatype" +if [ "${LD_RELEASE_IS_PRERELEASE}" == "true" ]; then + echo "PRERELEASE" + ./gradlew publishToSonatype -Psigning.keyId="${SIGNING_KEY_ID}" -Psigning.password="${SIGNING_KEY_PASSPHRASE}" -Psigning.secretKeyRingFile="${SIGNING_SECRET_KEY_RING_FILE}" -PsonatypeUsername="${SONATYPE_USER_NAME}" -PsonatypePassword="${SONATYPE_PASSWORD}" || { + echo "Gradle publish/release failed" >&2 + exit 1 + } +else + echo "RELEASE" + ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -Psigning.keyId="${SIGNING_KEY_ID}" -Psigning.password="${SIGNING_KEY_PASSPHRASE}" -Psigning.secretKeyRingFile="${SIGNING_SECRET_KEY_RING_FILE}" -PsonatypeUsername="${SONATYPE_USER_NAME}" -PsonatypePassword="${SONATYPE_PASSWORD}" || { + echo "Gradle publish/release failed" >&2 + exit 1 + } +fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..04cc1ed6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: Build and Test +on: + workflow_dispatch: + push: + branches: ['main'] + paths-ignore: + - '**.md' # Do not need to run CI for markdown changes. + pull_request: + branches: [ 'main' ] + paths-ignore: + - '**.md' + +jobs: + ci-build: + strategy: + matrix: +# TODO: Use full matrices +# android_api_level: ['21','25','30','34'] +# java_version: ['11', '17'] + android_api_level: ['25'] + java_version: ['17'] + runs-on: ubuntu-latest + + steps: + # This enables hardware acceleration on large linux runners + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - uses: actions/checkout@v4 + - uses: ./.github/actions/ci + with: + android_api_level: ${{ matrix.android_api_level }} + java_version: ${{ matrix.java_version }} diff --git a/.github/workflows/lint-pr-title.yml b/.github/workflows/lint-pr-title.yml new file mode 100644 index 00000000..4ba79c13 --- /dev/null +++ b/.github/workflows/lint-pr-title.yml @@ -0,0 +1,12 @@ +name: Lint PR title + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + lint-pr-title: + uses: launchdarkly/gh-actions/.github/workflows/lint-pr-title.yml@main diff --git a/.github/workflows/manual-publish-docs.yml b/.github/workflows/manual-publish-docs.yml new file mode 100644 index 00000000..80d440e7 --- /dev/null +++ b/.github/workflows/manual-publish-docs.yml @@ -0,0 +1,25 @@ +on: + workflow_dispatch: + +name: Publish Docs +jobs: + build-publish: + runs-on: ubuntu-latest + permissions: + id-token: write # Needed if using OIDC to get release secrets. + contents: write # Needed in this case to write github pages. + steps: + - uses: actions/checkout@v4 + + - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.0.1 + name: Assume aws role + with: + aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + + - name: Build and Test + uses: ./.github/actions/ci + + - name: Publish Documentation + uses: ./.github/actions/publish-docs + with: + token: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..2dae46fb --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,70 @@ +name: Publish Package +on: + workflow_dispatch: + inputs: + run_tests: + description: 'If true, run unit tests, otherwise skip them.' + type: boolean + default: true + dry_run: + description: 'Is this a dry run. If so no package will be published.' + type: boolean + required: true + prerelease: + description: 'If true, then this is a prerelease and should be published to the staging repository only.' + type: boolean + required: true + workflow_call: + inputs: + run_tests: + description: 'If true, run unit tests, otherwise skip them.' + required: false + type: boolean + default: true + dry_run: + description: 'Is this a dry run. If so no package will be published.' + type: boolean + required: true + prerelease: + description: 'If true, then this is a prerelease and should be published to the staging repository only.' + type: boolean + required: true + +jobs: + build-and-publish: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v4 + + - name: CI check + uses: ./.github/actions/ci + with: + run_tests: ${{ inputs.run_tests }} + android_api_level: [ '25' ] + java_version: [ '17' ] + + - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.1.0 + name: Get secrets + with: + aws_assume_role: ${{ vars.AWS_ROLE_ARN }} + ssm_parameter_pairs: '/production/common/releasing/sonatype/username = SONATYPE_USER_NAME, + /production/common/releasing/sonatype/password = SONATYPE_PASSWORD + /production/common/releasing/android_code_signing/private_key_id = SIGNING_KEY_ID + /production/common/releasing/android_code_signing/private_key_passphrase = SIGNING_KEY_PASSPHRASE' + s3_path_pairs: 'launchdarkly-releaser/android/code-signing-keyring.gpg = code-signing-keyring.gpg' + + - name: Publish + uses: ./.github/actions/publish + with: + dry_run: ${{ inputs.dry_run }} + prerelease: ${{ inputs.prerelease }} + code_signing_keyring: 'code-signing-keyring.gpg' + + - name: Publish Documentation + uses: ./.github/actions/publish-docs + with: + dry_run: ${{ inputs.dry_run }} + token: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..3a5ac763 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,35 @@ +name: Run Release Please + +on: + push: + branches: + - main + +jobs: + release-please: + runs-on: ubuntu-latest + + permissions: + id-token: write # Needed for OIDC to get release secrets. + contents: write # Contents and pull-requests are for release-please to make releases. + pull-requests: write + + outputs: + releases_created: ${{ steps.release.outputs.releases_created }} + + steps: + - uses: google-github-actions/release-please-action@v4 + id: release + with: + token: ${{ secrets.GITHUB_TOKEN }} + target-branch: ${{ github.ref_name }} + + call-workflow-publish: + needs: release-please + uses: ./.github/workflows/publish.yml + if: ${{ needs.release-please.outputs.releases_created == 'true' }} + with: + run_tests: true +# TODO: revert dry run put in place during testing + dry_run: true + prerelease: false diff --git a/.ldrelease/build-docs.sh b/.ldrelease/build-docs.sh deleted file mode 100755 index 60f4d5a8..00000000 --- a/.ldrelease/build-docs.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# This is the same as https://github.com/launchdarkly/project-releaser/blob/master/project_template/gradle/build-docs.sh -# but accounts for the fact that the docs appear in a different subdirectory. - -set -ue - -echo "Building Javadoc" -./gradlew javadoc || { echo "Javadoc build failed" >&2; exit 1; } - -cp -r "${LD_RELEASE_PROJECT_DIR}/launchdarkly-android-client-sdk/build/docs/javadoc"/* "${LD_RELEASE_DOCS_DIR}" diff --git a/.ldrelease/config.yml b/.ldrelease/config.yml deleted file mode 100644 index 8c47abb1..00000000 --- a/.ldrelease/config.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: 2 - -repo: - public: android-client-sdk - private: android-client-sdk-private - -publications: - - url: https://oss.sonatype.org/content/groups/public/com/launchdarkly/launchdarkly-android-client-sdk/ - description: Sonatype - - url: https://javadoc.io/doc/com.launchdarkly/launchdarkly-android-client-sdk - description: documentation (javadoc.io) - -jobs: - - docker: - image: cimg/android:2022.04 - template: - name: gradle - -branches: - - name: main - - name: 4.x - - name: 3.x - -documentation: - gitHubPages: true - -sdk: - displayName: "Android" diff --git a/.ldrelease/prepare.sh b/.ldrelease/prepare.sh deleted file mode 100755 index ec21f9f8..00000000 --- a/.ldrelease/prepare.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# See: https://github.com/launchdarkly/project-releaser/blob/master/docs/templates/gradle.md - -set -eu - -if [ -n "${LD_RELEASE_DRY_RUN:-}" ]; then - android_sonatype_username="" - android_sonatype_password="" -else - android_sonatype_username="$(cat "${LD_RELEASE_SECRETS_DIR}/android_sonatype_username")" - android_sonatype_password="$(cat "${LD_RELEASE_SECRETS_DIR}/android_sonatype_password")" -fi - -# temporary hack to allow us to override the hard-coded key ID and password in tests - we should -# move this value into AWS -android_code_signing_key_id=CA2B31DA -android_code_signing_password=$(cat "${LD_RELEASE_SECRETS_DIR}/android_code_signing_passphrase") - -mkdir -p ~/.gradle -cat >~/.gradle/gradle.properties <&2; exit 1; } diff --git a/.ldrelease/secrets.properties b/.ldrelease/secrets.properties deleted file mode 100644 index 048742d2..00000000 --- a/.ldrelease/secrets.properties +++ /dev/null @@ -1,11 +0,0 @@ -# GPG code-signing keyring. This is a "blob:" rather than a "param:" because it's several K of binary data. -android_code_signing_keyring=blob:/android/code-signing-keyring.gpg - -# passphrase for the GPG keyring -android_code_signing_passphrase=param:/production/common/releasing/android_code_signing/private_key_passphrase - -# Username for the Sonatype repository. -android_sonatype_username=param:/production/common/releasing/sonatype/username - -# Password for the Sonatype repository. -android_sonatype_password=param:/production/common/releasing/sonatype/password diff --git a/Makefile b/Makefile index c831dc30..cc2348da 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -TEST_HARNESS_PARAMS= -skip "events/disabling" +TEST_HARNESS_PARAMS= -skip "events/disabling" -status-timeout 60 # can add temporary test skips etc. here # Currently we are skipping the "events/disabling" tests because the Android SDK has no way to # disable events. That wasn't an issue earlier because the "events/disabling" tests were getting diff --git a/gradle.properties b/gradle.properties index e113cf83..f531dee2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,10 @@ # 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 + +#x-release-please-start-version version=5.0.4 +#x-release-please-end sonatypeUsername= sonatypePassword= diff --git a/launchdarkly-android-client-sdk/build.gradle b/launchdarkly-android-client-sdk/build.gradle index ecdd607e..328347ac 100644 --- a/launchdarkly-android-client-sdk/build.gradle +++ b/launchdarkly-android-client-sdk/build.gradle @@ -138,19 +138,6 @@ task javadocJar(type: Jar, dependsOn: javadoc) { from javadoc.destinationDir } -// Force the Javadoc build to fail if there are any Javadoc warnings. See: https://discuss.gradle.org/t/javadoc-fail-on-warning/18141/3 -if (JavaVersion.current().isJava8Compatible()) { - tasks.withType(Javadoc) { - // The '-quiet' as second argument is actually a hack, - // since the one parameter addStringOption doesn't seem to - // work, we extra add '-quiet', which is added anyway by - // gradle. See https://github.com/gradle/gradle/issues/2354 - // See JDK-8200363 (https://bugs.openjdk.java.net/browse/JDK-8200363) - // for information about the -Xwerror option. - options.addStringOption("Xwerror", "-quiet") - } -} - tasks.withType(Javadoc) { // The following should allow hyperlinks to com.launchdarkly.logging classes to go to // the correct external URLs diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/ConnectionInformation.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/ConnectionInformation.java index 875fb717..a8a62fd8 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/ConnectionInformation.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/ConnectionInformation.java @@ -1,17 +1,52 @@ package com.launchdarkly.sdk.android; +/** + * Provides various information about a current or previous connection. + */ public interface ConnectionInformation { /** * Enumerated type defining the possible values of {@link ConnectionInformation#getConnectionMode()}. */ enum ConnectionMode { + /** + * The SDK is either connected to the flag stream, or is actively attempting to acquire a connection. + */ STREAMING(true), + + /** + * The SDK is in foreground polling mode because it was configured with streaming disabled. + */ POLLING(true), + + /** + * The SDK has detected the application is in the background and has transitioned to battery-saving background + * polling. + */ BACKGROUND_POLLING(true), + + /** + * The SDK was configured with background polling disabled. The SDK has detected the application is in the + * background and is not attempting to update the flag cache. + */ BACKGROUND_DISABLED(false), + + /** + * The SDK has detected that the mobile device does not have an active network connection. It has ceased flag + * update attempts until the network status changes. + */ OFFLINE(false), + + /** + * The SDK has been explicitly set offline, either in the initial configuration, by + * {@link LDClient#setOffline()}, or as a result of failed authentication to LaunchDarkly. The SDK will stay + * offline unless {@link LDClient#setOnline()} is called. + */ SET_OFFLINE(false), + + /** + * The shutdown state indicates the SDK has been permanently shutdown as a result of a call to close(). + */ SHUTDOWN(false); private boolean connectionActive; @@ -20,16 +55,31 @@ enum ConnectionMode { this.connectionActive = connectionActive; } + /** + * @return true if connection is active, false otherwise + */ boolean isConnectionActive() { return connectionActive; } } + /** + * @return the {@link ConnectionMode} + */ ConnectionMode getConnectionMode(); + /** + * @return the last {@link LDFailure} + */ LDFailure getLastFailure(); + /** + * @return millis since epoch when the last successful connection occurred + */ Long getLastSuccessfulConnection(); + /** + * @return millis since epoch when the last connection connection failure occurred + */ Long getLastFailedConnection(); } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/DataModel.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/DataModel.java index b1a8d058..ca915618 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/DataModel.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/DataModel.java @@ -91,6 +91,11 @@ public Flag( this(key, value, version, flagVersion, variation, reason, trackEvents, trackReason, debugEventsUntilDate, false); } + /** + * @param key of the flag + * @param version of the flag + * @return a placeholder {@link Flag} to represent a deleted flag + */ public static Flag deletedItemPlaceholder(@NonNull String key, int version) { return new Flag(key, null, version, null, null, null, false, false, null, true); } @@ -161,6 +166,12 @@ public boolean equals(Object other) { return false; } + /** + * Deserializes a flag from JSON to {@link Flag} + * @param json to convert + * @return the {@link Flag} + * @throws SerializationException if unable to deserialize + */ public static Flag fromJson(String json) throws SerializationException { try { return gsonInstance().fromJson(json, Flag.class); @@ -169,6 +180,9 @@ public static Flag fromJson(String json) throws SerializationException { } } + /** + * @return JSON serialization of the flag + */ public String toJson() { return gsonInstance().toJson(this); } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDAndroidLogging.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDAndroidLogging.java index e4b31825..7d800d3d 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDAndroidLogging.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDAndroidLogging.java @@ -21,6 +21,10 @@ * @since 3.2.0 */ public abstract class LDAndroidLogging { + + /** + * @return an {@link LDLogAdapter} for Android logging + */ public static LDLogAdapter adapter() { return new AdapterImpl(false); } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDClient.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDClient.java index abce06da..2da16942 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDClient.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDClient.java @@ -279,6 +279,17 @@ public static LDClient getForMobileKey(String keyName) throws LaunchDarklyExcept return instancesNow.get(keyName); } + /** + * @param platformState the platform state + * @param environmentReporter the environment reporter + * @param taskExecutor the task executor + * @param environmentStore the environment store + * @param initialContext initial context + * @param config the config + * @param mobileKey the mobile key + * @param environmentName the environment name + * @throws LaunchDarklyException if {@link LDClient} cannot be created + */ @VisibleForTesting protected LDClient( @NonNull final PlatformState platformState, diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java index be5f1f96..807cc64a 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java @@ -108,36 +108,63 @@ public class LDConfig { this.loggerName = loggerName; } + /** + * @return the mobile key + */ public String getMobileKey() { return mobileKeys.get(primaryEnvironmentName); } + /** + * @return a map of mobile keys keyed by environment name + */ public Map getMobileKeys() { return mobileKeys; } + /** + * @return true if offline mode is enabled, false otherwise + */ public boolean isOffline() { return offline; } + /** + * @return true if background polling is disabled, false otherwise + */ public boolean isDisableBackgroundPolling() { return disableBackgroundUpdating; } + /** + * @return true if evaluation reasons are turned on, false otherwise + */ public boolean isEvaluationReasons() { return evaluationReasons; } + /** + * @return true if opting out of diagnostics, false otherwise + */ boolean getDiagnosticOptOut() { return diagnosticOptOut; } + /** + * @return the maximum number of contexts that will be cached locally + */ int getMaxCachedContexts() { return maxCachedContexts; } + /** + * @return true if keys should be generated for anonymous contexts, false otherwise + */ public boolean isGenerateAnonymousKeys() { return generateAnonymousKeys; } + /** + * @return true if automatic environment attributes should be included in contexts, false otherwise + */ public boolean isAutoEnvAttributes() { return autoEnvAttributes; } @@ -173,9 +200,14 @@ public static class Builder { that customers on previous versions don't use the earlier, unfinished version of the feature. */ public enum AutoEnvAttributes { - // Enables the Auto EnvironmentAttributes functionality. + /** + * Enables the Auto EnvironmentAttributes functionality. + */ Enabled, - // Disables the Auto EnvironmentAttributes functionality. + + /** + * Disables the Auto EnvironmentAttributes functionality. + */ Disabled } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDFailure.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDFailure.java index f3e28510..739f03e9 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDFailure.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDFailure.java @@ -4,6 +4,9 @@ import com.google.gson.annotations.JsonAdapter; +/** + * Container class representing a communication failure with LaunchDarkly servers. + */ @JsonAdapter(LDFailureSerialization.class) public class LDFailure extends LaunchDarklyException { @@ -11,26 +14,61 @@ public class LDFailure extends LaunchDarklyException { * Enumerated type defining the possible values of {@link LDFailure#getFailureType()}. */ public enum FailureType { + /** + * A response body received either through polling or streaming was unable to be parsed. + */ INVALID_RESPONSE_BODY, + + /** + * A network request for polling, or the EventSource stream reported a failure. + */ NETWORK_FAILURE, + + /** + * An event was received through the stream with an unknown event key. This could indicate a newer SDK is + * available if new event kinds have become available through the flag stream since the SDK's release. + */ UNEXPECTED_STREAM_ELEMENT_TYPE, + + /** + * This indicates the LDFailure is an instance of LDInvalidResponseCodeFailure. + */ UNEXPECTED_RESPONSE_CODE, + + /** + * Some other issue occurred. + */ UNKNOWN_ERROR } + /** + * The failure type + */ @NonNull private final FailureType failureType; + /** + * @param message the message + * @param failureType the failure type + */ public LDFailure(String message, @NonNull FailureType failureType) { super(message); this.failureType = failureType; } + /** + * @param message the message + * @param cause the cause of the failure + * @param failureType the failure type + */ public LDFailure(String message, Throwable cause, @NonNull FailureType failureType) { super(message, cause); this.failureType = failureType; } + /** + * @return the failure type + */ @NonNull public FailureType getFailureType() { return failureType; diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDInvalidResponseCodeFailure.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDInvalidResponseCodeFailure.java index cbc771b3..6c5b6f38 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDInvalidResponseCodeFailure.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDInvalidResponseCodeFailure.java @@ -2,27 +2,55 @@ import com.google.gson.annotations.JsonAdapter; +/** + * Container class representing a communication failure with LaunchDarkly servers in which the response was unexpected. + */ @JsonAdapter(LDFailureSerialization.class) public class LDInvalidResponseCodeFailure extends LDFailure { + + /** + * The response code + */ private final int responseCode; + + /** + * Whether or not the failure may be fixed by retrying + */ private final boolean retryable; + /** + * @param message the message + * @param responseCode the response code + * @param retryable whether or not retrying may resolve the issue + */ public LDInvalidResponseCodeFailure(String message, int responseCode, boolean retryable) { super(message, FailureType.UNEXPECTED_RESPONSE_CODE); this.responseCode = responseCode; this.retryable = retryable; } + /** + * @param message the message + * @param cause the cause of the failure + * @param responseCode the response code + * @param retryable whether or not retrying may resolve the issue + */ public LDInvalidResponseCodeFailure(String message, Throwable cause, int responseCode, boolean retryable) { super(message, cause, FailureType.UNEXPECTED_RESPONSE_CODE); this.responseCode = responseCode; this.retryable = retryable; } + /** + * @return true if retrying may resolve the issue + */ public boolean isRetryable() { return retryable; } + /** + * @return the response code + */ public int getResponseCode() { return responseCode; } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDPackageConsts.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDPackageConsts.java index 6210fe9e..11f4cc4a 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDPackageConsts.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDPackageConsts.java @@ -1,8 +1,28 @@ package com.launchdarkly.sdk.android; +/** + * Constants related to the SDK package + */ public class LDPackageConsts { + + /** + * Name of the SDK + */ public static final String SDK_NAME = "android-client-sdk"; + + /** + * Name of the platform this SDK is primarily for + */ public static final String SDK_PLATFORM_NAME = "Android"; + + /** + * Name that will be used for identifying this SDK when using a network client. An example would be the + * user agent in HTTP. + */ public static final String SDK_CLIENT_NAME = "AndroidClient"; + + /** + * Name the logger will use to identify this SDK. + */ public static final String DEFAULT_LOGGER_NAME = "LaunchDarklySdk"; } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDStatusListener.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDStatusListener.java index 81c02b44..9da1c8fd 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDStatusListener.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDStatusListener.java @@ -1,8 +1,20 @@ package com.launchdarkly.sdk.android; +/** + * Listener for various SDK state changes. + */ public interface LDStatusListener { + /** + * Invoked when the connection mode changes + * @param connectionInformation the connection information that gives details about the connection + */ void onConnectionModeChanged(ConnectionInformation connectionInformation); + + /** + * Invoked when an internal issue results in a failure to connect to LaunchDarkly + * @param ldFailure the failure + */ void onInternalFailure(LDFailure ldFailure); } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDTimberLogging.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDTimberLogging.java index 5df2fbe4..205fccb1 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDTimberLogging.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDTimberLogging.java @@ -24,6 +24,10 @@ * @since 3.2.0 */ public abstract class LDTimberLogging { + + /** + * @return an {@link LDLogAdapter} for Timber logging + */ public static LDLogAdapter adapter() { return new Adapter(true); } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDUtil.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDUtil.java index 1ae9fdf3..a5301e94 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDUtil.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDUtil.java @@ -29,6 +29,9 @@ import okhttp3.Headers; +/** + * Various utility functions + */ public class LDUtil { static final String AUTH_SCHEME = "api_key "; static final String USER_AGENT_HEADER_VALUE = LDPackageConsts.SDK_CLIENT_NAME + "/" + BuildConfig.VERSION_NAME; diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LaunchDarklyException.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LaunchDarklyException.java index 5cc0c572..da64d5ff 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LaunchDarklyException.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LaunchDarklyException.java @@ -4,6 +4,10 @@ * Exception class that can be thrown by LaunchDarkly client methods. */ public class LaunchDarklyException extends Exception { + + /** + * @param message for the exception + */ public LaunchDarklyException(String message) { super(message); } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/env/EnvironmentReporterBuilder.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/env/EnvironmentReporterBuilder.java index 6c8fb03d..6711965a 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/env/EnvironmentReporterBuilder.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/env/EnvironmentReporterBuilder.java @@ -39,6 +39,9 @@ public void enableCollectionFromPlatform(Application application) { this.application = application; } + /** + * @return the {@link IEnvironmentReporter} + */ public IEnvironmentReporter build() { /** * Create chain of responsibility with the following priority order diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/ApplicationInfoBuilder.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/ApplicationInfoBuilder.java index be7e3fc1..749a1625 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/ApplicationInfoBuilder.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/ApplicationInfoBuilder.java @@ -27,7 +27,6 @@ * ) * .build(); * - *

* * @since 4.1.0 */ diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EventProcessorBuilder.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EventProcessorBuilder.java index be373cac..2e5dd479 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EventProcessorBuilder.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EventProcessorBuilder.java @@ -46,10 +46,29 @@ public abstract class EventProcessorBuilder implements ComponentConfigurer privateAttributes; /** diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/HttpConfigurationBuilder.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/HttpConfigurationBuilder.java index ec384b5b..b8c9ebc8 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/HttpConfigurationBuilder.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/HttpConfigurationBuilder.java @@ -31,10 +31,29 @@ public abstract class HttpConfigurationBuilder implements ComponentConfigurer