public static LongSparseArray<XmlTvParser.XmlTvChannel> buildChannelMap( ContentResolver resolver, String inputId, List<XmlTvParser.XmlTvChannel> channels) { Uri uri = TvContract.buildChannelsUriForInput(inputId); String[] projection = { TvContract.Channels._ID, TvContract.Channels.COLUMN_DISPLAY_NUMBER }; LongSparseArray<XmlTvParser.XmlTvChannel> channelMap = new LongSparseArray<>(); try (Cursor cursor = resolver.query(uri, projection, null, null, null)) { if (cursor == null || cursor.getCount() == 0) { return null; } while (cursor.moveToNext()) { long channelId = cursor.getLong(0); String channelNumber = cursor.getString(1); channelMap.put(channelId, getChannelByNumber(channelNumber, channels)); } } catch (Exception e) { Log.d(TAG, "Content provider query: " + Arrays.toString(e.getStackTrace())); return null; } return channelMap; }
/** * Updates a column {@code columnName} of DB table {@code uri} with the value * {@code columnValue}. The selective rows in the ID list {@code ids} will be updated. * The DB operations will run on {@link AsyncDbTask#getExecutor()}. */ private void updateOneColumnValue( final String columnName, final int columnValue, final List<Long> ids) { if (!PermissionUtils.hasAccessAllEpg(mContext)) { // TODO: support this feature for non-system LC app. b/23939816 return; } AsyncDbTask.execute(new Runnable() { @Override public void run() { String selection = Utils.buildSelectionForIds(Channels._ID, ids); ContentValues values = new ContentValues(); values.put(columnName, columnValue); mContentResolver.update(TvContract.Channels.CONTENT_URI, values, selection, null); } }); }
@Override public String getString(int columnIndex) { String columnName = getColumnName(columnIndex); ChannelInfoWrapper channel = mContentProvider.get(mPosition); switch (columnName) { case Channels.COLUMN_DISPLAY_NAME: return channel.channelInfo.name; case Channels.COLUMN_DISPLAY_NUMBER: return channel.channelInfo.number; case Channels.COLUMN_INPUT_ID: return DUMMY_INPUT_ID; case Channels.COLUMN_VIDEO_FORMAT: return channel.channelInfo.getVideoFormat(); } if (DEBUG) { Log.d(TAG, "Column (" + columnName + ") is ignored in getString()"); } return null; }
@Override public int getInt(int columnIndex) { String columnName = getColumnName(columnIndex); ChannelInfoWrapper channel = mContentProvider.get(mPosition); switch (columnName) { case Channels.COLUMN_ORIGINAL_NETWORK_ID: return channel.channelInfo.originalNetworkId; case COLUMN_BROWSABLE: return channel.browsable ? 1 : 0; case COLUMN_LOCKED: return channel.locked ? 1 : 0; } if (DEBUG) { Log.d(TAG, "Column (" + columnName + ") is ignored in getInt()"); } return 0; }
/** * Query and return the map of (channel_id, ChannelInfo). * See: {@link ChannelInfo#fromCursor(Cursor)}. */ @WorkerThread public static Map<Long, ChannelInfo> queryChannelInfoMapForTvInput( Context context, String inputId) { Uri uri = TvContract.buildChannelsUriForInput(inputId); Map<Long, ChannelInfo> map = new HashMap<>(); String[] projections = new String[ChannelInfo.PROJECTION.length + 1]; projections[0] = Channels._ID; System.arraycopy(ChannelInfo.PROJECTION, 0, projections, 1, ChannelInfo.PROJECTION.length); try (Cursor cursor = context.getContentResolver() .query(uri, projections, null, null, null)) { if (cursor != null) { while (cursor.moveToNext()) { map.put(cursor.getLong(0), ChannelInfo.fromCursor(cursor)); } } return map; } }
public ChannelDescriptor(Cursor cursor) { mId = cursor.getInt(cursor.getColumnIndex(Channels._ID)); mDisplayNumber = cursor.getString(cursor .getColumnIndex(Channels.COLUMN_DISPLAY_NUMBER)); mType = convertTifTypeToSourceType(cursor.getString(cursor .getColumnIndex(Channels.COLUMN_TYPE))); mServiceType = convertTifServiceTypeToServiceType(cursor.getString(cursor .getColumnIndex(Channels.COLUMN_SERVICE_TYPE))); if (mType == SourceType.IP) { mUrl = cursor.getString(cursor .getColumnIndex(Channels.COLUMN_DISPLAY_NAME)); mName = ""; } else { mName = cursor.getString(cursor .getColumnIndex(Channels.COLUMN_DISPLAY_NAME)); mUrl = ""; } mServiceId = cursor.getInt(cursor .getColumnIndex(Channels.COLUMN_SERVICE_ID)); }
public ContentValues getContentValues(String inputId) { ContentValues ret = new ContentValues(); ret.put(Channels.COLUMN_DISPLAY_NUMBER, mDisplayNumber); if (mType == SourceType.IP) { ret.put(Channels.COLUMN_DISPLAY_NAME, mUrl); } else { ret.put(Channels.COLUMN_DISPLAY_NAME, mName); } ret.put(Channels.COLUMN_TYPE, convertSourceTypeToTifType(mType)); ret.put(Channels.COLUMN_SERVICE_ID, mServiceId); ret.put(Channels.COLUMN_INPUT_ID, inputId); ret.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, mId); ret.put(Channels.COLUMN_SERVICE_TYPE, convertServiceTypeToTifServiceType(mServiceType)); ret.put(Channels.COLUMN_SEARCHABLE, 1); ret.put(COLUMN_BROWSABLE, 1); return ret; }
private ArrayList<ChannelDescriptor> loadChannels(String inputId) { ArrayList<ChannelDescriptor> ret = new ArrayList<ChannelDescriptor>(); final String[] projection = { Channels._ID, Channels.COLUMN_DISPLAY_NAME, Channels.COLUMN_DISPLAY_NUMBER, Channels.COLUMN_SERVICE_ID, Channels.COLUMN_TYPE, Channels.COLUMN_SERVICE_TYPE }; Cursor cursor = mContext.getContentResolver().query( TvContract.buildChannelsUriForInput(mInputId), projection, null, null, null); if (cursor == null) { return ret; } cursor.moveToFirst(); while (!cursor.isAfterLast()) { ChannelDescriptor cd = new ChannelDescriptor(cursor); mLog.d("[loadChannels] index=" + cd.getChannelId() + " info=" + cd); ret.add(cd); cursor.moveToNext(); } cursor.close(); return ret; }
/** * Returns the current list of channels your app provides. * * @param resolver Application's ContentResolver. * @return List of channels. */ public static List<Channel> getChannels(ContentResolver resolver) { List<Channel> channels = new ArrayList<>(); // TvProvider returns programs in chronological order by default. Cursor cursor = null; try { cursor = resolver.query(Channels.CONTENT_URI, Channel.PROJECTION, null, null, null); if (cursor == null || cursor.getCount() == 0) { return channels; } while (cursor.moveToNext()) { channels.add(Channel.fromCursor(cursor)); } } catch (Exception e) { Log.w(TAG, "Unable to get channels", e); } finally { if (cursor != null) { cursor.close(); } } return channels; }
public static List<Channel> getChannels(ContentResolver resolver) { List<Channel> channels = new ArrayList<>(); // TvProvider returns programs in chronological order by default. try (Cursor cursor = resolver.query(Channels.CONTENT_URI, null, null, null, null)) { if (cursor == null || cursor.getCount() == 0) { return channels; } while (cursor.moveToNext()) { channels.add(Channel.fromCursor(cursor)); } } catch (Exception e) { Log.w(TAG, "Unable to get channels", e); } return channels; }
/** * Starts the manager. If data is ready, {@link Listener#onLoadFinished()} will be called. */ public void start() { if (mStarted) { return; } mStarted = true; // Should be called directly instead of posting MSG_UPDATE_CHANNELS message to the handler. // If not, other DB tasks can be executed before channel loading. handleUpdateChannels(); mContentResolver.registerContentObserver(TvContract.Channels.CONTENT_URI, true, mChannelObserver); mInputManager.addCallback(mTvInputCallback); }
@Override protected List<Channel> doInBackground(Void... arg) { // Load channels which doesn't have channel logos. if (DEBUG) Log.d(TAG, "Starts loading the channels from DB"); String[] projection = new String[] { Channels._ID, Channels.COLUMN_DISPLAY_NAME }; String selection = COLUMN_CHANNEL_LOGO + " IS NULL AND " + Channels.COLUMN_PACKAGE_NAME + "=?"; String[] selectionArgs = new String[] { mContext.getPackageName() }; try (Cursor c = mContext.getContentResolver().query(Channels.CONTENT_URI, projection, selection, selectionArgs, null)) { if (c == null) { Log.e(TAG, "Query returns null cursor", new RuntimeException()); return null; } List<Channel> channels = new ArrayList<>(); while (!isCancelled() && c.moveToNext()) { long channelId = c.getLong(0); if (sChannelIdBlackListSet.contains(channelId)) { continue; } channels.add(new Channel.Builder().setId(c.getLong(0)) .setDisplayName(c.getString(1).toUpperCase(Locale.getDefault())) .build()); } return channels; } }
@WorkerThread private List<SearchResult> searchChannels(String query, Set<Long> channels, int limit) { if (DEBUG) Log.d(TAG, "Searching channels: '" + query + "'"); long time = SystemClock.elapsedRealtime(); List<SearchResult> results = new ArrayList<>(); if (TextUtils.isDigitsOnly(query)) { results.addAll(searchChannels(query, new String[] { Channels.COLUMN_DISPLAY_NUMBER }, null, channels, NO_LIMIT)); if (results.size() > 1) { Collections.sort(results, new ChannelComparatorWithSameDisplayNumber()); } } if (results.size() < limit) { results.addAll(searchChannels(query, null, new String[] { Channels.COLUMN_DISPLAY_NAME, Channels.COLUMN_DESCRIPTION }, channels, limit - results.size())); } if (results.size() > limit) { results = results.subList(0, limit); } for (SearchResult result : results) { fillProgramInfo(result); } if (DEBUG) { Log.d(TAG, "Found " + results.size() + " channels. Elapsed time for searching" + " channels: " + (SystemClock.elapsedRealtime() - time) + "(msec)"); } return results; }
private static boolean isHdChannel(Channel channel) { String videoFormat = channel.getVideoFormat(); return videoFormat != null && (Channels.VIDEO_FORMAT_720P.equals(videoFormat) || Channels.VIDEO_FORMAT_1080I.equals(videoFormat) || Channels.VIDEO_FORMAT_1080P.equals(videoFormat) || Channels.VIDEO_FORMAT_2160P.equals(videoFormat) || Channels.VIDEO_FORMAT_4320P.equals(videoFormat)); }
/** * Checks if there are any available tuner channels. */ @UiThread public static boolean areChannelsAvailable(Context context) { ChannelDataManager manager = TvApplication.getSingletons(context).getChannelDataManager(); if (manager.isDbLoadFinished()) { return manager.getChannelCount() != 0; } // This method should block the UI thread. ContentResolver resolver = context.getContentResolver(); try (Cursor c = resolver.query(Channels.CONTENT_URI, new String[] {Channels._ID}, null, null, null)) { return c != null && c.getCount() != 0; } }
@WorkerThread public static String getInputIdForChannel(Context context, long channelId) { if (channelId == Channel.INVALID_ID) { return null; } Uri channelUri = TvContract.buildChannelUri(channelId); String[] projection = {TvContract.Channels.COLUMN_INPUT_ID}; try (Cursor cursor = context.getContentResolver() .query(channelUri, projection, null, null, null)) { if (cursor != null && cursor.moveToNext()) { return Utils.intern(cursor.getString(0)); } } return null; }
/** * Enable all channels synchronously. */ @WorkerThread public static void enableAllChannels(Context context) { ContentValues values = new ContentValues(); values.put(Channels.COLUMN_BROWSABLE, 1); context.getContentResolver().update(Channels.CONTENT_URI, values, null, null); }
@Override public long getLong(int columnIndex) { String columnName = getColumnName(columnIndex); switch (columnName) { case Channels._ID: return mContentProvider.keyAt(mPosition); } if (DEBUG) { Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()"); } return 0; }
public static LongSparseArray<Channel> buildChannelMap(ContentResolver resolver, String inputId, List<Channel> channels) { Uri uri = TvContract.buildChannelsUriForInput(inputId); String[] projection = { TvContract.Channels._ID, TvContract.Channels.COLUMN_DISPLAY_NUMBER }; LongSparseArray<Channel> channelMap = new LongSparseArray<>(); Cursor cursor = null; try { cursor = resolver.query(uri, projection, null, null, null); if (cursor == null || cursor.getCount() == 0) { return null; } while (cursor.moveToNext()) { long channelId = cursor.getLong(0); Log.d(TAG, "BUILD CHANNELS FOR "+channelId); String channelNumber = cursor.getString(1); channelMap.put(channelId, getChannelByNumber(channelNumber, channels)); } } catch (Exception e) { Log.d(TAG, "Content provider query: " + e.getStackTrace()); return null; } finally { if (cursor != null) { cursor.close(); } } return channelMap; }
private void processChannels() { ContentResolver resolver = getContext().getContentResolver(); deleteExistingChannels(resolver, inputId); ContentValues values = new ContentValues(); values.put(Channels.COLUMN_INPUT_ID, inputId); values.put(Channels.COLUMN_SERVICE_TYPE, Channels.SERVICE_TYPE_AUDIO_VIDEO); values.put(Channels.COLUMN_TYPE, Channels.TYPE_OTHER); values.put(Channels.COLUMN_VIDEO_FORMAT, Channels.VIDEO_FORMAT_720P); int id = 0; for (Channel channel : channels) { String title = channel.getTitle(); String url = getUrl(channel); if (url == null) { Log.d(TAG, String.format("Discarded channel [%s] because no suitable stream was found", title)); continue; } id++; values.put(Channels.COLUMN_DISPLAY_NAME, title); values.put(Channels.COLUMN_DISPLAY_NUMBER, id); values.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA, url); values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, id); values.put(Channels.COLUMN_SERVICE_ID, id); values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, id); resolver.insert(Channels.CONTENT_URI, values); } Log.d(TAG, "Added channels: " + id); }
private String convertSourceTypeToTifType(SourceType sourceType) { switch (sourceType) { case TER: return Channels.TYPE_DVB_T; case CAB: return Channels.TYPE_DVB_C; case SAT: return Channels.TYPE_DVB_S; default: return Channels.TYPE_OTHER; } }
private SourceType convertTifTypeToSourceType(String type) { switch (type) { case Channels.TYPE_DVB_T2: case Channels.TYPE_DVB_T: return SourceType.TER; case Channels.TYPE_DVB_C2: case Channels.TYPE_DVB_C: return SourceType.CAB; case Channels.TYPE_DVB_S2: case Channels.TYPE_DVB_S: return SourceType.SAT; default: return SourceType.IP; } }
private String convertServiceTypeToTifServiceType(ServiceType serviceType) { switch (serviceType) { case DIG_RAD: return Channels.SERVICE_TYPE_AUDIO; case DIG_TV: return Channels.SERVICE_TYPE_AUDIO_VIDEO; default: return Channels.SERVICE_TYPE_OTHER; } }
private ServiceType convertTifServiceTypeToServiceType(String type) { switch (type) { case Channels.SERVICE_TYPE_AUDIO_VIDEO: return ServiceType.DIG_TV; case Channels.SERVICE_TYPE_AUDIO: return ServiceType.DIG_RAD; default: return ServiceType.UNDEFINED; } }
/** * Inserts channels into TvProvider database * * @param context of a service * @param inputId this TV input service * @param channels to be inserted into a TVProvider database */ private void storeChannels(String inputId, List<ChannelDescriptor> channels) { final String[] projection = { TvContract.Channels._ID, TvContract.Channels.COLUMN_DISPLAY_NAME, TvContract.Channels.COLUMN_DISPLAY_NUMBER, }; Cursor cursor = mContext.getContentResolver().query( TvContract.buildChannelsUriForInput(mInputId), projection, null, null, null); if (cursor == null) { mLog.e("[storeChannels][cursor is null"); return; } for (ChannelDescriptor channel : channels) { Uri retUri = mContext.getContentResolver().insert( TvContract.Channels.CONTENT_URI, channel.getContentValues(inputId)); if (retUri == null) { mLog.e("[storeChannels][error adding channel to the database"); } else { channel.setId(ContentUris.parseId(retUri)); mLog.i("[storeChannels][add channel][" + channel + "]"); } } cursor.close(); }
@WorkerThread private List<SearchResult> searchChannels(String query, String[] columnForExactMatching, String[] columnForPartialMatching, Set<Long> channelsFound, int limit) { Assert.assertTrue( (columnForExactMatching != null && columnForExactMatching.length > 0) || (columnForPartialMatching != null && columnForPartialMatching.length > 0)); String[] projection = { Channels._ID, Channels.COLUMN_DISPLAY_NUMBER, Channels.COLUMN_DISPLAY_NAME, Channels.COLUMN_DESCRIPTION }; StringBuilder sb = new StringBuilder(); sb.append(Channels.COLUMN_BROWSABLE).append("=1 AND ") .append(Channels.COLUMN_SEARCHABLE).append("=1"); if (mTvInputManager.isParentalControlsEnabled()) { sb.append(" AND ").append(Channels.COLUMN_LOCKED).append("=0"); } sb.append(" AND ("); appendSelectionString(sb, columnForExactMatching, columnForPartialMatching); sb.append(")"); String selection = sb.toString(); int len = (columnForExactMatching == null ? 0 : columnForExactMatching.length) + (columnForPartialMatching == null ? 0 : columnForPartialMatching.length); String[] selectionArgs = new String[len]; insertSelectionArgumentStrings(selectionArgs, 0, query, columnForExactMatching, columnForPartialMatching); List<SearchResult> searchResults = new ArrayList<>(); try (Cursor c = mContentResolver.query(Channels.CONTENT_URI, projection, selection, selectionArgs, null)) { if (c != null) { int count = 0; while (c.moveToNext()) { long id = c.getLong(0); // Filter out the channel which has been already searched. if (channelsFound.contains(id)) { continue; } channelsFound.add(id); SearchResult result = new SearchResult(); result.channelId = id; result.channelNumber = c.getString(1); result.title = c.getString(2); result.description = c.getString(3); result.imageUri = TvContract.buildChannelLogoUri(result.channelId).toString(); result.intentAction = Intent.ACTION_VIEW; result.intentData = buildIntentData(result.channelId); result.contentType = Programs.CONTENT_ITEM_TYPE; result.isLive = true; result.progressPercentage = LocalSearchProvider.PROGRESS_PERCENTAGE_HIDE; searchResults.add(result); if (limit != NO_LIMIT && ++count >= limit) { break; } } } } return searchResults; }
private void assertChannelUri(Uri uri) { assertTrue("Uri(" + uri + ") isn't channel uri", uri.toString().startsWith(Channels.CONTENT_URI.toString())); }