diff options
author | Nick Chalko <nchalko@google.com> | 2015-09-01 09:05:04 -0700 |
---|---|---|
committer | Nick Chalko <nchalko@google.com> | 2015-09-16 06:46:50 -0700 |
commit | 07b043dc3db83d6d20f0e8513b946830ab00e37b (patch) | |
tree | 705ade719e5c2853c070fe40b8518a56ac37f6d0 /src/com/android/tv/recommendation | |
parent | b5429e4406a580953bbdac5817e421cf0ab7aae3 (diff) | |
download | TV-07b043dc3db83d6d20f0e8513b946830ab00e37b.tar.gz |
Sync to ub-tv-friends at 1.06.202
git hash 3c1965f5dcc60243f1fe600cb35f19bd5f01fc27
Change-Id: I90b77790f9074677ecef72a23235d2b33eacb76a
Diffstat (limited to 'src/com/android/tv/recommendation')
3 files changed, 158 insertions, 113 deletions
diff --git a/src/com/android/tv/recommendation/NotificationService.java b/src/com/android/tv/recommendation/NotificationService.java index 00cad116..835a3e53 100644 --- a/src/com/android/tv/recommendation/NotificationService.java +++ b/src/com/android/tv/recommendation/NotificationService.java @@ -31,13 +31,17 @@ import android.media.tv.TvInputInfo; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; import android.os.Message; +import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import android.util.SparseLongArray; import android.view.View; import com.android.tv.R; +import com.android.tv.TvApplication; +import com.android.tv.common.WeakHandler; import com.android.tv.data.Channel; import com.android.tv.data.Program; import com.android.tv.util.BitmapUtils; @@ -59,8 +63,13 @@ public class NotificationService extends Service implements Recommender.Listener public static final String ACTION_HIDE_RECOMMENDATION = "com.android.tv.notification.ACTION_HIDE_RECOMMENDATION"; - private static final String TUNE_PARAMS_RECOMMENDATION_TYPE = + /** + * Recommendation intent has an extra data for the recommendation type. It'll be also + * sent to a TV input as a tune parameter. + */ + public static final String TUNE_PARAMS_RECOMMENDATION_TYPE = "com.android.tv.recommendation_type"; + private static final String TYPE_RANDOM_RECOMMENDATION = "random"; private static final String TYPE_ROUTINE_WATCH_RECOMMENDATION = "routine_watch"; private static final String TYPE_ROUTINE_WATCH_AND_FAVORITE_CHANNEL_RECOMMENDATION = @@ -132,66 +141,52 @@ public class NotificationService extends Service implements Recommender.Listener getResources().getDimensionPixelOffset(R.dimen.notif_ch_logo_padding_bottom); mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - mTvInputManagerHelper = new TvInputManagerHelper(this); - mTvInputManagerHelper.start(); - + mTvInputManagerHelper = ((TvApplication) getApplicationContext()).getTvInputManagerHelper(); mHandlerThread = new HandlerThread("tv notification"); mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_INITIALIZE_RECOMMENDER: { - mRecommender = new Recommender( - NotificationService.this, NotificationService.this, true); - if (TYPE_RANDOM_RECOMMENDATION.equals(mRecommendationType)) { - mRecommender.registerEvaluator(new RandomEvaluator()); - } else if (TYPE_ROUTINE_WATCH_RECOMMENDATION.equals(mRecommendationType)) { - mRecommender.registerEvaluator(new RoutineWatchEvaluator()); - } else if (TYPE_ROUTINE_WATCH_AND_FAVORITE_CHANNEL_RECOMMENDATION.equals( - mRecommendationType)) { - mRecommender.registerEvaluator( - new FavoriteChannelEvaluator(), 0.5, 0.5); - mRecommender.registerEvaluator(new RoutineWatchEvaluator(), 1.0, 1.0); - } else { - throw new IllegalStateException("Undefined recommendation type: " - + mRecommendationType); - } - } - case MSG_SHOW_RECOMMENDATION: { - if (!mRecommender.isReady()) { - mShowRecommendationAfterRecommenderReady = true; - } else { - showRecommendation(); - } - break; - } - case MSG_UPDATE_RECOMMENDATION: { - int notificationId = msg.arg1; - Channel channel = ((Channel) msg.obj); - if (mNotificationChannels[notificationId] == Channel.INVALID_ID - || !sendNotification(channel.getId(), notificationId)) { - changeRecommendation(notificationId); - } - break; - } - case MSG_HIDE_RECOMMENDATION: { - if (!mRecommender.isReady()) { - mShowRecommendationAfterRecommenderReady = false; - } else { - hideAllRecommendation(); - } - break; - } - default: { - super.handleMessage(msg); - } - } - } - }; + mHandler = new NotificationHandler(mHandlerThread.getLooper(), this); mHandler.sendEmptyMessage(MSG_INITIALIZE_RECOMMENDER); } + private void handleInitializeRecommender() { + mRecommender = new Recommender(NotificationService.this, NotificationService.this, true); + if (TYPE_RANDOM_RECOMMENDATION.equals(mRecommendationType)) { + mRecommender.registerEvaluator(new RandomEvaluator()); + } else if (TYPE_ROUTINE_WATCH_RECOMMENDATION.equals(mRecommendationType)) { + mRecommender.registerEvaluator(new RoutineWatchEvaluator()); + } else if (TYPE_ROUTINE_WATCH_AND_FAVORITE_CHANNEL_RECOMMENDATION + .equals(mRecommendationType)) { + mRecommender.registerEvaluator(new FavoriteChannelEvaluator(), 0.5, 0.5); + mRecommender.registerEvaluator(new RoutineWatchEvaluator(), 1.0, 1.0); + } else { + throw new IllegalStateException( + "Undefined recommendation type: " + mRecommendationType); + } + } + + private void handleShowRecommendation() { + if (!mRecommender.isReady()) { + mShowRecommendationAfterRecommenderReady = true; + } else { + showRecommendation(); + } + } + + private void handleUpdateRecommendation(int notificationId, Channel channel) { + if (mNotificationChannels[notificationId] == Channel.INVALID_ID || !sendNotification( + channel.getId(), notificationId)) { + changeRecommendation(notificationId); + } + } + + private void handleHideRecommendation() { + if (!mRecommender.isReady()) { + mShowRecommendationAfterRecommenderReady = false; + } else { + hideAllRecommendation(); + } + } + @Override public void onDestroy() { mRecommender.release(); @@ -456,4 +451,37 @@ public class NotificationService extends Service implements Recommender.Listener } return -1; } + + private static class NotificationHandler extends WeakHandler<NotificationService> { + public NotificationHandler(@NonNull Looper looper, NotificationService ref) { + super(looper, ref); + } + + @Override + public void handleMessage(Message msg, @NonNull NotificationService notificationService) { + switch (msg.what) { + case MSG_INITIALIZE_RECOMMENDER: { + notificationService.handleInitializeRecommender(); + break; + } + case MSG_SHOW_RECOMMENDATION: { + notificationService.handleShowRecommendation(); + break; + } + case MSG_UPDATE_RECOMMENDATION: { + int notificationId = msg.arg1; + Channel channel = ((Channel) msg.obj); + notificationService.handleUpdateRecommendation(notificationId, channel); + break; + } + case MSG_HIDE_RECOMMENDATION: { + notificationService.handleHideRecommendation(); + break; + } + default: { + super.handleMessage(msg); + } + } + } + } } diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java index 2445cce8..0f59e2bd 100644 --- a/src/com/android/tv/recommendation/RecommendationDataManager.java +++ b/src/com/android/tv/recommendation/RecommendationDataManager.java @@ -28,9 +28,12 @@ import android.media.tv.TvInputManager.TvInputCallback; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; +import android.os.Looper; import android.os.Message; import android.support.annotation.NonNull; +import android.support.annotation.WorkerThread; +import com.android.tv.common.WeakHandler; import com.android.tv.data.Channel; import com.android.tv.data.Program; @@ -71,11 +74,12 @@ public class RecommendationDataManager { private static final int INVALID_INDEX = -1; private static RecommendationDataManager sManager; + private final static Object sListenerLock = new Object(); private final ContentObserver mContentObserver; private final Map<Long, ChannelRecord> mChannelRecordMap = new ConcurrentHashMap<>(); private final Map<Long, ChannelRecord> mAvailableChannelRecordMap = new ConcurrentHashMap<>(); - private Context mContext; + private final Context mContext; private boolean mStarted; private boolean mCancelLoadTask; private boolean mChannelRecordMapLoaded; @@ -90,7 +94,6 @@ public class RecommendationDataManager { private final HandlerThread mHandlerThread; - @SuppressWarnings("unchecked") private final Handler mHandler; private final List<ListenerRecord> mListeners = new ArrayList<>(); @@ -117,7 +120,7 @@ public class RecommendationDataManager { */ public void release(@NonNull Listener listener) { removeListener(listener); - synchronized (mListeners) { + synchronized (sListenerLock) { if (mListeners.size() == 0) { stop(); } @@ -183,46 +186,7 @@ public class RecommendationDataManager { mContext = context.getApplicationContext(); mHandlerThread = new HandlerThread("RecommendationDataManager"); mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_START: - onStart(); - break; - case MSG_STOP: - if (mStarted) { - onStop(); - } - break; - case MSG_UPDATE_CHANNEL: - if (mStarted) { - onUpdateChannel((Uri) msg.obj); - } - break; - case MSG_UPDATE_CHANNELS: - if (mStarted) { - onUpdateChannels((Uri) msg.obj); - } - break; - case MSG_UPDATE_WATCH_HISTORY: - if (mStarted) { - onLoadWatchHistory((Uri) msg.obj); - } - break; - case MSG_NOTIFY_CHANNEL_RECORD_MAP_LOADED: - if (mStarted) { - onNotifyChannelRecordMapLoaded(); - } - break; - case MSG_NOTIFY_CHANNEL_RECORD_MAP_CHANGED: - if (mStarted) { - onNotifyChannelRecordMapChanged(); - } - break; - } - } - }; + mHandler = new RecommendationHandler(mHandlerThread.getLooper(), this); mContentObserver = new RecommendationContentObserver(mHandler); } @@ -270,7 +234,7 @@ public class RecommendationDataManager { } private void addListener(Listener listener) { - synchronized (mListeners) { + synchronized (sListenerLock) { if (getListenerIndexLocked(listener) == INVALID_INDEX) { mListeners.add((new ListenerRecord(listener))); } @@ -278,10 +242,11 @@ public class RecommendationDataManager { } private void removeListener(Listener listener) { - synchronized (mListeners) { + synchronized (sListenerLock) { int idx = getListenerIndexLocked(listener); if (idx != INVALID_INDEX) { - mListeners.remove(idx); + ListenerRecord record = mListeners.remove(idx); + record.mListener = null; } } } @@ -319,6 +284,7 @@ public class RecommendationDataManager { mStarted = false; } + @WorkerThread private void onUpdateChannel(Uri uri) { Channel channel = null; try (Cursor cursor = mContext.getContentResolver().query(uri, Channel.PROJECTION, @@ -341,6 +307,7 @@ public class RecommendationDataManager { } } + @WorkerThread private void onUpdateChannels(Uri uri) { List<Channel> channels = new ArrayList<>(); try (Cursor cursor = mContext.getContentResolver().query(uri, Channel.PROJECTION, @@ -378,6 +345,7 @@ public class RecommendationDataManager { } } + @WorkerThread private void onLoadWatchHistory(Uri uri) { List<WatchedProgram> history = new ArrayList<>(); try (Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null)) { @@ -394,7 +362,7 @@ public class RecommendationDataManager { final ChannelRecord channelRecord = updateChannelRecordFromWatchedProgram(watchedProgram); if (mChannelRecordMapLoaded && channelRecord != null) { - synchronized (mListeners) { + synchronized (sListenerLock) { for (ListenerRecord l : mListeners) { l.postNewWatchLog(channelRecord); } @@ -437,7 +405,7 @@ public class RecommendationDataManager { private void onNotifyChannelRecordMapLoaded() { mChannelRecordMapLoaded = true; - synchronized (mListeners) { + synchronized (sListenerLock) { for (ListenerRecord l : mListeners) { l.postChannelRecordLoaded(); } @@ -445,7 +413,7 @@ public class RecommendationDataManager { } private void onNotifyChannelRecordMapChanged() { - synchronized (mListeners) { + synchronized (sListenerLock) { for (ListenerRecord l : mListeners) { l.postChannelRecordChanged(); } @@ -551,8 +519,10 @@ public class RecommendationDataManager { mHandler.post(new Runnable() { @Override public void run() { - if (mListener != null) { - mListener.onChannelRecordLoaded(); + synchronized (sListenerLock) { + if (mListener != null) { + mListener.onChannelRecordLoaded(); + } } } }); @@ -562,8 +532,10 @@ public class RecommendationDataManager { mHandler.post(new Runnable() { @Override public void run() { - if (mListener != null) { - mListener.onNewWatchLog(channelRecord); + synchronized (sListenerLock) { + if (mListener != null) { + mListener.onNewWatchLog(channelRecord); + } } } }); @@ -573,11 +545,58 @@ public class RecommendationDataManager { mHandler.post(new Runnable() { @Override public void run() { - if (mListener != null) { - mListener.onChannelRecordChanged(); + synchronized (sListenerLock) { + if (mListener != null) { + mListener.onChannelRecordChanged(); + } } } }); } } + + private static class RecommendationHandler extends WeakHandler<RecommendationDataManager> { + public RecommendationHandler(@NonNull Looper looper, RecommendationDataManager ref) { + super(looper, ref); + } + + @Override + public void handleMessage(Message msg, @NonNull RecommendationDataManager dataManager) { + switch (msg.what) { + case MSG_START: + dataManager.onStart(); + break; + case MSG_STOP: + if (dataManager.mStarted) { + dataManager.onStop(); + } + break; + case MSG_UPDATE_CHANNEL: + if (dataManager.mStarted) { + dataManager.onUpdateChannel((Uri) msg.obj); + } + break; + case MSG_UPDATE_CHANNELS: + if (dataManager.mStarted) { + dataManager.onUpdateChannels((Uri) msg.obj); + } + break; + case MSG_UPDATE_WATCH_HISTORY: + if (dataManager.mStarted) { + dataManager.onLoadWatchHistory((Uri) msg.obj); + } + break; + case MSG_NOTIFY_CHANNEL_RECORD_MAP_LOADED: + if (dataManager.mStarted) { + dataManager.onNotifyChannelRecordMapLoaded(); + } + break; + case MSG_NOTIFY_CHANNEL_RECORD_MAP_CHANGED: + if (dataManager.mStarted) { + dataManager.onNotifyChannelRecordMapChanged(); + } + break; + } + } + } } diff --git a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java index 8f6f203d..694da6bf 100644 --- a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java +++ b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java @@ -17,7 +17,6 @@ package com.android.tv.recommendation; import android.support.annotation.VisibleForTesting; -import android.text.TextUtils; import com.android.tv.data.Program; @@ -26,7 +25,6 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; public class RoutineWatchEvaluator extends Recommender.Evaluator { // TODO: test and refine constant values in WatchedProgramRecommender in order to |