本文主要介紹如何修改android系統下載下傳管理,以支援更多的功能及部分bug修改和如何編譯生效。目前内容包括暫停下載下傳、繼續下載下傳、通知設定notiextra和noticlass、wifi切換到3g自動暫停、bug修改。
ps: 很多童鞋不是自己做rom,是以就算修改了系統源碼編譯出來的包在其他系統上也不通用
下面需要修改的downloadmanager.java所在目錄為frameworks/base/core/java/android/app
downloadinfo.java, downloadprovider.java,downloadthread.java檔案所在目錄為packages/providers/downloadprovider/src/com/android/providers/downloads
1、暫停、繼續下載下傳功能
(1) downloadprovider類修改
java
1
public int update(final uri uri, final contentvalues values, final string where, final string[] whereargs)
函數,修改後代碼如下(隻增加了一行有效代碼):
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (binder.getcallingpid() != process.mypid()) {
filteredvalues = new contentvalues();
copystring(downloads.impl.column_app_data, values, filteredvalues);
copyinteger(downloads.impl.column_visibility, values, filteredvalues);
integer i = values.getasinteger(downloads.impl.column_control);
if (i != null) {
filteredvalues.put(downloads.impl.column_control, i);
startservice = true;
}
// trinea begin, added by [email protected] 2013/03/01
copyinteger(downloads.impl.column_status, values, filteredvalues);
// trinea end
copyinteger(downloads.impl.column_control, values, filteredvalues);
copystring(downloads.impl.column_title, values, filteredvalues);
copystring(downloads.impl.column_mediaprovider_uri, values, filteredvalues);
copystring(downloads.impl.column_description, values, filteredvalues);
copyinteger(downloads.impl.column_deleted, values, filteredvalues);
} else {
其中以// trinea begin開頭,// trinea end結尾為修改部分,下面代碼示例同樣如此。因為downloadprovider安全政策對非該程序id的修改會過濾掉column_status狀态,是以我們需要添加該行。
(2) downloadthread類修改
private void setupdestinationfile(state state, innerstate innerstate)
函數中這個注釋掉一個else if,如下:
// trinea begin, noted by [email protected] 2013/03/01
//} else if (minfo.metag == null && !minfo.mnointegrity) {
// // this should've been caught upon failure
// if (constants.logvv) {
// log.d(tag, "setupdestinationfile() unable to resume download, deleting "
// + state.mfilename);
// }
// f.delete();
// throw new stoprequestexception(downloads.impl.status_cannot_resume,
// "trying to resume a download that can't be resumed");
上面一段代碼表示一個驗證過程,可以去掉。
metag為資料庫中的etag字段值,代碼中沒有解釋,感覺是一個驗證值,類似hashcode。
mnointegrity為資料中no_integrity字段值,表示啟動下載下傳的應用程式能否驗證下載下傳的檔案的完整性。不過坑爹的是對于etag和no_integrity都沒有提供設定的接口
(3) downloadmanager類中添加對外接口
downloadmanager中添加暫停、繼續接口
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* pause download, added by [email protected] 2013/03/01
*
* @param ids the ids of the downloads to be paused
* @return the number of downloads actually paused
*/
public int pausedownload(long... ids) {
if (ids == null || ids.length == 0) {
// called with nothing to remove!
throw new illegalargumentexception("input param 'ids' can't be null");
contentvalues values = new contentvalues();
values.put(downloads.impl.column_control, downloads.impl.control_paused);
values.put(downloads.impl.column_status, downloads.impl.status_paused_by_app);
if (ids.length == 1) {
return mresolver.update(contenturis.withappendedid(mbaseuri, ids[0]), values,
null, null);
return mresolver.update(mbaseuri, values, getwhereclauseforids(ids),
getwhereargsforids(ids));
* resume download, added by [email protected] 2013/03/01
* @param ids the ids of the downloads to be resumed
* @return the number of downloads actually resumed
public int resumedownload(long... ids) {
values.put(downloads.impl.column_control, downloads.impl.control_run);
values.put(downloads.impl.column_status, downloads.impl.status_running);
點選展開代碼
之後我們直接調用downloadmanager的pausedownload和resumedownload接口即可
ps:也可以試試不做第二步的修改,而将第一步downloadprovider的update函數修改變為
copyinteger(downloads.impl.column_no_integrity, values, filteredvalues);
第二步修改變為在public int resumedownload(long… ids)加入
values.put(downloads.impl.column_no_integrity, true);
沒有親自試,不過按照邏輯應該也可以。
2、通知欄可以設定notiextra和noticlass
(1) downloadprovider類中修改private void checkinsertpermissions(contentvalues values)函數
values.remove(downloads.impl.column_is_visible_in_downloads_ui);
values.remove(downloads.impl.column_media_scanned);
// begin, added by [email protected] 2013/03/01
values.remove(downloads.impl.column_notification_class);
values.remove(downloads.impl.column_notification_extras);
在downloadprovider insert之前會調用checkinsertpermissions檢查不能被插入的字段插入,這裡我們需要允許這兩個字段存在。
(2) downloadmanager.request添加對外接口
downloadmanager.request支援setnoticlass、setnotiextras
在request中添加接口以及允許字段修改。通過允許設定notiextra和noticlass,我們可以給系統傳遞更豐富的參數,在通知欄點選相應或是downloadui中通過broadcast将這些參數傳遞出來友善應用調用。
3、wifi切換到3g自動暫停
(1) 修改downloadinfo.java
private int checkisnetworktypeallowed(int networktype) {
if (mispublicapi) {
final int flag = translatenetworktypetoapiflag(networktype);
final boolean allowallnetworktypes = mallowednetworktypes == ~0;
if (!allowallnetworktypes && (flag & mallowednetworktypes) == 0) {
return network_type_disallowed_by_requestor;
// trinea begin
if (mstatus == downloads.impl.status_waiting_for_network
&& flag != downloadmanager.request.network_wifi) {
return checksizeallowedfornetwork(networktype);
表示等待網絡時始終隻等待wifi
(2) 修改downloadreceiver.java
} else if (action.equals(connectivitymanager.connectivity_action)) {
networkinfo info = (networkinfo)
intent.getparcelableextra(connectivitymanager.extra_network_info);
if (info != null && info.isconnected()) {
startservice(context);
} else if (action.equals(constants.action_retry)) {
修改為:
* modified by [email protected] @2013/04/01, resume download only when network type is wifi
if (info != null && info.isconnected() && info.gettype() == connectivitymanager.type_wifi) {
表示隻有連接配接wifi時才喚醒service去檢查是否下載下傳
(3) 修改downloadthread.java
* check if the download has been paused or canceled, stopping the request appropriately if it
* has been.
private void checkpausedorcanceled(state state) throws stoprequestexception {
synchronized (minfo) {
if (minfo.mcontrol == downloads.impl.control_paused) {
xlog.i(constants.dl_enhance, "downloadthread: checkpausedorcanceled: user pause download");
throw new stoprequestexception(
downloads.impl.status_paused_by_app, "download paused by owner");
if (minfo.mstatus == downloads.impl.status_canceled) {
throw new stoprequestexception(downloads.impl.status_canceled, "download canceled");
// if policy has been changed, trigger connectivity check
if (mpolicydirty) {
* add by [email protected] @2013/04/01, when switched from wifi to 3g, pause all download
networkinfo info = msystemfacade.getactivenetworkinfo(minfo.muid);
if (info != null && !info.isconnected()) {
minfo.mstatus = downloads.impl.status_waiting_for_network;
checkconnectivity();
表示如果網絡變化并且表示網絡斷開時,下載下傳狀态變為等待網絡。
4、bug修改
(1) 當存儲空間不足時,利用downloadmanager下載下傳,隻顯示通知欄提示,在下載下傳管理ui中不顯示
downloadmanager的cursor runquery(contentresolver resolver, string[] projection, uri baseuri)函數修改如下:
if ((mstatusflags & status_running) != 0) {
parts.add(statusclause("=", downloads.impl.status_running));
parts.add(statusclause("=", downloads.impl.status_insufficient_space_error));
downloadmanager的cursortranslator類的private int translatestatus(int status) 函數修改如下:
case downloads.impl.status_insufficient_space_error:
case downloads.impl.status_running:
return status_running;
5、編譯安裝
修改後是需要重新編譯的,需同時編譯framweork和downloadprovider。
framework編譯指令為:./makemtk model mm frameworks/base/core/
編譯後apk所在路徑為out\target\product\model\system\framework\secondary_framework.jar,之後push到system/framework重新開機即可。編譯指令中model為機型,非mtk平台指令有所不同
downloadprovider編譯指令為./makemtk model mm packages/providers/downloadprovider/
編譯後apk所在路徑為out\target\product\model\system\app\downloadprovider.apk,之後push到system/app即可(可能需要先删除/system/app/目錄下的downloadprovider.odex)