Home | History | Annotate | Download | only in recommendation
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.tvleanback.recommendation;
     18 
     19 import android.app.Notification;
     20 import android.app.PendingIntent;
     21 import android.content.ContentProvider;
     22 import android.content.ContentValues;
     23 import android.content.Context;
     24 import android.database.Cursor;
     25 import android.graphics.Bitmap;
     26 import android.net.Uri;
     27 import android.os.Bundle;
     28 import android.os.ParcelFileDescriptor;
     29 import android.support.v4.app.NotificationCompat;
     30 import android.util.Log;
     31 
     32 import com.example.android.tvleanback.R;
     33 
     34 import java.io.File;
     35 import java.io.FileNotFoundException;
     36 import java.io.FileOutputStream;
     37 import java.io.IOException;
     38 
     39 /*
     40  * This class builds recommendations as notifications with videos as inputs.
     41  */
     42 public class RecommendationBuilder {
     43     private static final String TAG = "RecommendationBuilder";
     44     private static final String
     45             BACKGROUND_URI_PREFIX = "content://com.example.android.tvleanback.recommendation/";
     46 
     47     private Context mContext;
     48 
     49     private int mId;
     50     private int mPriority;
     51     private int mSmallIcon;
     52     private String mTitle;
     53     private String mDescription;
     54     private Bitmap mBitmap;
     55     private String mBackgroundUri;
     56     private String mGroupKey;
     57     private String mSort;
     58     private PendingIntent mIntent;
     59 
     60     public RecommendationBuilder() {
     61     }
     62 
     63     public RecommendationBuilder setContext(Context context) {
     64         mContext = context;
     65         return this;
     66     }
     67 
     68     public RecommendationBuilder setId(int id) {
     69         mId = id;
     70         return this;
     71     }
     72 
     73     public RecommendationBuilder setPriority(int priority) {
     74         mPriority = priority;
     75         return this;
     76     }
     77 
     78     public RecommendationBuilder setTitle(String title) {
     79         mTitle = title;
     80         return this;
     81     }
     82 
     83     public RecommendationBuilder setDescription(String description) {
     84         mDescription = description;
     85         return this;
     86     }
     87 
     88     public RecommendationBuilder setBitmap(Bitmap bitmap) {
     89         mBitmap = bitmap;
     90         return this;
     91     }
     92 
     93     public RecommendationBuilder setBackground(String uri) {
     94         mBackgroundUri = uri;
     95         return this;
     96     }
     97 
     98     public RecommendationBuilder setIntent(PendingIntent intent) {
     99         mIntent = intent;
    100         return this;
    101     }
    102 
    103     public RecommendationBuilder setSmallIcon(int resourceId) {
    104         mSmallIcon = resourceId;
    105         return this;
    106     }
    107 
    108     public Notification build() {
    109 
    110         Bundle extras = new Bundle();
    111         File bitmapFile = getNotificationBackground(mContext, mId);
    112 
    113         if (mBackgroundUri != null) {
    114             extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI,
    115                     Uri.parse(BACKGROUND_URI_PREFIX + Integer.toString(mId)).toString());
    116         }
    117 
    118         // the following simulates group assignment into "Top", "Middle", "Bottom"
    119         // by checking mId and similarly sort order
    120         mGroupKey = (mId < 3) ? "Top" : (mId < 5) ? "Middle" : "Bottom";
    121         mSort = (mId < 3) ? "1.0" : (mId < 5) ? "0.7" : "0.3";
    122 
    123         // save bitmap into files for content provider to serve later
    124         try {
    125             bitmapFile.createNewFile();
    126             FileOutputStream fOut = new FileOutputStream(bitmapFile);
    127             mBitmap.compress(Bitmap.CompressFormat.PNG, 85, fOut);
    128             fOut.flush();
    129             fOut.close();
    130         } catch (IOException ioe) {
    131             Log.d(TAG, "Exception caught writing bitmap to file!", ioe);
    132         }
    133 
    134         Notification notification = new NotificationCompat.BigPictureStyle(
    135                 new NotificationCompat.Builder(mContext)
    136                         .setAutoCancel(true)
    137                         .setContentTitle(mTitle)
    138                         .setContentText(mDescription)
    139                         .setPriority(mPriority)
    140                         .setLocalOnly(true)
    141                         .setOngoing(true)
    142                         /*
    143                         groupKey (optional): Can be used to group together recommendations, so
    144                         they are ranked by the launcher as a separate group. Can be useful if the
    145                         application has different sources for recommendations, like "trending",
    146                         "subscriptions", and "new music" categories for YouTube, where the user can
    147                         be more interested in recommendations from one group than another.
    148                          */
    149                         .setGroup(mGroupKey)
    150                         /*
    151                         sortKey (optional): A float number between 0.0 and 1.0, used to indicate
    152                         the relative importance (and sort order) of a single recommendation within
    153                         its specified group. The recommendations will be ordered in decreasing
    154                         order of importance within a given group.
    155                          */
    156                         .setSortKey(mSort)
    157                         .setColor(mContext.getResources().getColor(R.color.fastlane_background))
    158                         .setCategory(Notification.CATEGORY_RECOMMENDATION)
    159                         .setLargeIcon(mBitmap)
    160                         .setSmallIcon(mSmallIcon)
    161                         .setContentIntent(mIntent)
    162                         .setExtras(extras))
    163                 .build();
    164 
    165         Log.d(TAG, "Building notification - " + this.toString());
    166 
    167         return notification;
    168     }
    169 
    170     @Override
    171     public String toString() {
    172         return "RecommendationBuilder{" +
    173                 ", mId=" + mId +
    174                 ", mPriority=" + mPriority +
    175                 ", mSmallIcon=" + mSmallIcon +
    176                 ", mTitle='" + mTitle + '\'' +
    177                 ", mDescription='" + mDescription + '\'' +
    178                 ", mBitmap='" + mBitmap + '\'' +
    179                 ", mBackgroundUri='" + mBackgroundUri + '\'' +
    180                 ", mIntent=" + mIntent +
    181                 '}';
    182     }
    183 
    184     public static class RecommendationBackgroundContentProvider extends ContentProvider {
    185 
    186         @Override
    187         public boolean onCreate() {
    188             return true;
    189         }
    190 
    191         @Override
    192         public int delete(Uri uri, String selection, String[] selectionArgs) {
    193             return 0;
    194         }
    195 
    196         @Override
    197         public String getType(Uri uri) {
    198             return null;
    199         }
    200 
    201         @Override
    202         public Uri insert(Uri uri, ContentValues values) {
    203             return null;
    204         }
    205 
    206         @Override
    207         public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
    208                             String sortOrder) {
    209             return null;
    210         }
    211 
    212         @Override
    213         public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    214             return 0;
    215         }
    216 
    217         @Override
    218         /*
    219          * content provider serving files that are saved locally when recommendations are built
    220          */
    221         public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    222             int backgroundId = Integer.parseInt(uri.getLastPathSegment());
    223             File bitmapFile = getNotificationBackground(getContext(), backgroundId);
    224             return ParcelFileDescriptor.open(bitmapFile, ParcelFileDescriptor.MODE_READ_ONLY);
    225         }
    226     }
    227 
    228     private static File getNotificationBackground(Context context, int notificationId) {
    229         return new File(context.getCacheDir(), "tmp" + Integer.toString(notificationId) + ".png");
    230     }
    231 
    232 }
    233