Download File
Download Project
Settings
Line Wrap
Themes
default
ambiance
bespin
dracula
eclipse
material
mbo
mdn-like
neat
solarized dark
ttcn
zenburn
ChannelContents.java
/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v17.leanback.supportleanbackshowcase.app.rows; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.tv.TvContract; import android.net.Uri; import android.os.AsyncTask; import android.support.annotation.DrawableRes; import android.support.media.tv.Channel; import android.support.media.tv.ChannelLogoUtils; import android.support.media.tv.PreviewProgram; import android.support.media.tv.TvContractCompat; import android.support.v17.leanback.supportleanbackshowcase.R; import android.support.v17.leanback.supportleanbackshowcase.utils.Utils; import android.util.Log; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class is mainly used for the channel which has been added to the main-screen */ public final class ChannelContents { /** * All video resource inside this channel */ @SerializedName("videos") private List
mVideos; /** * A unique ID for different channels * This is channel is mainly for internal use, and won't be changed */ @SerializedName("channelId") private String mChannelContentsId; /** * The channel name shown in the main screen after adding it */ @SerializedName("category") private String mName; /** * The channel's description shown in the main screen after adding it */ private final String mDescription = "Demo To Show how to add channel from App to main screen"; /** * Is current channel published or not * This is the symbol to toggle add/ remove behavior */ private boolean mChannelPublished; /** * This ID is to identify the channel which has been added to main screen */ private long mChannelId; /** * This HashMap will keep the mapping relationship between * channel's publish ID (will be changed in different transaction) and * channel's actual content * * It is designed to toggle channel content's publish status */ private static final Map
sLookupTable = new HashMap<>(); /* package */ String getName() { return mName; } /* package */ List
getVideos() { return mVideos; } /* package */ String getDescription() { return mDescription; } /* package */String getChannelContentsId() { return mChannelContentsId; } /* package */boolean isChannelPublished() { return mChannelPublished; } /* package */void setChannelPublishedId(long id) { mChannelPublished = true; mChannelId = id; } /* package */void setChannelUnPublished() { mChannelPublished = false; } /* package */long getChannelId() { return mChannelId; } /* package */ static List
sChannelContents; /* package */ static void initializePlaylists(Context context) { if (sChannelContents == null) { sChannelContents = new ArrayList<>(); String json = Utils.inputStreamToString( context.getResources().openRawResource(R.raw.movie)); /** * Populate playlist from json file */ ChannelContents[] channels = new Gson().fromJson(json, ChannelContents[].class); for (int i = 0; i < channels.length; i++) { sChannelContents.add(channels[i]); } } } /** * Async Task to remove channel from home screen */ public static final class RemoveChannelInMainScreen extends AsyncTask
{ private static final String TAG = "RemoveChannelInMainScreen"; /** * Executor must provide context and Listener so to execute LoadAddedChannels task */ private Context mContext; public RemoveChannelInMainScreen(Context context) { mContext = context; } /** * Helper function to remove the channel from content provider, so it will * not be shown in home screen * * @param context used to resolve content provider * @param channelId the publish ID which is assigned by last adding transaction */ private void deleteChannel(Context context, long channelId) { Log.e(TAG, "deleteChannel: " + channelId ); sLookupTable.get(channelId).setChannelUnPublished(); int rowsDeleted = context.getContentResolver().delete( TvContractCompat.buildChannelUri(channelId), null, null); if (rowsDeleted < 1) { Log.e(TAG, "Delete channel failed"); } } @Override protected Void doInBackground(ChannelContents... params) { ChannelContents playlist = params[0]; deleteChannel(mContext, playlist.getChannelId()); return null; } } /** * Async Task to add channel to main screen/ remove channel from main screen */ public static final class CreateChannelInMainScreen extends AsyncTask
{ private static final String TAG = "CreateChannelInMainScreen"; private static final String SCHEME = "rowsnewapi"; private static final String PACKAGE_NAME = "android.support.v17.leanback.supportleanbackshowcase"; private static final String VIDEO_PLAY_ACTIVITY = "playvideo"; private static final String MAIN_ACTIVITY = "startapp"; public static final String CONTENT_ANDROID_MEDIA_TV_PREVIEW_PROGRAM = "content://android.media.tv/preview_program"; // this object is used ot call startActivityForResult method from this Async Task private Activity mActivity; private static final int ADD_CHANNEL_REQUEST = 1; public CreateChannelInMainScreen(Activity context) { mActivity = context; } /** * Channel Logo for published program */ private void createChannelLogo(Context context, long channelId, @DrawableRes int drawableId) { Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), drawableId); ChannelLogoUtils.storeChannelLogo(context, channelId, bitmap); } /** * The input Id is necessary so user can use the program in home screen to go back to this * application */ private String createInputId(Context context) { ComponentName cName = new ComponentName(context, DynamicVideoRowsActivity.class.getName()); return TvContractCompat.buildInputId(cName); } /** * A transaction id will be assigned to the added channel */ private Long addChannel(Context context, ChannelContents channelContents) { // This ID is associated with current context String channelInputId = createInputId(context); Channel channel = new Channel.Builder() .setDisplayName(channelContents.getName()) .setDescription(channelContents.getDescription()) .setType(TvContractCompat.Channels.TYPE_PREVIEW) .setInputId(channelInputId) .setAppLinkIntentUri(Uri.parse(SCHEME + "://" + PACKAGE_NAME + "/" + MAIN_ACTIVITY)) .setInternalProviderId(channelContents.getChannelContentsId()) .build(); /** * The interaction between current app and launcher interface is through ContentProvider * All the published data should be inserted into content provider */ Uri channelUri = context.getContentResolver().insert(TvContractCompat.Channels.CONTENT_URI, channel.toContentValues()); if (channelUri == null || channelUri.equals(Uri.EMPTY)) { Log.e(TAG, "Insert channel failed"); /** * If the task is failed return null as a signal for error handling */ return null; } long channelId = ContentUris.parseId(channelUri); sLookupTable.put(channelId, channelContents); channelContents.setChannelPublishedId(channelId); createChannelLogo(context, channelId, R.drawable.row_app_icon); List
videos = channelContents.getVideos(); int weight = videos.size(); for (int i = 0; i < videos.size(); ++i, --weight) { VideoContent clip = videos.get(i); final String clipId = clip.getVideoId(); /** * Enable preview feature for the video added to the home screen */ PreviewProgram program = new PreviewProgram.Builder() .setChannelId(channelId) .setTitle(clip.getTitle()) .setDescription(clip.getDescription()) .setPosterArtUri(Uri.parse(clip.getCardImageUrl())) .setIntentUri(Uri.parse(SCHEME + "://" + PACKAGE_NAME + "/" + VIDEO_PLAY_ACTIVITY + "/" + clipId)) .setPreviewVideoUri(Uri.parse(clip.getPreviewVideoUrl())) .setInternalProviderId(clipId) .setWeight(weight) .setPosterArtAspectRatio(clip.getAspectRatio()) .setType(TvContractCompat.PreviewPrograms.TYPE_MOVIE) .build(); Uri preview_uri = Uri.parse(CONTENT_ANDROID_MEDIA_TV_PREVIEW_PROGRAM); Uri programUri = context.getContentResolver().insert(preview_uri, program.toContentValues()); if (programUri == null || programUri.equals(Uri.EMPTY)) { Log.e(TAG, "Insert program failed"); } else { clip.setProgramId(ContentUris.parseId(programUri)); } } return channelId; } @Override protected Long doInBackground(ChannelContents... params) { return addChannel(mActivity, params[0]); } @Override protected void onPostExecute(Long channelId) { if (channelId == null) { Log.e(TAG, "Failed to add channel on home screen"); return; } Intent intent = new Intent(TvContract.ACTION_REQUEST_CHANNEL_BROWSABLE); intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId); try { mActivity.startActivityForResult(intent, ADD_CHANNEL_REQUEST); } catch (ActivityNotFoundException e) { Log.e(TAG, "could not start add channel approval UI", e); } } } }