├── res
├── drawable
│ └── icon.png
├── values
│ └── strings.xml
└── layout
│ └── main.xml
├── .classpath
├── default.properties
├── .project
├── AndroidManifest.xml
├── src
└── jp
│ └── sharakova
│ └── android
│ └── service
│ ├── ImageDownloadSampleActivity.java
│ └── ImageDownloadService.java
├── proguard.cfg
└── README
/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sharakova/ImageDownloadService/master/res/drawable/icon.png
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, ImageDownloadSampleActivity!
4 | ImageDownload
5 |
6 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-7
12 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ImageDownload
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/jp/sharakova/android/service/ImageDownloadSampleActivity.java:
--------------------------------------------------------------------------------
1 | package jp.sharakova.android.service;
2 |
3 | import jp.sharakova.android.imagedownload.R;
4 | import android.app.Activity;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.view.View;
8 | import android.view.View.OnClickListener;
9 | import android.widget.Toast;
10 |
11 | public class ImageDownloadSampleActivity extends Activity {
12 | /** Called when the activity is first created. */
13 | @Override
14 | public void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.main);
17 | findViewById(R.id.download_btn).setOnClickListener(downloadBtnListener);
18 | }
19 |
20 | OnClickListener downloadBtnListener = new OnClickListener() {
21 | @Override
22 | public void onClick(View arg0) {
23 | Intent intent = new Intent(ImageDownloadService.IMAGE_DOWNLOAD_SERVICE);
24 | intent.setClass(getApplicationContext(), ImageDownloadService.class);
25 | intent.putExtra("image_url", "http://lh5.googleusercontent.com/-U_ZrYg86EMc/S9uxmpuT6hI/AAAAAAAACUs/-zOKvjJKH8E/s640/golf.png");
26 | intent.putExtra("image_title", "golf");
27 | startService(intent);
28 | Toast.makeText(getApplicationContext(), "download start", Toast.LENGTH_SHORT).show();
29 | }
30 | };
31 | }
--------------------------------------------------------------------------------
/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class * extends android.app.backup.BackupAgentHelper
14 | -keep public class * extends android.preference.Preference
15 | -keep public class com.android.vending.licensing.ILicensingService
16 |
17 | -keepclasseswithmembernames class * {
18 | native ;
19 | }
20 |
21 | -keepclasseswithmembers class * {
22 | public (android.content.Context, android.util.AttributeSet);
23 | }
24 |
25 | -keepclasseswithmembers class * {
26 | public (android.content.Context, android.util.AttributeSet, int);
27 | }
28 |
29 | -keepclassmembers class * extends android.app.Activity {
30 | public void *(android.view.View);
31 | }
32 |
33 | -keepclassmembers enum * {
34 | public static **[] values();
35 | public static ** valueOf(java.lang.String);
36 | }
37 |
38 | -keep class * implements android.os.Parcelable {
39 | public static final android.os.Parcelable$Creator *;
40 | }
41 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | AndroidでWebにある画像をダウンロードするサービスクラス ImageDownloadService です。
2 | MIT Lisenceで、ご自由におつかいください。
3 |
4 | 説明
5 | ・DownloadManagerが利用できない、Android 2.1などで画像をダウンロードするプログラムです。
6 | ・大きな画像をバックグランドでダウンロードします。
7 | ・ダウンロードした画像は、ギャラリーやコンテンツマネージャーでも表示されるようになります。
8 | ・ダウンロードを開始すると、Notificationでダウンロードの状態を確認できます。
9 | ・ダウンロードは、URLと保存したいタイトルをIntentで渡すだけです。
10 | ・保存する画像は、他のアプリからも閲覧できる場所に保存されます。
11 | ・SDカードに画像を保存するため、SDカードが挿入されていない場合を想定してません。
12 | ・Notificationには、デフォルトのiconを設定していますが、他のICONも設定可能です。
13 |
14 | 利用方法
15 | # Android マニフェストに必要となる設定
16 | * Serviceクラスを設定する jp.sharakova.android.service.ImageDownloadService
17 |
18 |
19 |
20 | * android.permission.INTERNET ネットを利用するためのパーミッション
21 | * android.permission.WRITE_EXTERNAL_STORAGE SDカードを利用するためのパーミッション
22 |
23 |
24 |
25 |
26 | # Activityから呼び出し
27 | * Actionに、ImageDownloadService.IMAGE_DOWNLOAD_SERVICE を設定する。
28 | * image_urlに、画像のURLを渡す
29 | * image_titleには、画像のタイトルを設定する
30 |
31 | Intent intent = new Intent(ImageDownloadService.IMAGE_DOWNLOAD_SERVICE);
32 | intent.setClass(getApplicationContext(), ImageDownloadService.class);
33 | intent.putExtra("image_url", "画像URL");
34 | intent.putExtra("image_title", "画像の名前");
35 | startService(intent);
36 |
37 |
38 | (サンプル)
39 | # AndroidManifest.xml
40 |
41 |
42 |
46 |
47 |
48 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | # ImageDownloadSampleActivity
62 |
63 | package jp.sharakova.android.service;
64 |
65 | import jp.sharakova.android.imagedownload.R;
66 | import android.app.Activity;
67 | import android.content.Intent;
68 | import android.os.Bundle;
69 | import android.view.View;
70 | import android.view.View.OnClickListener;
71 | import android.widget.Toast;
72 |
73 | public class ImageDownloadSampleActivity extends Activity {
74 | /** Called when the activity is first created. */
75 | @Override
76 | public void onCreate(Bundle savedInstanceState) {
77 | super.onCreate(savedInstanceState);
78 | setContentView(R.layout.main);
79 |
80 | // ダウンロードのOnClickで、画像のダウンロードを開始する
81 | findViewById(R.id.download_btn).setOnClickListener(downloadBtnListener);
82 | }
83 |
84 | OnClickListener downloadBtnListener = new OnClickListener() {
85 | @Override
86 | public void onClick(View arg0) {
87 | Intent intent = new Intent(ImageDownloadService.IMAGE_DOWNLOAD_SERVICE);
88 | intent.setClass(getApplicationContext(), ImageDownloadService.class);
89 | intent.putExtra("image_url", "http://lh5.googleusercontent.com/-U_ZrYg86EMc/S9uxmpuT6hI/AAAAAAAACUs/-zOKvjJKH8E/s640/golf.png");
90 | intent.putExtra("image_title", "golf");
91 | startService(intent);
92 |
93 | // Toastの表示
94 | Toast.makeText(getApplicationContext(), "download start", Toast.LENGTH_SHORT).show();
95 | }
96 | };
97 | }
--------------------------------------------------------------------------------
/src/jp/sharakova/android/service/ImageDownloadService.java:
--------------------------------------------------------------------------------
1 | package jp.sharakova.android.service;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 |
8 | import jp.sharakova.android.imagedownload.R;
9 |
10 | import org.apache.http.HttpResponse;
11 | import org.apache.http.client.methods.HttpGet;
12 | import org.apache.http.impl.client.DefaultHttpClient;
13 |
14 | import android.app.Notification;
15 | import android.app.NotificationManager;
16 | import android.app.PendingIntent;
17 | import android.app.Service;
18 | import android.content.ContentResolver;
19 | import android.content.ContentValues;
20 | import android.content.Intent;
21 | import android.net.Uri;
22 | import android.os.Binder;
23 | import android.os.Environment;
24 | import android.os.IBinder;
25 | import android.provider.MediaStore.Images.Media;
26 | import android.util.Log;
27 |
28 | public class ImageDownloadService extends Service {
29 |
30 | public final static String IMAGE_DOWNLOAD_SERVICE = "jp.sharakova.android.service.ImageDownloadService";
31 | private NotificationManager mNM;
32 | private final IBinder mBinder = new LocalBinder();
33 |
34 | public class LocalBinder extends Binder {
35 | ImageDownloadService getService() {
36 | return ImageDownloadService.this;
37 | }
38 | }
39 |
40 | @Override
41 | public void onCreate() {
42 | mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
43 | }
44 |
45 | @Override
46 | public void onStart(Intent intent, int startId)
47 | {
48 | super.onStart(intent, startId);
49 |
50 | // とりあえず、アクションもチェックする
51 | if (intent != null && IMAGE_DOWNLOAD_SERVICE.equals(intent.getAction())) {
52 |
53 | // URLとタイトルを設定する
54 | final String imageUrl = intent.getStringExtra("image_url");
55 | final String imageTitle = intent.getStringExtra("image_title");
56 |
57 | // ダウンロード開始するメッセージをタスクトレイで表示
58 | showNotification(imageTitle, imageUrl);
59 |
60 | new Thread(null, new Runnable() {
61 | public void run() {
62 | String message = null;
63 | try {
64 | // HTTPで画像をダウンロード
65 | DefaultHttpClient httpClient = new DefaultHttpClient();
66 | HttpResponse response = httpClient.execute(new HttpGet(imageUrl));
67 | InputStream stream = response.getEntity().getContent();
68 |
69 | // ファイルへ保存
70 | saveImage(getContentResolver(), getFileName(imageUrl), imageTitle, stream);
71 |
72 | // タスクトレイで表示するメッセージ
73 | message = imageTitle + " download complete.";
74 |
75 | // コンテンツマネージャーなどのアプリでは、キャッシュをクリアしてやらないと
76 | // すぐに、画像が表示されないので、メディアマウントをしてやる。
77 | sendBroadcast(
78 | new Intent(
79 | Intent.ACTION_MEDIA_MOUNTED,
80 | Uri.parse("file://" + Environment.getExternalStorageDirectory())
81 | )
82 | );
83 | } catch (Exception e) {
84 | message = "Error.";
85 | } finally {
86 | mNM.cancel(imageUrl.hashCode());
87 | // メッセージをタスクトレイに表示
88 | showNotification(message, imageUrl);
89 | }
90 | }
91 | }, "ImageDownloadService").start();
92 | }
93 | }
94 |
95 | @Override
96 | public void onDestroy() {
97 | mNM.cancelAll();
98 | }
99 |
100 | @Override
101 | public IBinder onBind(Intent intent) {
102 | return mBinder;
103 | }
104 |
105 |
106 | private void showNotification(String message, String filePath) {
107 | Notification notification = new Notification(R.drawable.icon, message, System.currentTimeMillis());
108 |
109 | PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, null, 0);
110 | notification.setLatestEventInfo(this, "download picture.", message, contentIntent);
111 | mNM.notify(filePath.hashCode(), notification);
112 | }
113 |
114 | private static String saveImage(ContentResolver contentResolver, String filename, String title, InputStream inputStream) {
115 | OutputStream outputStream = null;
116 | File file = null;
117 | try {
118 | makeDownloadDir();
119 | file = new File(getDownloadPath(), filename);
120 | outputStream = new FileOutputStream(file);
121 | int DEFAULT_BUFFER_SIZE = 1024 * 4;
122 | byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
123 | int n = 0;
124 | while (-1 != (n = inputStream.read(buffer))) {
125 | outputStream.write(buffer, 0, n);
126 | }
127 | inputStream.close();
128 | outputStream.close();
129 | } catch (Exception e) {
130 | Log.w("save", e);
131 | if (file != null) {
132 | file.delete();
133 | }
134 | } finally {
135 | if (outputStream != null) {
136 | try {
137 | outputStream.close();
138 | } catch (Throwable t) {
139 | Log.w("save", "finally");
140 | }
141 | }
142 | if (inputStream != null) {
143 | try {
144 | inputStream.close();
145 | } catch (Throwable t) {
146 | Log.w("save", "finally");
147 | }
148 | }
149 | }
150 |
151 | // ContentResolver にファイル情報の書き込み。
152 | // これやらないと、ギャラリーなどのアプリでダウンロードした画像が表示されないです。
153 | String filePath = getDownloadPath() + "/" + filename;
154 | ContentValues values = new ContentValues(7);
155 | values.put(Media.TITLE, title);
156 | values.put(Media.DISPLAY_NAME, filename);
157 | values.put(Media.DATE_TAKEN, System.currentTimeMillis());
158 | values.put(Media.MIME_TYPE, getMimeType(filename));
159 | values.put(Media.DATA, filePath);
160 | contentResolver.insert(Media.EXTERNAL_CONTENT_URI, values);
161 |
162 | return filePath;
163 | }
164 |
165 | private static String getSdCardPath() {
166 | return Environment.getExternalStorageDirectory().toString();
167 | }
168 |
169 | private static String getDownloadPath() {
170 | // 別のフォルダを指定する場合は、下記のフォルダ名を変更してください。
171 | return getSdCardPath() + "/download";
172 | }
173 |
174 | private static void makeDownloadDir() {
175 | makeDir(new File(getDownloadPath()));
176 | }
177 |
178 | private static void makeDir(File dir) {
179 | if (!dir.exists()) {
180 | dir.mkdir();
181 | }
182 | }
183 |
184 | private static String getFileName(String url) {
185 | int point = url.lastIndexOf("/");
186 | if (point != -1) {
187 | return url.substring(point + 1, url.length());
188 | }
189 | int hash = url.hashCode();
190 | return String.valueOf(hash);
191 | }
192 |
193 |
194 | // mime-typeの判定が微妙です。すみません。
195 | private static String getMimeType(String filename) {
196 | int point = filename.lastIndexOf(".");
197 | if (point != -1) {
198 | String extension = filename.substring(point + 1, filename.length());
199 | if(extension.equals("jpeg") || extension.equals("jpg")) {
200 | return "image/jpeg";
201 | }
202 | if(extension.equals("png")) {
203 | return "image/png";
204 | }
205 | if(extension.equals("gif")) {
206 | return "image/gif";
207 | }
208 | }
209 | return "image/jpeg";
210 | }
211 |
212 |
213 | }
214 |
215 |
--------------------------------------------------------------------------------