DownloadDefaultStickers.java

  1package com.cheogram.android;
  2
  3import android.app.Notification;
  4import android.app.NotificationManager;
  5import android.app.Service;
  6import android.content.Context;
  7import android.content.SharedPreferences;
  8import android.content.Intent;
  9import android.database.Cursor;
 10import android.media.MediaScannerConnection;
 11import android.net.Uri;
 12import android.os.Environment;
 13import android.os.IBinder;
 14import android.provider.DocumentsContract;
 15import android.preference.PreferenceManager;
 16import android.provider.MediaStore;
 17import android.util.Log;
 18
 19import androidx.core.app.NotificationCompat;
 20
 21import com.google.common.io.ByteStreams;
 22
 23import io.ipfs.cid.Cid;
 24
 25import java.io.File;
 26import java.io.FileOutputStream;
 27import java.io.OutputStream;
 28import java.io.OutputStreamWriter;
 29import java.util.concurrent.atomic.AtomicBoolean;
 30
 31import org.json.JSONArray;
 32import org.json.JSONObject;
 33
 34import okhttp3.OkHttpClient;
 35import okhttp3.Request;
 36import okhttp3.Response;
 37
 38import eu.siacs.conversations.Config;
 39import eu.siacs.conversations.R;
 40import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore;
 41import eu.siacs.conversations.entities.Account;
 42import eu.siacs.conversations.entities.Conversation;
 43import eu.siacs.conversations.entities.Message;
 44import eu.siacs.conversations.persistance.DatabaseBackend;
 45import eu.siacs.conversations.persistance.FileBackend;
 46import eu.siacs.conversations.utils.Compatibility;
 47import eu.siacs.conversations.utils.FileUtils;
 48import eu.siacs.conversations.utils.MimeUtils;
 49
 50public class DownloadDefaultStickers extends Service {
 51
 52	private static final int NOTIFICATION_ID = 20;
 53	private static final AtomicBoolean RUNNING = new AtomicBoolean(false);
 54	private DatabaseBackend mDatabaseBackend;
 55	private NotificationManager notificationManager;
 56	private File mStickerDir;
 57	private OkHttpClient http = new OkHttpClient();
 58
 59	@Override
 60	public void onCreate() {
 61		mDatabaseBackend = DatabaseBackend.getInstance(getBaseContext());
 62		notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 63		mStickerDir = stickerDir();
 64	}
 65
 66	@Override
 67	public int onStartCommand(Intent intent, int flags, int startId) {
 68		if (RUNNING.compareAndSet(false, true)) {
 69			new Thread(() -> {
 70				try {
 71					download();
 72				} catch (final Exception e) {
 73					Log.d(Config.LOGTAG, "unable to download stickers", e);
 74				}
 75				stopForeground(true);
 76				RUNNING.set(false);
 77				stopSelf();
 78			}).start();
 79			return START_STICKY;
 80		} else {
 81			Log.d(Config.LOGTAG, "DownloadDefaultStickers. ignoring start command because already running");
 82		}
 83		return START_NOT_STICKY;
 84	}
 85
 86	private void oneSticker(JSONObject sticker) throws Exception {
 87		Response r = http.newCall(new Request.Builder().url(sticker.getString("url")).build()).execute();
 88		File file = new File(mStickerDir.getAbsolutePath() + "/" + sticker.getString("pack") + "/" + sticker.getString("name") + "." + MimeUtils.guessExtensionFromMimeType(r.headers().get("content-type")));
 89		file.getParentFile().mkdirs();
 90		OutputStream os = new FileOutputStream(file);
 91		ByteStreams.copy(r.body().byteStream(), os);
 92		os.close();
 93
 94		JSONArray cids = sticker.getJSONArray("cids");
 95		for (int i = 0; i < cids.length(); i++) {
 96			Cid cid = Cid.decode(cids.getString(i));
 97			mDatabaseBackend.saveCid(cid, file, sticker.getString("url"));
 98		}
 99
100		MediaScannerConnection.scanFile(
101			getBaseContext(),
102			new String[] { file.getAbsolutePath() },
103			null,
104			new MediaScannerConnection.MediaScannerConnectionClient() {
105				@Override
106				public void onMediaScannerConnected() {}
107
108				@Override
109				public void onScanCompleted(String path, Uri uri) {}
110			}
111		);
112
113		try {
114			File copyright = new File(mStickerDir.getAbsolutePath() + "/" + sticker.getString("pack") + "/copyright.txt");
115			OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(copyright, true), "utf-8");
116			w.write(sticker.getString("pack"));
117			w.write('/');
118			w.write(sticker.getString("name"));
119			w.write(": ");
120			w.write(sticker.getString("copyright"));
121			w.write('\n');
122			w.close();
123		} catch (final Exception e) { }
124	}
125
126	private void download() throws Exception {
127		NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
128		mBuilder.setContentTitle("Downloading Default Stickers")
129				.setSmallIcon(R.drawable.ic_archive_white_24dp)
130				.setProgress(1, 0, false);
131		startForeground(NOTIFICATION_ID, mBuilder.build());
132
133		Response r = http.newCall(new Request.Builder().url("https://stickers.cheogram.com/index.json").build()).execute();
134		JSONArray stickers = new JSONArray(r.body().string());
135
136		final Progress progress = new Progress(mBuilder, 1, 0);
137		for (int i = 0; i < stickers.length(); i++) {
138			oneSticker(stickers.getJSONObject(i));
139
140			final int percentage = i * 100 / stickers.length();
141			notificationManager.notify(NOTIFICATION_ID, progress.build(percentage));
142		}
143	}
144
145	private File stickerDir() {
146		SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
147		final String dir = p.getString("sticker_directory", "Stickers");
148		if (dir.startsWith("content://")) {
149			Uri uri = Uri.parse(dir);
150			uri = DocumentsContract.buildDocumentUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri));
151			return new File(FileUtils.getPath(getBaseContext(), uri));
152		} else {
153			return new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/" + dir);
154		}
155	}
156
157	@Override
158	public IBinder onBind(Intent intent) {
159		return null;
160	}
161
162	private static class Progress {
163		private final NotificationCompat.Builder builder;
164		private final int max;
165		private final int count;
166
167		private Progress(NotificationCompat.Builder builder, int max, int count) {
168			this.builder = builder;
169			this.max = max;
170			this.count = count;
171		}
172
173		private Notification build(int percentage) {
174			builder.setProgress(max * 100, count * 100 + percentage, false);
175			return builder.build();
176		}
177	}
178}