Advertisement
IonutCava

Untitled

May 28th, 2015
350
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 18.29 KB | None | 0 0
  1. package com.vestel.android.tvframework.gracenote;
  2.  
  3. import android.content.ContentResolver;
  4. import android.content.ContentUris;
  5. import android.content.ContentValues;
  6. import android.content.Context;
  7. import android.database.Cursor;
  8. import android.media.tv.TvContract;
  9. import android.net.Uri;
  10. import android.os.AsyncTask;
  11. import android.util.Log;
  12.  
  13. import com.vestel.android.tvframework.epg.EventInformation;
  14. import com.vestel.android.tvframework.gracenote.Cache.ImageCache;
  15. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSAiring;
  16. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSChannel;
  17. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSChannelArray;
  18. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSChannelFromSatellite;
  19. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSContributer;
  20. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSGNBase;
  21. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSProgram;
  22. import com.vestel.android.tvframework.gracenote.GracenoteImpl.VSSeries;
  23.  
  24. import java.util.ArrayList;
  25. import java.util.Date;
  26. import java.util.HashMap;
  27. import java.util.Iterator;
  28. import java.util.Map;
  29. import java.util.concurrent.CopyOnWriteArrayList;
  30.  
  31. public final class GraceNoteWrapper {
  32.  
  33.     private static class SingletonHolder {
  34.         static final GraceNoteWrapper mInstance = new GraceNoteWrapper();
  35.     }
  36.  
  37.     private static final int RAM_CACHE_SIZE = 256 * 1024;//256Kb;
  38.  
  39.     private Long mLastStartTime = 0L;
  40.     private Long mLastEndTime = 0L;
  41.     private VSChannel previousChannel = null;
  42.  
  43.     protected ImageCache mCache = null;
  44.     // ChannelArray is our main entry point into GraceNote
  45.     protected VSChannelArray mChannelArray = null;
  46.     protected boolean mChannelDataAvailable = false;
  47.     protected boolean mProgramDataAvailable = false;
  48.     // PendingChannels holds a list of channels not yet processed by GN
  49.     // Processed channels are removed automatically
  50.     protected ArrayList<VSChannelFromSatellite> mPendingChannels = null;
  51.     // Hold the list of channels returned by GraceNote
  52.     protected CopyOnWriteArrayList<VSChannel> mParsedChannels = null;
  53.     // Create a container to hold programs by row URI and event information
  54.     protected HashMap<Uri, EventInfoPair> mProgramMap = null;
  55.  
  56.     protected class EventInfoPair {
  57.         protected EventInformation eventinfo;
  58.         protected long channelID;
  59.     }
  60.  
  61.     public static GraceNoteWrapper getInstance(){
  62.         return SingletonHolder.mInstance;
  63.     }
  64.  
  65.     private GraceNoteWrapper()
  66.     {
  67.         mChannelArray = new VSChannelArray();
  68.         mChannelArray = new VSChannelArray();
  69.         mPendingChannels = new  ArrayList<>();
  70.         mParsedChannels = new CopyOnWriteArrayList<>();
  71.         mProgramMap = new HashMap<>();
  72.  
  73.         mChannelDataAvailable = false;
  74.         mProgramDataAvailable = false;
  75.  
  76.         Log.e("GraceNote","GrancenoteWrapper created");
  77.     }
  78.  
  79.     public boolean isParsedChannelDataAvailable() {
  80.         return mChannelDataAvailable;
  81.     }
  82.  
  83.     public void isParsedChannelDataAvailable(boolean state) {
  84.         mChannelDataAvailable = state;
  85.     }
  86.  
  87.     public boolean isParsedProgramDataAvailable() {
  88.         return mProgramDataAvailable;
  89.     }
  90.  
  91.     public void isParsedProgramDataAvailable(boolean state) {
  92.         mProgramDataAvailable = state;
  93.     }
  94.  
  95.     // Add a new channel to the pending list so that it may get parsed via GraceNote later on
  96.     public int registerChannel(VSChannelFromSatellite channel) {
  97.         // Get the dvbID hash value generated from the channel's onID, tsID and sID values
  98.         int dvbIDHash = channel.getDvbID().getHash();
  99.         // Prevent adding the same channel twice, unless the previous list was fully parsed
  100.         // In that case, ChannelArray should skip duplicate entries automatically
  101.         if (getChannelForDvbIDHash(dvbIDHash) == null &&
  102.             getGraceNoteChannel(dvbIDHash) == null) {
  103.             mPendingChannels.add(channel);
  104.         }
  105.         // Return the hash value so the user has a handle to work with when he wishes to retrieve
  106.         // a specific channel's data if, for example, the channel was crated using
  107.         // "registerChannel(ctx, new VSChannel....)"
  108.         return dvbIDHash;
  109.     }
  110.  
  111.     // Internally retrieve an unparsed channel based on the dvbID
  112.     protected VSChannelFromSatellite getChannelForDvbIDHash(int dvbIDHash) {
  113.         // Linear search is fine for a generic channel list
  114.         for (VSChannelFromSatellite channel : mPendingChannels) {
  115.             if (channel.getDvbID().getHash() == dvbIDHash) {
  116.                 return channel;
  117.             }
  118.         }
  119.  
  120.         return null;
  121.     }
  122.  
  123.     // Retrieve a channel using its dvbID
  124.     public VSChannel getGraceNoteChannel(int dvbIDHash) {
  125.         // Again, linear search should be fine for a generic channel list
  126.         for (VSChannel channel : mParsedChannels) {
  127.             if (channel.getDvbID().getHash() == dvbIDHash) {
  128.                 return channel;
  129.             }
  130.         }
  131.  
  132.         return null;
  133.     }
  134.  
  135.     public VSChannel getChannelForID(long channel_id) {
  136.         if (mParsedChannels.isEmpty()) {
  137.             Log.e("GraceNote", "Could not search for channel [ " + channel_id + " ]. Channel list is empty!");
  138.             return null;
  139.         }
  140.         // speed up loop-based channel requests
  141.         if (previousChannel != null &&
  142.                 previousChannel.getChannelID() == channel_id) {
  143.             return previousChannel;
  144.         }
  145.  
  146.         for (VSChannel channel : mParsedChannels) {
  147.             if (channel.getChannelID() == channel_id) {
  148.                 previousChannel = channel;
  149.                 return channel;
  150.             }
  151.         }
  152.  
  153.         return null;
  154.     }
  155.  
  156.     protected VSProgram getProgramByTitle(VSChannel channel, String title) {
  157.         if (channel != null && !title.isEmpty()) {
  158.             // Get the list of all airings for the current channel
  159.             CopyOnWriteArrayList<VSAiring> airingList = channel.getAiringList();
  160.             for (VSAiring airing : airingList) {
  161.                 VSProgram prog = airing.getProgram();
  162.                 if (prog != null && prog.getTitle().equalsIgnoreCase(title)) {
  163.                     return prog;
  164.                 }
  165.             }
  166.         }
  167.  
  168.         return null;
  169.     }
  170.  
  171.     protected VSProgram getProgramByTitle(Long channel_id, String title) {
  172.         if (!title.isEmpty()) {
  173.             VSChannel channelForID = getChannelForID(channel_id);
  174.             if (channelForID != null) {
  175.                 return getProgramByTitle(channelForID, title);
  176.             } else {
  177.                 Log.d("GraceNote", "Could not find channel for id [ " + channel_id + " ]. Parsing all channels.");
  178.                 for (VSChannel channel : mParsedChannels) {
  179.                     VSProgram prog = getProgramByTitle(channel, title);
  180.                     if (prog != null) {
  181.                         return prog;
  182.                     }
  183.                 }
  184.             }
  185.         }
  186.  
  187.         return null;
  188.     }
  189.    
  190.     public void parseChannels(String inputID, Context context) {
  191.         new ParseGraceNoteChannels(inputID, context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  192.     }
  193.  
  194.     public void parsePrograms(Context context, Long startTimeMS, Long endTimeMS) {
  195.         if (mLastStartTime != startTimeMS || mLastEndTime != endTimeMS) {
  196.             mLastStartTime = startTimeMS;
  197.             mLastEndTime = endTimeMS;
  198.             isParsedProgramDataAvailable(false);
  199.         }
  200.  
  201.         if (!isParsedProgramDataAvailable()) {
  202.             if (!mParsedChannels.isEmpty()) {
  203.                 ParseGraceNotePrograms programParse = new ParseGraceNotePrograms(context, startTimeMS, endTimeMS, mParsedChannels);
  204.                 programParse.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  205.             } else {
  206.                 Log.e("GraceNote", "Could not parse programs. Channel list is empty!");
  207.             }
  208.         }
  209.     }
  210.  
  211.     public void updateProgramInfo(Uri programURI, EventInformation eventinfo) {
  212.         EventInfoPair infoPair = mProgramMap.get(programURI);
  213.         if (infoPair != null) {
  214.             infoPair.eventinfo = eventinfo;
  215.         } else {
  216.             Log.e("GraceNote", "Invalid update call for URI [ " + programURI.toString() + " ]" );
  217.         }
  218.         isParsedProgramDataAvailable(false);
  219.     }
  220.  
  221.     public void addProgramInfo(Uri programURI, EventInformation eventinfo, long channelId) {
  222.         EventInfoPair pair = new EventInfoPair();
  223.         pair.eventinfo = eventinfo;
  224.         pair.channelID = channelId;
  225.  
  226.         mProgramMap.put(programURI, pair);
  227.         isParsedProgramDataAvailable(false);
  228.     }
  229.  
  230.     protected String getChannelUID(String channelName, int sID, int tsID) {
  231.         return channelName + sID + tsID;
  232.     }
  233.  
  234.     protected class ParseGraceNotePrograms extends AsyncTask<Void, Void, Void> {
  235.         Context context = null;
  236.         Long mStartTime = 0L;
  237.         Long mEndTime = 0L;
  238.         CopyOnWriteArrayList<VSChannel> mChannels;
  239.  
  240.         public ParseGraceNotePrograms(Context context, Long startTimeMS, Long endTimeMS, CopyOnWriteArrayList<VSChannel> channels) {
  241.             this.context = context;
  242.             this.mStartTime = startTimeMS;
  243.             this.mEndTime = endTimeMS;
  244.             this.mChannels = channels;
  245.         }
  246.  
  247.         @Override
  248.         protected Void doInBackground(Void... params) {
  249.             if (context != null) {
  250.                 mChannelArray.parse(context, new Date(mStartTime), new Date(mEndTime));
  251.                 CopyOnWriteArrayList<VSAiring> airingList;
  252.                 CopyOnWriteArrayList<VSContributer> contributors;
  253.                 for (VSChannel channel : mChannels) {
  254.                     airingList = channel.getAiringList();
  255.                     for (VSAiring airing : airingList) {
  256.                         VSProgram prog = airing.getProgram();
  257.                         if (prog != null) {
  258.                             if (prog.parse(context) == VSGNBase.StatusCode.OK) {
  259.                                 contributors = prog.getContributers();
  260.                                 for (VSContributer contributor : contributors) {
  261.                                     contributor.parse(context);
  262.                                 }
  263.  
  264.                                 VSSeries series = prog.getSeries();
  265.                                 if (series != null) {
  266.                                     series.parse(context);
  267.                                 }
  268.                                 /* Future season support
  269.                                 VSSeason season = prog.getSeason();
  270.                                 if (season != null) {
  271.                                     season.parse(context);
  272.                                 }*/
  273.                             }
  274.                         }
  275.                     }
  276.                 }
  277.  
  278.                 if (!mProgramMap.isEmpty()) {
  279.                     Iterator it = mProgramMap.entrySet().iterator();
  280.                     while (it.hasNext()) {
  281.                         Map.Entry<Uri, EventInfoPair> pair = (Map.Entry) it.next();
  282.                         EventInformation eventinfo = pair.getValue().eventinfo;
  283.                         long channelID = pair.getValue().channelID;
  284.                         VSProgram prog = getProgramByTitle(channelID, eventinfo.title);
  285.                         if (prog != null) {
  286.                             ContentValues content_values = new ContentValues();
  287.                             content_values.put(TvContract.Programs.COLUMN_POSTER_ART_URI, prog.getImgURL());
  288.                             context.getContentResolver().update(pair.getKey(), content_values, null, null);
  289.                         } else {
  290.                             Log.e("GraceNote", "program [ " + eventinfo.programid + " ] is null!");
  291.                         }
  292.                     }
  293.                 } else {
  294.                     Log.e("GraceNote", "no program data available for parsing!");
  295.                 }
  296.             }
  297.             return null;
  298.         }
  299.  
  300.         @Override
  301.         protected void onPreExecute() {
  302.             Log.d("GraceNote", "GraceNote program parsing started");
  303.             isParsedProgramDataAvailable(false);
  304.         }
  305.  
  306.         @Override
  307.         protected void onPostExecute(Void nothing){
  308.             this.context = null;
  309.             isParsedProgramDataAvailable(true);
  310.             Log.d("GraceNote", "GraceNote program parsing finished");
  311.         }
  312.     }
  313.  
  314.     protected class ParseGraceNoteChannels extends AsyncTask<Void, Void, CopyOnWriteArrayList<VSChannel>> {
  315.         Context context = null;
  316.         Integer dvbID = null;
  317.         String inputID = "";
  318.         ParseGraceNoteChannels(String inputID, Context context) {
  319.             this.context = context;
  320.             this.inputID = inputID;
  321.             if (mCache == null) {
  322.                 mCache = new ImageCache(context, RAM_CACHE_SIZE);
  323.             }
  324.         }
  325.  
  326.         ParseGraceNoteChannels(String inputID, Context context, Integer dvbID) {
  327.             this.context = context;
  328.             this.dvbID = dvbID;
  329.             this.inputID = inputID;
  330.             if (mCache == null) {
  331.                 mCache = new ImageCache(context, RAM_CACHE_SIZE);
  332.             }
  333.         }
  334.  
  335.         @Override
  336.         protected CopyOnWriteArrayList<VSChannel> doInBackground(Void... params) {
  337.             CopyOnWriteArrayList<VSChannel> channelsOut = new CopyOnWriteArrayList<>();
  338.             VSGNBase.StatusCode gnParseStatus = VSGNBase.StatusCode.OTHER;
  339.             if (dvbID == null) {
  340.                 gnParseStatus = mChannelArray.parseGNIDsWithChannels(context, mPendingChannels, false);
  341.             } else {
  342.                 VSChannelFromSatellite channel = getChannelForDvbIDHash(dvbID);
  343.                 if (channel != null) {
  344.                     gnParseStatus = mChannelArray.parseGNIDWithChannel(context, channel, false);
  345.                 }
  346.             }
  347.             if (gnParseStatus == VSGNBase.StatusCode.OK) {
  348.                 channelsOut = updateParsedChannels(inputID, context);
  349.             }
  350.  
  351.             return channelsOut;
  352.         }
  353.  
  354.         // Called after we submitted our pending channels to GraceNote for parsing
  355.         protected CopyOnWriteArrayList<VSChannel> updateParsedChannels(String inputID, Context context) {
  356.             // Retrieve the list of successfully parsed channels
  357.             CopyOnWriteArrayList<VSChannel> channelsOut = mChannelArray.getChannelList();
  358.             // Create a container to map a channel URI to a channel logo URL
  359.             HashMap<Uri, String> logos = new HashMap<>();
  360.             // Get all channels by querying TvInputManager
  361.             ContentResolver cr = context.getContentResolver();
  362.             // We need as much data as possible to match Android channels with GraceNote channels
  363.             String[] projection =  {
  364.                     TvContract.Channels._ID,
  365.                     TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID,
  366.                     TvContract.Channels.COLUMN_SERVICE_ID,
  367.                     TvContract.Channels.COLUMN_DISPLAY_NAME,
  368.             };
  369.  
  370.             // Attempt to match them with the live channel list used by AndroidTV
  371.             // Create a container to hold our existing android channels
  372.             HashMap<String, Long> existingChannelsMap = new HashMap<>();
  373.             // Create a container to hold the URI for each android channel
  374.             HashMap<Long, Uri> channelURIMap = new HashMap<>();
  375.  
  376.             Uri uri = TvContract.buildChannelsUriForInput(inputID);
  377.             // Try and build a list of channels with our requested data
  378.             Cursor cursor = cr.query(uri, projection, null, null, null);
  379.             // Move the cursor over every channel
  380.             while (cursor != null && cursor.moveToNext()) {
  381.                 // Generate a unique key to match channels later on
  382.                 long rowID = cursor.getLong(0);
  383.                 int tsID = cursor.getInt(1);
  384.                 int sID = cursor.getInt(2);
  385.                 String name = cursor.getString(3);
  386.                 // Store channel data in our mapping containers
  387.                 Uri channelUri = ContentUris.withAppendedId(TvContract.Channels.CONTENT_URI, rowID);
  388.                 existingChannelsMap.put(getChannelUID(name, sID, tsID), rowID);
  389.                 channelURIMap.put(rowID, channelUri);
  390.             }
  391.  
  392.             if (cursor != null) {
  393.                 cursor.close();
  394.             }
  395.  
  396.             Uri channelUri;
  397.             // We iterate over every GraceNote parsed channel
  398.             for (VSChannel newChannel : channelsOut) {
  399.                 // Try to generate a unique key for the current channel the same way we did above
  400.                 int tsID = newChannel.getDvbID().getTsID();
  401.                 int sID = newChannel.getDvbID().getsID();
  402.                 String name = newChannel.getName();
  403.                 // Attempt to find a valid match within the list of android channels
  404.                 Long rowId = existingChannelsMap.get(getChannelUID(name, sID, tsID));
  405.                 if (rowId != null) {
  406.                     newChannel.setChannelID(rowId);
  407.                     // If we found a match, retrieve the channelURI and save it to our logo map
  408.                     channelUri = channelURIMap.get(rowId);
  409.                     // And check that it has a valid logo
  410.                     String channelLogo = newChannel.getImgURL();
  411.                     if (channelLogo != null && !channelLogo.isEmpty()) {
  412.                         logos.put(channelUri, newChannel.getImgURL());
  413.                     }
  414.                 }
  415.             }
  416.  
  417.             // Download all of the needed logos upfront (to retrieve them later on)
  418.             // This is done asynchronously as well
  419.             mCache.cacheLogos(logos);
  420.  
  421.             return channelsOut;
  422.         }
  423.  
  424.         @Override
  425.         protected void onPreExecute() {
  426.             Log.d("GraceNote", "GraceNote channel parsing started");
  427.             isParsedChannelDataAvailable(false);
  428.         }
  429.  
  430.         @Override
  431.         protected void onPostExecute(CopyOnWriteArrayList<VSChannel> parsedChannels){
  432.             mParsedChannels = parsedChannels;
  433.             mPendingChannels.clear();
  434.             isParsedChannelDataAvailable(true);
  435.             Log.d("GraceNote", "GraceNote channel parsing finished. Parsed [ " + mParsedChannels.size() + " ] channels");
  436.         }
  437.     }
  438. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement