Project Setup
=============

.. javaimport::
    com.castlabs.*
    com.castlabs.android.*
    com.castlabs.android.player.*
    com.castlabs.android.player.hardware.*
    android.content.*

Requirements
------------
The |SDK| is delivered as a *Maven Repository* that can be added to
your application build. All required dependencies are either:

 * Contained in the bundle repository
 * Available on a public repository like *jcenter* or *Maven Central*
 * Part of the Android *Support Repository* that can be installed with the Android
   SDK-Manager.

To work with the |SDK| you need to use the Gradle build system for your
application builds.


Project Configuration
---------------------
The SDK bundle contains a ``repository`` folder. This folder is a local *Maven
Repository* that is used to find and integrate the |SDK| as a dependency
within your project.

You can enable the repository for your project in your `build.gradle`
script by adding it as a local Maven repository::

    repositories{
        maven{
            url '<path/to/castlabs/repository>'
        }
        jcenter()
    }

The `<path/to/castlabs/repository>` needs to be replaced with the actual path
to the ``repository`` folder that is bundled with the SDK. The repository does
not need to be part of your project structure explicitly and you do not need to
add it to your version control system. Instead, you can host the repository
outside of your project structure. You can for example use a Gradle property to
denote the path to the repository folder. 

The repository contains all the required `pom.xml` files to be uploaded to
a hosted *Maven* or *Ivy* repository. 

With the repository added to your build script, you can reference and load the
|SDK| and its components using::

    dependencies {
        ...
        compile 'com.castlabs.player:castlabs-sdk:3.0.0'
        ...
    }

This will add the SDK and its dependencies to the classpath of your application
and you can start referencing classes within the SDK.

After the SDK is added as a dependency, you need to initialize it before
you can use it. This is typically done in your Application class using the
:javaref:`PlayerSDK.init() <com.castlabs.android.PlayerSDK#init(Context)>`
method. For example:

.. code-block:: java

    public class DemoApp extends Application{
        @Override
        public void onCreate() {
            super.onCreate();
            ...
            PlayerSDK.init(getApplicationContext());
        }
    }
    
.. _license-loading:

License Loading
---------------
The |SDK| requires a license that needs to be distributed with your
application. By default, the SDK expects to find the license in your Application Manifest
as the `castlabs-license` meta-data Attribute. For example:

.. code-block:: xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest>
        ...
        <application>
            ...
            <meta-data android:name="castlabs-license"
                       android:value="<your-license-key>" />
            ...
        </application>
    </manifest>

The license key is bound to your Applications SHA-1 Fingerprint and Package name. You can
generate license keys on the  `castLabs Download Portal <https://downloads.castlabs.com/browse/licenses/>`_.
In the `Licenses` section, you can create License Keys for your Application.

Depending on how you decide to manage your license file, you might want to load
it from a different location or use a different name. For
this, you can use an implementation of the
:javaref:`com.castlabs.LicenseLoader` interface. The SDK already comes
with an implementation to load the licenses from the application's Manifest
with the :javaref:`ManifestLicenseLoader <com.castlabs.ManifestLicenseLoader>`. This
is the default implementation. If you want to use a different loader, you can pass an
instance of the :javaref:`LicenseLoader
<com.castlabs.LicenseLoader>` to :javaref:`PlayerSDK.init()
<com.castlabs.android.PlayerSDK#init(Context, LicenseLoader)>`. For example:

.. code-block:: java

    PlayerSDK.init(getContext(),
                   new MyLicenseLoader());


Note that in case the license key is invalid the SDK will not be initialized and the error will be sent via the 
:javaref:`PlayerListener.onError(CastlabsPlayerException) <com.castlabs.android.player.PlayerListener#onError(CastlabsPlayerException)>`.
The SDK however can still be re-initialized with a valid key if applicable.

User Id
+++++++

Your |SDK| license might require user tracking for accounting purposes. If this is the case, you
*must* provide a unique user id for each view session.


The value of this parameter must be unique for each end-user. Our backend only needs
to identify end users on a cross-session basis, but we don't use this information to do any correlation.

This means that the provided values should be `pseudonymized <https://en.wikipedia.org/wiki/Pseudonymization>`_.
One example of this could be hashing a user's email account.

This value can be informed through the parameter ``INTENT_USER_ID`` if using an ``Intent`` or with the ``userId`` field in ``PlayerConfig`` upon playback initialization.

.. note::
    In case your |SDK| license requires user identification, you *must* inform this field.

    Without specifying user ID parameter if mandatory, the SDK license check will result in a rejected license and failed playback attempt.
    If the license check fails due to missing USER_ID, a player exception will be raised::

        E/CastlabsPlayerException: [ERROR] [TYPE_USER_ID_NOT_PROVIDED] UserID is required for playback

If you're using DRMToday, the |SDK| will, by default, use the user id informed in the ``DrmConfiguration``, so there's no
obligation to fill in the ``userId`` in such scenario. You can still inform the value in the `Bundle` or
the ``PlayerConfig`` object and it will take precedence.

As mentioned, there are two ways of providing the end user ID to the SDK: ``INTENT_USER_ID`` or ``PlayerConfig.userId`` (which can be specified through the ``Builder``).
The example for this would be:

.. code-block:: java

    // Specify the UserID as an intent bundle parameter
    bundle.putString(SdkConsts.INTENT_USER_ID, "unique-user-id");

or:

.. code-block:: java

    // Alternatively, set the UserID in PlayerConfig as part of the config
    PlayerConfig playerConfig = new PlayerConfig.Builder("<url_to_stream>")
        .userID("unique-user-id")
        .get();

