aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSungsoo Lim <sungsoo@google.com>2014-06-05 13:37:01 +0900
committerSungsoo Lim <sungsoo@google.com>2014-06-06 10:14:33 +0900
commit566ceca13abf57ac85ac44993f19fcfa6959c986 (patch)
tree37ed1c7848072f7b297105ed0895fe5b66daba4d
parente78833548e244a5b4e191dadc5285a1afa0ad69a (diff)
downloadTV-566ceca13abf57ac85ac44993f19fcfa6959c986.tar.gz
Show top 2 results of the TV recommendation in LeanbackLauncher
Bug: 15415303 Change-Id: If90e1d13895fcf905bc1b4e2d2c33463c3883170
-rw-r--r--AndroidManifest.xml6
-rw-r--r--src/com/android/tv/notification/NotificationReceiver.java68
-rw-r--r--src/com/android/tv/notification/NotificationService.java83
-rw-r--r--src/com/android/tv/recommendation/TvRecommendation.java27
-rw-r--r--src/com/android/tv/ui/MainMenuView.java2
5 files changed, 179 insertions, 7 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b7b1f8f3..c3646126 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -57,6 +57,12 @@
android:enabled="true">
</provider>
+ <service android:name="com.android.tv.notification.NotificationService"/>
+ <receiver android:name="com.android.tv.notification.NotificationReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED"/>
+ </intent-filter>
+ </receiver>
<receiver android:name="com.android.tv.receiver.PackageIntentsReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
diff --git a/src/com/android/tv/notification/NotificationReceiver.java b/src/com/android/tv/notification/NotificationReceiver.java
new file mode 100644
index 00000000..1e5a5b04
--- /dev/null
+++ b/src/com/android/tv/notification/NotificationReceiver.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.notification;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/*
+ * Notification Broadcast Receiver
+ * Start notification service
+ */
+public class NotificationReceiver extends BroadcastReceiver {
+ private static final String TAG = NotificationReceiver.class.getName();
+ private static final int SERVICE_REQUEST_CODE = 7151940; // a random number
+ private static final int ONE_SECOND_MILLIS = 1000;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ startAutoLoadAlarm(context);
+ }
+
+ public static void startAutoLoadAlarm(Context context) {
+ Intent notificationService = new Intent(context, NotificationService.class);
+
+ // FLAG_ACTIVITY_BROUGHT_TO_FRONT is singleTask launch mode.
+ notificationService.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+
+ // FLAG_UPDATE_CURRENT flag indicates that if the described
+ // PendingIntent already exists, then keep it but replace its extra
+ // data with what is in this new intent.
+ PendingIntent pendingIntent = PendingIntent.getService(context, SERVICE_REQUEST_CODE,
+ notificationService, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ // The Alarm Manager is intended for cases where we want to have
+ // application code run at a specific time, even if the application is
+ // not currently running.
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+ // Schedule a repeating alarm.
+ // RTC : This alarm does not wake the device up; if it goes off while
+ // the device is asleep, it will not be delivered until the next time
+ // the device wakes up.
+ // System.currentTimeMillis() postpones the time to send notifications.
+ // The reason that Notifications wasn't posted immediately is we set up
+ // the alarm at boot time, but the network or other stuff were not been
+ // set up yet
+ // TODO: confirm the update time. Currently update every 15 minutes.
+ alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis() + ONE_SECOND_MILLIS,
+ AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
+ }
+}
diff --git a/src/com/android/tv/notification/NotificationService.java b/src/com/android/tv/notification/NotificationService.java
new file mode 100644
index 00000000..0553b4dd
--- /dev/null
+++ b/src/com/android/tv/notification/NotificationService.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.notification;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+
+import com.android.tv.R;
+import com.android.tv.data.Program;
+import com.android.tv.recommendation.RecentChannelRecommender;
+import com.android.tv.recommendation.TvRecommendation;
+import com.android.tv.recommendation.TvRecommendation.ChannelRecord;
+import com.android.tv.util.Utils;
+
+public class NotificationService extends IntentService {
+ private static final String TAG = NotificationService.class.getName();
+ private static final String NOTIFY_TAG = "tv_recommendation";
+ // TODO: find out proper number of notifications and whether to make it dynamically
+ // configurable from system property or etc.
+ private static final int NOTIFICATION_COUNT = 2;
+
+ private TvRecommendation mTvRecommendation;
+ private NotificationManager mNotificationManager;
+ private final Handler mHandler;
+
+ public NotificationService() {
+ super("TV Notification");
+ mHandler = new Handler();
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mTvRecommendation = new TvRecommendation(this, mHandler, true);
+ mTvRecommendation.registerTvRecommender(new RecentChannelRecommender());
+ mNotificationManager = (NotificationManager) getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ }
+
+ @Override
+ protected void onHandleIntent(final Intent intent) {
+ ChannelRecord[] channelRecords =
+ mTvRecommendation.getRecommendedChannelList(NOTIFICATION_COUNT);
+ for (ChannelRecord cr : channelRecords) {
+ sendNotification(cr);
+ }
+ }
+
+ public void sendNotification(ChannelRecord cr) {
+ Intent intent = new Intent(Intent.ACTION_VIEW, cr.getChannelUri());
+ PendingIntent notificationIntent = PendingIntent.getActivity(this, 0, intent, 0);
+ Program program = Utils.getCurrentProgram(this, cr.getChannelUri());
+ // TODO: provide large icon.
+ Notification notification = new Notification.Builder(this)
+ .setContentIntent(notificationIntent)
+ .setContentTitle(program.getTitle())
+ .setContentText(program.getDescription())
+ .setAutoCancel(true)
+ .setSmallIcon(R.drawable.app_icon)
+ .setCategory(Notification.CATEGORY_RECOMMENDATION)
+ .build();
+ mNotificationManager.notify(NOTIFY_TAG, (int) cr.getChannel().getId(), notification);
+ }
+}
diff --git a/src/com/android/tv/recommendation/TvRecommendation.java b/src/com/android/tv/recommendation/TvRecommendation.java
index fd6cd409..a8129007 100644
--- a/src/com/android/tv/recommendation/TvRecommendation.java
+++ b/src/com/android/tv/recommendation/TvRecommendation.java
@@ -41,17 +41,13 @@ public class TvRecommendation {
private static final int MATCH_CHANNEL_ID = 1;
private static final int MATCH_WATCHED_PROGRAM_ID = 2;
- private static final List<TvRecommenderWrapper> sTvRecommenders =
- new ArrayList<TvRecommenderWrapper>();
-
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(TvContract.AUTHORITY, "channel/#", MATCH_CHANNEL_ID);
sUriMatcher.addURI(TvContract.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID);
-
- sTvRecommenders.add(new TvRecommenderWrapper(new RecentChannelRecommender()));
}
+ private final List<TvRecommenderWrapper> mTvRecommenders;
private final Map<Long, ChannelRecord> mChannelRecordMap;
// TODO: Consider to define each observer rather than the list or observers.
private final List<ContentObserver> mContentObservers;
@@ -75,6 +71,7 @@ public class TvRecommendation {
mContentObservers = new ArrayList<ContentObserver>();
mHandler = handler;
mIncludeRecommendedOnly = includeRecommendedOnly;
+ mTvRecommenders = new ArrayList<TvRecommenderWrapper>();
registerContentObservers();
buildChannelRecordMap();
}
@@ -84,6 +81,15 @@ public class TvRecommendation {
mChannelRecordMap.clear();
}
+ public void registerTvRecommender(TvRecommender recommender) {
+ registerTvRecommender(recommender,
+ TvRecommenderWrapper.DEFAULT_BASE_SCORE, TvRecommenderWrapper.DEFAULT_WEIGHT);
+ }
+
+ public void registerTvRecommender(TvRecommender recommender, double baseScore, double weight) {
+ mTvRecommenders.add(new TvRecommenderWrapper(recommender, baseScore, weight));
+ }
+
/**
* Get the channel list of recommendation up to {@code n} or the number of channels.
*
@@ -96,7 +102,7 @@ public class TvRecommendation {
ArrayList<ChannelRecord> results = new ArrayList<ChannelRecord>();
for (ChannelRecord cr : mChannelRecordMap.values()) {
double maxScore = TvRecommender.NOT_RECOMMENDED;
- for (TvRecommenderWrapper recommender : sTvRecommenders) {
+ for (TvRecommenderWrapper recommender : mTvRecommenders) {
double score = recommender.calculateScaledScore(cr);
if (score > maxScore) {
maxScore = score;;
@@ -132,7 +138,7 @@ public class TvRecommendation {
if (cursor != null && cursor.moveToFirst()) {
ChannelRecord channelRecord =
updateChannelRecordFromWatchedProgramCursor(cursor);
- for (TvRecommenderWrapper recommender : sTvRecommenders) {
+ for (TvRecommenderWrapper recommender : mTvRecommenders) {
recommender.onNewWatchLog(channelRecord);
}
}
@@ -252,12 +258,15 @@ public class TvRecommendation {
public static class ChannelRecord implements Comparable<ChannelRecord> {
private final Channel mChannel;
+ private final Uri mChannelUri;
private long mLastWatchedTimeMs;
private long mLastWatchDurationMs;
private double mScore;
public ChannelRecord(Channel channel) {
mChannel = channel;
+ mChannelUri = ContentUris.withAppendedId(TvContract.Channels.CONTENT_URI,
+ channel.getId());
mLastWatchedTimeMs = 0l;
mLastWatchDurationMs = 0;
}
@@ -266,6 +275,10 @@ public class TvRecommendation {
return mChannel;
}
+ public Uri getChannelUri() {
+ return mChannelUri;
+ }
+
public long getLastWatchedTimeMs() {
return mLastWatchedTimeMs;
}
diff --git a/src/com/android/tv/ui/MainMenuView.java b/src/com/android/tv/ui/MainMenuView.java
index 6dcac0e6..1fa32a42 100644
--- a/src/com/android/tv/ui/MainMenuView.java
+++ b/src/com/android/tv/ui/MainMenuView.java
@@ -35,6 +35,7 @@ import com.android.tv.R;
import com.android.tv.TvActivity;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelMap;
+import com.android.tv.recommendation.RecentChannelRecommender;
import com.android.tv.recommendation.TvRecommendation;
import java.util.ArrayList;
@@ -108,6 +109,7 @@ public class MainMenuView extends FrameLayout implements View.OnClickListener,
// List for guide + recent channels
mTvRecommendation = new TvRecommendation(context, mHandler, true);
+ mTvRecommendation.registerTvRecommender(new RecentChannelRecommender());
mAllAdapterList.add(new RecommendationListAdapter(context, mHandler, this,
mTvRecommendation, true, MAX_COUNT_FOR_RECOMMENDATION, R.layout.channel_tile,
context.getString(R.string.channel_list_title),