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.leanback; 16 17 import android.app.LoaderManager; 18 import android.content.Intent; 19 import android.content.Loader; 20 import android.graphics.Color; 21 import android.graphics.drawable.Drawable; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.support.v17.leanback.app.BackgroundManager; 25 import android.support.v17.leanback.app.BrowseFragment; 26 import android.support.v17.leanback.widget.ArrayObjectAdapter; 27 import android.support.v17.leanback.widget.HeaderItem; 28 import android.support.v17.leanback.widget.ListRow; 29 import android.support.v17.leanback.widget.ListRowPresenter; 30 import android.support.v17.leanback.widget.OnItemClickedListener; 31 import android.support.v17.leanback.widget.OnItemSelectedListener; 32 import android.support.v17.leanback.widget.Presenter; 33 import android.support.v17.leanback.widget.Row; 34 import android.util.DisplayMetrics; 35 import android.util.Log; 36 import android.view.Gravity; 37 import android.view.View; 38 import android.view.ViewGroup; 39 import android.widget.TextView; 40 import android.widget.Toast; 41 42 import com.squareup.picasso.Picasso; 43 import com.squareup.picasso.Target; 44 45 import java.net.URI; 46 import java.util.*; 47 48 /* 49 * Main class to show BrowseFragment with header and rows of videos 50 */ 51 public class MainFragment extends BrowseFragment implements 52 LoaderManager.LoaderCallbacks<HashMap<String, List<Movie>>> { 53 private static final String TAG = "MainFragment"; 54 55 private static int BACKGROUND_UPDATE_DELAY = 300; 56 private static int GRID_ITEM_WIDTH = 200; 57 private static int GRID_ITEM_HEIGHT = 200; 58 59 private ArrayObjectAdapter mRowsAdapter; 60 private Drawable mDefaultBackground; 61 private Target mBackgroundTarget; 62 private DisplayMetrics mMetrics; 63 private Timer mBackgroundTimer; 64 private final Handler mHandler = new Handler(); 65 private URI mBackgroundURI; 66 private static String mVideosUrl; 67 68 @Override onActivityCreated(Bundle savedInstanceState)69 public void onActivityCreated(Bundle savedInstanceState) { 70 Log.i(TAG, "onCreate"); 71 super.onActivityCreated(savedInstanceState); 72 73 loadVideoData(); 74 75 prepareBackgroundManager(); 76 setupUIElements(); 77 setupEventListeners(); 78 } 79 prepareBackgroundManager()80 private void prepareBackgroundManager() { 81 BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity()); 82 backgroundManager.attach(getActivity().getWindow()); 83 mBackgroundTarget = new PicassoBackgroundManagerTarget(backgroundManager); 84 mDefaultBackground = getResources().getDrawable(R.drawable.default_background); 85 mMetrics = new DisplayMetrics(); 86 getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics); 87 } 88 setupUIElements()89 private void setupUIElements() { 90 // setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.videos_by_google_banner)); 91 setTitle(getString(R.string.browse_title)); // Badge, when set, takes precedent over title 92 setHeadersState(HEADERS_ENABLED); 93 setHeadersTransitionOnBackEnabled(true); 94 // set fastLane (or headers) background color 95 setBrandColor(getResources().getColor(R.color.fastlane_background)); 96 // set search icon color 97 setSearchAffordanceColor(getResources().getColor(R.color.search_opaque)); 98 } 99 loadVideoData()100 private void loadVideoData() { 101 VideoProvider.setContext(getActivity()); 102 mVideosUrl = getActivity().getResources().getString(R.string.catalog_url); 103 getLoaderManager().initLoader(0, null, this); 104 } 105 setupEventListeners()106 private void setupEventListeners() { 107 setOnSearchClickedListener(new View.OnClickListener() { 108 109 @Override 110 public void onClick(View view) { 111 Intent intent = new Intent(getActivity(), SearchActivity.class); 112 startActivity(intent); 113 } 114 }); 115 116 setOnItemSelectedListener(getDefaultItemSelectedListener()); 117 setOnItemClickedListener(getDefaultItemClickedListener()); 118 } 119 120 /* 121 * (non-Javadoc) 122 * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader(int, 123 * android.os.Bundle) 124 */ 125 @Override onCreateLoader(int arg0, Bundle arg1)126 public Loader<HashMap<String, List<Movie>>> onCreateLoader(int arg0, Bundle arg1) { 127 Log.d(TAG, "VideoItemLoader created "); 128 return new VideoItemLoader(getActivity(), mVideosUrl); 129 } 130 131 /* 132 * (non-Javadoc) 133 * @see android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android 134 * .support.v4.content.Loader, java.lang.Object) 135 */ 136 @Override onLoadFinished(Loader<HashMap<String, List<Movie>>> arg0, HashMap<String, List<Movie>> data)137 public void onLoadFinished(Loader<HashMap<String, List<Movie>>> arg0, 138 HashMap<String, List<Movie>> data) { 139 140 mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); 141 CardPresenter cardPresenter = new CardPresenter(); 142 143 int i = 0; 144 145 for (Map.Entry<String, List<Movie>> entry : data.entrySet()) 146 { 147 ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter); 148 List<Movie> list = entry.getValue(); 149 150 for (int j = 0; j < list.size(); j++) { 151 listRowAdapter.add(list.get(j)); 152 } 153 HeaderItem header = new HeaderItem(i, entry.getKey(), null); 154 i++; 155 mRowsAdapter.add(new ListRow(header, listRowAdapter)); 156 } 157 158 HeaderItem gridHeader = new HeaderItem(i, getResources().getString(R.string.preferences), 159 null); 160 161 GridItemPresenter gridPresenter = new GridItemPresenter(); 162 ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter); 163 gridRowAdapter.add(getResources().getString(R.string.grid_view)); 164 gridRowAdapter.add(getResources().getString(R.string.send_feeback)); 165 gridRowAdapter.add(getResources().getString(R.string.personal_settings)); 166 mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter)); 167 168 setAdapter(mRowsAdapter); 169 170 updateRecommendations(); 171 } 172 173 @Override onLoaderReset(Loader<HashMap<String, List<Movie>>> arg0)174 public void onLoaderReset(Loader<HashMap<String, List<Movie>>> arg0) { 175 mRowsAdapter.clear(); 176 } 177 getDefaultItemSelectedListener()178 protected OnItemSelectedListener getDefaultItemSelectedListener() { 179 return new OnItemSelectedListener() { 180 @Override 181 public void onItemSelected(Object item, Row row) { 182 if (item instanceof Movie) { 183 mBackgroundURI = ((Movie) item).getBackgroundImageURI(); 184 startBackgroundTimer(); 185 } 186 } 187 }; 188 } 189 190 protected OnItemClickedListener getDefaultItemClickedListener() { 191 return new OnItemClickedListener() { 192 @Override 193 public void onItemClicked(Object item, Row row) { 194 if (item instanceof Movie) { 195 Movie movie = (Movie) item; 196 Log.d(TAG, "Item: " + item.toString()); 197 Intent intent = new Intent(getActivity(), DetailsActivity.class); 198 intent.putExtra(getString(R.string.movie), movie); 199 startActivity(intent); 200 } 201 else if (item instanceof String) { 202 if (((String) item).indexOf(getResources().getString(R.string.grid_view)) >= 0) { 203 Intent intent = new Intent(getActivity(), VerticalGridActivity.class); 204 startActivity(intent); 205 } 206 else { 207 Toast.makeText(getActivity(), ((String) item), Toast.LENGTH_SHORT) 208 .show(); 209 } 210 } 211 212 } 213 }; 214 } 215 216 protected void setDefaultBackground(Drawable background) { 217 mDefaultBackground = background; 218 } 219 220 protected void setDefaultBackground(int resourceId) { 221 mDefaultBackground = getResources().getDrawable(resourceId); 222 } 223 224 protected void updateBackground(URI uri) { 225 Picasso.with(getActivity()) 226 .load(uri.toString()) 227 .resize(mMetrics.widthPixels, mMetrics.heightPixels) 228 .centerCrop() 229 .error(mDefaultBackground) 230 .into(mBackgroundTarget); 231 } 232 233 protected void updateBackground(Drawable drawable) { 234 BackgroundManager.getInstance(getActivity()).setDrawable(drawable); 235 } 236 237 protected void clearBackground() { 238 BackgroundManager.getInstance(getActivity()).setDrawable(mDefaultBackground); 239 } 240 241 private void startBackgroundTimer() { 242 if (null != mBackgroundTimer) { 243 mBackgroundTimer.cancel(); 244 } 245 mBackgroundTimer = new Timer(); 246 mBackgroundTimer.schedule(new UpdateBackgroundTask(), BACKGROUND_UPDATE_DELAY); 247 } 248 249 private class UpdateBackgroundTask extends TimerTask { 250 251 @Override 252 public void run() { 253 mHandler.post(new Runnable() { 254 @Override 255 public void run() { 256 if (mBackgroundURI != null) { 257 updateBackground(mBackgroundURI); 258 } 259 } 260 }); 261 } 262 } 263 264 private class GridItemPresenter extends Presenter { 265 @Override 266 public ViewHolder onCreateViewHolder(ViewGroup parent) { 267 TextView view = new TextView(parent.getContext()); 268 view.setLayoutParams(new ViewGroup.LayoutParams(GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT)); 269 view.setFocusable(true); 270 view.setFocusableInTouchMode(true); 271 view.setBackgroundColor(getResources().getColor(R.color.default_background)); 272 view.setTextColor(Color.WHITE); 273 view.setGravity(Gravity.CENTER); 274 return new ViewHolder(view); 275 } 276 277 @Override 278 public void onBindViewHolder(ViewHolder viewHolder, Object item) { 279 ((TextView) viewHolder.view).setText((String) item); 280 } 281 282 @Override 283 public void onUnbindViewHolder(ViewHolder viewHolder) { 284 } 285 } 286 287 private void updateRecommendations() { 288 Intent recommendationIntent = new Intent(getActivity(), UpdateRecommendationsService.class); 289 getActivity().startService(recommendationIntent); 290 } 291 } 292