Third party re-signing conflicts
--------------------------------

Each license for the |SDK| is tied to a unique developer certificate. This link is checked through
the certificate's SHA1 fingerprint. For this reason, some third party processes which introduce re-signing
operations may interfere with the |SDK| licence check if such re-signing is done with a different key.

Protection tools
++++++++++++++++

Some Android app protection and obfuscation software needs to re-sign the app bundle or apk after
the protection and obfuscation actions have taken place. In order for the |SDK| license check to
succeed, it is necessary that the fingerprint of the key that is used to sign the application is the one
indicated upon the |SDK| key generation.

If you are experiencing issues with license validation after running protection software,
please make sure the third party protection tool is using the same key to re-sign the binary.

DexProtector
^^^^^^^^^^^^

.. External reference to Dexprotector
.. |dexprotector_link| raw:: html

   <a class="reference external" href="https://licelus.com/products/dexprotector" target="_blank">Licel's DexProtector</a>

If using |dexprotector_link|, you should pay close attention to the ``signMode`` element in
the configuration. Such should be set to ``release``, alongside the path and
information about the keystore to use for signing.

This is the same keystore from which the SHA1 fingerprint should have been extracted in order
to generate the license for the |SDK|.

Amazon App Store
++++++++++++++++

Please note that the Amazon App store re-signs submitted APKs and hence changes the signature of the Application 
and the signing key. Since the Castlabs License is bound to the signing key, you need to create a dedicated 
license using the SHA1 that is exposed on the Amazon Developer console.

.. figure:: _static/img/amazon_sha1.png

   Amazon App Store SHA1

.. _oma_integration:

OMA Integration
---------------

The OMA plugin is bundled in the local repository that ships
with the |SDK|. You need to add the OMA dependency in your build
setup. For example::

    dependencies {
        ...
        compile 'com.castlabs.player:oma-plugin:3.4.0'
        ...
    }

Note that you should keep the base version of the plugin (in the example above
``3.5.0``) in sync with the version of the SDK you are loading.

Because the OMA integration is delivered as a plugin, you will need to
register it **before** you initialize the ``PlayerSDK``. You can register the
plugin using the :javaref:`PlayerSDK.register(PlayerPlugin)
<PlayerSDK#register(PlayerPlugin)>` method. For example:

.. code-block:: java

    PlayerSDK.register(new OmaPlugin());
    PlayerSDK.init(getApplicationContext());

.. _variant_builds:

Variant Builds
--------------

The OMA support is typically needed to support DRM protected content playback
on devices with Android 4.1 and 4.2. You can leverage the support of the
Android build plugin for `"build variants"
<http://developer.android.com/tools/building/configuring-gradle.html#workBuildVariants>`_
to create different variants of your application and reduce the size of
your final APK for Android versions 4.3 and beyond. A detailed discussion of
build variants is out of scope for this documentation, but a simple example
looks like this::

    ...
    android {
        ...
        defaultConfig {
            minSdkVersion 16
        }
        signingConfigs { ... }
        buildTypes { ... }
        productFlavors {
            modern {
                versionName "1.0-modern"
                versionCode 10020
                minSdkVersion 19
            }
            oma {
                versionName "1.0-oma"
                versionCode 10010
                maxSdkVersion 18
            }
        }
    }
    ...
    dependencies {
        ...
        compile 'com.castlabs.player:castlabs-sdk:3.4.0'
        omaCompile 'com.castlabs.player:oma-plugin:3.4.0'
        ...
    }
    ...

In this example, we create two variants: "modern" and "oma". The SDK
itself is added using `compile` as a compile time dependency to all variants.
Using `omaCompile` when referencing the OMA plugin ensures that it is only
added to the "oma" variant. In addition to the build setup, you will need to
make sure that the "oma" variant of the application has registered the plugin
before the SDK is initialized. 

Note also that we set the `minSdkVersion` for the `modern` variant to 19
while limiting deployment of the `maxSdkVersion` to API 18 and below. This
will separate the target platforms based on the API level. Further note
that the Google Play store `rules for Multiple APK Support
<https://developer.android.com/google/play/publishing/multiple-apks.html>`_
require to provide a higher version code for the modern variant. This
allows users who update their phones to get access to the modern build
variant. 


Split APK Builds
----------------

The SDK itself as well as the OMA plugin includes native components for ARM
and x86 architectures bundled in their AAR files. Similar to the variant builds
(see :ref:`variant_builds`), you can use the *split APK* feature of the Android
Gradle plugin to generate APK versions specific to ARM and x86 architectures
and further reduce the APK size of the final application for a single variant.
You can find more information about ABI splits and variant builds in `the
Android Tools wiki
<http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits>`_.


Proguard Configuration
----------------------

The |SDK| and all the plugins embed a Proguard configuration in their ``aar``
files and there is no need to specify anything specific to the castLabs SDK in
your Proguard configuration file.

Protocol buffer dependencies
----------------------------

The |SDK| uses Google's protobuf library some of its components. More precisely,
the ``protobuf-javalite`` artifact is being used. If you're using in your project
another version of such library, you'll need to exclude it from the conflicting
packages so the build goes through without finding duplicate classes.

Note that this also applies to transitive dependencies. One common example is Google's
``play-services-cast-framework`` used for the Google Cast sender:

.. code-block:: groovy

    // Don't include the transitive protobuf dependency
    implementation ('com.google.android.gms:play-services-cast-framework:X.Y.Z') {
        exclude group: 'com.google.protobuf'
    }

