aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/recommendation
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/recommendation')
-rw-r--r--src/com/android/tv/recommendation/ChannelPreviewUpdater.java151
-rw-r--r--src/com/android/tv/recommendation/ChannelRecord.java19
-rw-r--r--src/com/android/tv/recommendation/FavoriteChannelEvaluator.java5
-rw-r--r--src/com/android/tv/recommendation/NotificationService.java269
-rw-r--r--src/com/android/tv/recommendation/RecentChannelEvaluator.java11
-rw-r--r--src/com/android/tv/recommendation/RecommendationDataManager.java292
-rw-r--r--src/com/android/tv/recommendation/Recommender.java81
-rw-r--r--src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java113
-rw-r--r--src/com/android/tv/recommendation/RoutineWatchEvaluator.java88
9 files changed, 531 insertions, 498 deletions
diff --git a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
index 2709ebe1..410b8252 100644
--- a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
+++ b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
@@ -28,16 +28,14 @@ import android.support.annotation.RequiresApi;
import android.support.media.tv.TvContractCompat;
import android.text.TextUtils;
import android.util.Log;
-
-import com.android.tv.ApplicationSingletons;
-import com.android.tv.TvApplication;
-import com.android.tv.data.Channel;
+import com.android.tv.Starter;
+import com.android.tv.TvSingletons;
import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.PreviewProgramContent;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.util.Utils;
-
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -48,23 +46,19 @@ import java.util.concurrent.TimeUnit;
@RequiresApi(Build.VERSION_CODES.O)
public class ChannelPreviewUpdater {
private static final String TAG = "ChannelPreviewUpdater";
- // STOPSHIP: set it to false.
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final int UPATE_PREVIEW_PROGRAMS_JOB_ID = 1000001;
private static final long ROUTINE_INTERVAL_MS = TimeUnit.MINUTES.toMillis(10);
// The left time of a program should meet the threshold so that it could be recommended.
- private static final long RECOMMENDATION_THRESHOLD_LEFT_TIME_MS =
- TimeUnit.MINUTES.toMillis(10);
- private static final int RECOMMENDATION_THRESHOLD_PROGRESS = 90; // 90%
+ private static final long RECOMMENDATION_THRESHOLD_LEFT_TIME_MS = TimeUnit.MINUTES.toMillis(10);
+ private static final int RECOMMENDATION_THRESHOLD_PROGRESS = 90; // 90%
private static final int RECOMMENDATION_COUNT = 6;
private static final int MIN_COUNT_TO_ADD_ROW = 4;
private static ChannelPreviewUpdater sChannelPreviewUpdater;
- /**
- * Creates and returns the {@link ChannelPreviewUpdater}.
- */
+ /** Creates and returns the {@link ChannelPreviewUpdater}. */
public static ChannelPreviewUpdater getInstance(Context context) {
if (sChannelPreviewUpdater == null) {
sChannelPreviewUpdater = new ChannelPreviewUpdater(context.getApplicationContext());
@@ -82,21 +76,22 @@ public class ChannelPreviewUpdater {
private boolean mNeedUpdateAfterRecommenderReady = false;
- private Recommender.Listener mRecommenderListener = new Recommender.Listener() {
- @Override
- public void onRecommenderReady() {
- if (mNeedUpdateAfterRecommenderReady) {
- if (DEBUG) Log.d(TAG, "Recommender is ready");
- updatePreviewDataForChannelsImmediately();
- mNeedUpdateAfterRecommenderReady = false;
- }
- }
+ private Recommender.Listener mRecommenderListener =
+ new Recommender.Listener() {
+ @Override
+ public void onRecommenderReady() {
+ if (mNeedUpdateAfterRecommenderReady) {
+ if (DEBUG) Log.d(TAG, "Recommender is ready");
+ updatePreviewDataForChannelsImmediately();
+ mNeedUpdateAfterRecommenderReady = false;
+ }
+ }
- @Override
- public void onRecommendationChanged() {
- updatePreviewDataForChannelsImmediately();
- }
- };
+ @Override
+ public void onRecommendationChanged() {
+ updatePreviewDataForChannelsImmediately();
+ }
+ };
private ChannelPreviewUpdater(Context context) {
mContext = context;
@@ -104,15 +99,13 @@ public class ChannelPreviewUpdater {
mRecommender.registerEvaluator(new RandomEvaluator(), 0.1, 0.1);
mRecommender.registerEvaluator(new FavoriteChannelEvaluator(), 0.5, 0.5);
mRecommender.registerEvaluator(new RoutineWatchEvaluator(), 1.0, 1.0);
- ApplicationSingletons appSingleton = TvApplication.getSingletons(context);
- mPreviewDataManager = appSingleton.getPreviewDataManager();
- mParentalControlSettings = appSingleton.getTvInputManagerHelper()
- .getParentalControlSettings();
+ TvSingletons tvSingleton = TvSingletons.getSingletons(context);
+ mPreviewDataManager = tvSingleton.getPreviewDataManager();
+ mParentalControlSettings =
+ tvSingleton.getTvInputManagerHelper().getParentalControlSettings();
}
- /**
- * Starts the routine service for updating the preview programs.
- */
+ /** Starts the routine service for updating the preview programs. */
public void startRoutineService() {
JobScheduler jobScheduler =
(JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
@@ -120,11 +113,13 @@ public class ChannelPreviewUpdater {
if (DEBUG) Log.d(TAG, "UPDATE_PREVIEW_JOB already exists");
return;
}
- JobInfo job = new JobInfo.Builder(UPATE_PREVIEW_PROGRAMS_JOB_ID,
- new ComponentName(mContext, ChannelPreviewUpdateService.class))
- .setPeriodic(ROUTINE_INTERVAL_MS)
- .setPersisted(true)
- .build();
+ JobInfo job =
+ new JobInfo.Builder(
+ UPATE_PREVIEW_PROGRAMS_JOB_ID,
+ new ComponentName(mContext, ChannelPreviewUpdateService.class))
+ .setPeriodic(ROUTINE_INTERVAL_MS)
+ .setPersisted(true)
+ .build();
if (jobScheduler.schedule(job) < 0) {
Log.i(TAG, "JobScheduler failed to schedule the job");
}
@@ -138,9 +133,7 @@ public class ChannelPreviewUpdater {
updatePreviewDataForChannelsImmediately();
}
- /**
- * Updates the preview programs table.
- */
+ /** Updates the preview programs table. */
public void updatePreviewDataForChannelsImmediately() {
if (!mRecommender.isReady()) {
mNeedUpdateAfterRecommenderReady = true;
@@ -148,16 +141,17 @@ public class ChannelPreviewUpdater {
}
if (!mPreviewDataManager.isLoadFinished()) {
- mPreviewDataManager.addListener(new PreviewDataManager.PreviewDataListener() {
- @Override
- public void onPreviewDataLoadFinished() {
- mPreviewDataManager.removeListener(this);
- updatePreviewDataForChannels();
- }
+ mPreviewDataManager.addListener(
+ new PreviewDataManager.PreviewDataListener() {
+ @Override
+ public void onPreviewDataLoadFinished() {
+ mPreviewDataManager.removeListener(this);
+ updatePreviewDataForChannels();
+ }
- @Override
- public void onPreviewDataUpdateFinished() { }
- });
+ @Override
+ public void onPreviewDataUpdateFinished() {}
+ });
return;
}
updatePreviewDataForChannels();
@@ -225,8 +219,9 @@ public class ChannelPreviewUpdater {
}
private void updatePreviewDataForChannelsInternal(Set<Program> programs) {
- long defaultPreviewChannelId = mPreviewDataManager.getPreviewChannelId(
- PreviewDataManager.TYPE_DEFAULT_PREVIEW_CHANNEL);
+ long defaultPreviewChannelId =
+ mPreviewDataManager.getPreviewChannelId(
+ PreviewDataManager.TYPE_DEFAULT_PREVIEW_CHANNEL);
if (defaultPreviewChannelId == PreviewDataManager.INVALID_PREVIEW_CHANNEL_ID) {
// Only create if there is enough programs
if (programs.size() > MIN_COUNT_TO_ADD_ROW) {
@@ -248,7 +243,8 @@ public class ChannelPreviewUpdater {
});
}
} else {
- updatePreviewProgramsForPreviewChannel(defaultPreviewChannelId,
+ updatePreviewProgramsForPreviewChannel(
+ defaultPreviewChannelId,
generatePreviewProgramContentsFromPrograms(defaultPreviewChannelId, programs));
}
}
@@ -266,39 +262,38 @@ public class ChannelPreviewUpdater {
return result;
}
- private void updatePreviewProgramsForPreviewChannel(long previewChannelId,
- Set<PreviewProgramContent> previewProgramContents) {
- PreviewDataManager.PreviewDataListener previewDataListener
- = new PreviewDataManager.PreviewDataListener() {
- @Override
- public void onPreviewDataLoadFinished() { }
-
- @Override
- public void onPreviewDataUpdateFinished() {
- mPreviewDataManager.removeListener(this);
- if (mJobService != null && mJobParams != null) {
- if (DEBUG) Log.d(TAG, "UpdateAsyncTask.onPostExecute with JobService");
- mJobService.jobFinished(mJobParams, false);
- mJobService = null;
- mJobParams = null;
- } else {
- if (DEBUG) Log.d(TAG, "UpdateAsyncTask.onPostExecute without JobService");
- }
- }
- };
+ private void updatePreviewProgramsForPreviewChannel(
+ long previewChannelId, Set<PreviewProgramContent> previewProgramContents) {
+ PreviewDataManager.PreviewDataListener previewDataListener =
+ new PreviewDataManager.PreviewDataListener() {
+ @Override
+ public void onPreviewDataLoadFinished() {}
+
+ @Override
+ public void onPreviewDataUpdateFinished() {
+ mPreviewDataManager.removeListener(this);
+ if (mJobService != null && mJobParams != null) {
+ if (DEBUG) Log.d(TAG, "UpdateAsyncTask.onPostExecute with JobService");
+ mJobService.jobFinished(mJobParams, false);
+ mJobService = null;
+ mJobParams = null;
+ } else {
+ if (DEBUG)
+ Log.d(TAG, "UpdateAsyncTask.onPostExecute without JobService");
+ }
+ }
+ };
mPreviewDataManager.updatePreviewProgramsForChannel(
previewChannelId, previewProgramContents, previewDataListener);
}
- /**
- * Job to execute the update of preview programs.
- */
+ /** Job to execute the update of preview programs. */
public static class ChannelPreviewUpdateService extends JobService {
private ChannelPreviewUpdater mChannelPreviewUpdater;
@Override
public void onCreate() {
- TvApplication.setCurrentRunningProcess(this, true);
+ Starter.start(this);
if (DEBUG) Log.d(TAG, "ChannelPreviewUpdateService.onCreate");
mChannelPreviewUpdater = ChannelPreviewUpdater.getInstance(this);
}
diff --git a/src/com/android/tv/recommendation/ChannelRecord.java b/src/com/android/tv/recommendation/ChannelRecord.java
index 26f0fbf0..c7a7cb37 100644
--- a/src/com/android/tv/recommendation/ChannelRecord.java
+++ b/src/com/android/tv/recommendation/ChannelRecord.java
@@ -17,14 +17,12 @@
package com.android.tv.recommendation;
import android.content.Context;
+import android.support.annotation.GuardedBy;
import android.support.annotation.VisibleForTesting;
-
-import com.android.tv.TvApplication;
-import com.android.tv.data.Channel;
+import com.android.tv.TvSingletons;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
-import com.android.tv.util.Utils;
-
+import com.android.tv.data.api.Channel;
import java.util.ArrayDeque;
import java.util.Deque;
@@ -32,7 +30,10 @@ public class ChannelRecord {
// TODO: decide the value for max history size.
@VisibleForTesting static final int MAX_HISTORY_SIZE = 100;
private final Context mContext;
+
+ @GuardedBy("this")
private final Deque<WatchedProgram> mWatchHistory;
+
private Program mCurrentProgram;
private Channel mChannel;
private long mTotalWatchDurationMs;
@@ -62,7 +63,7 @@ public class ChannelRecord {
mInputRemoved = removed;
}
- public long getLastWatchEndTimeMs() {
+ public synchronized long getLastWatchEndTimeMs() {
WatchedProgram p = mWatchHistory.peekLast();
return (p == null) ? 0 : p.getWatchEndTimeMs();
}
@@ -71,7 +72,7 @@ public class ChannelRecord {
long time = System.currentTimeMillis();
if (mCurrentProgram == null || mCurrentProgram.getEndTimeUtcMillis() < time) {
ProgramDataManager manager =
- TvApplication.getSingletons(mContext).getProgramDataManager();
+ TvSingletons.getSingletons(mContext).getProgramDataManager();
mCurrentProgram = manager.getCurrentProgram(mChannel.getId());
}
return mCurrentProgram;
@@ -81,11 +82,11 @@ public class ChannelRecord {
return mTotalWatchDurationMs;
}
- public final WatchedProgram[] getWatchHistory() {
+ public final synchronized WatchedProgram[] getWatchHistory() {
return mWatchHistory.toArray(new WatchedProgram[mWatchHistory.size()]);
}
- public void logWatchHistory(WatchedProgram p) {
+ public synchronized void logWatchHistory(WatchedProgram p) {
mWatchHistory.offer(p);
mTotalWatchDurationMs += p.getWatchedDurationMs();
if (mWatchHistory.size() > MAX_HISTORY_SIZE) {
diff --git a/src/com/android/tv/recommendation/FavoriteChannelEvaluator.java b/src/com/android/tv/recommendation/FavoriteChannelEvaluator.java
index 9a6de7e2..8b0a3502 100644
--- a/src/com/android/tv/recommendation/FavoriteChannelEvaluator.java
+++ b/src/com/android/tv/recommendation/FavoriteChannelEvaluator.java
@@ -19,7 +19,7 @@ package com.android.tv.recommendation;
import java.util.List;
public class FavoriteChannelEvaluator extends Recommender.Evaluator {
- private static final long MIN_WATCH_PERIOD_MS = 1000 * 60 * 60 * 24; // 1 day
+ private static final long MIN_WATCH_PERIOD_MS = 1000 * 60 * 60 * 24; // 1 day
// When there is no watch history, use the current time as a default value.
private long mEarliestWatchStartTimeMs = System.currentTimeMillis();
@@ -46,7 +46,6 @@ public class FavoriteChannelEvaluator extends Recommender.Evaluator {
}
long watchPeriodMs = System.currentTimeMillis() - mEarliestWatchStartTimeMs;
- return (double) cr.getTotalWatchDurationMs() /
- Math.max(watchPeriodMs, MIN_WATCH_PERIOD_MS);
+ return (double) cr.getTotalWatchDurationMs() / Math.max(watchPeriodMs, MIN_WATCH_PERIOD_MS);
}
}
diff --git a/src/com/android/tv/recommendation/NotificationService.java b/src/com/android/tv/recommendation/NotificationService.java
index a44eca41..f40a0862 100644
--- a/src/com/android/tv/recommendation/NotificationService.java
+++ b/src/com/android/tv/recommendation/NotificationService.java
@@ -40,42 +40,39 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseLongArray;
import android.view.View;
-
-import com.android.tv.ApplicationSingletons;
import com.android.tv.MainActivityWrapper.OnCurrentChannelChangeListener;
import com.android.tv.R;
-import com.android.tv.TvApplication;
+import com.android.tv.Starter;
+import com.android.tv.TvSingletons;
+import com.android.tv.common.CommonConstants;
import com.android.tv.common.WeakHandler;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
-import com.android.tv.util.BitmapUtils;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
-
+import com.android.tv.util.images.BitmapUtils;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.util.images.ImageLoader;
import java.util.ArrayList;
import java.util.List;
-/**
- * A local service for notify recommendation at home launcher.
- */
-public class NotificationService extends Service implements Recommender.Listener,
- OnCurrentChannelChangeListener {
+/** A local service for notify recommendation at home launcher. */
+public class NotificationService extends Service
+ implements Recommender.Listener, OnCurrentChannelChangeListener {
private static final String TAG = "NotificationService";
private static final boolean DEBUG = false;
public static final String ACTION_SHOW_RECOMMENDATION =
- "com.android.tv.notification.ACTION_SHOW_RECOMMENDATION";
+ CommonConstants.BASE_PACKAGE + ".notification.ACTION_SHOW_RECOMMENDATION";
public static final String ACTION_HIDE_RECOMMENDATION =
- "com.android.tv.notification.ACTION_HIDE_RECOMMENDATION";
+ CommonConstants.BASE_PACKAGE + ".notification.ACTION_HIDE_RECOMMENDATION";
/**
- * Recommendation intent has an extra data for the recommendation type. It'll be also
- * sent to a TV input as a tune parameter.
+ * 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";
+ CommonConstants.BASE_PACKAGE + ".recommendation_type";
private static final String TYPE_RANDOM_RECOMMENDATION = "random";
private static final String TYPE_ROUTINE_WATCH_RECOMMENDATION = "routine_watch";
@@ -92,9 +89,9 @@ public class NotificationService extends Service implements Recommender.Listener
private static final int MSG_UPDATE_RECOMMENDATION = 1002;
private static final int MSG_HIDE_RECOMMENDATION = 1003;
- private static final long RECOMMENDATION_RETRY_TIME_MS = 5 * 60 * 1000; // 5 min
- private static final long RECOMMENDATION_THRESHOLD_LEFT_TIME_MS = 10 * 60 * 1000; // 10 min
- private static final int RECOMMENDATION_THRESHOLD_PROGRESS = 90; // 90%
+ private static final long RECOMMENDATION_RETRY_TIME_MS = 5 * 60 * 1000; // 5 min
+ private static final long RECOMMENDATION_THRESHOLD_LEFT_TIME_MS = 10 * 60 * 1000; // 10 min
+ private static final int RECOMMENDATION_THRESHOLD_PROGRESS = 90; // 90%
private static final int MAX_PROGRAM_UPDATE_COUNT = 20;
private TvInputManagerHelper mTvInputManagerHelper;
@@ -126,17 +123,17 @@ public class NotificationService extends Service implements Recommender.Listener
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "onCreate");
- TvApplication.setCurrentRunningProcess(this, true);
+ Starter.start(this);
super.onCreate();
mCurrentNotificationCount = 0;
mNotificationChannels = new long[NOTIFICATION_COUNT];
for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
mNotificationChannels[i] = Channel.INVALID_ID;
}
- mNotificationCardMaxWidth = getResources().getDimensionPixelSize(
- R.dimen.notif_card_img_max_width);
- mNotificationCardHeight = getResources().getDimensionPixelSize(
- R.dimen.notif_card_img_height);
+ mNotificationCardMaxWidth =
+ getResources().getDimensionPixelSize(R.dimen.notif_card_img_max_width);
+ mNotificationCardHeight =
+ getResources().getDimensionPixelSize(R.dimen.notif_card_img_height);
mCardImageHeight = getResources().getDimensionPixelSize(R.dimen.notif_card_img_height);
mCardImageMaxWidth = getResources().getDimensionPixelSize(R.dimen.notif_card_img_max_width);
mCardImageMinWidth = getResources().getDimensionPixelSize(R.dimen.notif_card_img_min_width);
@@ -150,17 +147,17 @@ public class NotificationService extends Service implements Recommender.Listener
getResources().getDimensionPixelOffset(R.dimen.notif_ch_logo_padding_bottom);
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- ApplicationSingletons appSingletons = TvApplication.getSingletons(this);
- mTvInputManagerHelper = appSingletons.getTvInputManagerHelper();
+ TvSingletons tvSingletons = TvSingletons.getSingletons(this);
+ mTvInputManagerHelper = tvSingletons.getTvInputManagerHelper();
mHandlerThread = new HandlerThread("tv notification");
mHandlerThread.start();
mHandler = new NotificationHandler(mHandlerThread.getLooper(), this);
mHandler.sendEmptyMessage(MSG_INITIALIZE_RECOMMENDER);
// Just called for early initialization.
- appSingletons.getChannelDataManager();
- appSingletons.getProgramDataManager();
- appSingletons.getMainActivityWrapper().addOnCurrentChannelChangeListener(this);
+ tvSingletons.getChannelDataManager();
+ tvSingletons.getProgramDataManager();
+ tvSingletons.getMainActivityWrapper().addOnCurrentChannelChangeListener(this);
}
@UiThread
@@ -178,8 +175,8 @@ public class NotificationService extends Service implements Recommender.Listener
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)) {
+ } 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 {
@@ -189,6 +186,9 @@ public class NotificationService extends Service implements Recommender.Listener
}
private void handleShowRecommendation() {
+ if (mRecommender == null) {
+ return;
+ }
if (!mRecommender.isReady()) {
mShowRecommendationAfterRecommenderReady = true;
} else {
@@ -197,13 +197,16 @@ public class NotificationService extends Service implements Recommender.Listener
}
private void handleUpdateRecommendation(int notificationId, Channel channel) {
- if (mNotificationChannels[notificationId] == Channel.INVALID_ID || !sendNotification(
- channel.getId(), notificationId)) {
+ if (mNotificationChannels[notificationId] == Channel.INVALID_ID
+ || !sendNotification(channel.getId(), notificationId)) {
changeRecommendation(notificationId);
}
}
private void handleHideRecommendation() {
+ if (mRecommender == null) {
+ return;
+ }
if (!mRecommender.isReady()) {
mShowRecommendationAfterRecommenderReady = false;
} else {
@@ -213,7 +216,8 @@ public class NotificationService extends Service implements Recommender.Listener
@Override
public void onDestroy() {
- TvApplication.getSingletons(this).getMainActivityWrapper()
+ TvSingletons.getSingletons(this)
+ .getMainActivityWrapper()
.removeOnCurrentChannelChangeListener(this);
if (mRecommender != null) {
mRecommender.release();
@@ -316,7 +320,7 @@ public class NotificationService extends Service implements Recommender.Listener
}
for (Channel c : channels) {
if (!isNotifiedChannel(c.getId())) {
- if(sendNotification(c.getId(), notificationId)) {
+ if (sendNotification(c.getId(), notificationId)) {
return;
}
}
@@ -334,13 +338,13 @@ public class NotificationService extends Service implements Recommender.Listener
}
private void hideAllRecommendation() {
- for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
- if (mNotificationChannels[i] != Channel.INVALID_ID) {
- mNotificationChannels[i] = Channel.INVALID_ID;
- mNotificationManager.cancel(NOTIFY_TAG, i);
- }
- }
- mCurrentNotificationCount = 0;
+ for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
+ if (mNotificationChannels[i] != Channel.INVALID_ID) {
+ mNotificationChannels[i] = Channel.INVALID_ID;
+ mNotificationManager.cancel(NOTIFY_TAG, i);
+ }
+ }
+ mCurrentNotificationCount = 0;
}
private boolean sendNotification(final long channelId, final int notificationId) {
@@ -350,8 +354,13 @@ public class NotificationService extends Service implements Recommender.Listener
}
final Channel channel = cr.getChannel();
if (DEBUG) {
- Log.d(TAG, "sendNotification (channelName=" + channel.getDisplayName() + " notifyId="
- + notificationId + ")");
+ Log.d(
+ TAG,
+ "sendNotification (channelName="
+ + channel.getDisplayName()
+ + " notifyId="
+ + notificationId
+ + ")");
}
// TODO: Move some checking logic into TvRecommendation.
@@ -363,17 +372,18 @@ public class NotificationService extends Service implements Recommender.Listener
if (inputInfo == null) {
return false;
}
- final String inputDisplayName = inputInfo.loadLabel(this).toString();
final Program program = Utils.getCurrentProgram(this, channel.getId());
if (program == null) {
return false;
}
- final long programDurationMs = program.getEndTimeUtcMillis()
- - program.getStartTimeUtcMillis();
+ final long programDurationMs =
+ program.getEndTimeUtcMillis() - program.getStartTimeUtcMillis();
long programLeftTimsMs = program.getEndTimeUtcMillis() - System.currentTimeMillis();
- final int programProgress = (programDurationMs <= 0) ? -1
- : 100 - (int) (programLeftTimsMs * 100 / programDurationMs);
+ final int programProgress =
+ (programDurationMs <= 0)
+ ? -1
+ : 100 - (int) (programLeftTimsMs * 100 / programDurationMs);
// We recommend those programs that meet the condition only.
if (programProgress >= RECOMMENDATION_THRESHOLD_PROGRESS
@@ -382,19 +392,24 @@ public class NotificationService extends Service implements Recommender.Listener
}
// We don't trust TIS to provide us with proper sized image
- ScaledBitmapInfo posterArtBitmapInfo = BitmapUtils.decodeSampledBitmapFromUriString(this,
- program.getPosterArtUri(), (int) mNotificationCardMaxWidth,
- (int) mNotificationCardHeight);
+ ScaledBitmapInfo posterArtBitmapInfo =
+ BitmapUtils.decodeSampledBitmapFromUriString(
+ this,
+ program.getPosterArtUri(),
+ (int) mNotificationCardMaxWidth,
+ (int) mNotificationCardHeight);
if (posterArtBitmapInfo == null) {
Log.e(TAG, "Failed to decode poster image for " + program.getPosterArtUri());
return false;
}
final Bitmap posterArtBitmap = posterArtBitmapInfo.bitmap;
- channel.loadBitmap(this, Channel.LOAD_IMAGE_TYPE_CHANNEL_LOGO, mChannelLogoMaxWidth,
+ channel.loadBitmap(
+ this,
+ Channel.LOAD_IMAGE_TYPE_CHANNEL_LOGO,
+ mChannelLogoMaxWidth,
mChannelLogoMaxHeight,
- createChannelLogoCallback(this, notificationId, inputDisplayName, channel, program,
- posterArtBitmap));
+ createChannelLogoCallback(this, notificationId, channel, program, posterArtBitmap));
if (mNotificationChannels[notificationId] == Channel.INVALID_ID) {
++mCurrentNotificationCount;
@@ -404,62 +419,77 @@ public class NotificationService extends Service implements Recommender.Listener
return true;
}
- @NonNull
- private static ImageLoader.ImageLoaderCallback<NotificationService> createChannelLogoCallback(
- NotificationService service, final int notificationId, final String inputDisplayName,
- final Channel channel, final Program program, final Bitmap posterArtBitmap) {
- return new ImageLoader.ImageLoaderCallback<NotificationService>(service) {
- @Override
- public void onBitmapLoaded(NotificationService service, Bitmap channelLogo) {
- service.sendNotification(notificationId, channelLogo, channel, posterArtBitmap,
- program, inputDisplayName);
- }
- };
- }
-
- private void sendNotification(int notificationId, Bitmap channelLogo, Channel channel,
- Bitmap posterArtBitmap, Program program, String inputDisplayName) {
- final long programDurationMs = program.getEndTimeUtcMillis() - program
- .getStartTimeUtcMillis();
+ private void sendNotification(
+ int notificationId,
+ Bitmap channelLogo,
+ Channel channel,
+ Bitmap posterArtBitmap,
+ Program program) {
+ final long programDurationMs =
+ program.getEndTimeUtcMillis() - program.getStartTimeUtcMillis();
long programLeftTimsMs = program.getEndTimeUtcMillis() - System.currentTimeMillis();
- final int programProgress = (programDurationMs <= 0) ? -1
- : 100 - (int) (programLeftTimsMs * 100 / programDurationMs);
+ final int programProgress =
+ (programDurationMs <= 0)
+ ? -1
+ : 100 - (int) (programLeftTimsMs * 100 / programDurationMs);
Intent intent = new Intent(Intent.ACTION_VIEW, channel.getUri());
intent.putExtra(TUNE_PARAMS_RECOMMENDATION_TYPE, mRecommendationType);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
final PendingIntent notificationIntent = PendingIntent.getActivity(this, 0, intent, 0);
// This callback will run on the main thread.
- Bitmap largeIconBitmap = (channelLogo == null) ? posterArtBitmap
- : overlayChannelLogo(channelLogo, posterArtBitmap);
+ Bitmap largeIconBitmap =
+ (channelLogo == null)
+ ? posterArtBitmap
+ : overlayChannelLogo(channelLogo, posterArtBitmap);
String channelDisplayName = channel.getDisplayName();
- Notification notification = new Notification.Builder(this)
- .setContentIntent(notificationIntent)
- .setContentTitle(program.getTitle())
- .setContentText(TextUtils.isEmpty(channelDisplayName) ? channel.getDisplayNumber()
- : channelDisplayName)
- .setContentInfo(channelDisplayName)
- .setAutoCancel(true).setLargeIcon(largeIconBitmap)
- .setSmallIcon(R.drawable.ic_launcher_s)
- .setCategory(Notification.CATEGORY_RECOMMENDATION)
- .setProgress((programProgress > 0) ? 100 : 0, programProgress, false)
- .setSortKey(mRecommender.getChannelSortKey(channel.getId()))
- .build();
+ Notification notification =
+ new Notification.Builder(this)
+ .setContentIntent(notificationIntent)
+ .setContentTitle(program.getTitle())
+ .setContentText(
+ TextUtils.isEmpty(channelDisplayName)
+ ? channel.getDisplayNumber()
+ : channelDisplayName)
+ .setContentInfo(channelDisplayName)
+ .setAutoCancel(true)
+ .setLargeIcon(largeIconBitmap)
+ .setSmallIcon(R.drawable.ic_launcher_s)
+ .setCategory(Notification.CATEGORY_RECOMMENDATION)
+ .setProgress((programProgress > 0) ? 100 : 0, programProgress, false)
+ .setSortKey(mRecommender.getChannelSortKey(channel.getId()))
+ .build();
notification.color = getResources().getColor(R.color.recommendation_card_background, null);
if (!TextUtils.isEmpty(program.getThumbnailUri())) {
- notification.extras
- .putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, program.getThumbnailUri());
+ notification.extras.putString(
+ Notification.EXTRA_BACKGROUND_IMAGE_URI, program.getThumbnailUri());
}
mNotificationManager.notify(NOTIFY_TAG, notificationId, notification);
Message msg = mHandler.obtainMessage(MSG_UPDATE_RECOMMENDATION, notificationId, 0, channel);
mHandler.sendMessageDelayed(msg, programDurationMs / MAX_PROGRAM_UPDATE_COUNT);
}
+ @NonNull
+ private static ImageLoader.ImageLoaderCallback<NotificationService> createChannelLogoCallback(
+ NotificationService service,
+ final int notificationId,
+ final Channel channel,
+ final Program program,
+ final Bitmap posterArtBitmap) {
+ return new ImageLoader.ImageLoaderCallback<NotificationService>(service) {
+ @Override
+ public void onBitmapLoaded(NotificationService service, Bitmap channelLogo) {
+ service.sendNotification(
+ notificationId, channelLogo, channel, posterArtBitmap, program);
+ }
+ };
+ }
+
private Bitmap overlayChannelLogo(Bitmap logo, Bitmap background) {
- Bitmap result = BitmapUtils.getScaledMutableBitmap(
- background, Integer.MAX_VALUE, mCardImageHeight);
- Bitmap scaledLogo = BitmapUtils.scaleBitmap(
- logo, mChannelLogoMaxWidth, mChannelLogoMaxHeight);
+ Bitmap result =
+ BitmapUtils.getScaledMutableBitmap(background, Integer.MAX_VALUE, mCardImageHeight);
+ Bitmap scaledLogo =
+ BitmapUtils.scaleBitmap(logo, mChannelLogoMaxWidth, mChannelLogoMaxHeight);
Canvas canvas;
try {
canvas = new Canvas(result);
@@ -524,27 +554,32 @@ public class NotificationService extends Service implements Recommender.Listener
@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);
- }
+ 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/RecentChannelEvaluator.java b/src/com/android/tv/recommendation/RecentChannelEvaluator.java
index e724f4ce..f4c4877d 100644
--- a/src/com/android/tv/recommendation/RecentChannelEvaluator.java
+++ b/src/com/android/tv/recommendation/RecentChannelEvaluator.java
@@ -51,9 +51,12 @@ public class RecentChannelEvaluator extends Recommender.Evaluator {
if (watchDuration < WATCH_DURATION_MS_LOWER_BOUND) {
watchDurationScore = MAX_SCORE_FOR_LOWER_BOUND;
} else if (watchDuration < WATCH_DURATION_MS_UPPER_BOUND) {
- watchDurationScore = (watchDuration - WATCH_DURATION_MS_LOWER_BOUND)
- / (WATCH_DURATION_MS_UPPER_BOUND - WATCH_DURATION_MS_LOWER_BOUND)
- * (1 - MAX_SCORE_FOR_LOWER_BOUND) + MAX_SCORE_FOR_LOWER_BOUND;
+ watchDurationScore =
+ (watchDuration - WATCH_DURATION_MS_LOWER_BOUND)
+ / (WATCH_DURATION_MS_UPPER_BOUND
+ - WATCH_DURATION_MS_LOWER_BOUND)
+ * (1 - MAX_SCORE_FOR_LOWER_BOUND)
+ + MAX_SCORE_FOR_LOWER_BOUND;
} else {
watchDurationScore = 1.0;
}
@@ -61,4 +64,4 @@ public class RecentChannelEvaluator extends Recommender.Evaluator {
}
return (maxScore > 0.0) ? maxScore : NOT_RECOMMENDED;
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java
index dc148ec8..649920fb 100644
--- a/src/com/android/tv/recommendation/RecommendationDataManager.java
+++ b/src/com/android/tv/recommendation/RecommendationDataManager.java
@@ -33,16 +33,14 @@ import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
-
-import com.android.tv.TvApplication;
+import com.android.tv.TvSingletons;
import com.android.tv.common.WeakHandler;
-import com.android.tv.data.Channel;
+import com.android.tv.common.util.PermissionUtils;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
import com.android.tv.data.WatchedHistoryManager;
-import com.android.tv.util.PermissionUtils;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.TvUriMatcher;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -52,6 +50,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+/** Manages teh data need to make recommendations. */
public class RecommendationDataManager implements WatchedHistoryManager.Listener {
private static final int MSG_START = 1000;
private static final int MSG_STOP = 1001;
@@ -84,40 +83,38 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final Handler mMainHandler;
- @Nullable
- private WatchedHistoryManager mWatchedHistoryManager;
+ @Nullable private WatchedHistoryManager mWatchedHistoryManager;
private final ChannelDataManager mChannelDataManager;
private final ChannelDataManager.Listener mChannelDataListener =
new ChannelDataManager.Listener() {
- @Override
- @MainThread
- public void onLoadFinished() {
- updateChannelData();
- }
+ @Override
+ @MainThread
+ public void onLoadFinished() {
+ updateChannelData();
+ }
- @Override
- @MainThread
- public void onChannelListUpdated() {
- updateChannelData();
- }
+ @Override
+ @MainThread
+ public void onChannelListUpdated() {
+ updateChannelData();
+ }
- @Override
- @MainThread
- public void onChannelBrowsableChanged() {
- updateChannelData();
- }
- };
+ @Override
+ @MainThread
+ public void onChannelBrowsableChanged() {
+ updateChannelData();
+ }
+ };
// For thread safety, this variable is handled only on main thread.
private final List<Listener> mListeners = new ArrayList<>();
/**
- * Gets instance of RecommendationDataManager, and adds a {@link Listener}.
- * The listener methods will be called in the same thread as its caller of the method.
- * Note that {@link #release(Listener)} should be called when this manager is not needed
- * any more.
+ * Gets instance of RecommendationDataManager, and adds a {@link Listener}. The listener methods
+ * will be called in the same thread as its caller of the method. Note that {@link
+ * #release(Listener)} should be called when this manager is not needed any more.
*/
- public synchronized static RecommendationDataManager acquireManager(
+ public static synchronized RecommendationDataManager acquireManager(
Context context, @NonNull Listener listener) {
if (sManager == null) {
sManager = new RecommendationDataManager(context);
@@ -129,7 +126,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
private final TvInputCallback mInternalCallback =
new TvInputCallback() {
@Override
- public void onInputStateChanged(String inputId, int state) { }
+ public void onInputStateChanged(String inputId, int state) {}
@Override
public void onInputAdded(String inputId) {
@@ -144,8 +141,8 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
for (ChannelRecord channelRecord : mChannelRecordMap.values()) {
if (channelRecord.getChannel().getInputId().equals(inputId)) {
channelRecord.setInputRemoved(false);
- mAvailableChannelRecordMap.put(channelRecord.getChannel().getId(),
- channelRecord);
+ mAvailableChannelRecordMap.put(
+ channelRecord.getChannel().getId(), channelRecord);
channelRecordMapChanged = true;
}
}
@@ -179,7 +176,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
}
@Override
- public void onInputUpdated(String inputId) { }
+ public void onInputUpdated(String inputId) {}
};
private RecommendationDataManager(Context context) {
@@ -189,48 +186,44 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
mHandler = new RecommendationHandler(mHandlerThread.getLooper(), this);
mMainHandler = new RecommendationMainHandler(Looper.getMainLooper(), this);
mContentObserver = new RecommendationContentObserver(mHandler);
- mChannelDataManager = TvApplication.getSingletons(mContext).getChannelDataManager();
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- start();
- }
- });
+ mChannelDataManager = TvSingletons.getSingletons(mContext).getChannelDataManager();
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ start();
+ }
+ });
}
/**
- * Removes the {@link Listener}, and releases RecommendationDataManager
- * if there are no listeners remained.
+ * Removes the {@link Listener}, and releases RecommendationDataManager if there are no
+ * listeners remained.
*/
public void release(@NonNull final Listener listener) {
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- removeListener(listener);
- if (mListeners.size() == 0) {
- stop();
- }
- }
- });
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ removeListener(listener);
+ if (mListeners.size() == 0) {
+ stop();
+ }
+ }
+ });
}
- /**
- * Returns a {@link ChannelRecord} corresponds to the channel ID {@code ChannelId}.
- */
+ /** Returns a {@link ChannelRecord} corresponds to the channel ID {@code ChannelId}. */
public ChannelRecord getChannelRecord(long channelId) {
return mAvailableChannelRecordMap.get(channelId);
}
- /**
- * Returns the number of channels registered in ChannelRecord map.
- */
+ /** Returns the number of channels registered in ChannelRecord map. */
public int getChannelRecordCount() {
return mAvailableChannelRecordMap.size();
}
- /**
- * Returns a Collection of ChannelRecords.
- */
+ /** Returns a Collection of ChannelRecords. */
public Collection<ChannelRecord> getChannelRecords() {
return Collections.unmodifiableCollection(mAvailableChannelRecordMap.values());
}
@@ -264,12 +257,13 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
}
private void addListener(Listener listener) {
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- mListeners.add(listener);
- }
- });
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ mListeners.add(listener);
+ }
+ });
}
@MainThread
@@ -286,10 +280,11 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
mWatchedHistoryManager.setListener(this);
mWatchedHistoryManager.start();
} else {
- mContext.getContentResolver().registerContentObserver(
- TvContract.WatchedPrograms.CONTENT_URI, true, mContentObserver);
- mHandler.obtainMessage(MSG_UPDATE_WATCH_HISTORY,
- TvContract.WatchedPrograms.CONTENT_URI)
+ mContext.getContentResolver()
+ .registerContentObserver(
+ TvContract.WatchedPrograms.CONTENT_URI, true, mContentObserver);
+ mHandler.obtainMessage(
+ MSG_UPDATE_WATCH_HISTORY, TvContract.WatchedPrograms.CONTENT_URI)
.sendToTarget();
}
mTvInputManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE);
@@ -333,7 +328,8 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
}
}
}
- if (isChannelRecordMapChanged && mChannelRecordMapLoaded
+ if (isChannelRecordMapChanged
+ && mChannelRecordMapLoaded
&& !mHandler.hasMessages(MSG_NOTIFY_CHANNEL_RECORD_MAP_CHANGED)) {
mHandler.sendEmptyMessage(MSG_NOTIFY_CHANNEL_RECORD_MAP_CHANGED);
}
@@ -356,14 +352,15 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
final ChannelRecord channelRecord =
updateChannelRecordFromWatchedProgram(watchedProgram);
if (mChannelRecordMapLoaded && channelRecord != null) {
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- for (Listener l : mListeners) {
- l.onNewWatchLog(channelRecord);
- }
- }
- });
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ for (Listener l : mListeners) {
+ l.onNewWatchLog(channelRecord);
+ }
+ }
+ });
}
}
if (!mChannelRecordMapLoaded) {
@@ -374,96 +371,99 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
private WatchedProgram convertFromWatchedHistoryManagerRecords(
WatchedHistoryManager.WatchedRecord watchedRecord) {
long endTime = watchedRecord.watchedStartTime + watchedRecord.duration;
- Program program = new Program.Builder()
- .setChannelId(watchedRecord.channelId)
- .setTitle("")
- .setStartTimeUtcMillis(watchedRecord.watchedStartTime)
- .setEndTimeUtcMillis(endTime)
- .build();
+ Program program =
+ new Program.Builder()
+ .setChannelId(watchedRecord.channelId)
+ .setTitle("")
+ .setStartTimeUtcMillis(watchedRecord.watchedStartTime)
+ .setEndTimeUtcMillis(endTime)
+ .build();
return new WatchedProgram(program, watchedRecord.watchedStartTime, endTime);
}
@Override
public void onLoadFinished() {
- for (WatchedHistoryManager.WatchedRecord record
- : mWatchedHistoryManager.getWatchedHistory()) {
- updateChannelRecordFromWatchedProgram(
- convertFromWatchedHistoryManagerRecords(record));
+ for (WatchedHistoryManager.WatchedRecord record :
+ mWatchedHistoryManager.getWatchedHistory()) {
+ updateChannelRecordFromWatchedProgram(convertFromWatchedHistoryManagerRecords(record));
}
mHandler.sendEmptyMessage(MSG_NOTIFY_CHANNEL_RECORD_MAP_LOADED);
}
@Override
public void onNewRecordAdded(WatchedHistoryManager.WatchedRecord watchedRecord) {
- final ChannelRecord channelRecord = updateChannelRecordFromWatchedProgram(
- convertFromWatchedHistoryManagerRecords(watchedRecord));
+ final ChannelRecord channelRecord =
+ updateChannelRecordFromWatchedProgram(
+ convertFromWatchedHistoryManagerRecords(watchedRecord));
if (mChannelRecordMapLoaded && channelRecord != null) {
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- for (Listener l : mListeners) {
- l.onNewWatchLog(channelRecord);
- }
- }
- });
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ for (Listener l : mListeners) {
+ l.onNewWatchLog(channelRecord);
+ }
+ }
+ });
}
}
private WatchedProgram createWatchedProgramFromWatchedProgramCursor(Cursor cursor) {
// Have to initiate the indexes of WatchedProgram Columns.
if (mIndexWatchChannelId == -1) {
- mIndexWatchChannelId = cursor.getColumnIndex(
- TvContract.WatchedPrograms.COLUMN_CHANNEL_ID);
- mIndexProgramTitle = cursor.getColumnIndex(
- TvContract.WatchedPrograms.COLUMN_TITLE);
- mIndexProgramStartTime = cursor.getColumnIndex(
- TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS);
- mIndexProgramEndTime = cursor.getColumnIndex(
- TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS);
- mIndexWatchStartTime = cursor.getColumnIndex(
- TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS);
- mIndexWatchEndTime = cursor.getColumnIndex(
- TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS);
+ mIndexWatchChannelId =
+ cursor.getColumnIndex(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID);
+ mIndexProgramTitle = cursor.getColumnIndex(TvContract.WatchedPrograms.COLUMN_TITLE);
+ mIndexProgramStartTime =
+ cursor.getColumnIndex(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS);
+ mIndexProgramEndTime =
+ cursor.getColumnIndex(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS);
+ mIndexWatchStartTime =
+ cursor.getColumnIndex(
+ TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS);
+ mIndexWatchEndTime =
+ cursor.getColumnIndex(
+ TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS);
}
- Program program = new Program.Builder()
- .setChannelId(cursor.getLong(mIndexWatchChannelId))
- .setTitle(cursor.getString(mIndexProgramTitle))
- .setStartTimeUtcMillis(cursor.getLong(mIndexProgramStartTime))
- .setEndTimeUtcMillis(cursor.getLong(mIndexProgramEndTime))
- .build();
+ Program program =
+ new Program.Builder()
+ .setChannelId(cursor.getLong(mIndexWatchChannelId))
+ .setTitle(cursor.getString(mIndexProgramTitle))
+ .setStartTimeUtcMillis(cursor.getLong(mIndexProgramStartTime))
+ .setEndTimeUtcMillis(cursor.getLong(mIndexProgramEndTime))
+ .build();
- return new WatchedProgram(program,
- cursor.getLong(mIndexWatchStartTime),
- cursor.getLong(mIndexWatchEndTime));
+ return new WatchedProgram(
+ program, cursor.getLong(mIndexWatchStartTime), cursor.getLong(mIndexWatchEndTime));
}
private void onNotifyChannelRecordMapLoaded() {
mChannelRecordMapLoaded = true;
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- for (Listener l : mListeners) {
- l.onChannelRecordLoaded();
- }
- }
- });
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ for (Listener l : mListeners) {
+ l.onChannelRecordLoaded();
+ }
+ }
+ });
}
private void onNotifyChannelRecordMapChanged() {
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- for (Listener l : mListeners) {
- l.onChannelRecordChanged();
- }
- }
- });
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ for (Listener l : mListeners) {
+ l.onChannelRecordChanged();
+ }
+ }
+ });
}
- /**
- * Returns true if ChannelRecords are added into mChannelRecordMap or removed from it.
- */
+ /** Returns true if ChannelRecords are added into mChannelRecordMap or removed from it. */
private boolean updateChannelRecordMapFromChannel(Channel channel) {
if (!channel.isBrowsable()) {
mChannelRecordMap.remove(channel.getId());
@@ -507,8 +507,8 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
public void onChange(final boolean selfChange, final Uri uri) {
switch (TvUriMatcher.match(uri)) {
case TvUriMatcher.MATCH_WATCHED_PROGRAM_ID:
- if (!mHandler.hasMessages(MSG_UPDATE_WATCH_HISTORY,
- TvContract.WatchedPrograms.CONTENT_URI)) {
+ if (!mHandler.hasMessages(
+ MSG_UPDATE_WATCH_HISTORY, TvContract.WatchedPrograms.CONTENT_URI)) {
mHandler.obtainMessage(MSG_UPDATE_WATCH_HISTORY, uri).sendToTarget();
}
break;
@@ -524,15 +524,11 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
}
}
- /**
- * A listener interface to receive notification about the recommendation data.
- *
- * @MainThread
- */
+ /** A listener interface to receive notification about the recommendation data. @MainThread */
public interface Listener {
/**
- * Called when loading channel record map from database is finished.
- * It will be called after RecommendationDataManager.start() is finished.
+ * Called when loading channel record map from database is finished. It will be called after
+ * RecommendationDataManager.start() is finished.
*
* <p>Note that this method is called on the main thread.
*/
@@ -601,6 +597,6 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
}
@Override
- protected void handleMessage(Message msg, @NonNull RecommendationDataManager referent) { }
+ protected void handleMessage(Message msg, @NonNull RecommendationDataManager referent) {}
}
}
diff --git a/src/com/android/tv/recommendation/Recommender.java b/src/com/android/tv/recommendation/Recommender.java
index 82c2893d..f350799f 100644
--- a/src/com/android/tv/recommendation/Recommender.java
+++ b/src/com/android/tv/recommendation/Recommender.java
@@ -20,9 +20,7 @@ import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.Pair;
-
-import com.android.tv.data.Channel;
-
+import com.android.tv.data.api.Channel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -35,8 +33,7 @@ import java.util.concurrent.TimeUnit;
public class Recommender implements RecommendationDataManager.Listener {
private static final String TAG = "Recommender";
- @VisibleForTesting
- static final String INVALID_CHANNEL_SORT_KEY = "INVALID";
+ @VisibleForTesting static final String INVALID_CHANNEL_SORT_KEY = "INVALID";
private static final long MINIMUM_RECOMMENDATION_UPDATE_PERIOD = TimeUnit.MINUTES.toMillis(5);
private static final Comparator<Pair<Channel, Double>> mChannelScoreComparator =
new Comparator<Pair<Channel, Double>>() {
@@ -69,7 +66,9 @@ public class Recommender implements RecommendationDataManager.Listener {
}
@VisibleForTesting
- Recommender(Listener listener, boolean includeRecommendedOnly,
+ Recommender(
+ Listener listener,
+ boolean includeRecommendedOnly,
RecommendationDataManager dataManager) {
mListener = listener;
mIncludeRecommendedOnly = includeRecommendedOnly;
@@ -85,16 +84,16 @@ public class Recommender implements RecommendationDataManager.Listener {
}
public void registerEvaluator(Evaluator evaluator) {
- registerEvaluator(evaluator,
- EvaluatorWrapper.DEFAULT_BASE_SCORE, EvaluatorWrapper.DEFAULT_WEIGHT);
+ registerEvaluator(
+ evaluator, EvaluatorWrapper.DEFAULT_BASE_SCORE, EvaluatorWrapper.DEFAULT_WEIGHT);
}
/**
* Register the evaluator used in recommendation.
*
- * The range of evaluated scores by this evaluator will be between {@code baseScore} and
+ * <p>The range of evaluated scores by this evaluator will be between {@code baseScore} and
* {@code baseScore} + {@code weight} (inclusive).
-
+ *
* @param evaluator The evaluator to register inside this recommender.
* @param baseScore Base(Minimum) score of the score evaluated by {@code evaluator}.
* @param weight Weight value to rearrange the score evaluated by {@code evaluator}.
@@ -108,13 +107,13 @@ public class Recommender implements RecommendationDataManager.Listener {
}
/**
- * Return the channel list of recommendation up to {@code n} or the number of channels.
- * During the evaluation, this method updates the channel sort key of recommended channels.
+ * Return the channel list of recommendation up to {@code n} or the number of channels. During
+ * the evaluation, this method updates the channel sort key of recommended channels.
*
* @param size The number of channels that might be recommended.
- * @return Top {@code size} channels recommended sorted by score in descending order. If
- * {@code size} is bigger than the number of channels, the number of results could
- * be less than {@code size}.
+ * @return Top {@code size} channels recommended sorted by score in descending order. If {@code
+ * size} is bigger than the number of channels, the number of results could be less than
+ * {@code size}.
*/
public List<Channel> recommendChannels(int size) {
List<Pair<Channel, Double>> records = new ArrayList<>();
@@ -154,7 +153,7 @@ public class Recommender implements RecommendationDataManager.Listener {
*
* @param channelId The channel ID to retrieve the {@link Channel} object for.
* @return the {@link Channel} object for the given channel ID, {@code null} if such a channel
- * is not found.
+ * is not found.
*/
public Channel getChannel(long channelId) {
ChannelRecord record = mDataManager.getChannelRecord(channelId);
@@ -172,10 +171,10 @@ public class Recommender implements RecommendationDataManager.Listener {
}
/**
- * Returns the sort key of a given channel Id. Sort key is determined in
- * {@link #recommendChannels()} and getChannelSortKey must be called after that.
+ * Returns the sort key of a given channel Id. Sort key is determined in {@link
+ * #recommendChannels()} and getChannelSortKey must be called after that.
*
- * If getChannelSortKey was called before evaluating the channels or trying to get sort key
+ * <p>If getChannelSortKey was called before evaluating the channels or trying to get sort key
* of non-recommended channel, it returns {@link #INVALID_CHANNEL_SORT_KEY}.
*/
public String getChannelSortKey(long channelId) {
@@ -231,27 +230,25 @@ public class Recommender implements RecommendationDataManager.Listener {
mLastRecommendationUpdatedTimeUtcMillis = newUpdatedTimeMs;
}
- public static abstract class Evaluator {
+ public abstract static class Evaluator {
public static final double NOT_RECOMMENDED = -1.0;
private Recommender mRecommender;
protected Evaluator() {}
- protected void onChannelRecordListChanged(List<ChannelRecord> channelRecords) {
- }
+ protected void onChannelRecordListChanged(List<ChannelRecord> channelRecords) {}
/**
* This will be called when a new watch log comes into WatchedPrograms table.
*
* @param channelRecord The channel record corresponds to the new watch log.
*/
- protected void onNewWatchLog(ChannelRecord channelRecord) {
- }
+ protected void onNewWatchLog(ChannelRecord channelRecord) {}
/**
- * The implementation should return the recommendation score for the given channel ID.
- * The return value should be in the range of [0.0, 1.0] or NOT_RECOMMENDED for denoting
- * that it gives up to calculate the score for the channel.
+ * The implementation should return the recommendation score for the given channel ID. The
+ * return value should be in the range of [0.0, 1.0] or NOT_RECOMMENDED for denoting that it
+ * gives up to calculate the score for the channel.
*
* @param channelId The channel ID which will be evaluated by this recommender.
* @return The recommendation score
@@ -278,8 +275,8 @@ public class Recommender implements RecommendationDataManager.Listener {
// this value.
private final double mWeight;
- public EvaluatorWrapper(Recommender recommender, Evaluator evaluator,
- double baseScore, double weight) {
+ public EvaluatorWrapper(
+ Recommender recommender, Evaluator evaluator, double baseScore, double weight) {
mEvaluator = evaluator;
evaluator.setRecommender(recommender);
mBaseScore = baseScore;
@@ -287,27 +284,27 @@ public class Recommender implements RecommendationDataManager.Listener {
}
/**
- * This returns the scaled score for the given channel ID based on the returned value
- * of evaluateChannel().
+ * This returns the scaled score for the given channel ID based on the returned value of
+ * evaluateChannel().
*
* @param channelId The channel ID which will be evaluated by the recommender.
* @return Returns the scaled score (mBaseScore + score * mWeight) when evaluateChannel() is
- * in the range of [0.0, 1.0]. If evaluateChannel() returns NOT_RECOMMENDED or any
- * negative numbers, it returns NOT_RECOMMENDED. If calculateScore() returns more
- * than 1.0, it returns (mBaseScore + mWeight).
+ * in the range of [0.0, 1.0]. If evaluateChannel() returns NOT_RECOMMENDED or any
+ * negative numbers, it returns NOT_RECOMMENDED. If calculateScore() returns more than
+ * 1.0, it returns (mBaseScore + mWeight).
*/
private double getScaledEvaluatorScore(long channelId) {
double score = mEvaluator.evaluateChannel(channelId);
if (score < 0.0) {
if (score != Evaluator.NOT_RECOMMENDED) {
- Log.w(TAG, "Unexpected score (" + score + ") from the recommender"
- + mEvaluator);
+ Log.w(
+ TAG,
+ "Unexpected score (" + score + ") from the recommender" + mEvaluator);
}
// If the recommender gives up to calculate the score, return 0.0
return Evaluator.NOT_RECOMMENDED;
} else if (score > 1.0) {
- Log.w(TAG, "Unexpected score (" + score + ") from the recommender"
- + mEvaluator);
+ Log.w(TAG, "Unexpected score (" + score + ") from the recommender" + mEvaluator);
score = 1.0;
}
return mBaseScore + score * mWeight;
@@ -323,14 +320,10 @@ public class Recommender implements RecommendationDataManager.Listener {
}
public interface Listener {
- /**
- * Called after channel record map is loaded.
- */
+ /** Called after channel record map is loaded. */
void onRecommenderReady();
- /**
- * Called when the recommendation changes.
- */
+ /** Called when the recommendation changes. */
void onRecommendationChanged();
}
}
diff --git a/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java b/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java
index ad55afb7..edc23c53 100644
--- a/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java
+++ b/src/com/android/tv/recommendation/RecordedProgramPreviewUpdater.java
@@ -21,39 +21,32 @@ import android.os.Build;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import android.util.Log;
-
-import com.android.tv.ApplicationSingletons;
-import com.android.tv.TvApplication;
+import com.android.tv.TvSingletons;
import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.PreviewProgramContent;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.data.RecordedProgram;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-/**
- * Class to update the preview data for {@link RecordedProgram}
- */
+/** Class to update the preview data for {@link RecordedProgram} */
@RequiresApi(Build.VERSION_CODES.O)
+@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
public class RecordedProgramPreviewUpdater {
private static final String TAG = "RecordedProgramPreviewUpdater";
- // STOPSHIP: set it to false.
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final int RECOMMENDATION_COUNT = 6;
private static RecordedProgramPreviewUpdater sRecordedProgramPreviewUpdater;
- /**
- * Creates and returns the {@link RecordedProgramPreviewUpdater}.
- */
+ /** Creates and returns the {@link RecordedProgramPreviewUpdater}. */
public static RecordedProgramPreviewUpdater getInstance(Context context) {
if (sRecordedProgramPreviewUpdater == null) {
- sRecordedProgramPreviewUpdater
- = new RecordedProgramPreviewUpdater(context.getApplicationContext());
+ sRecordedProgramPreviewUpdater =
+ new RecordedProgramPreviewUpdater(context.getApplicationContext());
}
return sRecordedProgramPreviewUpdater;
}
@@ -64,56 +57,56 @@ public class RecordedProgramPreviewUpdater {
private RecordedProgramPreviewUpdater(Context context) {
mContext = context.getApplicationContext();
- ApplicationSingletons applicationSingletons = TvApplication.getSingletons(mContext);
- mPreviewDataManager = applicationSingletons.getPreviewDataManager();
- mDvrDataManager = applicationSingletons.getDvrDataManager();
- mDvrDataManager.addRecordedProgramListener(new DvrDataManager.RecordedProgramListener() {
- @Override
- public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
- if (DEBUG) Log.d(TAG, "Add new preview recorded programs");
- updatePreviewDataForRecordedPrograms();
- }
+ TvSingletons tvSingletons = TvSingletons.getSingletons(mContext);
+ mPreviewDataManager = tvSingletons.getPreviewDataManager();
+ mDvrDataManager = tvSingletons.getDvrDataManager();
+ mDvrDataManager.addRecordedProgramListener(
+ new DvrDataManager.RecordedProgramListener() {
+ @Override
+ public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
+ if (DEBUG) Log.d(TAG, "Add new preview recorded programs");
+ updatePreviewDataForRecordedPrograms();
+ }
- @Override
- public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
- if (DEBUG) Log.d(TAG, "Update preview recorded programs");
- updatePreviewDataForRecordedPrograms();
- }
+ @Override
+ public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
+ if (DEBUG) Log.d(TAG, "Update preview recorded programs");
+ updatePreviewDataForRecordedPrograms();
+ }
- @Override
- public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
- if (DEBUG) Log.d(TAG, "Delete preview recorded programs");
- updatePreviewDataForRecordedPrograms();
- }
- });
+ @Override
+ public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
+ if (DEBUG) Log.d(TAG, "Delete preview recorded programs");
+ updatePreviewDataForRecordedPrograms();
+ }
+ });
}
- /**
- * Updates the preview data for recorded programs.
- */
+ /** Updates the preview data for recorded programs. */
public void updatePreviewDataForRecordedPrograms() {
if (!mPreviewDataManager.isLoadFinished()) {
- mPreviewDataManager.addListener(new PreviewDataManager.PreviewDataListener() {
- @Override
- public void onPreviewDataLoadFinished() {
- mPreviewDataManager.removeListener(this);
- updatePreviewDataForRecordedPrograms();
- }
+ mPreviewDataManager.addListener(
+ new PreviewDataManager.PreviewDataListener() {
+ @Override
+ public void onPreviewDataLoadFinished() {
+ mPreviewDataManager.removeListener(this);
+ updatePreviewDataForRecordedPrograms();
+ }
- @Override
- public void onPreviewDataUpdateFinished() { }
- });
+ @Override
+ public void onPreviewDataUpdateFinished() {}
+ });
return;
}
if (!mDvrDataManager.isRecordedProgramLoadFinished()) {
mDvrDataManager.addRecordedProgramLoadFinishedListener(
new DvrDataManager.OnRecordedProgramLoadFinishedListener() {
- @Override
- public void onRecordedProgramLoadFinished() {
- mDvrDataManager.removeRecordedProgramLoadFinishedListener(this);
- updatePreviewDataForRecordedPrograms();
- }
- });
+ @Override
+ public void onRecordedProgramLoadFinished() {
+ mDvrDataManager.removeRecordedProgramLoadFinishedListener(this);
+ updatePreviewDataForRecordedPrograms();
+ }
+ });
return;
}
updatePreviewDataForRecordedProgramsInternal();
@@ -121,15 +114,18 @@ public class RecordedProgramPreviewUpdater {
private void updatePreviewDataForRecordedProgramsInternal() {
Set<RecordedProgram> recordedPrograms = generateRecommendationRecordedPrograms();
- Long recordedPreviewChannelId = mPreviewDataManager.getPreviewChannelId(
- PreviewDataManager.TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL);
+ Long recordedPreviewChannelId =
+ mPreviewDataManager.getPreviewChannelId(
+ PreviewDataManager.TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL);
if (recordedPreviewChannelId == PreviewDataManager.INVALID_PREVIEW_CHANNEL_ID
&& !recordedPrograms.isEmpty()) {
createPreviewChannelForRecordedPrograms();
} else {
- mPreviewDataManager.updatePreviewProgramsForChannel(recordedPreviewChannelId,
+ mPreviewDataManager.updatePreviewProgramsForChannel(
+ recordedPreviewChannelId,
generatePreviewProgramContentsFromRecordedPrograms(
- recordedPreviewChannelId, recordedPrograms), null);
+ recordedPreviewChannelId, recordedPrograms),
+ null);
}
}
@@ -168,8 +164,9 @@ public class RecordedProgramPreviewUpdater {
long previewChannelId, Set<RecordedProgram> recordedPrograms) {
Set<PreviewProgramContent> result = new HashSet<>();
for (RecordedProgram recordedProgram : recordedPrograms) {
- result.add(PreviewProgramContent.createFromRecordedProgram(mContext, previewChannelId,
- recordedProgram));
+ result.add(
+ PreviewProgramContent.createFromRecordedProgram(
+ mContext, previewChannelId, recordedProgram));
}
return result;
}
diff --git a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java
index 5ff7cae9..9240682a 100644
--- a/src/com/android/tv/recommendation/RoutineWatchEvaluator.java
+++ b/src/com/android/tv/recommendation/RoutineWatchEvaluator.java
@@ -19,9 +19,7 @@ package com.android.tv.recommendation;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
-
import com.android.tv.data.Program;
-
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Calendar;
@@ -32,8 +30,7 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
// TODO: test and refine constant values in WatchedProgramRecommender in order to
// improve the performance of this recommender.
private static final double REQUIRED_MIN_SCORE = 0.15;
- @VisibleForTesting
- static final double MULTIPLIER_FOR_UNMATCHED_DAY_OF_WEEK = 0.7;
+ @VisibleForTesting static final double MULTIPLIER_FOR_UNMATCHED_DAY_OF_WEEK = 0.7;
private static final double TITLE_MATCH_WEIGHT = 0.5;
private static final double TIME_MATCH_WEIGHT = 1 - TITLE_MATCH_WEIGHT;
private static final long DIFF_MS_TOLERANCE_FOR_OLD_PROGRAM = TimeUnit.DAYS.toMillis(14);
@@ -57,8 +54,8 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
}
Program watchedProgram = watchHistory[watchHistory.length - 1].getProgram();
- long startTimeDiffMsWithCurrentProgram = currentProgram.getStartTimeUtcMillis()
- - watchedProgram.getStartTimeUtcMillis();
+ long startTimeDiffMsWithCurrentProgram =
+ currentProgram.getStartTimeUtcMillis() - watchedProgram.getStartTimeUtcMillis();
if (startTimeDiffMsWithCurrentProgram >= MAX_DIFF_MS_FOR_OLD_PROGRAM) {
return NOT_RECOMMENDED;
}
@@ -70,42 +67,48 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
== watchHistory[i].getProgram().getStartTimeUtcMillis()) {
watchedDurationMs += watchHistory[i].getWatchedDurationMs();
} else {
- double score = calculateRoutineWatchScore(
- currentProgram, watchedProgram, watchedDurationMs);
+ double score =
+ calculateRoutineWatchScore(
+ currentProgram, watchedProgram, watchedDurationMs);
if (score >= REQUIRED_MIN_SCORE && score > maxScore) {
maxScore = score;
}
watchedProgram = watchHistory[i].getProgram();
watchedDurationMs = watchHistory[i].getWatchedDurationMs();
- startTimeDiffMsWithCurrentProgram = currentProgram.getStartTimeUtcMillis()
- - watchedProgram.getStartTimeUtcMillis();
+ startTimeDiffMsWithCurrentProgram =
+ currentProgram.getStartTimeUtcMillis()
+ - watchedProgram.getStartTimeUtcMillis();
if (startTimeDiffMsWithCurrentProgram >= MAX_DIFF_MS_FOR_OLD_PROGRAM) {
return maxScore;
}
}
}
- double score = calculateRoutineWatchScore(
- currentProgram, watchedProgram, watchedDurationMs);
+ double score =
+ calculateRoutineWatchScore(currentProgram, watchedProgram, watchedDurationMs);
if (score >= REQUIRED_MIN_SCORE && score > maxScore) {
maxScore = score;
}
return maxScore;
}
- private static double calculateRoutineWatchScore(Program currentProgram, Program watchedProgram,
- long watchedDurationMs) {
+ private static double calculateRoutineWatchScore(
+ Program currentProgram, Program watchedProgram, long watchedDurationMs) {
double timeMatchScore = calculateTimeMatchScore(currentProgram, watchedProgram);
- double titleMatchScore = calculateTitleMatchScore(
- currentProgram.getTitle(), watchedProgram.getTitle());
+ double titleMatchScore =
+ calculateTitleMatchScore(currentProgram.getTitle(), watchedProgram.getTitle());
double watchDurationScore = calculateWatchDurationScore(watchedProgram, watchedDurationMs);
- long diffMs = currentProgram.getStartTimeUtcMillis()
- - watchedProgram.getStartTimeUtcMillis();
- double multiplierForOldProgram = (diffMs < MAX_DIFF_MS_FOR_OLD_PROGRAM)
- ? 1.0 - (double) Math.max(diffMs - DIFF_MS_TOLERANCE_FOR_OLD_PROGRAM, 0)
- / (MAX_DIFF_MS_FOR_OLD_PROGRAM - DIFF_MS_TOLERANCE_FOR_OLD_PROGRAM)
- : 0.0;
+ long diffMs =
+ currentProgram.getStartTimeUtcMillis() - watchedProgram.getStartTimeUtcMillis();
+ double multiplierForOldProgram =
+ (diffMs < MAX_DIFF_MS_FOR_OLD_PROGRAM)
+ ? 1.0
+ - (double) Math.max(diffMs - DIFF_MS_TOLERANCE_FOR_OLD_PROGRAM, 0)
+ / (MAX_DIFF_MS_FOR_OLD_PROGRAM
+ - DIFF_MS_TOLERANCE_FOR_OLD_PROGRAM)
+ : 0.0;
return (titleMatchScore * TITLE_MATCH_WEIGHT + timeMatchScore * TIME_MATCH_WEIGHT)
- * watchDurationScore * multiplierForOldProgram;
+ * watchDurationScore
+ * multiplierForOldProgram;
}
@VisibleForTesting
@@ -118,8 +121,7 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
if (wordList1.isEmpty() || wordList2.isEmpty()) {
return 0;
}
- int maxMatchedWordSeqLen = calculateMaximumMatchedWordSequenceLength(
- wordList1, wordList2);
+ int maxMatchedWordSeqLen = calculateMaximumMatchedWordSequenceLength(wordList1, wordList2);
// F-measure score
double precision = (double) maxMatchedWordSeqLen / wordList1.size();
@@ -128,8 +130,8 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
}
@VisibleForTesting
- static int calculateMaximumMatchedWordSequenceLength(List<String> toSearchWords,
- List<String> toMatchWords) {
+ static int calculateMaximumMatchedWordSequenceLength(
+ List<String> toSearchWords, List<String> toMatchWords) {
int[] matchedWordSeqLen = new int[toMatchWords.size()];
int maxMatchedWordSeqLen = 0;
for (String word : toSearchWords) {
@@ -170,14 +172,20 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
boolean sameDay = false;
// Handle cases like (00:00 - 02:00) - (01:00 - 03:00) or (22:00 - 25:00) - (23:00 - 26:00).
- double score = Math.max(0, Math.min(t1.endTimeOfDayInSec, t2.endTimeOfDayInSec)
- - Math.max(t1.startTimeOfDayInSec, t2.startTimeOfDayInSec));
+ double score =
+ Math.max(
+ 0,
+ Math.min(t1.endTimeOfDayInSec, t2.endTimeOfDayInSec)
+ - Math.max(t1.startTimeOfDayInSec, t2.startTimeOfDayInSec));
if (score > 0) {
sameDay = (t1.weekDay == t2.weekDay);
} else if (t1.dayChanged != t2.dayChanged) {
// To handle cases like t1 : (00:00 - 01:00) and t2 : (23:00 - 25:00).
- score = Math.max(0, Math.min(t1.endTimeOfDayInSec, t2.endTimeOfDayInSec - 24 * 60 * 60)
- - t1.startTimeOfDayInSec);
+ score =
+ Math.max(
+ 0,
+ Math.min(t1.endTimeOfDayInSec, t2.endTimeOfDayInSec - 24 * 60 * 60)
+ - t1.startTimeOfDayInSec);
// Same day if next day of t2's start day equals to t1's start day. (1 <= weekDay <= 7)
sameDay = (t1.weekDay == ((t2.weekDay % 7) + 1));
}
@@ -206,7 +214,8 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
BreakIterator boundary = BreakIterator.getWordInstance();
boundary.setText(text);
int start = boundary.first();
- for (int end = boundary.next(); end != BreakIterator.DONE;
+ for (int end = boundary.next();
+ end != BreakIterator.DONE;
start = end, end = boundary.next()) {
String word = text.substring(start, end);
if (Character.isLetterOrDigit(word.charAt(0))) {
@@ -233,15 +242,20 @@ public class RoutineWatchEvaluator extends Recommender.Evaluator {
time.setTimeInMillis(p.getEndTimeUtcMillis());
boolean dayChanged = (weekDay != time.get(Calendar.DAY_OF_WEEK));
// Set maximum program duration time to 12 hours.
- int endTimeOfDayInSec = startTimeOfDayInSec +
- (int) Math.min(p.getEndTimeUtcMillis() - p.getStartTimeUtcMillis(),
- TimeUnit.HOURS.toMillis(12)) / 1000;
+ int endTimeOfDayInSec =
+ startTimeOfDayInSec
+ + (int)
+ Math.min(
+ p.getEndTimeUtcMillis()
+ - p.getStartTimeUtcMillis(),
+ TimeUnit.HOURS.toMillis(12))
+ / 1000;
return new ProgramTime(startTimeOfDayInSec, endTimeOfDayInSec, weekDay, dayChanged);
}
- private ProgramTime(int startTimeOfDayInSec, int endTimeOfDayInSec, int weekDay,
- boolean dayChanged) {
+ private ProgramTime(
+ int startTimeOfDayInSec, int endTimeOfDayInSec, int weekDay, boolean dayChanged) {
this.startTimeOfDayInSec = startTimeOfDayInSec;
this.endTimeOfDayInSec = endTimeOfDayInSec;
this.weekDay = weekDay;