/* * Copyright (c) 2015 [1076559197@qq.com | tchen0707@gmail.com] * * 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.youku.service.download; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.os.Handler; import android.os.RemoteException; import android.text.TextUtils; import com.baseproject.utils.Logger; import com.baseproject.utils.Util; import com.youku.player.YoukuPlayerApplication; import com.youku.player.ui.R; import com.youku.player.util.PlayerUtil; import com.youku.player.util.URLContainer; import com.youku.service.acc.AcceleraterManager; import com.youku.service.acc.AcceleraterServiceManager; /** * DownloadServiceManager.缓存管理 * * @author 刘仲男 qq81595157@126.com * @version v3.5 * @created time 2012-11-5 下午1:16:02 */ @SuppressWarnings("rawtypes") public class DownloadServiceManager extends BaseDownload { private static final String TAG = "Download_ServiceManager"; private static DownloadServiceManager instance; private HashMap<String, DownloadInfo> downloadingData; private FileDownloadThread thread; private ICallback callback; /** 初始化注册网络广播的锁,防止错误的网络变化 */ private boolean initlock = false; private boolean first_tips = true; private AcceleraterManager acceleraterManager; /** 网络改变事件接收器 */ private BroadcastReceiver networkReceiver = new BroadcastReceiver() { @Override public void onReceive(Context c, Intent intent) { if (initlock) { initlock = false; return; } boolean hasNetwork = Util.hasInternet(); Logger.d(TAG, "network changed : " + hasNetwork); if (!hasNetwork) {// 无网络 if (hasLivingTask()) { PlayerUtil.showTips(R.string.download_no_network); } stopAllTask(); } else {// 有网络 cleanRetry(); /* * if (getP2p_switch() == 1 && * IAcceleraterService.isACCEnable(YoukuPlayerApplication.context)) { if * (YoukuUtil.isWifi()) {// wifi可用加速器 switch * (Accstub.isAvailable()) { case -1: * IAcceleraterService.startAcc(YoukuPlayerApplication.context); break; case 0: * Accstub.resume(); break; } } else {// 2g/3g不可用加速器 if * (Accstub.isAvailable() == 1) { Accstub.pause(); } } } else { * IAcceleraterService.closeAcc(YoukuPlayerApplication.context); } */ if (hasDownloadingTask()) {// 有网络,且有下载中视频 // if (!isAccAvailable() && canUseAcc()) { // new Handler() { // }.postDelayed(new Runnable() { // // @Override // public void run() { // IAcceleraterService.startAcc();// ACC加速的Service // } // }, 3000); // } else { // if (BuildConfig.DEBUG) // Logger.d("Download_ACCFlow", "有下载中视频,acc状态保持不变"); // } } else {// 有网络,且无下载中视频 new Handler() { }.postDelayed(new Runnable() { @Override public void run() { startNewTask(); } }, 1500); } if (Util.isWifi()) {// wifi first_tips = true; } else {// 3G friendlyTips(); } } } }; /** SD卡事件接收器 */ private BroadcastReceiver sdcardReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {// 装载的;删除SD上的文件时也会执行此方法 if (sdCard_list == null) { Logger.d(TAG, "装载的"); sdCard_list = SDCardManager.getExternalStorageDirectory(); refresh(); } else { String path = intent.getData().getPath(); boolean hasPath = false; for (int i = 0; i < sdCard_list.size(); i++) { if (sdCard_list.get(i).path.equals(path)) { hasPath = true; break; } } if (!hasPath) { Logger.d(TAG, "装载的"); sdCard_list = SDCardManager .getExternalStorageDirectory(); refresh(); } else { Logger.d(TAG, "有文件被删除"); } } context.sendBroadcast(new Intent( IDownload.ACTION_SDCARD_CHANGED)); startNewTask(); } else if (Intent.ACTION_MEDIA_EJECT.equals(action)/* 弹出的 */) { Logger.d(TAG, "弹出的"); if (sdCard_list == null) sdCard_list = SDCardManager.getExternalStorageDirectory(); String path = intent.getData().getPath(); // 因为卸载SD卡后mount命令刷新是不是很及时,所以做以下处理 if (sdCard_list != null) { for (int i = 0; i < sdCard_list.size(); i++) { if (sdCard_list.get(i).path.equals(path)) { sdCard_list.remove(i); break; } } if (sdCard_list.size() != 0) setCurrentDownloadSDCardPath(sdCard_list.get(0).path); } removeByPath(path); context.sendBroadcast(new Intent( IDownload.ACTION_SDCARD_CHANGED)); NotificationManager nm = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); nm.cancel(NOTIFY_ID); YoukuPlayerApplication.savePreference(KEY_LAST_NOTIFY_TASKID, ""); startNewTask(); } } }; public synchronized static DownloadServiceManager getInstance() { if (instance == null) { Logger.d(TAG, "getInstance()"); instance = new DownloadServiceManager(YoukuPlayerApplication.context); } return instance; } private DownloadServiceManager(Context context) { acceleraterManager = AcceleraterManager.getInstance(context); acceleraterManager.bindService(); this.context = context; initlock = true; try { String path = getCurrentDownloadSDCardPath(); Logger.d(TAG, "getDownloadFilePath():" + path); registerReceiver(); File f = new File(path + "/youku/offlinedata/"); if (!f.exists()) f.mkdirs(); if (f.exists()) new File(path + "/youku/offlinedata/", ".nomedia") .createNewFile(); } catch (IOException e) { Logger.e(TAG, e); } } /** 网络改变及SD卡事件注册 */ private void registerReceiver() { IntentFilter i = new IntentFilter(); i.addAction(ConnectivityManager.CONNECTIVITY_ACTION); context.registerReceiver(networkReceiver, i); i = new IntentFilter(); i.addAction(Intent.ACTION_MEDIA_MOUNTED); i.addAction(Intent.ACTION_MEDIA_EJECT); i.addDataScheme("file"); context.registerReceiver(sdcardReceiver, i); } public void registerCallback(ICallback cb) { callback = cb; } public void unregister() { callback = null; } public ICallback getCallback() { return callback; } /** 是否有正在下载中的任务 */ public boolean hasDownloadingTask() { boolean state = false; if (thread != null && thread.isStop() == false) { state = true; } Logger.d(TAG, "hasDownloadingTask():" + state); return state; } @Override public HashMap<String, DownloadInfo> getDownloadingData() { if (downloadingData != null) { return downloadingData; } downloadingData = getNewDownloadingData(); return downloadingData; } public void addDownloadingInfo(DownloadInfo info) { Logger.d("DownloadFlow","DownloadServiceManager: addDownloadingInfo()"); if (getDownloadingData() != null) { info.downloadListener = new DownloadListenerImpl(context, info); downloadingData.put(info.taskId, info); } } /** * 创建下载任务 */ public void createDownload(String videoId, String videoName) { // 先判断是否存在 if (FileCreateThread.tempCreateData != null && FileCreateThread.tempCreateData.containsKey(videoId)) { PlayerUtil.showTips(R.string.download_exist_not_finished); } else if (existsDownloadInfo(videoId)) { if (isDownloadFinished(videoId)) {// 已下载完成 PlayerUtil.showTips(R.string.download_exist_finished); } else { PlayerUtil.showTips(R.string.download_exist_not_finished); } } else if (!Util.hasSDCard()) {// 无sd卡 PlayerUtil.showTips(R.string.download_no_sdcard); } else if (Util.hasInternet()) { if (Util.isWifi()) { new FileCreateThread(videoId, videoName).start(); return; } else { friendlyTips(); if (canUse3GDownload()) { new FileCreateThread(videoId, videoName).start(); return; } else {// 不可用3G/2G下载 PlayerUtil.showTips(R.string.download_cannot_ues_3g); } } } else {// 无网络 PlayerUtil.showTips(R.string.download_no_network); } if (FileCreateThread.tempCreateData != null && FileCreateThread.tempCreateData.containsKey(videoId)) { PlayerUtil.showTips(R.string.download_exist_not_finished); } context.sendBroadcast(new Intent( IDownload.ACTION_CREATE_DOWNLOAD_ALL_READY).putExtra( IDownload.KEY_CREATE_DOWNLOAD_IS_NEED_REFRESH, false)); } /** * 创建下载任务(批量) */ public void createDownloads(String[] videoIds, String[] videoNames) { if (!Util.hasSDCard()) {// 无sd卡 PlayerUtil.showTips(R.string.download_no_sdcard); } else if (Util.hasInternet()) { if (Util.isWifi()) { new FileCreateThread(videoIds, videoNames).start(); return; } else { friendlyTips(); if (canUse3GDownload()) { new FileCreateThread(videoIds, videoNames).start(); return; } else {// 不可用3G/2G下载 PlayerUtil.showTips(R.string.download_cannot_ues_3g); } } } else {// 无网络 PlayerUtil.showTips(R.string.download_no_network); } context.sendBroadcast(new Intent( IDownload.ACTION_CREATE_DOWNLOAD_ALL_READY).putExtra( IDownload.KEY_CREATE_DOWNLOAD_IS_NEED_REFRESH, false)); } @Override public void startDownload(String taskId) { if (hasDownloadingTask()) { getDownloadingData().get(taskId).setState( DownloadInfo.STATE_WAITING); } else { startThread(taskId); } } private void startThread(String taskId) { Logger.d("DownloadFlow","DownloadServiceManager: startThread()"); DownloadInfo info = getDownloadingData().get(taskId); thread = new FileDownloadThread(info); info.thread = thread; thread.start(); } @Override public void pauseDownload(String taskId) { getDownloadingData().get(taskId).setState(DownloadInfo.STATE_PAUSE); } @Override public void startNewTask() { Logger.d("DownloadFlow","DownloadServiceManager: startNewTask()"); Logger.d(TAG, "startNewTask()"); if (!Util.hasInternet()) { stopAllTaskNoTips(); return; } else if (!Util.isWifi()) {// 如果不是wifi if (canUse3GDownload() == false) {// 不可用3G/2G下载 return; } } if (hasDownloadingTask())// 如果有下载中视频,直接返回 return; long startTime = 0l; String taskId = null; Iterator iter = getDownloadingData().entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); int state = info.getState(); if (state == DownloadInfo.STATE_DOWNLOADING) {// 发现有正在下载中状态的,则优先下载 startThread(info.taskId); return; } else if ((state == DownloadInfo.STATE_WAITING || state == DownloadInfo.STATE_EXCEPTION || state == DownloadInfo.STATE_INIT) && info.startTime > startTime) { startTime = info.startTime; taskId = info.taskId; } } // 开始最后下载操作的视频 DownloadInfo lastInfo = getDownloadingData().get(taskId); Logger.d("DownloadFlow","DownloadUtil: download_info: " + lastInfo); if (lastInfo == null) { } else if (lastInfo.getState() == DownloadInfo.STATE_WAITING || lastInfo.getState() == DownloadInfo.STATE_INIT) { startThread(taskId); return; } else if (lastInfo.getState() == DownloadInfo.STATE_EXCEPTION && lastInfo.retry <= 0) {// 可控制重试次数 lastInfo.retry++; startThread(taskId); return; } // 没有最后可操作的视频,则按创建时间顺序开始下载 long firstStartTime = 999999999999999999L; iter = getDownloadingData().entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); int state = info.getState(); if (state == DownloadInfo.STATE_DOWNLOADING) {// 发现有正在下载中状态的,则优先下载 startThread(info.taskId); return; }else if ((state == DownloadInfo.STATE_WAITING || state == DownloadInfo.STATE_INIT || state == DownloadInfo.STATE_EXCEPTION) && info.retry < 1 && info.createTime < firstStartTime) {// 可控制重试次数 firstStartTime = info.createTime; taskId = info.taskId; } } DownloadInfo firstInfo = getDownloadingData().get(taskId); if (firstInfo == null) { return; } else if (firstInfo.getState() == DownloadInfo.STATE_WAITING || firstInfo.getState() == DownloadInfo.STATE_INIT) { startThread(taskId); return; } else if (firstInfo.getState() == DownloadInfo.STATE_EXCEPTION && firstInfo.retry <= 0) {// 可控制重试次数 firstInfo.retry++; startThread(taskId); return; } } @Override public void refresh() { Logger.d("DownloadFlow","refresh()"); if (thread != null) thread.cancel(); downloadingData = getNewDownloadingData(); if (callback != null) { Logger.d("DownloadFlow","refresh(), callback != null"); try { callback.refresh(); } catch (RemoteException e) { Logger.e(TAG, e); } } } public void removeByPath(String path) { Iterator iter = getDownloadingData().entrySet().iterator(); ArrayList<String> list = new ArrayList<String>(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); if (info.savePath.contains(path)) { if (info.thread != null) { thread.cancel(); } list.add(info.taskId); } } for (String taskId : list) { downloadingData.remove(taskId); } if (callback != null) { try { callback.refresh(); } catch (RemoteException e) { Logger.e(TAG, e); } } } @Override public void stopAllTask() { if (thread != null) thread.cancel(); Iterator iter = getDownloadingData().entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); if (info.getState() == DownloadInfo.STATE_DOWNLOADING) { info.setState(DownloadInfo.STATE_WAITING); } } } public void stopAllTaskNoTips() { if (thread != null) thread.cancel(); Iterator iter = getDownloadingData().entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); if (info.getState() == DownloadInfo.STATE_DOWNLOADING) { info.state = DownloadInfo.STATE_WAITING; DownloadUtils.makeDownloadInfoFile(info); try { if (getCallback() != null) getCallback().onChanged(info); } catch (Exception e) { Logger.e(TAG, e); } } } } @Override public boolean deleteDownloading(String taskId) { final DownloadInfo info = getDownloadingData().get(taskId); // 如果是下载中的视频,改变状态自己就会删除 info.setState(DownloadInfo.STATE_CANCEL); downloadingData.remove(taskId); if (thread != null && thread.isStop() == false && taskId.equals(thread.getTaskId())) { thread.cancel(); } NotificationManager nm = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); if (YoukuPlayerApplication.getPreference(KEY_LAST_NOTIFY_TASKID).equals(info.taskId)) { nm.cancel(NOTIFY_ID); YoukuPlayerApplication.savePreference(KEY_LAST_NOTIFY_TASKID, ""); } new Thread() { public void run() { PlayerUtil.deleteFile(new File(info.savePath)); }; }.start(); startNewTask(); return true; } @SuppressWarnings("unchecked") @Override public boolean deleteAllDownloading() { String nId = YoukuPlayerApplication.getPreference(KEY_LAST_NOTIFY_TASKID); final HashMap<String, DownloadInfo> clone = (HashMap<String, DownloadInfo>) getDownloadingData() .clone(); Iterator iter = clone.entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); info.setState(DownloadInfo.STATE_CANCEL); if (nId.equals(info.taskId)) { NotificationManager nm = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); nm.cancel(NOTIFY_ID); YoukuPlayerApplication.savePreference(KEY_LAST_NOTIFY_TASKID, ""); } } new Thread() { public void run() { Iterator iter = clone.entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); PlayerUtil.deleteFile(new File(info.savePath)); } }; }.start(); getDownloadingData().clear(); return true; } /** 是否有正在下载和等待下载的任务 */ private boolean hasLivingTask() { Iterator iter = getDownloadingData().entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); int state = info.getState(); if (state == DownloadInfo.STATE_INIT || state == DownloadInfo.STATE_DOWNLOADING || state == DownloadInfo.STATE_WAITING || state == DownloadInfo.STATE_EXCEPTION) { Logger.d(TAG, "hasLivingTask():true"); return true; } } Logger.d(TAG, "hasLivingTask():false"); return false; } /** * 清除重试次数 */ public void cleanRetry() { Iterator iter = getDownloadingData().entrySet().iterator(); while (iter.hasNext()) { Entry entry = (Entry) iter.next(); DownloadInfo info = (DownloadInfo) entry.getValue(); info.retry = 0; } } /** * 友情提示:您将使用2G或3G网络缓存视频 */ private void friendlyTips() { if (first_tips) { // 同一网络环境下,只提示一次友情提示 PlayerUtil.showTips(R.string.player_tips_use_3g); first_tips = false; } } public void destroy() { stopAllTaskNoTips(); NotificationManager nm = (NotificationManager) context .getSystemService(Context.NOTIFICATION_SERVICE); nm.cancel(NOTIFY_ID); } @Override public final String getCurrentDownloadSDCardPath() { String defauleSDCardPath = SDCardManager.getDefauleSDCardPath(); if (YoukuPlayerApplication.getPreferenceBoolean("first_install_for_download_path", true)) { YoukuPlayerApplication.savePreference("first_install_for_download_path", false); if (sdCard_list == null || sdCard_list.size() == 0) { sdCard_list = SDCardManager.getExternalStorageDirectory(); } // 如果有两个存储空间 if (sdCard_list != null && sdCard_list.size() > 1) { File dir = new File(defauleSDCardPath + YoukuPlayerApplication.getDownloadPath()); int count = 0; if (dir.exists()) {// 如果内置的存储区可能存在缓存 String[] dirs = dir.list(); for (int i = dirs.length - 1; i >= 0; i--) { String vid = dirs[i]; DownloadInfo d = getDownloadInfo(vid); if (d != null && d.getState() != DownloadInfo.STATE_CANCEL) { count++; } } } // 如果内置卡里没有缓存的视频,则设外置为默认 if (count == 0) { for (int i = 0; i < sdCard_list.size(); i++) { if (sdCard_list.get(i).isExternal) { YoukuPlayerApplication.savePreference("download_file_path", sdCard_list.get(i).path); break; } } } } } else if (YoukuPlayerApplication.getPreferenceBoolean( "first_install_for_download_path_33", true)) {// 兼容一个S4手机上的错误,在v3.3上修复 YoukuPlayerApplication.savePreference("first_install_for_download_path_33", false); String path = YoukuPlayerApplication.getPreference("download_file_path", defauleSDCardPath); if (sdCard_list != null) { boolean xiangtong = false; for (int i = 0; i < sdCard_list.size(); i++) { if (sdCard_list.get(i).path.equals(path)) { xiangtong = true; } } if (xiangtong == false) { YoukuPlayerApplication.savePreference("first_install_for_download_path", true); return getCurrentDownloadSDCardPath(); } } } else if (YoukuPlayerApplication.getPreferenceBoolean( "first_install_for_download_path_40", true)) { // 4.0 版本 OS 4.4 以上,只能选择主外置 SD 卡的默认位置 YoukuPlayerApplication.savePreference("first_install_for_download_path_40", false); String path = YoukuPlayerApplication.getPreference("download_file_path", ""); if (!TextUtils.isEmpty(path) && !SDCardManager.getDefauleSDCardPath().equals(path)) { YoukuPlayerApplication.savePreference("first_install_for_download_path", true); return getCurrentDownloadSDCardPath(); } } String path = YoukuPlayerApplication.getPreference("download_file_path", defauleSDCardPath); SDCardManager m = new SDCardManager(path); if (!m.exist()) { if (!defauleSDCardPath.equals(path)) { path = defauleSDCardPath; YoukuPlayerApplication.savePreference("download_file_path", path); } } return path; } @Override public void setCurrentDownloadSDCardPath(String path) { YoukuPlayerApplication.savePreference("download_file_path", path); context.sendBroadcast(new Intent(IDownload.ACTION_SDCARD_PATH_CHANGED)); } @Override public boolean canUse3GDownload() { return YoukuPlayerApplication.getPreferenceBoolean("allowCache3G", false); } @Override public void setCanUse3GDownload(boolean flag) { YoukuPlayerApplication.savePreference("allowCache3G", flag); } @Override public boolean canUseAcc() { if (getP2p_switch() == 1 && AcceleraterServiceManager.isACCEnable() && Util.hasInternet() && Util.isWifi()) { return true; } return false; } /** * P2P 开关,-1获取失败,0关闭,1开启 * * @return */ public int getP2p_switch() { return YoukuPlayerApplication.getPreferenceInt("p2p_switch", -1); } @Override public void setP2p_switch(int value) { YoukuPlayerApplication.savePreference("p2p_switch", value); } @Override public String getAccPort() { // return YoukuPlayerApplication.getPreference("acc_port", ""); return acceleraterManager.getAccPort(); } public boolean isAccAvailable() { return acceleraterManager.isAvailable() == 1 && getAccPort().length() != 0; } public int getAccState() { return acceleraterManager.isAvailable(); } @Override public int getDownloadFormat() { return DownloadUtils.getDownloadFormat(); } @Override public void setDownloadFormat(int format) { DownloadUtils.setDownloadFormat(format); } @Override public int getDownloadLanguage() { return DownloadUtils.getDownloadLanguage(); } @Override public void setDownloadLanguage(int language) { DownloadUtils.setDownloadLanguage(language); } public void setTimeStamp(long time) { URLContainer.TIMESTAMP = time; } }