Android SDK
Our Android SDK is hosted as a GitHub package here: https://github.com/hotmic-wp/android-sdk
Make sure when installing that you follow this guide:
In the build.gradle (root), add the following repositories
- For the personal access token, granting the read: packages permission should be enough
- In the build.gradle(app), include the following dependency: `implementation 'io.hotmic.player:hotmic-android-sdk:1.4.1'`
- Minimum SDK version of the player SDK is 21
- Compile / Target SDK version of the player SDK is 30
- Enable microphone permissions if you want to support TV Sync or Guest Call In.
HotMic offers a sample app to see how to use our Android SDK in your application. Here is a step-by-step guide to downloading and running the HotMic SDK sample applications for Android.
- A link to the HotMic SDK sample application provided by HotMic.
- An API Key provided by HotMic.
- A JWT token created using a Secret provided by HotMic. Instructions for how to create the token can be found below.
- A white labeled production dashboard where you will produce streams.
For security, when using the SDK your app controls authentication with a JWT Token, which you pass to HotMic.
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties. - jwt.io
You will receive an API Secret from HotMic, which you will use to create the token. The token will be used to authenticate the user, as well as provide information such as their name, an avatar, a unique ID, or another information which is needed by the SDK.
This is the expected format of the JWT token:
Note, the user_id field should be consistent for each invocation of the SDK for that particular user.
You can also generate JWT tokens online! This is good for test purposes while getting started, or to use the sample app. Here is one way to do it. We do not recommend using this method with any sensitive data.
Go to https://jwt.io/ and scroll down add a payload like the following into the "Payload" section. Paste your secret into the "Verify Signature" section. This screenshot shows how it looks:
And here is a sample payload that should work for your application:
Then copy the code from the "Encoded" section of this page, and use that in the sample app.
The player screen in the SDK is implemented as a fragment:
- Single Activity: If you have a single activity app, then the player fragment can be launched in the desired layout container.
- Separate Activity: In case you want to launch the player in its own separate activity then you can create the activity in your app and then load the fragment into it
You will need an API_KEY that has been generated specifically for your application. In case you do not have this, please contact the HotMic team.
At a high level, you can use the Android SDK to do things like:
- Get a list of streams
- Open a stream
- Take actions inside a stream
- Receive callback & analytics events for actions taken inside the SDK
For fetching all streams to be listed to the user, call the below code:
You can optionally pass in params to filter the results of the streams. Streams are returned in reverse chronological order. The possible filters are:
- userID: the userid you want to filter the streams by:
- Type: string
- Default: NULL (all possible streams)
- limit: The max number of streams to return
- Type: integer
- Example: 40
- Default: 30
- skip: The number of results to skip you want to not return in the results, typically used for pagination.
- Type: integer
- Example: 10
- Default: 0
The data will be returned as a list of HMStreamBasic Objects:
Field | Description |
---|---|
Id | Id of the stream. If the user taps on this listing, then pass this param as the stream id |
userId | Uid of the user who is hosting this stream |
state | SCHEDULED – The stream has been scheduled but is yet to live LIVE – The stream is live VOD – The stream is a past recording ENDED – The stream has ended (you will not be getting this state in this list) |
type | broadcast – The stream is a broadcast audio_room – The stream is an audio room watch_party – The stream is a video watch party |
title | Title of this stream |
thumbnail | An image url of the program thumbnail |
scheduledDate | Timestamp of when this program is scheduled to start |
viewers | Number of viewers who are currently watching this stream |
visitors | Number of users who have visited this stream |
eventId | Id of the event to which the stream belongs to |
featuredAttendees | List of image uris, each pointing to the profile photo of someone who is viewing/visiting this stream |
user | User object holding the information of the host of this stream (name, profile_url) |
When the user taps on any of the listed stream, the app can then show the stream player using the following code:
- setStreamId - Mandatory – Sets the stream id (stream.id of the listing the user chose)
- setUICallback – Mandatory – Provide the callback interface that the SDk will use for fetching certain information, for notifying certain events, or to complete flows that only your app code can handle
- credential – Mandatory – Provide the api-key
- setAnalyticHandler – Optional – Provide the analytic callback interface which will be called by SDK whenever an analytic event occurs. The app code can then log the event as necessary
- show – Starts the player screen. Provide the layout container resource id, where the player fragment needs to be launched into
If the app wants to close the player, then call:
- reason - Analytic reason for the player closure, probable values will be USER_CLOSED, SIGNOUT
- allowStateLoss: Setting this to true will result in the fragment being removed with state loss. The default is false. For most scenarios, the default value of false is recommended, especially if the parent activity is having features/fragments other than the player.
Once the player is closed, the SDK will make a call back on PlayerCallback.onPlayerClosed().
The SDK also might trigger a player closure. This may be in response to events like stream getting over, error in fetching the stream or the user leaving the stream from the player. Once the player is closed, the SDK will make a call back to PlayerCallback.onPlayerClosed().
Inside the menu, there are several options which can be used to
- Leave - The leave button stops the player in the sdk and gives a callback in the onPlayerClosed method, so the parent app can remove the fragment. This should be handled on the host app, but most of the time you would want to "go back" to the prior page.
- Troubleshoot - When this is enabled, the troubleshoot button allows you to allow the end user to report any technical issue back to the app owner. For example, if a video was not loading or a chat was missing, the user can tap on troubleshoot, which in turn will invoke a 3rd party diagnostic sdk. The sdk will capture parameters like device logs, etc and make a ticket in the system which the app owner can access. The option is hidden behind a flag which can be set while building the player, default is false. Let the HotMic team know your diagnostic SDK and we can help you set this up.
If the user taps the device back key, and if the player is open.
HotMicPlayer.handleBackKeyPress(activity): Boolean
If the player consumes the key press (say for dismissing an overlay/dialog), then it will return true. The app should not handle the back press in this scenario. Else this will return false, and the app can handle the back press as it wants to.
Is the Player open?
The app can check if the player is open in multiple ways. It can check with the sdk by calling:
HotMicPlayer.isPlayerOpen(activity)
Or it can check whether a fragment is loaded in the ui player container:
supportFragmentManager.findFragmentById(R.id.<player_fragment_container>)
To allow your video player to go into full screen mode with a tap, you need to enable it in your application. To do so properly, add android:configChanges="orientation|keyboardHidden|screenSize" to the activity hosting the fragment
Picture in Picture Mode can be of two types:
- For a single activity app, showing the player fragment in a PIP when navigating to other fragments in the app. This is achieved by reducing the player fragment layout container to the desired size and moving it to the required location.
- Placing the app in the background by tapping the device Home button or by navigating to some other app
In both the cases the player has to resize itself so that in the PIP mode, the player displays just the video.
Also if the user taps on the PIP to get back to the expanded mode, the player will have to again change its UI to show all the layouts and controls.
To change the UI, manually (for scenario 1):
- enable: Set it to true for the player to show the PIP mode UI, false if the player is coming out of PIP and being expanded
- Returns true if the operation was success, false if the player is not open
For scenario 2 (android PIP mode), the player will change the UI itself, triggered by the android PIP callback. Note: this assumes that the activity has been enabled for PIP in the manifest. Refer https://developer.android.com/guide/topics/ui/picture-in-picture for more.
Also, for scenario 2, if the user closes the pip and at a later point of time returns to the app, then the app should show the UI with the player closed. To ensure this, add the below line in the activity onStart:
HotMicPlayer.checkPlayerStateOnStart(activity)
For displaying an ad, you can pass the view holding the ad (like the Google AdView) to the Player, using the following api:
It is assumed that the click interaction will be implemented in the view that is passed. The SDK is going to display the ad-banner with the passed view. The Ad will be displayed with an initial delay of 0 seconds, i.e., immediate, but this can be changed by passing a displayAfter value (in milliseconds). The Ad will be displayed for 10 seconds by default, this duration can also be changed by passing the right ttl value in the above function (in milliseconds)
If the ad is to be dismissed, before its auto removed, then the below api can be invoked
dismissHotMicAd(activity: FragmentActivity)
The below table lists the TextAppearance styles used in the app. The SDK does not have any fonts packaged with it, and hence the lack of font definitions in the below styles. You can change the appearance by defining the style with the same name in your app theme/style xml file
Style name | Current Definition |
---|---|
TextAppearance.HMPlayerHeadline4 | <style name="TextAppearance.HMPlayerHeadline4" parent="TextAppearance.MaterialComponents.Headline4"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">24sp</item> <item name="android:letterSpacing">0</item> </style> |
TextAppearance.HMPlayerHeadline5 | <style name="TextAppearance.HMPlayerHeadline5" parent="TextAppearance.MaterialComponents.Headline5"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">20sp</item> <item name="android:letterSpacing">0</item> </style> |
TextAppearance.HMPlayerHeadline6 | <style name="TextAppearance.HMPlayerHeadline6" parent="TextAppearance.MaterialComponents.Headline6"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">16sp</item> <item name="android:letterSpacing">0</item> </style> |
TextAppearance.HMPlayerBody1 | <style name="TextAppearance.HMPlayerBody1" parent="TextAppearance.MaterialComponents.Body1"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">16sp</item> <item name="android:letterSpacing">0</item> </style> |
TextAppearance.HMPlayerBody2 | <style name="TextAppearance.HMPlayerBody2" parent="TextAppearance.MaterialComponents.Body2"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">14sp</item> <item name="android:letterSpacing">0</item> </style> |
TextAppearance.HMPlayerBody | <style name="TextAppearance.HMPlayerBody3" parent="TextAppearance.MaterialComponents.Body2"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">14sp</item> <item name="android:letterSpacing">0</item> </style> |
TextAppearance.HMPlayerButton | <style name="TextAppearance.HMPlayerButton" parent="TextAppearance.MaterialComponents.Button"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">16sp</item> <item name="android:letterSpacing">0</item> </style> |
TextAppearance.HMPlayerOverline | <style name="TextAppearance.HMPlayerOverline" parent="TextAppearance.MaterialComponents.Overline"> <item name="android:textStyle">normal</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">10sp</item> <item name="android:letterSpacing">0</item> </style> |
The table below lists the colors used in the app, for both day and night modes. You can change the colors by defining colors with the same name in your colors xml file(s)
Color Style Name | Day | Night |
---|---|---|
hmp_colorPrimary | #F6F8FA | #121212 |
hmp_colorSecondary | #FFFFFF | #000000 |
hmp_colorTertiary | #FFFFFF | #222222 |
hmp_colorBackground | #FFFFFF | #000000 |
hmp_colorSurface | #FFFFFF | #121212 |
hmp_colorHighlight | #D1D1D5 | #3A3A3C |
| | |
hmp_textPrimary | #303234 | #FFFFFF |
hmp_textSecondary | #86898C | #999999 |
hmp_tintPrimary | #FF7106 | #FF7106 |
hmp_tintPrimaryContrast | #C93400 | #C93400 |
hmp_tintTertiary | #D0D3D7 | #606060 |
hmp_tintTertiaryContrast | #76767B | #919198 |
hmp_tintError | #DB3B3C | #DB3B3C |
hmp_tintWarning | #EDAC46 | #EDAC46 |
hmp_tintSuccess | #53D973 | #53D973 |
hmp_tintLive | #AD3632 | #AD3632 |
hmp_divider | #D1D1D6 | #38383A |
| | |
hmp_textPrimaryDisabled | #80000000 | #80FFFFFF |
hmp_textMedia | #FFFFFF | #FFFFFF |
hmp_tintDisabled | #90929F | #90929F |
hmp_tintDisabled2 | #20000000 | #20000000 |
hmp_tintAction | #000000 | #FFFFFF |
hmp_pollPrimary | set in your app | set in your app |
hmp_pollPrimaryContrast | set in your app | set in your app |
hmp_pollSecondary | #CCCDCE | #A7A8AA |
hmp_pollPercentage | #E2E2E3 | #484B50 |
fun getPlatformToken(): String
The platform token is required by the SDK to authenticate any requests with the HotMic Server. The SDK expects the app to return the platform token through this callback. Note that the HotMic Server expects the token to be constructed in a certain format, please contact the HotMic team to learn more.
Params: None
Returns: Platform Token
fun onRequestBugReport()
(OPTIONAL) User has requested to capture bug report. If the app is using any sort of bug capturing (like shake/instabug/etc), then trigger it
Params: None
fun onPlayerClosed()
(OPTIONAL) Called after the player is closed. Player closure can be triggered by the sdk on certain events like stream over, error. Or it can be triggered by the app by calling HotMicPlayer.closePlayer
Params: None
fun getShareLink(context: Context, streamId: String): Observable<String>
(OPTIONAL) User has requested a share/invite message for a stream. The message would be then available to the user to share with others.
Params:
- context
- streamId – id of the stream for which the invite link is to be created
Returns: Observable with the message string
getFollowData has been replaced by getUserProfile.
fun getFollowData(uid: String): Observable<HMFollowData>?
(OPTIONAL) Return null or do not implement, if you do not support the follow feature. If implementing, then gather and return the follow information. This information includes,
- Is the logged in user following the user identified by the passed uid
- If the logged in user being followed by the specific user
- How many followers does the specific user have
- How many people does the specific user follow
Params:
- uid – user id of the user whose follow information you need
Returns: An observable with the FollowData object. The observable will be invoked in the background by the implementation.
getUserProfile has replaced getFollowData, please use this moving forward.
(OPTIONAL) Return the user profile information, including meta data like name, profile pic. Return null or do not implement, if you do not want to provide information from your application. If implementing, then gather and return all information for the user profile, such as following information. This information includes,
- Is the logged in user following the user identified by the passed uid
- If the logged in user being followed by the specific user
- How many followers does the specific user have
- How many people does the specific user follow
Params:
- uid - user id of the user whose profile info is needed
- restriction - type of restriction on this account (if any), possible values are "none", "view_and_polls_only", "read_only". A null value on this can be interpreted as no restriction.
- "view_and_polls_only" - user can view and answer polls, but cannot chat, join a stream, follow, tip, view a profile.
- "read_only" - same as "view_and_polls_only", plus the user cannot answer polls
- isHost - boolean - is the user id that of the host of this stream
- isCohost - boolean - is the user one of the cohost in this stream
Returns:
An observable with the HMProfile object. The observable will be invoked in the background by the implementation. Here is what the return looks like:
If showFullProfileOption is returned to getUserProfile(), then there will be a button displayed to "See Full Profile". If a user taps that button, they trigger seeFullProfileTapped.
Params:
- uid - user id of the user whose profile info is needed
- restriction - type of restriction on this account (if any), possible values are "none", "view_and_polls_only", "read_only". A null value on this can be interpreted as no restriction.
- "view_and_polls_only" - user can view and answer polls, but cannot chat, join a stream, follow, tip, view a profile.
- "read_only" - same as "view_and_polls_only", plus the user cannot answer polls
- isHost - boolean - is the user id that of the host of this stream
- isCohost - boolean - is the user one of the cohost in this stream
Returns:
true if you want the profile panel shown by the sdk to be dismissed, false otherwise
fun followUser(user: HMUserBasic, shouldFollow: Boolean): Observable<Unit>?
(OPTIONAL) Follow/Unfollow the passed user. Required only if you app is having the follow-user feature
Params:
- user – User to be followed/unfollowed
- shouldFollow – true if to be followed, false otherwise
Returns: Observable
The return for followUser is:
fun onAdClick(streamId: String, adId: String)
(OPTIONAL) Called in the event of the user clicking on any advertisement banner on the player.
Params:
- streamId – id of the stream being played
- adId – id of the advertisement banner
Returns: Nothing
fun isBlockedByHost(hostId: String): Observable<Boolean>?
(OPTIONAL) Return true in the observable if the host, identified by the host id has blocked the current logged in user from the stream. If true, then the user will not be able to send any chat message. Default implementation returns null, indicating no blocking
Params:
- hostId – Uid of the host for the current stream being played
Returns: Observable with Boolean value, null will be treated as non-blocked
fun getTipSkus(): LiveData<List<AppSku>>
(OPTIONAL) Return the full list of billing products that is configured for tips in the app
Params: None
Returns: LiveData with the list of billings skus
fun makeTipPurchase(activity: Activity,userId: String,hostId: String,streamId: String,streamType: String,message: String,anonymous: Boolean,appSkuDetail: AppSku)
(OPTIONAL) Make the Google billing purchase for when the user has opted to tip a certain amount in the stream
Params:
- activity – Parent fragment activity of the player
- userId – Unique id of the logged in user requesting the cameo
- hostId – Unique id of the host of the stream being played
- streamId – Unique id of the stream being played
- streamType – type of the stream for analytic purposes (broadcast|watch_party|audio_room)
- message – Message that the user has typed while giving the tip
- anonymous – True if the user wants to stay anonymous
- appSkuDetail – Billing product details which the user has agreed to pay for
Returns: Observable with the billing result
fun makeJoinGuestPurchase(activity: Activity,userId: String,hostId: String,streamId: String,streamType: String,appSkuDetail: AppSku): Observable<AppBillingResult>
(OPTIONAL) Make the Google billing purchase for when the user has opted to pay for joining a stream as a guest (cameo)
Params:
- activity – Parent fragment activity of the player
- userId – Unique id of the logged in user requesting the cameo
- hostId – Unique id of the host of the stream being played
- streamId – Unique id of the stream being played
- streamType – type of the stream for analytic purposes (broadcast|watch_party|audio_room)
- appSkuDetail – Billing product details which the user has agreed to pay for
Returns: Observable with the billing result
fun fetchSkuDetails(skuId: String?): Flowable<List<AppSku>>
(OPTIONAL) Fetch the billing product details for the given sku id
Params:
- skuId – id of the app billing product
Returns: FLowable where the list of matching billing products are returned. Ideally only one entry is expected and the sdk is only going to consider the first entry. Emit empty list if no match is found. And emit error exception in case of any error in fetching
fun logEvent(event: ANEvent, data: Map<String, Any>)
Log the event passed and the associated data using the app analytics
Params:
- event – Event to be logged
- data - Param data associated with the event logged
fun startEventTimer(event: ANEvent)
This is mainly for timed events, where you want to record the duration of the event. This logs the start of an event. The end of the event will be triggered from the above logEvent
Params:
- event – Event to be logged