Skip to content

A photo-sharing app with only verifiable photos and videos for professionals.


Notifications You must be signed in to change notification settings


Repository files navigation

Starling Capture

build Codacy Badge

Highlight Features

Getting Started

Android Studio 4.0 or later is required.

Open the Build Variants tool window by clicking View > Tool Windows > Build Variants. Then, set the active build variant to masterQa in Android Studio. Now, you can build the debuggable APK(s). Or, you can use the following commands to build the APK with the main product flavor:

./gradlew assembleMasterQa

To install the build to your device (or emulator), follow the steps in the Android documentation. Or, use the following command:

./gradlew installMasterQa


To verify the signature, create the JSON string from the SortedProofInformation class and use it as the message.



Product Flavors

Master (Main) Flavor

  • This is the public flavor.
  • It should be always buildable without manual configurations.
  • This flavor only contains a sample publisher.

Internal Flavor

  • This is an internal product flavor, which cannot be build directly.
  • Crashlytics is enabled.
Build Requirements

Set the system environment variable NUMBERS_STORAGE_BASE_URL before build the app by appending the following string in ~/.profile:


Build Types


  • LeakCanary is enabled.


  • The quality of this build type should be product-ready. Thus, it should not contain any visible debugging artifacts (e.g. LeakCanary) except error messages.

Tech Stack

  • Kotlin
  • AndroidX
  • MVVM Architecture
  • Android Architecture Component
    • Paging Library
    • Work Manager
    • Preference Library
    • Navigation Component
    • Room Database
  • Material Component
  • Koin - dependecy injection
  • Retrofit - networking
  • Moshi - proof serialization
  • Coil - image loading
  • Timber - logging
  • LeakCanary - memory leak detection


  • The committed codes should pass all GitHub workflows.
  • The committed codes should not have warnings from Android Studio linter. You can use ./gradlew lint to verify.
  • The committed codes should not have memory leak reports by LeakCanary, which is enabled in the debug variant.


The name in string.xml should match the English content in snake case. If the content of the string is a long message, the name should start with message_. For example:

<string name="public_key_signature">Public Key Signature</string>
<string name="message_are_you_sure">The action cannot be undone.</string>



Source Providers

Currently, three types of media source are implemented:

  1. Internal camera (image)
  2. Internal camera (video)
  3. Canon Camera with CCAPI (image and video)

The components regarding media source should be placed in ./app/src/main/.../source/.

Information Providers

Currently, we only use android-info-snapshot as information provider. The components regarding information collection should be placed in ./app/src/main/.../collector/information/.

To add new information provider,

  1. Extends the InformationProvider.
  2. Override the provideInformation() method.
  3. Store the information to the DB with InformationRepository class.

Signature Providers

Currently, two types of signature provider are implemented:

  1. AndroidOpenSSL (default signature)
  2. Zion signature (opt-in)

The components regarding information collection should be placed in ./app/src/main/.../collector/signature/.

To add new signature provider,

  1. Extends the SignatureProvider.
  2. Override the provideSignature() method.
  3. Sign the SortedProofInformation from the given proof hash.
  4. Store the signature to the DB with SignatureRepository class.


Currently, we only provide a sample publisher which does nothing.

The components regarding information collection should be placed in ./app/src/main/.../publisher/.

To add new signature provider, see the SampleProofPublisher class for details.

Data Flow


Steps in ProofCollector

  1. Store the proof raw file into the internal directory.
  2. Store the hash of proof into proof repository.
  3. Collect information.
  4. Sign the proof and its collected information even if some information providers failed.

Serialization Schema

SortedProofInformation (Metadata)

The SortedProofInformation class provides the message of signature provider.

    proof: {
        hash: String,
        mimeType: String,
        timestamp: Long
    information: [{
        provider: String,
        name: String,
        value: String


         "name":"Current Location",
         "value":"121.0, 23.0"


        proofHash: String,
        provider: String,
        signature: String,
        publicKey: String


    "proofHash": "845ace0144620a18abf1d73c1dceaa51ea78cd5d791dbbbd2368d75260431bd9",
    "provider": "AndroidOpenSSL",
    "signature": "3046022100b96babf7fb1a374792ce47cebdf0b5a40166352a4e8aed2d8e84a04699898c72022100ec0646e318a0701f794fd0a3dc28da41ff864a1f9156e694b890a1800edd86b0",
    "publicKey": "3059301306072a8648ce3d020106082a8648ce3d030107034200043e4ba565aa9158b9aeafc1bb4a970bfc7fcdcc398c35bb525aedd37bbf459dbd30868b909ec6b78f7904474c225e02f45c2384b0f4ece0d68e2c3c84fce04686"
    "proofHash": "845ace0144620a18abf1d73c1dceaa51ea78cd5d791dbbbd2368d75260431bd9",
    "provider": "Zion",
    "signature": "3045022100dbfe89fe13a4758f2124fc35d440d6ca8a6b3c3d72429a3a70b3a8146695c0db02204d8d387bba770d16e100e05109061897013317682a8cd2ac45162d381effa1ee",
    "publicKey": "Session:\n3059301306072a8648ce3d020106082a8648ce3d03010703420004b4b85c26384dda113f029cfb3b71c1769a44f78093b91b8bd5965506dc3ea00b4abc780d93a23f4dda5ae65c95f61a31a808b2e22f654cfcf2b76905046f4992\n\nReceive:\n03583ea032d0607a9d0d9748b445e4e170277921ed3eebec10795521be11a2f04d\n\nSend:\n03583ea032d0607a9d0d9748b445e4e170277921ed3eebec10795521be11a2f04d"


  1. Increase the versionName and versionCode in app/build.gradle file.
  2. Update the file.
  3. Commit and push the update.
  4. Go to Action > release > Run workflow > Branch: develop > Run workflow. The workflow will do the following things.
    • Create GitHub Release page with master-debug and master-qa APKs.
    • Show a Slack notification on release-reminders channel.
    • Upload master-debug, master-qa, internal-debug and internal-qa APKs to private Google Drive.
    • Deploy internal-release to the alpha closed testing on Google Play Console.


  • The default keypair is not encrypted in AndroidKeyStore. Thus, if the device is rooted, your default key pair could be compromised.