Home | History | Annotate | Download | only in util
      1 package com.example.android.tv.channelsprograms.util;
      2 
      3 import android.net.Uri;
      4 import android.support.annotation.StringDef;
      5 
      6 import java.util.List;
      7 
      8 /** Builds and parses uris for deep linking within the app. */
      9 public class AppLinkHelper {
     10 
     11     private static final String SCHEMA_URI_PREFIX = "tvrecommendation://app/";
     12     public static final String PLAYBACK = "playback";
     13     public static final String BROWSE = "browse";
     14     private static final String URI_PLAY = SCHEMA_URI_PREFIX + PLAYBACK;
     15     private static final String URI_VIEW = SCHEMA_URI_PREFIX + BROWSE;
     16     private static final int URI_INDEX_OPTION = 0;
     17     private static final int URI_INDEX_CHANNEL = 1;
     18     private static final int URI_INDEX_MOVIE = 2;
     19     private static final int URI_INDEX_POSITION = 3;
     20     public static final int DEFAULT_POSITION = -1;
     21 
     22     /**
     23      * Builds a {@link Uri} for deep link into playing a movie from the beginning.
     24      *
     25      * @param channelId - id of the channel the movie is in.
     26      * @param movieId - id of the movie.
     27      * @return a uri.
     28      */
     29     public static Uri buildPlaybackUri(long channelId, long movieId) {
     30         return buildPlaybackUri(channelId, movieId, DEFAULT_POSITION);
     31     }
     32 
     33     /**
     34      * Builds a {@link Uri} to deep link into continue playing a movie from a position.
     35      *
     36      * @param channelId - id of the channel the movie is in.
     37      * @param movieId - id of the movie.
     38      * @param position - position to continue playing.
     39      * @return a uri.
     40      */
     41     public static Uri buildPlaybackUri(long channelId, long movieId, long position) {
     42         return Uri.parse(URI_PLAY)
     43                 .buildUpon()
     44                 .appendPath(String.valueOf(channelId))
     45                 .appendPath(String.valueOf(movieId))
     46                 .appendPath(String.valueOf(position))
     47                 .build();
     48     }
     49 
     50     /**
     51      * Builds a {@link Uri} to deep link into viewing a subscription.
     52      *
     53      * @param subscriptionName - name of the subscription.
     54      * @return a uri.
     55      */
     56     public static Uri buildBrowseUri(String subscriptionName) {
     57         return Uri.parse(URI_VIEW).buildUpon().appendPath(subscriptionName).build();
     58     }
     59 
     60     /**
     61      * Returns an {@link AppLinkAction} for the given Uri.
     62      *
     63      * @param uri to determine the intended action.
     64      * @return an action.
     65      */
     66     public static AppLinkAction extractAction(Uri uri) {
     67         if (isPlaybackUri(uri)) {
     68             return new PlaybackAction(
     69                     extractChannelId(uri), extractMovieId(uri), extractPosition(uri));
     70         } else if (isBrowseUri(uri)) {
     71             return new BrowseAction(extractSubscriptionName(uri));
     72         }
     73         throw new IllegalArgumentException("No action found for uri " + uri);
     74     }
     75 
     76     /**
     77      * Tests if the {@link Uri} was built for playing a movie.
     78      *
     79      * @param uri to examine.
     80      * @return true if the uri is for playing a movie.
     81      */
     82     private static boolean isPlaybackUri(Uri uri) {
     83         if (uri.getPathSegments().isEmpty()) {
     84             return false;
     85         }
     86         String option = uri.getPathSegments().get(URI_INDEX_OPTION);
     87         return PLAYBACK.equals(option);
     88     }
     89 
     90     /**
     91      * Tests if a {@link Uri} was built for browsing a subscription.
     92      *
     93      * @param uri to examine.
     94      * @return true if the Uri is for browsing a subscription.
     95      */
     96     private static boolean isBrowseUri(Uri uri) {
     97         if (uri.getPathSegments().isEmpty()) {
     98             return false;
     99         }
    100         String option = uri.getPathSegments().get(URI_INDEX_OPTION);
    101         return BROWSE.equals(option);
    102     }
    103 
    104     /**
    105      * Extracts the subscription name from the {@link Uri}.
    106      *
    107      * @param uri that contains a subscription name.
    108      * @return the subscription name.
    109      */
    110     private static String extractSubscriptionName(Uri uri) {
    111         return extract(uri, URI_INDEX_CHANNEL);
    112     }
    113 
    114     /**
    115      * Extracts the channel id from the {@link Uri}.
    116      *
    117      * @param uri that contains a channel id.
    118      * @return the channel id.
    119      */
    120     private static long extractChannelId(Uri uri) {
    121         return extractLong(uri, URI_INDEX_CHANNEL);
    122     }
    123 
    124     /**
    125      * Extracts the movie id from the {@link Uri}.
    126      *
    127      * @param uri that contains a movie id.
    128      * @return the movie id.
    129      */
    130     private static long extractMovieId(Uri uri) {
    131         return extractLong(uri, URI_INDEX_MOVIE);
    132     }
    133 
    134     /**
    135      * Extracts the playback mPosition from the {@link Uri}.
    136      *
    137      * @param uri that contains a playback mPosition.
    138      * @return the playback mPosition.
    139      */
    140     private static long extractPosition(Uri uri) {
    141         return extractLong(uri, URI_INDEX_POSITION);
    142     }
    143 
    144     private static long extractLong(Uri uri, int index) {
    145         return Long.valueOf(extract(uri, index));
    146     }
    147 
    148     private static String extract(Uri uri, int index) {
    149         List<String> pathSegments = uri.getPathSegments();
    150         if (pathSegments.isEmpty() || pathSegments.size() < index) {
    151             return null;
    152         }
    153         return pathSegments.get(index);
    154     }
    155 
    156     @StringDef({BROWSE, PLAYBACK})
    157     public @interface ActionFlags {}
    158 
    159     /** Action for deep linking. */
    160     public interface AppLinkAction {
    161         /** Returns an string representation of the action. */
    162         @ActionFlags
    163         String getAction();
    164     }
    165 
    166     /** Browse a subscription. */
    167     public static class BrowseAction implements AppLinkAction {
    168 
    169         private final String mSubscriptionName;
    170 
    171         private BrowseAction(String subscriptionName) {
    172             this.mSubscriptionName = subscriptionName;
    173         }
    174 
    175         public String getSubscriptionName() {
    176             return mSubscriptionName;
    177         }
    178 
    179         @Override
    180         public String getAction() {
    181             return BROWSE;
    182         }
    183     }
    184 
    185     /** Play a movie. */
    186     public static class PlaybackAction implements AppLinkAction {
    187 
    188         private final long mChannelId;
    189         private final long mMovieId;
    190         private final long mPosition;
    191 
    192         private PlaybackAction(long channelId, long movieId, long position) {
    193             this.mChannelId = channelId;
    194             this.mMovieId = movieId;
    195             this.mPosition = position;
    196         }
    197 
    198         public long getChannelId() {
    199             return mChannelId;
    200         }
    201 
    202         public long getMovieId() {
    203             return mMovieId;
    204         }
    205 
    206         public long getPosition() {
    207             return mPosition;
    208         }
    209 
    210         @Override
    211         public String getAction() {
    212             return PLAYBACK;
    213         }
    214     }
    215 }
    216