Home | History | Annotate | Download | only in dvr
      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.android.tv.dvr;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.Service;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.os.Binder;
     24 import android.os.HandlerThread;
     25 import android.os.IBinder;
     26 import android.support.annotation.Nullable;
     27 import android.support.annotation.VisibleForTesting;
     28 import android.util.Log;
     29 
     30 import com.android.tv.ApplicationSingletons;
     31 import com.android.tv.TvApplication;
     32 import com.android.tv.common.feature.CommonFeatures;
     33 import com.android.tv.util.Clock;
     34 import com.android.tv.util.RecurringRunner;
     35 import com.android.tv.common.SoftPreconditions;
     36 
     37 /**
     38  * DVR Scheduler service.
     39  *
     40  * <p> This service is responsible for:
     41  * <ul>
     42  *     <li>Send record commands to TV inputs</li>
     43  *     <li>Wake up at proper timing for recording</li>
     44  *     <li>Deconflict schedule, handling overlapping times etc.</li>
     45  *     <li>
     46  *
     47  * </ul>
     48  *
     49  * <p>The service does not stop it self.
     50  */
     51 public class DvrRecordingService extends Service {
     52     private static final String TAG = "DvrRecordingService";
     53     private static final boolean DEBUG = false;
     54     public static final String HANDLER_THREAD_NAME = "DvrRecordingService-handler";
     55 
     56     public static void startService(Context context) {
     57         Intent dvrSchedulerIntent = new Intent(context, DvrRecordingService.class);
     58         context.startService(dvrSchedulerIntent);
     59     }
     60 
     61     private final Clock mClock = Clock.SYSTEM;
     62     private RecurringRunner mReaperRunner;
     63     private WritableDvrDataManager mDataManager;
     64 
     65     /**
     66      * Class for clients to access. Because we know this service always
     67      * runs in the same process as its clients, we don't need to deal with
     68      * IPC.
     69      */
     70     public class SchedulerBinder extends Binder {
     71         Scheduler getScheduler() {
     72             return mScheduler;
     73         }
     74     }
     75 
     76     private final IBinder mBinder = new SchedulerBinder();
     77 
     78     private Scheduler mScheduler;
     79     private HandlerThread mHandlerThread;
     80 
     81     @Override
     82     public void onCreate() {
     83         if (DEBUG) Log.d(TAG, "onCreate");
     84         super.onCreate();
     85         SoftPreconditions.checkFeatureEnabled(this, CommonFeatures.DVR, TAG);
     86         ApplicationSingletons singletons = TvApplication.getSingletons(this);
     87         mDataManager = (WritableDvrDataManager) singletons.getDvrDataManager();
     88 
     89         AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
     90         // mScheduler may have been set for testing.
     91         if (mScheduler == null) {
     92             mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
     93             mHandlerThread.start();
     94             mScheduler = new Scheduler(mHandlerThread.getLooper(), singletons.getDvrManager(),
     95                     singletons.getDvrSessionManger(), mDataManager,
     96                     singletons.getChannelDataManager(), this, mClock, alarmManager);
     97         }
     98         mDataManager.addScheduledRecordingListener(mScheduler);
     99         mReaperRunner = new RecurringRunner(this, java.util.concurrent.TimeUnit.DAYS.toMillis(1),
    100                 new ScheduledProgramReaper(mDataManager, mClock), null);
    101         mReaperRunner.start();
    102     }
    103 
    104     @Override
    105     public int onStartCommand(Intent intent, int flags, int startId) {
    106         if (DEBUG) Log.d(TAG, "onStartCommand (" + intent + "," + flags + "," + startId + ")");
    107         mScheduler.update();
    108         return START_STICKY;
    109     }
    110 
    111     @Override
    112     public void onDestroy() {
    113         if (DEBUG) Log.d(TAG, "onDestroy");
    114         mReaperRunner.stop();
    115         mDataManager.removeScheduledRecordingListener(mScheduler);
    116         mScheduler = null;
    117         if (mHandlerThread != null) {
    118             mHandlerThread.quit();
    119             mHandlerThread = null;
    120         }
    121         super.onDestroy();
    122     }
    123 
    124     @Nullable
    125     @Override
    126     public IBinder onBind(Intent intent) {
    127         return mBinder;
    128     }
    129 
    130     @VisibleForTesting
    131     void setScheduler(Scheduler scheduler) {
    132         Log.i(TAG, "Setting scheduler for tests to " + scheduler);
    133         mScheduler = scheduler;
    134     }
    135 }
    136