• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.sampletvinput.rich;
18 
19 import android.accounts.Account;
20 import android.app.Activity;
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.SyncStatusObserver;
24 import android.graphics.Bitmap;
25 import android.graphics.drawable.Drawable;
26 import android.media.tv.TvContract;
27 import android.media.tv.TvInputInfo;
28 import android.net.Uri;
29 import android.os.AsyncTask;
30 import android.os.Bundle;
31 import android.support.v17.leanback.app.BackgroundManager;
32 import android.support.v17.leanback.app.DetailsFragment;
33 import android.support.v17.leanback.widget.Action;
34 import android.support.v17.leanback.widget.ArrayObjectAdapter;
35 import android.support.v17.leanback.widget.ClassPresenterSelector;
36 import android.support.v17.leanback.widget.DetailsOverviewRow;
37 import android.support.v17.leanback.widget.DetailsOverviewRowPresenter;
38 import android.support.v17.leanback.widget.ListRow;
39 import android.support.v17.leanback.widget.ListRowPresenter;
40 import android.support.v17.leanback.widget.OnActionClickedListener;
41 import android.util.DisplayMetrics;
42 import android.util.Log;
43 import android.widget.Toast;
44 
45 import com.example.android.sampletvinput.R;
46 import com.example.android.sampletvinput.TvContractUtils;
47 import com.example.android.sampletvinput.rich.RichTvInputService.ChannelInfo;
48 import com.example.android.sampletvinput.rich.RichTvInputService.TvInput;
49 import com.example.android.sampletvinput.syncadapter.StubAccountService;
50 import com.example.android.sampletvinput.syncadapter.SyncUtils;
51 import com.squareup.picasso.Picasso;
52 import com.squareup.picasso.Target;
53 
54 import java.io.IOException;
55 import java.util.List;
56 
57 /**
58  * Fragment which shows a sample UI for registering channels and setting up SyncAdapter to
59  * provide program information in the background.
60  */
61 public class RichSetupFragment extends DetailsFragment {
62     private static final String TAG = "SetupFragment";
63 
64     private static final int ACTION_ADD_CHANNELS = 1;
65     private static final int ACTION_CANCEL = 2;
66     private static final int ACTION_IN_PROGRESS = 3;
67 
68     private static final int DETAIL_THUMB_WIDTH = 274;
69     private static final int DETAIL_THUMB_HEIGHT = 274;
70 
71     private Drawable mDefaultBackground;
72     private Target mBackgroundTarget;
73     private DisplayMetrics mMetrics;
74     private DetailsOverviewRowPresenter mDorPresenter;
75 
76     private List<ChannelInfo> mChannels = null;
77     private TvInput mTvInput = null;
78     private String mInputId = null;
79 
80     private Action mAddChannelAction;
81     private Action mCancelAction;
82     private Action mInProgressAction;
83     private ArrayObjectAdapter mAdapter;
84     private Object mSyncObserverHandle;
85     private boolean mSyncRequested;
86 
87     @Override
onCreate(Bundle savedInstanceState)88     public void onCreate(Bundle savedInstanceState) {
89         Log.d(TAG, "onCreate SetupFragment");
90         super.onCreate(savedInstanceState);
91 
92         mInputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
93         new SetupRowTask().execute();
94     }
95 
96     @Override
onDestroy()97     public void onDestroy() {
98         super.onDestroy();
99         if (mSyncObserverHandle != null) {
100             ContentResolver.removeStatusChangeListener(mSyncObserverHandle);
101             mSyncObserverHandle = null;
102         }
103     }
104 
updateBackground(String uri)105     protected void updateBackground(String uri) {
106         BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());
107         backgroundManager.attach(getActivity().getWindow());
108         mBackgroundTarget = new PicassoBackgroundManagerTarget(backgroundManager);
109 
110         mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
111 
112         mMetrics = new DisplayMetrics();
113         getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
114 
115         Picasso.with(getActivity())
116                 .load(uri)
117                 .resize(mMetrics.widthPixels, mMetrics.heightPixels)
118                 .error(mDefaultBackground)
119                 .into(mBackgroundTarget);
120     }
121 
122     private class SetupRowTask extends AsyncTask<Uri, String, Bitmap> {
123 
124         @Override
doInBackground(Uri... params)125         protected Bitmap doInBackground(Uri... params) {
126             mChannels = RichFeedUtil.getRichChannels(getActivity());
127             mTvInput = RichFeedUtil.getTvInput(getActivity());
128             if (mTvInput != null) {
129                 return getPoster();
130             } else {
131                 publishProgress(getResources().getString(R.string.feed_error_message));
132                 return null;
133             }
134         }
135 
136         @Override
onPostExecute(Bitmap poster)137         protected void onPostExecute(Bitmap poster) {
138             if (poster != null) {
139                 addSetupChannelDetailedRow(poster);
140                 updateBackground(mTvInput.logoBackgroundUrl);
141             }
142         }
143 
onProgressUpdate(String... progress)144         protected void onProgressUpdate(String... progress) {
145             Toast.makeText(getActivity(), progress[0], Toast.LENGTH_SHORT).show();
146         }
147 
addSetupChannelDetailedRow(Bitmap poster)148         private void addSetupChannelDetailedRow(Bitmap poster) {
149             mDorPresenter = new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
150             mDorPresenter.setSharedElementEnterTransition(getActivity(), "SetUpFragment");
151 
152             mAddChannelAction = new Action(ACTION_ADD_CHANNELS, getResources().getString(
153                     R.string.rich_setup_add_channel));
154             mCancelAction = new Action(ACTION_CANCEL, getResources().getString(
155                     R.string.rich_setup_cancel));
156             mInProgressAction = new Action(ACTION_IN_PROGRESS, getResources().getString(
157                     R.string.rich_setup_in_progress));
158 
159             DetailsOverviewRow row = new DetailsOverviewRow(mTvInput);
160             row.setImageBitmap(getActivity(), poster);
161 
162             row.addAction(mAddChannelAction);
163             row.addAction(mCancelAction);
164 
165             ClassPresenterSelector presenterSelector = new ClassPresenterSelector();
166             // set detail background and style
167             mDorPresenter.setBackgroundColor(getResources().getColor(R.color.detail_background));
168             mDorPresenter.setStyleLarge(true);
169 
170             mDorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
171                 @Override
172                 public void onActionClicked(Action action) {
173                     if (action.getId() == ACTION_ADD_CHANNELS) {
174                         setupChannels(mInputId);
175                     } else if (action.getId() == ACTION_CANCEL) {
176                         getActivity().finish();
177                     }
178                 }
179             });
180 
181             presenterSelector.addClassPresenter(DetailsOverviewRow.class, mDorPresenter);
182             presenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
183             mAdapter = new ArrayObjectAdapter(presenterSelector);
184             mAdapter.add(row);
185 
186             setAdapter(mAdapter);
187         }
188 
getPoster()189         private Bitmap getPoster() {
190             try {
191                 Bitmap poster = Picasso.with(getActivity())
192                         .load(mTvInput.logoBackgroundUrl)
193                         .resize(convertDpToPixel(getActivity()
194                                         .getApplicationContext(), DETAIL_THUMB_WIDTH),
195                                 convertDpToPixel(getActivity()
196                                         .getApplicationContext(), DETAIL_THUMB_HEIGHT))
197                         .centerCrop()
198                         .get();
199                 return poster;
200             } catch (IOException e) {
201                 Log.e(TAG, e.toString());
202                 return null;
203             }
204         }
205     }
206 
setupChannels(String inputId)207     private void setupChannels(String inputId) {
208         if (mChannels == null) {
209             return;
210         }
211         TvContractUtils.updateChannels(getActivity(), inputId, mChannels);
212         SyncUtils.setUpPeriodicSync(getActivity(), inputId);
213         SyncUtils.requestSync(inputId);
214         mSyncRequested = true;
215         // Watch for sync state changes
216         if (mSyncObserverHandle == null) {
217             final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
218                     ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
219             mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask,
220                     mSyncStatusObserver);
221         }
222     }
223 
convertDpToPixel(Context ctx, int dp)224     private int convertDpToPixel(Context ctx, int dp) {
225         float density = ctx.getResources().getDisplayMetrics().density;
226         return Math.round((float) dp * density);
227     }
228 
229     private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {
230         private boolean mSyncServiceStarted;
231         private boolean mFinished;
232 
233         @Override
234         public void onStatusChanged(int which) {
235             getActivity().runOnUiThread(new Runnable() {
236                 @Override
237                 public void run() {
238                     if (mFinished) {
239                         return;
240                     }
241                     Account account = StubAccountService.getAccount(SyncUtils.ACCOUNT_TYPE);
242                     boolean syncActive = ContentResolver.isSyncActive(account,
243                             TvContract.AUTHORITY);
244                     boolean syncPending = ContentResolver.isSyncPending(account,
245                             TvContract.AUTHORITY);
246                     boolean syncServiceInProgress = syncActive || syncPending;
247                     if (mSyncRequested && mSyncServiceStarted && !syncServiceInProgress) {
248                         getActivity().setResult(Activity.RESULT_OK);
249                         getActivity().finish();
250                         mFinished = true;
251                     }
252                     if (!mSyncServiceStarted && syncServiceInProgress) {
253                         mSyncServiceStarted = syncServiceInProgress;
254                         DetailsOverviewRow detailRow = (DetailsOverviewRow) mAdapter.get(0);
255                         detailRow.removeAction(mAddChannelAction);
256                         detailRow.addAction(0, mInProgressAction);
257                         mAdapter.notifyArrayItemRangeChanged(0, 1);
258                     }
259                 }
260             });
261         }
262     };
263 }
264