• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.android.tv.menu;
18 
19 import android.content.Context;
20 import android.os.Handler;
21 import android.os.Looper;
22 import android.os.Message;
23 import android.support.annotation.MainThread;
24 import android.support.annotation.NonNull;
25 import android.util.Log;
26 import com.android.tv.R;
27 import com.android.tv.common.SoftPreconditions;
28 import com.android.tv.common.WeakHandler;
29 import com.android.tv.data.ChannelImpl;
30 import com.android.tv.data.Program;
31 import com.android.tv.data.ProgramDataManager;
32 import com.android.tv.data.api.Channel;
33 import java.util.List;
34 
35 /** A poster image prefetcher to show the program poster art in the Channels row faster. */
36 public class ChannelsPosterPrefetcher {
37     private static final String TAG = "PosterPrefetcher";
38     private static final boolean DEBUG = false;
39     private static final int MSG_PREFETCH_IMAGE = 1000;
40     private static final int ONDEMAND_POSTER_PREFETCH_DELAY_MILLIS = 500; // 500 milliseconds
41 
42     private final ProgramDataManager mProgramDataManager;
43     private final ChannelsRowAdapter mChannelsAdapter;
44     private final int mPosterArtWidth;
45     private final int mPosterArtHeight;
46     private final Context mContext;
47     private final Handler mHandler = new PrefetchHandler(this);
48 
49     private boolean isCanceled;
50 
51     /** Create {@link ChannelsPosterPrefetcher} object with given parameters. */
ChannelsPosterPrefetcher( Context context, ProgramDataManager programDataManager, ChannelsRowAdapter adapter)52     public ChannelsPosterPrefetcher(
53             Context context, ProgramDataManager programDataManager, ChannelsRowAdapter adapter) {
54         mProgramDataManager = programDataManager;
55         mChannelsAdapter = adapter;
56         mPosterArtWidth =
57                 context.getResources().getDimensionPixelSize(R.dimen.card_image_layout_width);
58         mPosterArtHeight =
59                 context.getResources().getDimensionPixelSize(R.dimen.card_image_layout_height);
60         mContext = context.getApplicationContext();
61     }
62 
63     /** Start prefetching of program poster art of recommendation. */
prefetch()64     public void prefetch() {
65         SoftPreconditions.checkState(!isCanceled, TAG, "Prefetch called after cancel was called.");
66         if (isCanceled) {
67             return;
68         }
69         if (DEBUG) Log.d(TAG, "startPrefetching()");
70         /*
71          * When a user browse channels, this method could be called many times. We don't need to
72          * prefetch the intermediate channels. So ignore previous schedule.
73          */
74         mHandler.removeMessages(MSG_PREFETCH_IMAGE);
75         mHandler.sendMessageDelayed(
76                 mHandler.obtainMessage(MSG_PREFETCH_IMAGE), ONDEMAND_POSTER_PREFETCH_DELAY_MILLIS);
77     }
78 
79     /** Cancels pending and current prefetch requests. */
cancel()80     public void cancel() {
81         isCanceled = true;
82         mHandler.removeCallbacksAndMessages(null);
83     }
84 
85     @MainThread // ProgramDataManager.getCurrentProgram must be called from the main thread
doPrefetchImages()86     private void doPrefetchImages() {
87         if (DEBUG) Log.d(TAG, "doPrefetchImages() started");
88 
89         // This executes on the main thread, but since the item list is expected to be about 5 items
90         // and ImageLoader spawns an async task so this is fast enough. 1 ms in local testing.
91         List<ChannelsRowItem> items = mChannelsAdapter.getItemList();
92         if (items != null) {
93             for (ChannelsRowItem item : items) {
94                 if (isCanceled) {
95                     return;
96                 }
97                 Channel channel = item.getChannel();
98                 if (!ChannelImpl.isValid(channel)) {
99                     continue;
100                 }
101                 channel.prefetchImage(
102                         mContext,
103                         Channel.LOAD_IMAGE_TYPE_CHANNEL_LOGO,
104                         mPosterArtWidth,
105                         mPosterArtHeight);
106                 Program program = mProgramDataManager.getCurrentProgram(channel.getId());
107                 if (program != null) {
108                     program.prefetchPosterArt(mContext, mPosterArtWidth, mPosterArtHeight);
109                 }
110             }
111         }
112         if (DEBUG) {
113             Log.d(
114                     TAG,
115                     "doPrefetchImages() finished. ImageLoader may still have async tasks for "
116                             + "channels "
117                             + items);
118         }
119     }
120 
121     private static class PrefetchHandler extends WeakHandler<ChannelsPosterPrefetcher> {
PrefetchHandler(ChannelsPosterPrefetcher ref)122         public PrefetchHandler(ChannelsPosterPrefetcher ref) {
123             // doPrefetchImages must be called from the main thread.
124             super(Looper.getMainLooper(), ref);
125         }
126 
127         @Override
128         @MainThread
handleMessage(Message msg, @NonNull ChannelsPosterPrefetcher prefetcher)129         public void handleMessage(Message msg, @NonNull ChannelsPosterPrefetcher prefetcher) {
130             switch (msg.what) {
131                 case MSG_PREFETCH_IMAGE:
132                     prefetcher.doPrefetchImages();
133                     break;
134             }
135         }
136     }
137 }
138