diff options
author | Sungsoo Lim <sungsoo@google.com> | 2014-06-05 13:37:01 +0900 |
---|---|---|
committer | Sungsoo Lim <sungsoo@google.com> | 2014-06-06 10:14:33 +0900 |
commit | 566ceca13abf57ac85ac44993f19fcfa6959c986 (patch) | |
tree | 37ed1c7848072f7b297105ed0895fe5b66daba4d | |
parent | e78833548e244a5b4e191dadc5285a1afa0ad69a (diff) | |
download | TV-566ceca13abf57ac85ac44993f19fcfa6959c986.tar.gz |
Show top 2 results of the TV recommendation in LeanbackLauncher
Bug: 15415303
Change-Id: If90e1d13895fcf905bc1b4e2d2c33463c3883170
-rw-r--r-- | AndroidManifest.xml | 6 | ||||
-rw-r--r-- | src/com/android/tv/notification/NotificationReceiver.java | 68 | ||||
-rw-r--r-- | src/com/android/tv/notification/NotificationService.java | 83 | ||||
-rw-r--r-- | src/com/android/tv/recommendation/TvRecommendation.java | 27 | ||||
-rw-r--r-- | src/com/android/tv/ui/MainMenuView.java | 2 |
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), |