Home | History | Annotate | Download | only in rich
      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.DummyAccountService;
     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
     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
     97     public void onDestroy() {
     98         super.onDestroy();
     99         if (mSyncObserverHandle != null) {
    100             ContentResolver.removeStatusChangeListener(mSyncObserverHandle);
    101             mSyncObserverHandle = null;
    102         }
    103     }
    104 
    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
    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
    137         protected void onPostExecute(Bitmap poster) {
    138             if (poster != null) {
    139                 addSetupChannelDetailedRow(poster);
    140                 updateBackground(mTvInput.logoBackgroundUrl);
    141             }
    142         }
    143 
    144         protected void onProgressUpdate(String... progress) {
    145             Toast.makeText(getActivity(), progress[0], Toast.LENGTH_SHORT).show();
    146         }
    147 
    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 
    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 
    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 
    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 = DummyAccountService.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