1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.example.android.tvleanback.ui; 16 17 import android.app.LoaderManager; 18 import android.content.Intent; 19 import android.content.Loader; 20 import android.graphics.drawable.Drawable; 21 import android.os.Bundle; 22 import android.os.Handler; 23 import android.support.v17.leanback.app.BackgroundManager; 24 import android.support.v17.leanback.app.BrowseFragment; 25 import android.support.v17.leanback.widget.ArrayObjectAdapter; 26 import android.support.v17.leanback.widget.HeaderItem; 27 import android.support.v17.leanback.widget.ImageCardView; 28 import android.support.v17.leanback.widget.ListRow; 29 import android.support.v17.leanback.widget.ListRowPresenter; 30 import android.support.v17.leanback.widget.OnItemViewClickedListener; 31 import android.support.v17.leanback.widget.OnItemViewSelectedListener; 32 import android.support.v17.leanback.widget.Presenter; 33 import android.support.v17.leanback.widget.Row; 34 import android.support.v17.leanback.widget.RowPresenter; 35 import android.support.v4.app.ActivityOptionsCompat; 36 import android.util.DisplayMetrics; 37 import android.util.Log; 38 import android.view.View; 39 import android.widget.Toast; 40 41 42 import com.bumptech.glide.Glide; 43 import com.bumptech.glide.load.resource.drawable.GlideDrawable; 44 import com.bumptech.glide.request.animation.GlideAnimation; 45 import com.bumptech.glide.request.target.SimpleTarget; 46 47 import com.example.android.tvleanback.R; 48 import com.example.android.tvleanback.data.VideoItemLoader; 49 import com.example.android.tvleanback.data.VideoProvider; 50 import com.example.android.tvleanback.model.Movie; 51 import com.example.android.tvleanback.presenter.CardPresenter; 52 import com.example.android.tvleanback.presenter.GridItemPresenter; 53 import com.example.android.tvleanback.recommendation.UpdateRecommendationsService; 54 55 import java.net.URI; 56 import java.util.HashMap; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.Timer; 60 import java.util.TimerTask; 61 62 /* 63 * Main class to show BrowseFragment with header and rows of videos 64 */ 65 public class MainFragment extends BrowseFragment implements 66 LoaderManager.LoaderCallbacks<HashMap<String, List<Movie>>> { 67 private static final String TAG = "MainFragment"; 68 69 private static int BACKGROUND_UPDATE_DELAY = 300; 70 private static String mVideosUrl; 71 private final Handler mHandler = new Handler(); 72 private ArrayObjectAdapter mRowsAdapter; 73 private Drawable mDefaultBackground; 74 private DisplayMetrics mMetrics; 75 private Timer mBackgroundTimer; 76 private URI mBackgroundURI; 77 private BackgroundManager mBackgroundManager; 78 79 @Override 80 public void onActivityCreated(Bundle savedInstanceState) { 81 Log.d(TAG, "onCreate"); 82 super.onActivityCreated(savedInstanceState); 83 84 loadVideoData(); 85 86 prepareBackgroundManager(); 87 setupUIElements(); 88 setupEventListeners(); 89 } 90 91 @Override 92 public void onDestroy() { 93 super.onDestroy(); 94 if (null != mBackgroundTimer) { 95 Log.d(TAG, "onDestroy: " + mBackgroundTimer.toString()); 96 mBackgroundTimer.cancel(); 97 } 98 } 99 100 private void prepareBackgroundManager() { 101 mBackgroundManager = BackgroundManager.getInstance(getActivity()); 102 mBackgroundManager.attach(getActivity().getWindow()); 103 mDefaultBackground = getResources().getDrawable(R.drawable.default_background); 104 mMetrics = new DisplayMetrics(); 105 getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics); 106 } 107 108 private void setupUIElements() { 109 setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.videos_by_google_banner)); 110 setTitle(getString(R.string.browse_title)); // Badge, when set, takes precedent over title 111 setHeadersState(HEADERS_ENABLED); 112 setHeadersTransitionOnBackEnabled(true); 113 // set fastLane (or headers) background color 114 setBrandColor(getResources().getColor(R.color.fastlane_background)); 115 // set search icon color 116 setSearchAffordanceColor(getResources().getColor(R.color.search_opaque)); 117 } 118 119 private void loadVideoData() { 120 VideoProvider.setContext(getActivity()); 121 mVideosUrl = getActivity().getResources().getString(R.string.catalog_url); 122 getLoaderManager().initLoader(0, null, this); 123 } 124 125 private void setupEventListeners() { 126 setOnSearchClickedListener(new View.OnClickListener() { 127 128 @Override 129 public void onClick(View view) { 130 Intent intent = new Intent(getActivity(), SearchActivity.class); 131 startActivity(intent); 132 } 133 }); 134 135 setOnItemViewClickedListener(new ItemViewClickedListener()); 136 setOnItemViewSelectedListener(new ItemViewSelectedListener()); 137 } 138 139 /* 140 * (non-Javadoc) 141 * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader(int, 142 * android.os.Bundle) 143 */ 144 @Override 145 public Loader<HashMap<String, List<Movie>>> onCreateLoader(int arg0, Bundle arg1) { 146 Log.d(TAG, "VideoItemLoader created "); 147 return new VideoItemLoader(getActivity(), mVideosUrl); 148 } 149 150 /* 151 * (non-Javadoc) 152 * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android 153 * .support.v4.content.Loader, java.lang.Object) 154 */ 155 @Override 156 public void onLoadFinished(Loader<HashMap<String, List<Movie>>> arg0, 157 HashMap<String, List<Movie>> data) { 158 159 mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); 160 CardPresenter cardPresenter = new CardPresenter(); 161 162 int i = 0; 163 164 for (Map.Entry<String, List<Movie>> entry : data.entrySet()) { 165 ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter); 166 List<Movie> list = entry.getValue(); 167 168 for (int j = 0; j < list.size(); j++) { 169 listRowAdapter.add(list.get(j)); 170 } 171 HeaderItem header = new HeaderItem(i, entry.getKey()); 172 i++; 173 mRowsAdapter.add(new ListRow(header, listRowAdapter)); 174 } 175 176 HeaderItem gridHeader = new HeaderItem(i, getString(R.string.more_samples)); 177 178 GridItemPresenter gridPresenter = new GridItemPresenter(this); 179 ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter); 180 gridRowAdapter.add(getString(R.string.grid_view)); 181 gridRowAdapter.add(getString(R.string.error_fragment)); 182 gridRowAdapter.add(getString(R.string.personal_settings)); 183 mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter)); 184 185 setAdapter(mRowsAdapter); 186 187 updateRecommendations(); 188 } 189 190 @Override 191 public void onLoaderReset(Loader<HashMap<String, List<Movie>>> arg0) { 192 mRowsAdapter.clear(); 193 } 194 195 protected void setDefaultBackground(Drawable background) { 196 mDefaultBackground = background; 197 } 198 199 protected void setDefaultBackground(int resourceId) { 200 mDefaultBackground = getResources().getDrawable(resourceId); 201 } 202 203 protected void updateBackground(String uri) { 204 int width = mMetrics.widthPixels; 205 int height = mMetrics.heightPixels; 206 Glide.with(getActivity()) 207 .load(uri) 208 .centerCrop() 209 .error(mDefaultBackground) 210 .into(new SimpleTarget<GlideDrawable>(width, height) { 211 @Override 212 public void onResourceReady(GlideDrawable resource, 213 GlideAnimation<? super GlideDrawable> 214 glideAnimation) { 215 mBackgroundManager.setDrawable(resource); 216 } 217 }); 218 mBackgroundTimer.cancel(); 219 } 220 221 protected void updateBackground(Drawable drawable) { 222 BackgroundManager.getInstance(getActivity()).setDrawable(drawable); 223 } 224 225 protected void clearBackground() { 226 BackgroundManager.getInstance(getActivity()).setDrawable(mDefaultBackground); 227 } 228 229 private void startBackgroundTimer() { 230 if (null != mBackgroundTimer) { 231 mBackgroundTimer.cancel(); 232 } 233 mBackgroundTimer = new Timer(); 234 mBackgroundTimer.schedule(new UpdateBackgroundTask(), BACKGROUND_UPDATE_DELAY); 235 } 236 237 private void updateRecommendations() { 238 Intent recommendationIntent = new Intent(getActivity(), UpdateRecommendationsService.class); 239 getActivity().startService(recommendationIntent); 240 } 241 242 private class UpdateBackgroundTask extends TimerTask { 243 244 @Override 245 public void run() { 246 mHandler.post(new Runnable() { 247 @Override 248 public void run() { 249 if (mBackgroundURI != null) { 250 updateBackground(mBackgroundURI.toString()); 251 } 252 } 253 }); 254 } 255 } 256 257 private final class ItemViewClickedListener implements OnItemViewClickedListener { 258 @Override 259 public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, 260 RowPresenter.ViewHolder rowViewHolder, Row row) { 261 262 if (item instanceof Movie) { 263 Movie movie = (Movie) item; 264 Log.d(TAG, "Movie: " + movie.toString()); 265 Intent intent = new Intent(getActivity(), MovieDetailsActivity.class); 266 intent.putExtra(MovieDetailsActivity.MOVIE, movie); 267 268 Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation( 269 getActivity(), 270 ((ImageCardView) itemViewHolder.view).getMainImageView(), 271 MovieDetailsActivity.SHARED_ELEMENT_NAME).toBundle(); 272 getActivity().startActivity(intent, bundle); 273 } else if (item instanceof String) { 274 if (((String) item).indexOf(getString(R.string.grid_view)) >= 0) { 275 Intent intent = new Intent(getActivity(), VerticalGridActivity.class); 276 startActivity(intent); 277 } else if (((String) item).indexOf(getString(R.string.error_fragment)) >= 0) { 278 Intent intent = new Intent(getActivity(), BrowseErrorActivity.class); 279 startActivity(intent); 280 } else { 281 Toast.makeText(getActivity(), ((String) item), Toast.LENGTH_SHORT) 282 .show(); 283 } 284 } 285 } 286 } 287 288 289 private final class ItemViewSelectedListener implements OnItemViewSelectedListener { 290 @Override 291 public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, 292 RowPresenter.ViewHolder rowViewHolder, Row row) { 293 if (item instanceof Movie) { 294 mBackgroundURI = ((Movie) item).getBackgroundImageURI(); 295 startBackgroundTimer(); 296 } 297 298 } 299 } 300 } 301