天天看點

Android下載下傳管理DownloadManager功能擴充和bug修改

本文主要介紹如何修改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)