Home | History | Annotate | Download | only in buffer
      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.tuner.exoplayer.buffer;
     18 
     19 import android.content.Context;
     20 import android.os.AsyncTask;
     21 import android.provider.Settings;
     22 import android.support.annotation.NonNull;
     23 import android.util.Pair;
     24 
     25 import com.android.tv.common.SoftPreconditions;
     26 
     27 import java.io.File;
     28 import java.util.ArrayList;
     29 import java.util.List;
     30 import java.util.SortedMap;
     31 
     32 /**
     33  * Manages Trickplay storage.
     34  */
     35 public class TrickplayStorageManager implements BufferManager.StorageManager {
     36     // TODO: Support multi-sessions.
     37     private static final String BUFFER_DIR = "timeshift";
     38 
     39     // Copied from android.provider.Settings.Global (hidden fields)
     40     private static final String
     41             SYS_STORAGE_THRESHOLD_PERCENTAGE = "sys_storage_threshold_percentage";
     42     private static final String
     43             SYS_STORAGE_THRESHOLD_MAX_BYTES = "sys_storage_threshold_max_bytes";
     44 
     45     // Copied from android.os.StorageManager
     46     private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
     47     private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500L * 1024 * 1024;
     48 
     49     private static AsyncTask<Void, Void, Void> sLastCacheCleanUpTask;
     50     private static File sBufferDir;
     51     private static long sStorageBufferBytes;
     52 
     53     private final long mMaxBufferSize;
     54 
     55     private static void initParamsIfNeeded(Context context, @NonNull File path) {
     56         // TODO: Support multi-sessions.
     57         SoftPreconditions.checkState(
     58                 sBufferDir == null || sBufferDir.equals(path));
     59         if (path.equals(sBufferDir)) {
     60             return;
     61         }
     62         sBufferDir = path;
     63         long lowPercentage = Settings.Global.getInt(context.getContentResolver(),
     64                 SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
     65         long lowPercentageToBytes = path.getTotalSpace() * lowPercentage / 100;
     66         long maxLowBytes = Settings.Global.getLong(context.getContentResolver(),
     67                 SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
     68         sStorageBufferBytes = Math.min(lowPercentageToBytes, maxLowBytes);
     69     }
     70 
     71     public TrickplayStorageManager(Context context, @NonNull File baseDir, long maxBufferSize) {
     72         initParamsIfNeeded(context, new File(baseDir, BUFFER_DIR));
     73         sBufferDir.mkdirs();
     74         mMaxBufferSize = maxBufferSize;
     75         clearStorage();
     76     }
     77 
     78     private void clearStorage() {
     79         long now = System.currentTimeMillis();
     80         if (sLastCacheCleanUpTask != null) {
     81             sLastCacheCleanUpTask.cancel(true);
     82         }
     83         sLastCacheCleanUpTask = new AsyncTask<Void, Void, Void>() {
     84             @Override
     85             protected Void doInBackground(Void... params) {
     86                 if (isCancelled()) {
     87                     return null;
     88                 }
     89                 File files[] = sBufferDir.listFiles();
     90                 if (files == null || files.length == 0) {
     91                     return null;
     92                 }
     93                 for (File file : files) {
     94                     if (isCancelled()) {
     95                         break;
     96                     }
     97                     long lastModified = file.lastModified();
     98                     if (lastModified != 0 && lastModified < now) {
     99                         file.delete();
    100                     }
    101                 }
    102                 return null;
    103             }
    104         };
    105         sLastCacheCleanUpTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    106     }
    107 
    108     @Override
    109     public File getBufferDir() {
    110         return sBufferDir;
    111     }
    112 
    113     @Override
    114     public boolean isPersistent() {
    115         return false;
    116     }
    117 
    118     @Override
    119     public boolean reachedStorageMax(long bufferSize, long pendingDelete) {
    120         return bufferSize - pendingDelete > mMaxBufferSize;
    121     }
    122 
    123     @Override
    124     public boolean hasEnoughBuffer(long pendingDelete) {
    125         return sBufferDir.getUsableSpace() + pendingDelete >= sStorageBufferBytes;
    126     }
    127 
    128     @Override
    129     public List<BufferManager.TrackFormat> readTrackInfoFiles(boolean isAudio) {
    130         return null;
    131     }
    132 
    133     @Override
    134     public ArrayList<BufferManager.PositionHolder> readIndexFile(String trackId) {
    135         return null;
    136     }
    137 
    138     @Override
    139     public void writeTrackInfoFiles(List<BufferManager.TrackFormat> formatList, boolean isAudio) {
    140     }
    141 
    142     @Override
    143     public void writeIndexFile(String trackName,
    144             SortedMap<Long, Pair<SampleChunk, Integer>> index) {
    145     }
    146 
    147 }
    148