# DHIS2 Android SDK

[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.hisp.dhis/android-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.hisp.dhis/android-core)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=dhis2_dhis2-android-sdk&metric=coverage&branch=master)](https://sonarcloud.io/summary/new_code?id=dhis2_dhis2-android-sdk&branch=master)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=dhis2_dhis2-android-sdk&metric=ncloc&branch=master)](https://sonarcloud.io/summary/new_code?id=dhis2_dhis2-android-sdk&branch=master)

## Introduction

DHIS2 Android SDK is a library that abstracts the complexity of interacting with DHIS2 web api. It aims to be an starting point to build Android apps for DHIS2, covering some tasks that any Android app should implement, like metadata and data synchronization.

Main goals:

- **Abstract DHIS2 web api**. There is no need to perform api queries against the server. The SDK includes methods to interact with the web api.
- **Work offline**. It implements a simplified version of DHIS2 model that is persisted in a local database (SQLite). It ensures that all the metadata required to perform data entry tasks is available at any time to build the data entry forms. Data is saved locally and upload to the server when connectivity is available.
- **Ensure DHIS2 compatibility**. It encapsulates the changes between DHIS2 versions so the app does not have to care about them. In case the SDK introduces some changes to accommodate a new DHIS2 version, the app can safely detect these changes at compile-time.

## Documentation

Developer-oriented documentation can be found in [Documentation section](https://docs.dhis2.org/en/develop/developing-with-the-android-sdk/about-this-guide.html) in DHIS2 web. It is intended to be used by developers.

## Examples

Code examples can be found in the [Android Skeleton app](https://github.com/dhis2/dhis2-android-skeleton-app). This app contains different branches showing different use cases of the SDK.

## Community

Community support can be found in [Android SDK Development](https://community.dhis2.org/c/development/sdk-android-development) category in the community portal. Any feedback on the SDK will be highly appreciated.

To report bugs or request new features, there is project in DHIS2 Jira named [ANDROSDK](https://jira.dhis2.org/projects/ANDROSDK/issues). Please do not hesitate to create an issue with your request.


Open Food Facts - Legacy Android app (still used for Open Beauty, Pet Food and Products Facts)
=============================

Open Food Facts is collaborative food products database made by everyone, for everyone. Open Food Facts contributors gathers information and data on food products from around the world, using mobile apps.

> ### ⚠ WARNING
>
> The new Open Food Facts app is located [HERE](https://github.com/openfoodfacts/smooth-app)
>
> **Note: This codebase is currently only deployed for Open Beauty Facts, Open Pet Food Facts and Open Products Facts apps.**

[![Project Status](https://opensource.box.com/badges/active.svg)](https://opensource.box.com/badges)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=openfoodfacts_openfoodfacts-androidapp&metric=alert_status)](https://sonarcloud.io/dashboard/index/openfoodfacts_openfoodfacts-androidapp)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/openfoodfacts/localized.svg)](https://crowdin.com/project/openfoodfacts)
![Build](https://github.com/openfoodfacts/openfoodfacts-androidapp/workflows/Android%20Integration/badge.svg)
[![Open Source Helpers](https://www.codetriage.com/openfoodfacts/openfoodfacts-androidapp/badges/users.svg)](https://www.codetriage.com/openfoodfacts/openfoodfacts-androidapp)

- [Open Beauty Facts](https://play.google.com/store/apps/details?id=org.openbeautyfacts.scanner), [Open Pet Food Facts](https://play.google.com/store/apps/details?id=org.openpetfoodfacts.scanner) and [Open Products Facts](https://play.google.com/store/apps/details?id=org.openproductsfacts.scanner) are also built from this codebase.

 What is Open Food Facts?

### A food products database

Open Food Facts is a database of food products with ingredients, allergens, nutrition facts… which allow us to compute scores like Nutri-Score, NOVA groups and Eco-Score.

### Made by everyone

Open Food Facts is a non-profit association of volunteers.
25000+ contributors like you have added 3M+ products from 150 countries using our Android or iPhone apps to scan barcodes and upload pictures of products and their labels.

### For everyone

Data about food is of public interest and has to be open. The complete database is published as open data and can be reused by anyone.

## User flows
[Visual documentation of the App on Figma](https://www.figma.com/file/BQ7CSyFvl7D9ljcXT0ay0u/Navigation-within-the-app)

## Documentation of the source code
The documentation is generated automatically from the source code and your improvements to code documentation are published automatically.
[Code documentation on GitHub pages](https://openfoodfacts.github.io/openfoodfacts-androidapp/)

## Helping with our next release
Here are issues and feature requests you can work on:
- [ ] [3.6.6 milestone](https://github.com/openfoodfacts/openfoodfacts-androidapp/milestone/36)

 What can I work on ?

Open Food Facts on Android has 0,5M users and 1,6M products. *Each contribution you make will have a large impact on food transparency worldwide.* Finding the right issue or feature will help you have even more more impact. Feel free to ask for feedback on the #android channel before you start work, and to document what you intend to code.

- [Here are issues and feature requests you can work on](https://github.com/openfoodfacts/openfoodfacts-androidapp/issues/4169)
- [P1 issues](https://github.com/openfoodfacts/openfoodfacts-androidapp/labels/p1)
- [Small issues (Hacktoberfest)](https://github.com/openfoodfacts/openfoodfacts-androidapp/labels/hacktoberfest)

If you don't have time to contribute code, you're very welcome to
* Scan new products
* [**Make a donation** to help pay for the hosting and general costs](https://donate.openfoodfacts.org)

## Help translate Open Food Facts in your language

You can help translate Open Food Facts and the app at (no technical knowledge required, takes a minute to signup):

https://translate.openfoodfacts.org

## Installation

| Choose the right flavor | Install steps|
| ------------- | ------------- |
| | * Download the latest [Android Studio](https://developer.android.com/studio) stable build.
* If you are running the app for the first time, Android Studio will ask you to install the Gradle dependencies.
* If you are a new contributor to open-source, we recommend you read our [Setup Guidelines](https://github.com/openfoodfacts/openfoodfacts-androidapp/blob/master/SETUP_GUIDELINES.md)
* In Android Studio, make sure to select `OFF` as the default flavor for Open Food Facts (`OBF` is Open Beauty Facts, `OPF` - Open Products Facts, `OPFF` - Open Pet Food Facts)
* You should be able to install Open Food Facts on your phone using an USB cable, or run it in an emulator.
* The package name on the Play Store is org.openfoodfacts.scanner. For historic reasons, it's openfoodfacts.github.scrachx.openfood in the code and on F-Droid.|

## Running a Fastlane lane
The project uses Fastlane to automate release and screenshots generation.
* First time you checkout, run `bundle install` at the root of the project.
* Then launch lanes using `bundle exec fastlane release` (for example the release lane).
* We're moving Fastlane related things to https://github.com/openfoodfacts/fastlane-descriptions.

### Who do I talk to?

* Any member of the Android team or contact@openfoodfacts.org
* Join our #android and #android-alerts discussion room on Slack (Get an invite: <https://slack.openfoodfacts.org/>)

### Contributing

If you're new to open-source, we recommend to checkout our [Contributing Guidelines](https://github.com/openfoodfacts/openfoodfacts-androidapp/blob/master/CONTRIBUTING.md). Feel free to fork the project and send a pull request.

 Libraries Used

We use the following libraries, and we're not closed to changes where relevant :-)

 If you spot any libraries we added or we don't use anymore, feel free to update this list using a Pull Request.

- [Dagger 2](https://github.com/google/dagger) - A fast dependency injector for Android and Java
- [Retrofit](https://square.github.io/retrofit/) - Retrofit turns your REST API into a Java interface
- [OkHttp](https://github.com/square/okhttp) - An HTTP+SPDY client for Android and Java applications
- [Mockito](https://github.com/mockito/mockito) - Most popular Mocking framework for unit tests written in Java
- [Apache](https://github.com/apache/commons-io) - The Apache Commons IO library contains utility classes, stream implementations, file filters, file comparators, endian transformation classes, and much more.
- [Kotlin Coroutines](https://developer.android.com/kotlin/coroutines) - A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously.
- [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) - Hilt is a dependency injection library for Android that reduces the boilerplate of doing manual dependency injection in your project.
- [Dagger](https://developer.android.com/training/dependency-injection/dagger-android) - Manual dependency injection or service locators in an Android app can be problematic depending on the size of your project. You can limit your project's complexity as it scales up by using Dagger to manage dependencies. Dagger automatically generates code that mimics the code you would otherwise have hand-written.
- [Jackson](https://github.com/FasterXML/jackson) - Core part of Jackson that defines Streaming API as well as basic shared abstractions
- [journeyapps/zxing-android-embedded](https://github.com/journeyapps/zxing-android-embedded) - Barcode scanner library for Android, based on the ZXing decoder
- GreenDao
- [mikepenz/MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) - The flexible, easy to use, all in one drawer library for your Android project.

Big thanks to their contributors!

Copyright and License

    Copyright 2016-2022 Open Food Facts

    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.

## Contributors

The project was initially started by [Scot Scriven](https://github.com/itchix), other contributors include:
- [Aurélien Leboulanger](https://github.com/herau)
- [Pierre Slamich](https://github.com/teolemon)
- [Friedger Müffke](https://github.com/friedger)
- [Qian Jin](https://github.com/jinqian)
- [Fred Deniger](https://github.com/deniger)
- [VaiTon](https://github.com/VaiTon)


# Easy xkcd [![GitHub CI](https://github.com/tom-anders/Easy_xkcd/workflows/CI/badge.svg)](https://github.com/tom-anders/Easy_xkcd/actions/workflows/main.yml)

[](https://f-droid.org/packages/de.tap.easy_xkcd)
[](https://play.google.com/store/apps/details?id=de.tap.easy_xkcd&hl=de&gl=US&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)

A beautiful, fast, and easy to use [xkcd](http://xkcd.com/) reader for Android.

# Features

## Comic Browser

- Offline Mode
- Favorites
- Notifications
- Explain xkcd integration
- Long press to view alt text
- Overview Mode
- Open Reddit Thread
- Search for title, transcript or number
- Share comic url or image
- Support for large images (e.g comic 657)
- Option to display alt text by default

## What If?

- Full support for footnotes, formulas and alt text
- Offline mode and notifications
- Mark articles as read and hide them
- Swipe between articles (disabled by default)
- Quick search for article titles
- Random articles

## General

- Custom themes
- (Auto) Night mode (with option to invert comic colors)

# Licenses
- Easy xkcd is licensed under the [Apache License v2](https://github.com/Foggalong/Easy_xkcd/blob/master/LICENSE).
- xkcd is licensed under a [Creative Commons Attribution-NonCommercial 2.5 License](http://creativecommons.org/licenses/by-nc/2.5/).
- Google Play and the Google Play logo are trademarks of Google LLC.


[![Latest Version](https://img.shields.io/maven-central/v/com.adobe.testing/s3mock.svg?maxAge=3600&label=Latest%20Release)](https://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.adobe.testing%20a%3As3mock)
![Maven Build](https://github.com/adobe/S3Mock/workflows/Maven%20Build/badge.svg)
[![Docker Hub](https://img.shields.io/badge/docker-latest-blue.svg)](https://hub.docker.com/r/adobe/s3mock/)
[![Docker Pulls](https://img.shields.io/docker/pulls/adobe/s3mock)](https://hub.docker.com/r/adobe/s3mock)
[![Java17](https://img.shields.io/badge/MADE%20with-Java17-RED.svg)](#Java)
[![Kotlin](https://img.shields.io/badge/MADE%20with-Kotlin-RED.svg)](#Kotlin)
[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7673/badge)](https://bestpractices.coreinfrastructure.org/projects/7673)
[![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/adobe/S3Mock?label=openssf%20scorecard&style=flat)](https://api.securityscorecards.dev/projects/github.com/adobe/S3Mock)
[![Project Map](https://sourcespy.com/shield.svg)](https://sourcespy.com/github/adobes3mock/)
[![GitHub stars](https://img.shields.io/github/stars/adobe/S3Mock.svg?style=social&label=Star&maxAge=2592000)](https://github.com/adobe/S3Mock/stargazers/)

<!-- TOC -->
  * [S3Mock](#s3mock)
  * [Changelog](#changelog)
  * [Supported S3 operations](#supported-s3-operations)
  * [Usage](#usage)
    * [Usage of AWS S3 SDKs](#usage-of-aws-s3-sdks)
      * [Path-style vs Domain-style access](#path-style-vs-domain-style-access)
      * [Presigned URLs](#presigned-urls)
    * [Usage of AWS CLI](#usage-of-aws-cli)
    * [Usage of plain HTTP](#usage-of-plain-http)
    * [S3Mock configuration options](#s3mock-configuration-options)
    * [S3Mock Docker](#s3mock-docker)
      * [Start using the command-line](#start-using-the-command-line)
      * [Start using the Fabric8 Docker-Maven-Plugin](#start-using-the-fabric8-docker-maven-plugin)
      * [Start using Testcontainers](#start-using-testcontainers)
      * [Start using Docker compose](#start-using-docker-compose)
        * [Simple example](#simple-example)
        * [Expanded example](#expanded-example)
    * [S3Mock Java](#s3mock-java)
      * [Start using the JUnit4 Rule](#start-using-the-junit4-rule)
      * [Start using the JUnit5 Extension](#start-using-the-junit5-extension)
      * [Start using the TestNG Listener](#start-using-the-testng-listener)
      * [Start programmatically](#start-programmatically)
  * [File System Structure](#file-system-structure)
    * [Root-Folder](#root-folder)
    * [Buckets](#buckets)
    * [Objects](#objects)
    * [Multipart Uploads](#multipart-uploads)
  * [Build & Run](#build--run)
    * [Java](#java)
    * [Kotlin](#kotlin)
  * [Contributing](#contributing)
  * [Licensing](#licensing)
<!-- TOC -->

## S3Mock
`S3Mock` is a lightweight server that implements parts of the [Amazon S3 API](https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html).
It has been created to support local integration testing by reducing infrastructure dependencies.

The `S3Mock` server can be started as a standalone *Docker* container, using *Testcontainers*, *JUnit4*, *JUnit5* and *TestNG* support, or programmatically.

## Changelog

See [GitHub releases](https://github.com/adobe/S3Mock/releases).
See also the [changelog](CHANGELOG.md) for detailed information about changes in releases and changes planned for future releases.

## Supported S3 operations

Of these [operations of the Amazon S3 API](https://docs.aws.amazon.com/AmazonS3/latest/API/API_Operations_Amazon_Simple_Storage_Service.html), all marked :white_check_mark: are supported by S3Mock:

| Operation                                                                                | Support            | Comment                   |
|-----------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|---------------------------|
| [AbortMultipartUpload](https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html)                                               | :white_check_mark: |                           |
| [CompleteMultipartUpload](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html)                                         | :white_check_mark: |                           |
| [CopyObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html)                                                                   | :white_check_mark: |                           |
| [CreateBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html)                                                               | :white_check_mark: |                           |
| [CreateMultipartUpload](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html)                                             | :white_check_mark: |                           |
| [DeleteBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html)                                                               | :white_check_mark: |                           |
| [DeleteBucketAnalyticsConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketAnalyticsConfiguration.html)                   | :x:                |                           |
| [DeleteBucketCors](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html)                                                       | :x:                |                           |
| [DeleteBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketEncryption.html)                                           | :x:                |                           |
| [DeleteBucketIntelligentTieringConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketIntelligentTieringConfiguration.html) | :x:                |                           |
| [DeleteBucketInventoryConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketInventoryConfiguration.html)                   | :x:                |                           |
| [DeleteBucketLifecycle](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html)                                             | :white_check_mark: |                           |
| [DeleteBucketMetricsConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketMetricsConfiguration.html)                       | :x:                |                           |
| [DeleteBucketOwnershipControls](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketOwnershipControls.html)                             | :x:                |                           |
| [DeleteBucketPolicy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketPolicy.html)                                                   | :x:                |                           |
| [DeleteBucketReplication](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketReplication.html)                                         | :x:                |                           |
| [DeleteBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketTagging.html)                                                 | :x:                |                           |
| [DeleteBucketWebsite](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketWebsite.html)                                                 | :x:                |                           |
| [DeleteObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html)                                                               | :white_check_mark: |                           |
| [DeleteObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html)                                                             | :white_check_mark: |                           |
| [DeleteObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html)                                                 | :x:                |                           |
| [DeletePublicAccessBlock](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeletePublicAccessBlock.html)                                         | :x:                |                           |
| [GetBucketAccelerateConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAccelerateConfiguration.html)                       | :x:                |                           |
| [GetBucketAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html)                                                               | :x:                |                           |
| [GetBucketAnalyticsConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAnalyticsConfiguration.html)                         | :x:                |                           |
| [GetBucketCors](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketCors.html)                                                             | :x:                |                           |
| [GetBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html)                                                 | :x:                |                           |
| [GetBucketIntelligentTieringConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketIntelligentTieringConfiguration.html)       | :x:                |                           |
| [GetBucketInventoryConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketInventoryConfiguration.html)                         | :x:                |                           |
| [GetBucketLifecycle](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycle.html)                                                   | :x:                | Deprecated in S3 API      |
| [GetBucketLifecycleConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html)                         | :white_check_mark: |                           |
| [GetBucketLocation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html)                                                     | :white_check_mark: |                           |
| [GetBucketLogging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLogging.html)                                                       | :x:                |                           |
| [GetBucketMetricsConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketMetricsConfiguration.html)                             | :x:                |                           |
| [GetBucketNotification](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotification.html)                                             | :x:                |                           |
| [GetBucketNotificationConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotificationConfiguration.html)                   | :x:                |                           |
| [GetBucketOwnershipControls](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketOwnershipControls.html)                                   | :x:                |                           |
| [GetBucketPolicy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicy.html)                                                         | :x:                |                           |
| [GetBucketPolicyStatus](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicyStatus.html)                                             | :x:                |                           |
| [GetBucketReplication](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketReplication.html)                                               | :x:                |                           |
| [GetBucketRequestPayment](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketRequestPayment.html)                                         | :x:                |                           |
| [GetBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html)                                                       | :x:                |                           |
| [GetBucketVersioning](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html)                                                 | :x:                |                           |
| [GetBucketWebsite](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketWebsite.html)                                                       | :x:                |                           |
| [GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html)                                                                     | :white_check_mark: |                           |
| [GetObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html)                                                               | :white_check_mark: |                           |
| [GetObjectAttributes](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html)                                                 | :white_check_mark: | for objects, not parts    |
| [GetObjectLegalHold](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLegalHold.html)                                                   | :white_check_mark: |                           |
| [GetObjectLockConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLockConfiguration.html)                                   | :white_check_mark: |                           |
| [GetObjectRetention](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectRetention.html)                                                   | :white_check_mark: |                           |
| [GetObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html)                                                       | :white_check_mark: |                           |
| [GetObjectTorrent](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTorrent.html)                                                       | :x:                |                           |
| [GetPublicAccessBlock](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetPublicAccessBlock.html)                                               | :x:                |                           |
| [HeadBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html)                                                                   | :white_check_mark: |                           |
| [HeadObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html)                                                                   | :white_check_mark: |                           |
| [ListBucketAnalyticsConfigurations](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketAnalyticsConfigurations.html)                     | :x:                |                           |
| [ListBucketIntelligentTieringConfigurations](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketIntelligentTieringConfigurations.html)   | :x:                |                           |
| [ListBucketInventoryConfigurations](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketInventoryConfigurations.html)                     | :x:                |                           |
| [ListBucketMetricsConfigurations](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketMetricsConfigurations.html)                         | :x:                |                           |
| [ListBuckets](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html)                                                                 | :white_check_mark: |                           |
| [ListMultipartUploads](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html)                                               | :white_check_mark: |                           |
| [ListObjects](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html)                                                                 | :white_check_mark: | Deprecated in S3 API      |
| [ListObjectsV2](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html)                                                             | :white_check_mark: |                           |
| [ListObjectVersions](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectVersions.html)                                                   | :white_check_mark: | Only dummy implementation |
| [ListParts](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html)                                                                     | :white_check_mark: |                           |
| [PutBucketAccelerateConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAccelerateConfiguration.html)                       | :x:                |                           |
| [PutBucketAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAcl.html)                                                               | :x:                |                           |
| [PutBucketAnalyticsConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAnalyticsConfiguration.html)                         | :x:                |                           |
| [PutBucketCors](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html)                                                             | :x:                |                           |
| [PutBucketEncryption](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html)                                                 | :x:                |                           |
| [PutBucketIntelligentTieringConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketIntelligentTieringConfiguration.html)       | :x:                |                           |
| [PutBucketInventoryConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketInventoryConfiguration.html)                         | :x:                |                           |
| [PutBucketLifecycle](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycle.html)                                                   | :x:                | Deprecated in S3 API      |
| [PutBucketLifecycleConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html)                         | :white_check_mark: |                           |
| [PutBucketLogging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLogging.html)                                                       | :x:                |                           |
| [PutBucketMetricsConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketMetricsConfiguration.html)                             | :x:                |                           |
| [PutBucketNotification](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotification.html)                                             | :x:                |                           |
| [PutBucketNotificationConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotificationConfiguration.html)                   | :x:                |                           |
| [PutBucketOwnershipControls](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketOwnershipControls.html)                                   | :x:                |                           |
| [PutBucketPolicy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketPolicy.html)                                                         | :x:                |                           |
| [PutBucketReplication](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketReplication.html)                                               | :x:                |                           |
| [PutBucketRequestPayment](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketRequestPayment.html)                                         | :x:                |                           |
| [PutBucketTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html)                                                       | :x:                |                           |
| [PutBucketVersioning](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html)                                                 | :x:                |                           |
| [PutBucketWebsite](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketWebsite.html)                                                       | :x:                |                           |
| [PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html)                                                                     | :white_check_mark: |                           |
| [PutObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html)                                                               | :white_check_mark: |                           |
| [PutObjectLegalHold](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectLegalHold.html)                                                   | :white_check_mark: |                           |
| [PutObjectLockConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectLockConfiguration.html)                                   | :white_check_mark: |                           |
| [PutObjectRetention](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectRetention.html)                                                   | :white_check_mark: |                           |
| [PutObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html)                                                       | :white_check_mark: |                           |
| [PutPublicAccessBlock](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutPublicAccessBlock.html)                                               | :x:                |                           |
| [RestoreObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html)                                                             | :x:                |                           |
| [SelectObjectContent](https://docs.aws.amazon.com/AmazonS3/latest/API/API_SelectObjectContent.html)                                                 | :x:                |                           |
| [UploadPart](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html)                                                                   | :white_check_mark: |                           |
| [UploadPartCopy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html)                                                           | :white_check_mark: |                           |
| [WriteGetObjectResponse](https://docs.aws.amazon.com/AmazonS3/latest/API/API_WriteGetObjectResponse.html)                                           | :x:                |                           |

## Usage

### Usage of AWS S3 SDKs

S3Mock can be used with any of the available AWS S3 SDKs.

The [Integration Tests](integration-tests) contain various examples of how to use the S3Mock with the AWS SDK for Java v1 and v2 in Kotlin.
The modules below [testsupport](testsupport) contain examples in Java.

`S3Client` or `S3Presigner` instances are created here:
* Kotlin: [Integration Test base class](integration-tests/src/test/kotlin/com/adobe/testing/s3mock/its/S3TestBase.kt)
* Java: [S3Mock unit test starter base class](testsupport/common/src/main/java/com/adobe/testing/s3mock/testsupport/common/S3MockStarter.java)

#### Path-style vs Domain-style access

AWS S3 SDKs usually use domain-style access by default. Configuration is needed for path-style access.

S3Mock currently only supports path-style access (e.g., `http://localhost:9090/bucket/someKey`).

Domain-style access to buckets (e.g., `http://bucket.localhost:9090/someKey`) does not work.
This is due to the fact that the domain `localhost` is special and does not allow for subdomain access without modifications to the operating system.

#### Presigned URLs

S3 SDKs can be used to [create presigned URLs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html), the S3 API supports access through those URLs.

S3Mock will accept presigned URLs, but it *ignores all parameters*.
For instance, S3Mock does not verify the HTTP verb that the presigned uri was created with, and it does not validate whether the link is expired or not.

S3 SDKs can be used to create presigned URLs pointing to S3Mock if they're configured for path-style access. See the "Usage of..." section above for links to examples on how to use the SDK with presigned URLs.

### Usage of AWS CLI

S3Mock can be used with the AWS CLI. Setting the `--endpoint-url` enables path-style access.

Examples:

Create bucket
```shell
aws s3api create-bucket --bucket my-bucket --endpoint-url=http://localhost:9090
```

Put object
```shell
aws s3api put-object --bucket my-bucket --key my-file --body ./my-file --endpoint-url=http://localhost:9090
```

Get object
```shell
aws s3api get-object --bucket my-bucket --key my-file --endpoint-url=http://localhost:9090 my-file-output
```

### Usage of plain HTTP

As long as the requests work with the S3 API, they will work with S3Mock as well.

Examples:

Create bucket
```shell
curl --request PUT "http://localhost:9090/my-test-bucket/"
```

Put object
```shell
curl --request PUT --upload-file ./my-file http://localhost:9090/my-test-bucket/my-file
```

Get object
```shell
curl --request GET http://localhost:9090/my-test-bucket/my-file
```

### S3Mock configuration options

The mock can be configured with the following environment variables:

- `validKmsKeys`: list of KMS Key-Refs that are to be treated as *valid*.
  - KMS keys must be configured as valid ARNs in the format of "`arn:aws:kms:region:acct-id:key/key-id`", for example "`arn:aws:kms:us-east-1:1234567890:key/valid-test-key-id`"
  - The list must be comma separated keys like `arn-1, arn-2`
  - When requesting with KMS encryption, the key ID is passed to the SDK / CLI, in the example above this would be "`valid-test-key-id`".
  - *S3Mock does not implement KMS encryption*, if a key ID is passed in a request, S3Mock will just validate if a given Key was configured during startup and reject the request if the given Key was not configured.
- `initialBuckets`: list of names for buckets that will be available initially.
  - The list must be comma separated names like `bucketa, bucketb`
- `root`: the base directory to place the temporary files exposed by the mock. If S3Mock is started in Docker, a volume must be mounted as the `root` directory, see examples below.
- `debug`: set to `true` to enable [Spring Boot's debug output](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.logging.console-output).
- `trace`: set to `true` to enable  [Spring Boot's trace output](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.logging.console-output).
- `retainFilesOnExit`: set to `true` to let S3Mock keep all files that were created during its lifetime. Default is `false`, all files are removed if S3Mock shuts down.

### S3Mock Docker

The `S3Mock` Docker container is the recommended way to use `S3Mock`.
It is released to [Docker Hub](https://hub.docker.com/r/adobe/s3mock).
The container is lightweight, built on top of the official [Linux Alpine image](https://hub.docker.com/_/alpine).

If needed, configure [memory](https://docs.docker.com/engine/reference/commandline/run/#specify-hard-limits-on-memory-available-to-containers--m---memory) and [cpu](https://docs.docker.com/engine/reference/commandline/run/#options) limits for the S3Mock docker container.

The JVM will automatically use half the available memory.

#### Start using the command-line

Starting on the command-line:

    docker run -p 9090:9090 -p 9191:9191 -t adobe/s3mock

The port `9090` is for HTTP, port `9191` is for HTTPS.

Example with configuration via environment variables:

    docker run -p 9090:9090 -p 9191:9191 -e initialBuckets=test -e debug=true -t adobe/s3mock

#### Start using the Fabric8 Docker-Maven-Plugin

Our [integration tests](integration-tests) are using the Amazon S3 Client to verify the server functionality against the S3Mock. During the Maven build, the Docker image is started using the [docker-maven-plugin](https://dmp.fabric8.io/) and the corresponding ports are passed to the JUnit test through the `maven-failsafe-plugin`. See [`BucketV2IT`](integration-tests/src/test/kotlin/com/adobe/testing/s3mock/its/BucketV2IT.kt) as an example on how it's used in the code.

This way, one can easily switch between calling the S3Mock or the real S3 endpoint and this doesn't add any additional Java dependencies to the project.

#### Start using Testcontainers

The [`S3MockContainer`](testsupport/testcontainers/src/main/java/com/adobe/testing/s3mock/testcontainers/S3MockContainer.java) is a `Testcontainer` implementation that comes pre-configured exposing HTTP and HTTPS ports. Environment variables can be set on startup.

The example [`S3MockContainerJupiterTest`](testsupport/testcontainers/src/test/java/com/adobe/testing/s3mock/testcontainers/S3MockContainerJupiterTest.java) demonstrates the usage with JUnit 5.  The example [`S3MockContainerManualTest`](testsupport/testcontainers/src/test/java/com/adobe/testing/s3mock/testcontainers/S3MockContainerManualTest.java) demonstrates the usage with plain Java.

Testcontainers provides integrations for JUnit 4, JUnit 5 and Spock.
For more information, visit the [Testcontainers](https://www.testcontainers.org/) website.

To use the [`S3MockContainer`](testsupport/testcontainers/src/main/java/com/adobe/testing/s3mock/testcontainers/S3MockContainer.java), use the following Maven artifact in `test` scope:

```xml
<dependency>
 <groupId>com.adobe.testing</groupId>
 <artifactId>s3mock-testcontainers</artifactId>
 <version>...</version>
 <scope>test</scope>
</dependency>
```

#### Start using Docker compose

##### Simple example

Create a file `docker-compose.yml`

```yaml
services:
  s3mock:
    image: adobe/s3mock:latest
    environment:
      - initialBuckets=bucket1
    ports:
      - 9090:9090
```

Start with `docker compose up -d`

Stop with `docker compose down`

##### Expanded example

Suppose we want to see what S3Mock is persisting, and look at the logs it generates in detail.

A local directory is needed, let's call it `locals3root`. This directory must be mounted as a volume into the Docker container when it's started, and that mounted volume must then be configured as the `root` for S3Mock. Let's call the mounted volume inside the container `containers3root`. S3Mock will delete all files when it shuts down, `retainFilesOnExit=true` tells it to leave all files instead.

Also, to see debug logs, `debug=true` must be configured for S3Mock.

Create a file `docker-compose.yml`

```yaml
services:
  s3mock:
    image: adobe/s3mock:latest
    environment:
      - debug=true
      - retainFilesOnExit=true
      - root=containers3root
    ports:
      - 9090:9090
      - 9191:9191
    volumes:
      - ./locals3root:/containers3root
```

Create a directory `locals3root`.

Start with `docker compose up -d`

Create a bucket "my-test-bucket" with `curl --request PUT "http://localhost:9090/my-test-bucket/"`

Stop with `docker compose down`

Look into the directory `locals3root` where metadata and contents of the bucket are stored.

```shell
$ mkdir s3mock-mounttest
$ cd s3mock-mounttest
$ mkdir locals3root
$ cat docker-compose.yml
services:
  s3mock:
    image: adobe/s3mock:latest
    environment:
      - debug=true
      - retainFilesOnExit=true
      - root=containers3root
    ports:
      - 9090:9090
      - 9191:9191
    volumes:
      - ./locals3root:/containers3root

$ docker compose up -d
[+] Running 2/2
 ✔ Network s3mock-mounttest_default     Created
 ✔ Container s3mock-mounttest-s3mock-1  Started
$ curl --request PUT "http://localhost:9090/my-test-bucket/"
$ docker compose down
[+] Running 2/0
 ✔ Container s3mock-mounttest-s3mock-1  Removed
 ✔ Network s3mock-mounttest_default     Removed

$ ls locals3root
my-test-bucket
$ ls locals3root/my-test-bucket
bucketMetadata.json
```

### S3Mock Java

`S3Mock` Java libraries are released and published to the Sonatype Maven Repository and subsequently published to
the official [Maven mirrors](https://search.maven.org/search?q=g:com.adobe.testing%20a:s3mock).

| :warning: WARNING                                                                                |
|:--------------------------------------------------------------------------------------------------|
| Using the Java libraries is **discouraged**, see explanation below                                |
| Using the Docker image is **encouraged** to insulate both S3Mock and your application at runtime. |

`S3Mock` is built using Spring Boot, if projects use `S3Mock` by adding the dependency to their project and starting
the `S3Mock` during a JUnit test, classpaths of the tested application and of the `S3Mock` are merged, leading
to unpredictable and undesired effects such as class conflicts or dependency version conflicts.
This is especially problematic if the tested application itself is a Spring (Boot) application, as both applications will load configurations based on availability of certain classes in the classpath, leading to unpredictable runtime behaviour.

_This is the opposite of what software engineers are trying to achieve when thoroughly testing code in continuous integration..._

`S3Mock` dependencies are updated regularly, any update could break any number of projects.
**See also [issues labelled "dependency-problem"](https://github.com/adobe/S3Mock/issues?q=is%3Aissue+label%3Adependency-problem).**

**See also [the Java section below](#Java)**

#### Start using the JUnit4 Rule

The example [`S3MockRuleTest`](testsupport/junit4/src/test/java/com/adobe/testing/s3mock/junit4/S3MockRuleTest.java) demonstrates the usage of the `S3MockRule`, which can be configured through a _builder_.

To use the JUnit4 Rule, use the following Maven artifact in `test` scope:

```xml
<dependency>
 <groupId>com.adobe.testing</groupId>
 <artifactId>s3mock-junit4</artifactId>
 <version>...</version>
 <scope>test</scope>
</dependency>
```

#### Start using the JUnit5 Extension

The `S3MockExtension` can currently be used in two ways:

1. Declaratively using `@ExtendWith(S3MockExtension.class)` and by injecting a properly configured instance of `AmazonS3` client and/or the started `S3MockApplication` to the tests.
See examples: [`S3MockExtensionDeclarativeTest`](testsupport/junit5/src/test/java/com/adobe/testing/s3mock/junit5/sdk1/S3MockExtensionDeclarativeTest.java)  (for SDKv1)
or [`S3MockExtensionDeclarativeTest`](testsupport/junit5/src/test/java/com/adobe/testing/s3mock/junit5/sdk2/S3MockExtensionDeclarativeTest.java) (for SDKv2)

2. Programmatically using `@RegisterExtension` and by creating and configuring the `S3MockExtension` using a _builder_.
See examples: [`S3MockExtensionProgrammaticTest`](testsupport/junit5/src/test/java/com/adobe/testing/s3mock/junit5/sdk1/S3MockExtensionProgrammaticTest.java) (for SDKv1)
or [`S3MockExtensionProgrammaticTest`](testsupport/junit5/src/test/java/com/adobe/testing/s3mock/junit5/sdk2/S3MockExtensionProgrammaticTest.java) (for SDKv2)

To use the JUnit5 Extension, use the following Maven artifact in `test` scope:

```xml
<dependency>
  <groupId>com.adobe.testing</groupId>
  <artifactId>s3mock-junit5</artifactId>
  <version>...</version>
  <scope>test</scope>
</dependency>
```

#### Start using the TestNG Listener

The example [`S3MockListenerXMLConfigurationTest`](testsupport/testng/src/test/java/com/adobe/testing/s3mock/testng/S3MockListenerXmlConfigurationTest.java) demonstrates the usage of the `S3MockListener`, which can be configured as shown in [`testng.xml`](testsupport/testng/src/test/resources/testng.xml). The listener bootstraps the S3Mock application before TestNG execution starts and shuts down the application just before the execution terminates. Please refer to [`IExecutionListener`](https://github.com/testng-team/testng/blob/master/testng-core-api/src/main/java/org/testng/IExecutionListener.java) from the TestNG API.

To use the TestNG Listener, use the following Maven artifact in `test` scope:

```xml
<dependency>
 <groupId>com.adobe.testing</groupId>
 <artifactId>s3mock-testng</artifactId>
 <version>...</version>
 <scope>test</scope>
</dependency>
```

#### Start programmatically

Include the following dependency and use one of the `start` methods in `com.adobe.testing.s3mock.S3MockApplication`:

```xml
<dependency>
  <groupId>com.adobe.testing</groupId>
  <artifactId>s3mock</artifactId>
  <version>...</version>
</dependency>
```

## File System Structure

S3Mock stores Buckets, Objects, Parts and other data on disk.
This lets users inspect the stored data while the S3Mock is running.
If the config property `retainFilesOnExit` is set to `true`, this data will not be deleted when S3Mock is shut down.

| :exclamation: FYI                                                                                |
|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| While it _may_ be possible to start S3Mock on a root folder from a previous run and have all data available through the S3 API, the structure and contents of the files are not considered Public API, and are subject to change in later releases. |
| Also, there are no automated test cases for this behaviour.                                                                                |

### Root-Folder
S3Mock stores buckets and objects a root-folder.

This folder is expected to be empty when S3Mock starts. See also FYI above.
```
/<root-folder>/
```

### Buckets
Buckets are stored as a folder with their name as created through the S3 API directly below the root:
```
/<root-folder>/<bucket-name>/
```
[BucketMetadata](server/src/main/java/com/adobe/testing/s3mock/store/BucketMetadata.java) is stored in a file in the bucket directory, serialized as JSON.
[BucketMetadata](server/src/main/java/com/adobe/testing/s3mock/store/BucketMetadata.java) contains the "key" -> "uuid" dictionary for all objects uploaded to this bucket among other data.
```
/<root-folder>/<bucket-name>/bucketMetadata.json
```
### Objects

Objects are stored in folders below the bucket they were created in.
A folder is created that uses the Object's UUID assigned in the [BucketMetadata](server/src/main/java/com/adobe/testing/s3mock/store/BucketMetadata.java) as a name.
```
/<root-folder>/<bucket-name>/<uuid>/
```
Object data is stored below that UUID folder.

Binary data is always stored in a file `binaryData`
```
/<root-folder>/<bucket-name>/<uuid>/binaryData
```

[Object metadata](server/src/main/java/com/adobe/testing/s3mock/store/S3ObjectMetadata.java) is serialized as JSON and stored as `objectMetadata.json`
```
/<root-folder>/<bucket-name>/<uuid>/objectMetadata.json
```

[Object ACL](server/src/main/java/com/adobe/testing/s3mock/dto/AccessControlPolicy.java) is serialized as JSON and stored as `objectAcl.xml`
```
/<root-folder>/<bucket-name>/<uuid>/objectAcl.json
```

### Multipart Uploads

Multipart Uploads are created in a bucket using object keys and an uploadId.
The object is assigned a UUID within the bucket (stored in [BucketMetadata](server/src/main/java/com/adobe/testing/s3mock/store/BucketMetadata.java)).
The [Multipart upload metadata](server/src/main/java/com/adobe/testing/s3mock/store/MultipartUploadInfo.java) is currently not stored on disk.

The multiparts folder is created below the bucket folder and named with the `uploadId`:
```
/<root-folder>/<bucket-name>/multiparts/<uploadId>/
```

The multiparts metadata file is created below the folder named with the `uploadId`:
```
/<root-folder>/<bucket-name>/multiparts/<uploadId>/multipartMetadata.json
```

Each part is stored in the parts folder with the `partNo` as name and `.part` as a suffix.
```
/<root-folder>/<bucket-name>/multiparts/<uploadId>/<partNo>.part
```

Once the MultipartUpload is completed, the `uploadId` folder is deleted.

## Build & Run

To build this project, you need Docker, JDK 17 or higher, and Maven:

    ./mvnw clean install

If you want to skip the Docker build, pass the optional parameter "skipDocker":

    ./mvnw clean install -DskipDocker

You can run the S3Mock from the sources by either of the following methods:

* Run or Debug the class `com.adobe.testing.s3mock.S3MockApplication` in the IDE.
* using Docker:
  * `./mvnw clean package -pl server -am -DskipTests`
  * `docker run -p 9090:9090 -p 9191:9191 -t adobe/s3mock:latest`
* using the Docker Maven plugin:
  * `./mvnw clean package docker:start -pl server -am -DskipTests -Ddocker.follow -Dit.s3mock.port_http=9090 -Dit.s3mock.port_https=9191` (stop with `ctrl-c`)

Once the application is started, you can execute the `*IT` tests from your IDE.

### Java
This repo is built with Java 17, output is _currently_ bytecode compatible with Java 17.

### Kotlin
The [Integration Tests](integration-tests) are built in Kotlin.

## Contributing

Contributions are welcomed! Read the [Contributing Guide](./.github/CONTRIBUTING.md) for more information.

## Licensing

This project is licensed under the Apache V2 License. See [LICENSE](LICENSE) for more information.


[![Build and test](https://github.com/mediathekview/zapp/actions/workflows/build.yml/badge.svg)](https://github.com/mediathekview/zapp/actions/workflows/build.yml)

![ZAPP](fastlane/metadata/android/en-US/images/featureGraphic.jpg)

1. [Über](#über)
2. [FAQ](app/src/main/res/raw/faq.md)
3. [Changelog](app/src/main/res/raw/changelog.md)
4. [Bibliotheken](#bibliotheken)

---------------------

## Über

Zapp ist Teil von MediathekView und gibt dir einen schnellen Zugang zu vielen deutschen öffentlich-rechtlichen Fernsehsendern. Schaue ARD, ZDF und andere Sender live oder aus der Mediathek.

Features:

Android-Client für MediathekView

Live-Streams von über 30 Sendern

Adaptives Streaming – passend zur Geschwindigkeit deiner Netzwerkverbindung

Schneller Sender-Wechsel

Aktuelle Programminformationen

Sender-Shortcuts für neuere Android-Versionen

Sendungen aus fast 20 Mediatheken zum Streamen

Bequeme Sendungssuche in der Mediathek

Zuschaltbare Untertitel für einige Mediathek-Sendungen

Teilen-Funktion für Live- und Mediathek-Videos

Hintergrund-Playback

**Achtung:** Wenn du Zapp außerhalb Deutschlands benutzt, können manche Sender – wie zum Beispiel ZDF – geblockt sein.

---------------------

## Übersetzungen

Zapp wird in Deutsch entwickelt, kann aber über [Transifex](https://www.transifex.com/none-581/zapp-android-app/) in andere Sprachen übersetzt werden. Vorschläge für weitere Sprachen und Helfer beim Übersetzen sind herzlich willkommen!

## Bibliotheken

Zapp uses a lot of awesome open source libraries:
- [JUnit](http://junit.org/junit4/) to test things out
- [Gson](https://github.com/google/gson) to parse the list of channels
- [Commons IO](https://commons.apache.org/proper/commons-io/) for a sane way to handle files on Android
- [DragListView](https://github.com/woxblom/DragListView) to let you reorder the channel list intuitively
- [exo player](https://google.github.io/ExoPlayer/) the better video player
- [Retrofit](https://square.github.io/retrofit/) for easy server api communication
- [Joda time](http://www.joda.org/joda-time/) for sane date and time handling in Java


# Shizuku

## Background

When developing apps that requires root, the most common method is to run some commands in the su shell. For example, there is an app that uses the `pm enable/disable` command to enable/disable components.

This method has very big disadvantages:

1. **Extremely slow** (Multiple process creation)
2. Needs to process texts (**Super unreliable**)
3. The possibility is limited to available commands
4. Even if ADB has sufficient permissions, the app requires root privileges to run

Shizuku uses a completely different way. See detailed description below.

## User guide & Download

<https://shizuku.rikka.app/>

## How does Shizuku work?

First, we need to talk about how app use system APIs. For example, if the app wants to get installed apps, we all know we should use `PackageManager#getInstalledPackages()`. This is actually an interprocess communication (IPC) process of the app process and system server process, just the Android framework did the inner works for us.

Android uses `binder` to do this type of IPC. `Binder` allows the server-side to learn the uid and pid of the client-side, so that the system server can check if the app has the permission to do the operation.

Usually, if there is a "manager" (e.g., `PackageManager`) for apps to use, there should be a "service" (e.g., `PackageManagerService`) in the system server process. We can simply think if the app holds the `binder` of the "service", it can communicate with the "service". The app process will receive binders of system services on start.

Shizuku guides users to run a process, Shizuku server, with root or ADB first. When the app starts, the `binder` to Shizuku server will also be sent to the app.

The most important feature Shizuku provides is something like be a middle man to receive requests from the app, sent them to the system server, and send back the results. You can see the `transactRemote` method in `rikka.shizuku.server.ShizukuService` class, and `moe.shizuku.api.ShizukuBinderWrapper` class for the detail.

So, we reached our goal, to use system APIs with higher permission. And to the app, it is almost identical to the use of system APIs directly.

## Developer guide

### API & sample

https://github.com/RikkaApps/Shizuku-API

### Migrating from pre-v11

> Existing applications still works, of course.

https://github.com/RikkaApps/Shizuku-API#migration-guide-for-existing-applications-use-shizuku-pre-v11

### Attention

1. ADB permissions are limited

   ADB has limited permissions and different on various system versions. You can see permissions granted to ADB [here](https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml).

   Before calling the API, you can use `ShizukuService#getUid` to check if Shizuku is running user ADB, or use `ShizukuService#checkPermission` to check if the server has sufficient permissions.

2. Hidden API limitation from Android 9

   As of Android 9, the usage of the hidden APIs is limited for normal apps. Please use other methods (such as <https://github.com/LSPosed/AndroidHiddenApiBypass>).

3. Android 8.0 & ADB

   At present, the way Shizuku service gets the app process is to combine `IActivityManager#registerProcessObserver` and `IActivityManager#registerUidObserver` (26+) to ensure that the app process will be sent when the app starts. However, on API 26, ADB lacks permissions to use `registerUidObserver`, so if you need to use Shizuku in a process that might not be started by an Activity, it is recommended to trigger the send binder by starting a transparent activity.

4. Direct use of `transactRemote` requires attention

   * The API may be different under different Android versions, please be sure to check it carefully. Also, the `android.app.IActivityManager` has the aidl form in API 26 and later, and `android.app.IActivityManager$Stub` exists only on API 26.

   * `SystemServiceHelper.getTransactionCode` may not get the correct transaction code, such as `android.content.pm.IPackageManager$Stub.TRANSACTION_getInstalledPackages` does not exist on API 25 and there is `android.content.pm.IPackageManager$Stub.TRANSACTION_getInstalledPackages_47` (this situation has been dealt with, but it is not excluded that there may be other circumstances). This problem is not encountered with the `ShizukuBinderWrapper` method.

## Developing Shizuku itself

### Build

- Clone with `git clone --recurse-submodules`
- Run gradle task `:manager:assembleDebug` or `:manager:assembleRelease`

The `:manager:assembleDebug` task generates a debuggable server. You can attach a debugger to `shizuku_server` to debug the server. Be aware that, in Android Studio, "Run/Debug configurations" - "Always install with package manager" should be checked, so that the server will use the latest code.

## License

The code for this project is available under the Apache-2.0 license.

### Exceptions

* You are **FORBIDDEN** to use image files listed below in any way (unless for displaying Shizuku itself).

  ```
  manager/src/main/res/mipmap-hdpi/ic_launcher.png
  manager/src/main/res/mipmap-hdpi/ic_launcher_background.png
  manager/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
  manager/src/main/res/mipmap-xhdpi/ic_launcher.png
  manager/src/main/res/mipmap-xhdpi/ic_launcher_background.png
  manager/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
  manager/src/main/res/mipmap-xxhdpi/ic_launcher.png
  manager/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
  manager/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
  manager/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  manager/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
  manager/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
  ```

* For the project as a whole, it is not free.
You are **FORBIDDEN** to distribute the apk compiled by **you**
(including modified, e.g., rename app name "Shizuku" to something else)
to any store (IBNLT Google Play Store, F-Droid, Amazon Appstore etc.).


# [DanDanPlayForAndroid](https://github.com/xyoye/DanDanPlayForAndroid)

## 简介

《弹弹play 概念版》是一个本地视频播放器，是弹弹play系列应用安卓平台的实现，致力于视频+弹幕的播放，为您带来愉悦的观影体验。

## 下载

安卓平台:

[1.正式版本](https://github.com/xyoye/DanDanPlayForAndroid/releases)

[2.最新测试版本](https://github.com/xyoye/DanDanPlayForAndroid/releases)

其他平台:

[弹弹play官网](http://www.dandanplay.com)

# 一、 应用介绍

## 功能介绍

- 视频
  - 提供双内核（IJK、EXO）切换，适配常见视频格式
  - 支持局域网文件浏览播放
  - 支持FTP文件浏览播放
  - 支持WebDav文件浏览播放
- 弹幕
  - 支持根据视频自动匹配弹幕
  - 支持弹幕搜索、下载
  - 支持弹幕样式调整，大小、速度、描边、透明度等
  - 支持关键字屏蔽、正则表达式屏蔽
- 字幕
  - 支持根据视频自动匹配字幕
  - 支持字幕搜索、下载
  - 支持字幕样式调整，大小、描边、颜色等
  - 支持外挂字幕
- 动漫资讯
  - 提供每周番剧，动漫更新不错过
  - 提供番剧搜索，你想要的都能找到
  - 提供番剧详情，番剧信息一网打尽

## 应用截图

# 二、项目介绍

4.x版本（当前）使用Kotlin + MVVM + 组件化方案实现

3.x版本使用Java + MVP模式开发，详细信息请切换分支查看

本项目接口由[弹弹play开放平台](https://api.dandanplay.net/swagger/ui/index)提供

## 项目结构

## 模块介绍

|  模块   | 说明  |
|  ----  | ----  |
| APP  | 项目入口，包含启动页及主框架 |
| Anime  | 动画模块，首页、搜索、季番、番剧详情等 |
| Download  | 下载模块，包括Torrent下载（未完成）、磁链解析 |
| Stream  | 网络数据模块，包含SMB、FTP、WebDav、串流等 |
| Local  | 本地数据模块，包含本地视频、弹幕下载、字幕下载 |
| User  | 用户模块，包含用户信息、登录注册、应用设置等 |
| Player  | 播放器模块 |
| Common  | 基础模块，包括基类、通用组件、工具类等 |
| Data  | 数据模块，包含普通Bean类、数据库Entity类、枚举类等 |

注：其中User模块出于安全考虑，已关闭用户相关接口的调用，编译安装后将无法使用相关功能

## 项目配置

1.日志开关，根目录下gradle.properties文件，配置IS_DEBUG_MODE，修改后rebuild project

2.单独编译模块，根目录下gradle.properties文件，配置IS_APPLICATION_RUN，设置true代表模块以应用类型编译，修改后rebuild project

## 自定义工具说明

### 1. MVVM插件

plugin目录下有MVVMTemplate-xx.jar，此插件用于快速生成符合项目的MVVM文件（Activity/Fragment、ViewModel、layout），可通过Android Studio安装此插件。使用及更多说明见[MVVMTemplate](https://github.com/xyoye/MVVMTemplate)项目。

### 2. MMKV注解

项目中使用MMKV实现key-value
数据存储，通过自定义注解的方式，实现了快速生成MMKV调用方法，使用实例见common模块下config目录，关于注解的更多说明见[MMKVStorage](https://github.com/xyoye/MMKVStorage)项目。


![](https://wiki.ptms.ink/images/6/69/Taboolib-png-blue-v2.png)

## TabooLib Framework

[![](https://app.codacy.com/project/badge/Grade/3e9c747cd4aa484ab7cd74b7666c4c43)](https://www.codacy.com/gh/TabooLib/TabooLib/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TabooLib/TabooLib&utm_campaign=Badge_Grade)
[![](https://www.codefactor.io/repository/github/taboolib/taboolib/badge)](https://www.codefactor.io/repository/github/taboolib/taboolib)
![](https://img.shields.io/github/contributors/taboolib/taboolib)
![](https://img.shields.io/github/languages/code-size/taboolib/taboolib)

TabooLib 正式创建于 2018/02/06, 为 Minecraft（Java 版）提供一个跨平台的插件开发框架，旨在替代频繁的操作，以及解决一些令人头疼的问题。

+ 基于 `Kotlin` 独特的语法。
+ 仅占 `35 KB` 插件体积。
+ 魔术般的工具。

### 6.1 发生了什么?

随着 `6.1` 的巨大结构更新, TabooLib 的加载模式发生了一些转变。

[[版本迁移]](https://docs.tabooproject.org/migration)

## 版本信息

| 构建版本                                                                                | 发行时间                                                                                | 发行者                                                                                | 插件版本                                                                                |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ![](https://img.shields.io/badge/dynamic/json?label=Version&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2FTabooLib%2FTabooLib%2Freleases%2Flatest) | ![](https://img.shields.io/badge/dynamic/json?label=Date&query=%24.created_at&url=https%3A%2F%2Fapi.github.com%2Frepos%2FTabooLib%2FTabooLib%2Freleases%2Flatest) | ![](https://img.shields.io/badge/dynamic/json?label=Author&query=%24.author.login&url=https%3A%2F%2Fapi.github.com%2Frepos%2FTabooLib%2FTabooLib%2Freleases%2Flatest) | ![](https://img.shields.io/badge/dynamic/json?label=Plugin&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2FTabooLib%2Ftaboolib-gradle-plugin%2Freleases%2Flatest) |

## 相关链接

+ [TabooLib Home](https://tabooproject.org)
+ [TabooLib Docs](https://docs.tabooproject.org)
+ [TabooLib Repository](https://repo.tabooproject.org)
+ [Kether Docs](https://kether.tabooproject.org)


# MinCal Widget

Minimal calendar widget that's always on current date's month

* 3x2 (resizable)
* Displays all visible events from your calendars with a symbol set (high number becomes generic)
* Native widget configuration access or press widget's top right corner
* Pressing on any other part of the widget opens calendar application
* Configurable:
  - start day of the week
  - calendar (gregorian or holocene)
  - show declined events
  - focus on current week
  - open calendar on clicked day
  - theme
  - symbol set
  - symbol set colour
  - transparency
  - text size

## Installation

[](https://play.google.com/store/apps/details?id=cat.mvmike.minimalcalendarwidget)
[](https://f-droid.org/en/packages/cat.mvmike.minimalcalendarwidget)
[](https://github.com/mvmike/min-cal-widget/releases)

## Screenshots

## Supported languages

[](https://hosted.weblate.org/engage/min-cal-widget)
[](https://hosted.weblate.org/engage/min-cal-widget)

Everyone can help adding or updating translations under https://hosted.weblate.org/engage/min-cal-widget

## Licensing

MinCal Widget is licensed under the [BSD 3-clause](LICENSE.md).


> **Note**
> As part of our ongoing commitment to best security practices, we have rotated the signing keys used to sign previous releases of this SDK. As a result, new patch builds have been released using the new signing key. Please upgrade at your earliest convenience.
>
> While this change won't affect most developers, if you have implemented a dependency signature validation step in your build process, you may notice a warning that past releases can't be verified. This is expected, and a result of the key rotation process. Updating to the latest version will resolve this for you.

![Auth0.Android](https://cdn.auth0.com/website/sdks/banners/auth0-android-banner.png)

[![Maven Central](https://img.shields.io/maven-central/v/com.auth0.android/auth0.svg?style=flat-square)](https://search.maven.org/artifact/com.auth0.android/auth0)
[![Coverage Status](https://img.shields.io/codecov/c/github/auth0/Auth0.Android/master.svg?style=flat-square)](https://codecov.io/github/auth0/Auth0.Android)
[![CircleCI](https://img.shields.io/circleci/project/github/auth0/Auth0.Android.svg?style=flat-square)](https://circleci.com/gh/auth0/Auth0.Android/tree/master)
[![License](https://img.shields.io/:license-mit-blue.svg?style=flat-square)](https://doge.mit-license.org/)
[![javadoc](https://javadoc.io/badge2/com.auth0.android/auth0/javadoc.svg)](https://javadoc.io/doc/com.auth0.android/auth0)

📚 [Documentation](#documentation) • 🚀 [Getting Started](#getting-started) • 💬 [Feedback](#feedback)

## Documentation
- [Quickstart](https://auth0.com/docs/quickstart/native/android/interactive)
- [Sample App](https://github.com/auth0-samples/auth0-android-sample/tree/master/00-Login-Kt)
- [FAQs](https://github.com/auth0/auth0.android/blob/main/FAQ.md)
- [Examples](https://github.com/auth0/auth0.android/blob/main/EXAMPLES.md)
- [Docs Site](https://javadoc.io/doc/com.auth0.android/auth0/latest/index.html)

## Getting Started

### Requirements

Android API version 31 or later and Java 8+.

> :warning: Applications targeting Android SDK version 30 (`targetSdkVersion = 30`) and below should use version 2.9.0.

Here’s what you need in `build.gradle` to target Java 8 byte code for Android and Kotlin plugins respectively.

```groovy
android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }
}
```

### Installation

To install Auth0.Android with [Gradle](https://gradle.org/), simply add the following line to your `build.gradle` file:

```gradle
dependencies {
    implementation 'com.auth0.android:auth0:2.11.0'
}
```

#### Permissions

Open your app's `AndroidManifest.xml` file and add the following permission.

```xml
<uses-permission android:name="android.permission.INTERNET" />
```

### Configure the SDK

First, create an instance of `Auth0` with your Application information

```kotlin
val account = Auth0("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}")
```

  Using Java

```java
Auth0 account = new Auth0("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}");
```

  Configure using Android Context

Alternatively, you can save your Application information in the `strings.xml` file using the following names:

```xml
<resources>
    <string name="com_auth0_client_id">YOUR_CLIENT_ID</string>
    <string name="com_auth0_domain">YOUR_DOMAIN</string>
</resources>
```

You can then create a new Auth0 instance by passing an Android Context:

```kotlin
val account = Auth0(context)
```

### Authentication with Universal Login

First go to the [Auth0 Dashboard](https://manage.auth0.com/#/applications) and go to your application's settings. Make sure you have in **Allowed Callback URLs** a URL with the following format:

```
https://{YOUR_AUTH0_DOMAIN}/android/{YOUR_APP_PACKAGE_NAME}/callback
```

> ⚠ Make sure that the [application type](https://auth0.com/docs/configure/applications) of the Auth0 application is **Native**.

Replace `{YOUR_APP_PACKAGE_NAME}` with your actual application's package name, available in your `app/build.gradle` file as the `applicationId` value.

Next, define the Manifest Placeholders for the Auth0 Domain and Scheme which are going to be used internally by the library to register an **intent-filter**. Go to your application's `build.gradle` file and add the `manifestPlaceholders` line as shown below:

```groovy
apply plugin: 'com.android.application'

android {
    compileSdkVersion 30
    defaultConfig {
        applicationId "com.auth0.samples"
        minSdkVersion 21
        targetSdkVersion 30
        //...

        //---> Add the next line
        manifestPlaceholders = [auth0Domain: "@string/com_auth0_domain", auth0Scheme: "https"]
        //<---
    }
    //...
}
```

It's a good practice to define reusable resources like `@string/com_auth0_domain`, but you can also hard-code the value.

> The scheme value can be either `https` or a custom one. Read [this section](#a-note-about-app-deep-linking) to learn more.

Declare the callback instance that will receive the authentication result and authenticate by showing the **Auth0 Universal Login**:

```kotlin
val callback = object : Callback<Credentials, AuthenticationException> {
    override fun onFailure(exception: AuthenticationException) {
        // Failure! Check the exception for details
    }

    override fun onSuccess(credentials: Credentials) {
        // Success! Access token and ID token are presents
    }
}

WebAuthProvider.login(account)
    .start(this, callback)
```

  Using coroutines

```kotlin
try {
    val credentials = WebAuthProvider.login(account)
        .await(requireContext())
    println(credentials)
} catch(e: AuthenticationException) {
    e.printStacktrace()
}
```

  Using Java

```java
Callback<Credentials, AuthenticationException> callback = new Callback<Credentials, AuthenticationException>() {
    @Override
    public void onFailure(@NonNull AuthenticationException exception) {
        //failed with an exception
    }

    @Override
    public void onSuccess(@Nullable Credentials credentials) {
        //succeeded!
    }
};

WebAuthProvider.login(account)
    .start(this, callback);
```

The callback will get invoked when the user returns to your application. There are a few scenarios where this may fail:

* When the device cannot open the URL because it doesn't have any compatible browser application installed. You can check this scenario with `error.isBrowserAppNotAvailable`.
* When the user manually closed the browser (e.g. pressing the back key). You can check this scenario with `error.isAuthenticationCanceled`.
* When there was a server error. Check the received exception for details.

> If the `redirect` URL is not found in the **Allowed Callback URLs** of your Auth0 Application, the server will not make the redirection and the browser will remain open.

##### A note about App Deep Linking:

If you followed the configuration steps documented here, you may have noticed the default scheme used for the Callback URI is `https`. This works best for Android API 23 or newer if you're using [Android App Links](https://auth0.com/docs/applications/enable-android-app-links), but in previous Android versions this _may_ show the intent chooser dialog prompting the user to choose either your application or the browser. You can change this behaviour by using a custom unique scheme so that the OS opens directly the link with your app.

1. Update the `auth0Scheme` Manifest Placeholder on the `app/build.gradle` file or update the intent-filter declaration in the `AndroidManifest.xml` to use the new scheme.
2. Update the **Allowed Callback URLs** in your [Auth0 Dashboard](https://manage.auth0.com/#/applications) application's settings.
3. Call `withScheme()` in the `WebAuthProvider` builder passing the custom scheme you want to use.

```kotlin
WebAuthProvider.login(account)
    .withScheme("myapp")
    .start(this, callback)
```

> Note that the schemes [can only have lowercase letters](https://developer.android.com/guide/topics/manifest/data-element).

### Clearing the session

To log the user out and clear the SSO cookies that the Auth0 Server keeps attached to your browser app, you need to call the [logout endpoint](https://auth0.com/docs/api/authentication?#logout). This can be done in a similar fashion to how you authenticated before: using the `WebAuthProvider` class.

Make sure to [revisit this section](#authentication-with-universal-login) to configure the Manifest Placeholders if you still cannot authenticate successfully. The values set there are used to generate the URL that the server will redirect the user back to after a successful log out.

In order for this redirection to happen, you must copy the **Allowed Callback URLs** value you added for authentication into the **Allowed Logout URLs** field in your [application settings](https://manage.auth0.com/#/applications). Both fields should have an URL with the following format:

```
https://{YOUR_AUTH0_DOMAIN}/android/{YOUR_APP_PACKAGE_NAME}/callback
```

Remember to replace `{YOUR_APP_PACKAGE_NAME}` with your actual application's package name, available in your `app/build.gradle` file as the `applicationId` value.

Initialize the provider, this time calling the static method `logout`.

```kotlin
//Declare the callback that will receive the result
val logoutCallback = object: Callback<Void?, AuthenticationException> {
    override fun onFailure(exception: AuthenticationException) {
        // Failure! Check the exception for details
    }

    override fun onSuccess(result: Void?) {
        // Success! The browser session was cleared
    }
}

//Configure and launch the log out
WebAuthProvider.logout(account)
        .start(this, logoutCallback)
```

  Using coroutines

```kotlin
try {
    WebAuthProvider.logout(account)
        .await(requireContext())
    println("Logged out")
} catch(e: AuthenticationException) {
    e.printStacktrace()
}
```

  Using Java

```java
//Declare the callback that will receive the result
Callback<Void, AuthenticationException> logoutCallback = new Callback<Void, AuthenticationException>() {
    @Override
    public void onFailure(@NonNull Auth0Exception exception) {
        //failed with an exception
    }

    @Override
    public void onSuccess(@Nullable Void payload) {
        //succeeded!
    }
};

//Configure and launch the log out
WebAuthProvider.logout(account)
    .start(MainActivity.this, logoutCallback);
```

The callback will get invoked when the user returns to your application. There are a few scenarios where this may fail:

* When the device cannot open the URL because it doesn't have any compatible browser application installed. You can check this scenario with `error.isBrowserAppNotAvailable`.
* When the user manually closed the browser (e.g. pressing the back key). You can check this scenario with `error.isAuthenticationCanceled`.

If the `returnTo` URL is not found in the **Allowed Logout URLs** of your Auth0 Application, the server will not make the redirection and the browser will remain open.

### Trusted Web Activity (Experimental Release)

> **⚠ Warning:** Trusted Web Activity support in Auth0.Android is still experimental and can change in the future.
>
> Please test it thoroughly in all the targeted browsers and OS variants and let us know your feedback.

Trusted Web Activity is a feature provided by some browsers to provide a native look and feel.

To use this feature, there are some additional steps you must take:

- We need the SHA256 fingerprints of the app’s signing certificate. To get this, you can run the following command on your APK:
```shell
keytool -printcert -jarfile sample-debug.apk
```
- The fingerprint has to be updated in the [Auth0 Dashboard](https://manage.auth0.com/dashboard/eu/poovamraj/applications) under
Applications > *Specific Application* > Settings > Advanced Settings > Device Settings > Key Hashes
- The app's package name has to be entered in the field above

Once the above prerequisites are met, you can call your login method as shown below to open your web authentication in Trusted Web Activity.

```kotlin
WebAuthProvider.login(account)
    .withTrustedWebActivity()
    .await(this)
```

## Credentials Manager

This library ships with two additional classes that help you manage the Credentials received during authentication.

### Basic

The basic version supports asking for `Credentials` existence, storing them and getting them back. If the credentials have expired and a refresh_token was saved, they are automatically refreshed. The class is called `CredentialsManager`.

#### Usage
1. **Instantiate the manager:**
   You'll need an `AuthenticationAPIClient` instance to renew the credentials when they expire and a `Storage` object. We provide a `SharedPreferencesStorage` class that makes use of `SharedPreferences` to create a file in the application's directory with **Context.MODE_PRIVATE** mode.

```kotlin
val authentication = AuthenticationAPIClient(account)
val storage = SharedPreferencesStorage(this)
val manager = CredentialsManager(authentication, storage)
```

  Using Java

```java
AuthenticationAPIClient authentication = new AuthenticationAPIClient(account);
Storage storage = new SharedPreferencesStorage(this);
CredentialsManager manager = new CredentialsManager(authentication, storage);
```

2. **Save credentials:**
   The credentials to save **must have** `expires_at` and at least an `access_token` or `id_token` value. If one of the values is missing when trying to set the credentials, the method will throw a `CredentialsManagerException`. If you want the manager to successfully renew the credentials when expired you must also request the `offline_access` scope when logging in in order to receive a `refresh_token` value along with the rest of the tokens. i.e. Logging in with a database connection and saving the credentials:

```kotlin
authentication
    .login("info@auth0.com", "a secret password", "my-database-connection")
    .setScope("openid email profile offline_access")
    .start(object : Callback<Credentials, AuthenticationException> {
        override fun onFailure(exception: AuthenticationException) {
            // Error
        }

        override fun onSuccess(credentials: Credentials) {
            //Save the credentials
            manager.saveCredentials(credentials)
        }
    })
```

  Using coroutines

```kotlin
try {
    val credentials = authentication
        .login("info@auth0.com", "a secret password", "my-database-connection")
        .setScope("openid email profile offline_access")
        .await()
    manager.saveCredentials(credentials)
} catch (e: AuthenticationException) {
    e.printStacktrace()
}
```

  Using Java

```java
authentication
    .login("info@auth0.com", "a secret password", "my-database-connection")
    .setScope("openid email profile offline_access")
    .start(new BaseCallback<Credentials, AuthenticationException>() {
        @Override
        public void onSuccess(Credentials payload) {
            //Save the credentials
            manager.saveCredentials(credentials);
        }

        @Override
        public void onFailure(AuthenticationException error) {
            //Error!
        }
    });
```

**Note:** This method has been made thread-safe after version 2.8.0.

3. **Check credentials existence:**
   There are cases were you just want to check if a user session is still valid (i.e. to know if you should present the login screen or the main screen). For convenience, we include a `hasValidCredentials` method that can let you know in advance if a non-expired token is available without making an additional network call. The same rules of the `getCredentials` method apply:

```kotlin
val authenticated = manager.hasValidCredentials()
```

  Using Java

```java
boolean authenticated = manager.hasValidCredentials();
```

4. **Retrieve credentials:**
   Existing credentials will be returned if they are still valid, otherwise the `refresh_token` will be used to attempt to renew them. If the `expires_at` or both the `access_token` and `id_token` values are missing, the method will throw a `CredentialsManagerException`. The same will happen if the credentials have expired and there's no `refresh_token` available.

```kotlin
manager.getCredentials(object : Callback<Credentials, CredentialsManagerException> {
    override fun onFailure(exception: CredentialsManagerException) {
        // Error
    }

    override fun onSuccess(credentials: Credentials) {
        // Use the credentials
    }
})
```

  Using coroutines

```kotlin
try {
    val credentials = manager.awaitCredentials()
    println(credentials)
} catch (e: CredentialsManagerException) {
    e.printStacktrace()
}
```

  Using Java

```java
manager.getCredentials(new BaseCallback<Credentials, CredentialsManagerException>() {
    @Override
    public void onSuccess(Credentials credentials){
        //Use the Credentials
    }

    @Override
    public void onFailure(CredentialsManagerException error){
        //Error!
    }
});
```

**Note:** In the scenario where the stored credentials have expired and a `refresh_token` is available, the newly obtained tokens are automatically saved for you by the Credentials Manager. This method has been made thread-safe after version 2.8.0.

5. **Clear credentials:**
   When you want to log the user out:

```kotlin
manager.clearCredentials()
```

## Feedback

### Contributing

We appreciate feedback and contribution to this repo! Before you get started, please see the following:

- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)

### Raise an issue
To provide feedback or report a bug, [please raise an issue on our issue tracker](https://github.com/auth0/Auth0.Android/issues).

### Vulnerability Reporting
Please do not report security vulnerabilities on the public Github issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.

---

  <picture>
    <source media="(prefers-color-scheme: light)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
    <source media="(prefers-color-scheme: dark)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_dark_mode.png" width="150">

  </picture>

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

This project is licensed under the MIT license. See the  LICENSE file for more info.


Wear OS Samples Repository
======================

This repository contains a set of individual Android Studio projects to help you get started writing Wear OS apps and watch faces.

Read below for a description of each sample.

Samples
----------

* **[ComposeStarter](ComposeStarter)** (Compose/Kotlin) - Demonstrates simple Compose for Wear OS app devs can use as a starting point for their own Compose app.

* **[DataLayer](DataLayer)** (Compose/Kotlin) - Demonstrates communicating via the data layer between the watch and the phone. [Guide](https://developer.android.com/training/wearables/data-layer)

* **[WatchFaceFormat](WatchFaceFormat)** - Demos the new Watch Face Format which allows quick development of performant watch
    faces in XML [Guide](https://developer.android.com/training/wearables/wff)

* **[WatchFaceKotlin](WatchFaceKotlin)** (Kotlin) - Demos the AndroidX Watch Face APIs which provide their own storage mechanism for watch face preference values.

* **[Complications](Complications)** (Kotlin) - If you are writing a watch face with complications, this app gives you a full suite of data sources to test against your implementation of complications to make sure it looks good. [Complication Guide](https://developer.android.com/training/wearables/watch-faces/adding-complications)

* **[WearOAuth](WearOAuth)** (Kotlin) - Demonstrates how developers can authenticate a user on their Wear OS app via the user's mobile/phone device without requiring a mobile app (Wear OS companion app handles the request on the mobile side). The sample uses OAuth. [Guide](https://developer.android.com/training/wearables/apps/auth-wear)

* **[WearSpeakerSample](WearSpeakerSample)** (Compose/Kotlin) - Demonstrates audio recording and playback if the wearable device has a speaker. This is also demonstrate how to handling permissions. [Guide](https://developer.android.com/training/wearables/wearable-sounds)

* **[WearTilesKotlin](WearTilesKotlin)** (Kotlin) - Demonstrates tiles using the new AndroidX library. [Guide](https://developer.android.com/training/articles/wear-tiles)