forked from organicmaps/organicmaps
made APK much smaller by downloading required files at program startup.
This commit is contained in:
parent
e8c348f12a
commit
d5759f50f5
9 changed files with 501 additions and 376 deletions
|
@ -33,7 +33,7 @@ LOCAL_SRC_FILES := \
|
|||
com/mapswithme/maps/MWMActivity.cpp \
|
||||
com/mapswithme/maps/MWMApplication.cpp \
|
||||
com/mapswithme/maps/Lifecycle.cpp \
|
||||
com/mapswithme/maps/CopyResourcesActivity.cpp \
|
||||
com/mapswithme/maps/DownloadResourcesActivity.cpp \
|
||||
com/mapswithme/platform/Platform.cpp \
|
||||
com/mapswithme/platform/HttpThread.cpp \
|
||||
com/mapswithme/platform/Language.cpp \
|
||||
|
|
|
@ -1,177 +0,0 @@
|
|||
#include <jni.h>
|
||||
// To get free disk space
|
||||
#include <sys/vfs.h>
|
||||
|
||||
#include "../../../../../defines.hpp"
|
||||
|
||||
#include "../../../../../base/logging.hpp"
|
||||
|
||||
#include "../../../../../coding/zip_reader.hpp"
|
||||
|
||||
#include "../../../../../platform/platform.hpp"
|
||||
|
||||
#include "../../../../../std/vector.hpp"
|
||||
#include "../../../../../std/string.hpp"
|
||||
#include "../../../../../std/bind.hpp"
|
||||
|
||||
// Special error codes to notify GUI about free space
|
||||
//@{
|
||||
#define ERR_COPIED_SUCCESSFULLY 0
|
||||
#define ERR_NOT_ENOUGH_MEMORY -1
|
||||
#define ERR_NOT_ENOUGH_FREE_SPACE -2
|
||||
#define ERR_STORAGE_DISCONNECTED -3
|
||||
//@}
|
||||
|
||||
struct FileToCopy
|
||||
{
|
||||
string m_pathInZip;
|
||||
string m_pathInSdcard;
|
||||
uint64_t m_uncompressedSize;
|
||||
};
|
||||
|
||||
static string g_apkPath;
|
||||
static string g_sdcardPath;
|
||||
static vector<FileToCopy> g_filesToCopy;
|
||||
static jint g_copiedBytesProgress = 0;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_mapswithme_maps_CopyResourcesActivity_nativeGetBytesToCopy(JNIEnv * env, jobject thiz,
|
||||
jstring apkPath, jstring sdcardPath)
|
||||
{
|
||||
{
|
||||
char const * strApkPath = env->GetStringUTFChars(apkPath, 0);
|
||||
if (!strApkPath)
|
||||
return ERR_NOT_ENOUGH_MEMORY;
|
||||
g_apkPath = strApkPath;
|
||||
env->ReleaseStringUTFChars(apkPath, strApkPath);
|
||||
|
||||
char const * strSdcardPath = env->GetStringUTFChars(sdcardPath, 0);
|
||||
if (!strSdcardPath)
|
||||
return ERR_NOT_ENOUGH_MEMORY;
|
||||
g_sdcardPath = strSdcardPath;
|
||||
env->ReleaseStringUTFChars(sdcardPath, strSdcardPath);
|
||||
}
|
||||
|
||||
jint totalSizeToCopy = 0;
|
||||
Platform::FilesList zipFiles = ZipFileReader::FilesList(g_apkPath);
|
||||
// Check which assets/* files are compressed and copy only these files
|
||||
string const ASSETS_PREFIX = "assets/";
|
||||
for (Platform::FilesList::iterator it = zipFiles.begin(); it != zipFiles.end(); ++it)
|
||||
{
|
||||
// Ignore non-assets files
|
||||
if (it->find(ASSETS_PREFIX) != 0)
|
||||
continue;
|
||||
|
||||
uint64_t compressed, uncompressed;
|
||||
{
|
||||
ZipFileReader fileInZip(g_apkPath, *it);
|
||||
compressed = fileInZip.Size();
|
||||
uncompressed = fileInZip.UncompressedSize();
|
||||
// Skip files which are not compressed inside zip
|
||||
if (compressed == uncompressed)
|
||||
continue;
|
||||
}
|
||||
|
||||
FileToCopy f;
|
||||
f.m_pathInSdcard = g_sdcardPath + it->substr(ASSETS_PREFIX.size());
|
||||
|
||||
uint64_t realSizeInSdcard = 0;
|
||||
Platform::GetFileSizeByFullPath(f.m_pathInSdcard, realSizeInSdcard);
|
||||
if (uncompressed != realSizeInSdcard)
|
||||
{
|
||||
f.m_pathInZip = *it;
|
||||
f.m_uncompressedSize = uncompressed;
|
||||
g_filesToCopy.push_back(f);
|
||||
totalSizeToCopy += uncompressed;
|
||||
}
|
||||
}
|
||||
|
||||
return totalSizeToCopy;
|
||||
}
|
||||
|
||||
void CopyFileProgress(JNIEnv * env, jobject obj, jmethodID method, int size, int pos)
|
||||
{
|
||||
env->CallVoidMethod(obj, method, size, pos);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_mapswithme_maps_CopyResourcesActivity_nativeCopyNextFile(JNIEnv * env,
|
||||
jobject thiz, jobject observer)
|
||||
{
|
||||
if (g_filesToCopy.empty())
|
||||
return ERR_COPIED_SUCCESSFULLY;
|
||||
|
||||
vector<FileToCopy>::iterator it = g_filesToCopy.begin() + g_filesToCopy.size() - 1;
|
||||
// Check for free space available on the device
|
||||
struct statfs st;
|
||||
if (statfs(g_sdcardPath.c_str(), &st) != 0)
|
||||
{
|
||||
LOG(LWARNING, ("External filesystem is not available"));
|
||||
return ERR_STORAGE_DISCONNECTED;
|
||||
}
|
||||
if (st.f_bsize * st.f_bavail <= it->m_uncompressedSize)
|
||||
{
|
||||
LOG(LERROR, ("Not enough free space to extract file", it->m_pathInSdcard));
|
||||
return ERR_NOT_ENOUGH_FREE_SPACE;
|
||||
}
|
||||
|
||||
jmethodID method = env->GetMethodID(env->GetObjectClass(observer), "onFileProgress", "(II)V");
|
||||
CHECK(method, ("Not existing method: void onFileProgress(int,int)"));
|
||||
|
||||
// Perform copying
|
||||
try
|
||||
{
|
||||
ZipFileReader::UnzipFile(g_apkPath, it->m_pathInZip, it->m_pathInSdcard,
|
||||
bind(CopyFileProgress, env, observer, method, _1, _2));
|
||||
}
|
||||
catch (std::exception const & e)
|
||||
{
|
||||
LOG(LERROR, ("Error while extracting", it->m_pathInZip, "from apk to", it->m_pathInSdcard));
|
||||
return ERR_NOT_ENOUGH_FREE_SPACE;
|
||||
}
|
||||
|
||||
g_copiedBytesProgress += it->m_uncompressedSize;
|
||||
g_filesToCopy.erase(it);
|
||||
return g_copiedBytesProgress;
|
||||
}
|
||||
|
||||
// Move downloaded maps from /sdcard/Android/data/com.mapswithme.maps/files/ to /sdcard/MapsWithMe
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_mapswithme_maps_CopyResourcesActivity_nativeMoveMaps(JNIEnv * env, jobject thiz,
|
||||
jstring fromPath, jstring toPath)
|
||||
{
|
||||
string from, to;
|
||||
{
|
||||
char const * strFrom = env->GetStringUTFChars(fromPath, 0);
|
||||
if (!strFrom)
|
||||
return;
|
||||
from = strFrom;
|
||||
env->ReleaseStringUTFChars(fromPath, strFrom);
|
||||
|
||||
char const * strTo = env->GetStringUTFChars(toPath, 0);
|
||||
if (!strTo)
|
||||
return;
|
||||
to = strTo;
|
||||
env->ReleaseStringUTFChars(toPath, strTo);
|
||||
}
|
||||
|
||||
Platform & pl = GetPlatform();
|
||||
Platform::FilesList files;
|
||||
// Move *.mwm files
|
||||
pl.GetFilesInDir(from, "*" DATA_FILE_EXTENSION, files);
|
||||
for (size_t i = 0; i < files.size(); ++i)
|
||||
{
|
||||
LOG(LINFO, (from + files[i], to + files[i]));
|
||||
rename((from + files[i]).c_str(), (to + files[i]).c_str());
|
||||
}
|
||||
|
||||
// Delete not finished *.downloading files
|
||||
files.clear();
|
||||
pl.GetFilesInDir(from, "*" DOWNLOADING_FILE_EXTENSION, files);
|
||||
pl.GetFilesInDir(from, "*" RESUME_FILE_EXTENSION, files);
|
||||
for (size_t i = 0; i < files.size(); ++i)
|
||||
remove((from + files[i]).c_str());
|
||||
}
|
||||
}
|
296
android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp
Normal file
296
android/jni/com/mapswithme/maps/DownloadResourcesActivity.cpp
Normal file
|
@ -0,0 +1,296 @@
|
|||
#include <jni.h>
|
||||
// To get free disk space
|
||||
#include <sys/vfs.h>
|
||||
|
||||
#include "../../../../../defines.hpp"
|
||||
|
||||
#include "../../../../../platform/http_request.hpp"
|
||||
|
||||
#include "../../../../../base/logging.hpp"
|
||||
#include "../../../../../base/string_utils.hpp"
|
||||
|
||||
#include "../../../../../coding/zip_reader.hpp"
|
||||
#include "../../../../../coding/url_encode.hpp"
|
||||
|
||||
#include "../../../../../platform/platform.hpp"
|
||||
#include "../../../../../platform/http_request.hpp"
|
||||
|
||||
#include "../../../../../std/vector.hpp"
|
||||
#include "../../../../../std/string.hpp"
|
||||
#include "../../../../../std/bind.hpp"
|
||||
|
||||
#include "../core/jni_helper.hpp"
|
||||
|
||||
#include "Framework.hpp"
|
||||
|
||||
|
||||
// Special error codes to notify GUI about free space
|
||||
//@{
|
||||
#define ERR_DOWNLOAD_SUCCESS 0
|
||||
#define ERR_NOT_ENOUGH_MEMORY -1
|
||||
#define ERR_NOT_ENOUGH_FREE_SPACE -2
|
||||
#define ERR_STORAGE_DISCONNECTED -3
|
||||
#define ERR_DOWNLOAD_ERROR -4
|
||||
#define ERR_NO_MORE_FILES -5
|
||||
#define ERR_FILE_IN_PROGRESS -6
|
||||
//@}
|
||||
|
||||
struct FileToDownload
|
||||
{
|
||||
vector<string> m_urls;
|
||||
string m_fileName;
|
||||
string m_pathOnSdcard;
|
||||
uint64_t m_fileSize;
|
||||
};
|
||||
|
||||
static string g_apkPath;
|
||||
static string g_sdcardPath;
|
||||
static vector<FileToDownload> g_filesToDownload;
|
||||
static int g_totalDownloadedBytes;
|
||||
static int g_totalBytesToDownload;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int HasSpaceForFiles(size_t fileSize)
|
||||
{
|
||||
struct statfs st;
|
||||
|
||||
if (statfs(g_sdcardPath.c_str(), &st) != 0)
|
||||
return ERR_STORAGE_DISCONNECTED;
|
||||
|
||||
if (st.f_bsize * st.f_bavail <= fileSize)
|
||||
return ERR_NOT_ENOUGH_FREE_SPACE;
|
||||
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_mapswithme_maps_DownloadResourcesActivity_nativeGetBytesToDownload(JNIEnv * env, jobject thiz,
|
||||
jstring apkPath, jstring sdcardPath)
|
||||
{
|
||||
{
|
||||
char const * strApkPath = env->GetStringUTFChars(apkPath, 0);
|
||||
if (!strApkPath)
|
||||
return ERR_NOT_ENOUGH_MEMORY;
|
||||
g_apkPath = strApkPath;
|
||||
env->ReleaseStringUTFChars(apkPath, strApkPath);
|
||||
|
||||
char const * strSdcardPath = env->GetStringUTFChars(sdcardPath, 0);
|
||||
if (!strSdcardPath)
|
||||
return ERR_NOT_ENOUGH_MEMORY;
|
||||
g_sdcardPath = strSdcardPath;
|
||||
env->ReleaseStringUTFChars(sdcardPath, strSdcardPath);
|
||||
}
|
||||
|
||||
jint totalBytesToDownload = 0;
|
||||
|
||||
string buffer;
|
||||
ReaderPtr<Reader>(GetPlatform().GetReader("external_resources.txt")).ReadAsString(buffer);
|
||||
|
||||
stringstream in(buffer);
|
||||
|
||||
string name;
|
||||
int size;
|
||||
|
||||
while (true)
|
||||
{
|
||||
in >> name;
|
||||
|
||||
if (!in.good())
|
||||
break;
|
||||
|
||||
in >> size;
|
||||
|
||||
if (!in.good())
|
||||
break;
|
||||
|
||||
FileToDownload f;
|
||||
|
||||
f.m_pathOnSdcard = g_sdcardPath + name;
|
||||
f.m_fileName = name;
|
||||
|
||||
uint64_t sizeOnSdcard = 0;
|
||||
Platform::GetFileSizeByFullPath(f.m_pathOnSdcard, sizeOnSdcard);
|
||||
|
||||
if (size != sizeOnSdcard)
|
||||
{
|
||||
LOG(LINFO, ("should check : ", name, "sized", size, "bytes"));
|
||||
f.m_fileSize = size;
|
||||
g_filesToDownload.push_back(f);
|
||||
totalBytesToDownload += size;
|
||||
}
|
||||
}
|
||||
|
||||
g_totalDownloadedBytes = 0;
|
||||
|
||||
int res = HasSpaceForFiles(totalBytesToDownload);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case ERR_STORAGE_DISCONNECTED:
|
||||
LOG(LWARNING, ("External file system is not available"));
|
||||
break;
|
||||
case ERR_NOT_ENOUGH_FREE_SPACE:
|
||||
LOG(LWARNING, ("Not enough space to extract files"));
|
||||
break;
|
||||
};
|
||||
|
||||
g_totalBytesToDownload = totalBytesToDownload;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void DownloadFileFinished(shared_ptr<jobject> obj, downloader::HttpRequest & req)
|
||||
{
|
||||
int errorCode = 0;
|
||||
|
||||
CHECK(req.Status() != downloader::HttpRequest::EInProgress, ("should be either Completed or Failed"));
|
||||
|
||||
switch (req.Status())
|
||||
{
|
||||
case downloader::HttpRequest::ECompleted:
|
||||
errorCode = ERR_DOWNLOAD_SUCCESS;
|
||||
break;
|
||||
case downloader::HttpRequest::EFailed:
|
||||
errorCode = ERR_DOWNLOAD_ERROR;
|
||||
break;
|
||||
};
|
||||
|
||||
FileToDownload & curFile = g_filesToDownload.back();
|
||||
|
||||
LOG(LINFO, ("finished downloading", curFile.m_fileName, "sized", curFile.m_fileSize, "bytes"));
|
||||
|
||||
/// slight hack, check manually for Maps extension and AddMap accordingly
|
||||
if (curFile.m_fileName.find(".mwm") != string::npos)
|
||||
{
|
||||
LOG(LINFO, ("adding it as a map"));
|
||||
g_framework->AddMap(curFile.m_fileName);
|
||||
}
|
||||
|
||||
g_totalDownloadedBytes += curFile.m_fileSize;
|
||||
|
||||
LOG(LINFO, ("totalDownloadedBytes:", g_totalDownloadedBytes));
|
||||
|
||||
g_filesToDownload.pop_back();
|
||||
|
||||
JNIEnv * env = jni::GetEnv();
|
||||
|
||||
jmethodID onFinishMethod = env->GetMethodID(env->GetObjectClass(*obj.get()), "onDownloadFinished", "(I)V");
|
||||
CHECK(onFinishMethod, ("Not existing method: void onDownloadFinished(int)"));
|
||||
|
||||
env->CallVoidMethod(*obj.get(), onFinishMethod, errorCode);
|
||||
}
|
||||
|
||||
void DownloadFileProgress(shared_ptr<jobject> obj, downloader::HttpRequest & req)
|
||||
{
|
||||
LOG(LINFO, (req.Progress().first, "bytes for", g_filesToDownload.back().m_fileName, "was downloaded"));
|
||||
|
||||
JNIEnv * env = jni::GetEnv();
|
||||
|
||||
jmethodID onProgressMethod = env->GetMethodID(env->GetObjectClass(*obj.get()), "onDownloadProgress", "(IIII)V");
|
||||
CHECK(onProgressMethod, ("Not existing method: void onDownloadProgress(int, int, int, int)"));
|
||||
|
||||
FileToDownload & curFile = g_filesToDownload.back();
|
||||
|
||||
jint curTotal = req.Progress().second;
|
||||
jint curProgress = req.Progress().first;
|
||||
jint glbTotal = g_totalBytesToDownload;
|
||||
jint glbProgress = g_totalDownloadedBytes + req.Progress().first;
|
||||
|
||||
env->CallVoidMethod(*obj.get(), onProgressMethod,
|
||||
curTotal, curProgress,
|
||||
glbTotal, glbProgress);
|
||||
}
|
||||
|
||||
void DownloadURLListFinished(downloader::HttpRequest & req,
|
||||
downloader::HttpRequest::CallbackT onFinish,
|
||||
downloader::HttpRequest::CallbackT onProgress)
|
||||
{
|
||||
if (req.Status() == downloader::HttpRequest::EFailed)
|
||||
onFinish(req);
|
||||
else
|
||||
{
|
||||
FileToDownload & curFile = g_filesToDownload.back();
|
||||
|
||||
LOG(LINFO, ("finished URL list download for", curFile.m_fileName));
|
||||
|
||||
downloader::ParseServerList(req.Data(), curFile.m_urls);
|
||||
|
||||
for (size_t i = 0; i < curFile.m_urls.size(); ++i)
|
||||
{
|
||||
curFile.m_urls[i] = curFile.m_urls[i] + OMIM_OS_NAME "/"
|
||||
+ strings::to_string(g_framework->Storage().GetCurrentVersion()) + "/"
|
||||
+ UrlEncode(curFile.m_fileName);
|
||||
LOG(LINFO, (curFile.m_urls[i]));
|
||||
}
|
||||
|
||||
downloader::HttpRequest::GetFile(curFile.m_urls,
|
||||
curFile.m_pathOnSdcard,
|
||||
curFile.m_fileSize,
|
||||
onFinish,
|
||||
onProgress);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT int JNICALL
|
||||
Java_com_mapswithme_maps_DownloadResourcesActivity_nativeDownloadNextFile(JNIEnv * env,
|
||||
jobject thiz, jobject observer)
|
||||
{
|
||||
if (g_filesToDownload.empty())
|
||||
return ERR_NO_MORE_FILES;
|
||||
|
||||
FileToDownload & curFile = g_filesToDownload.back();
|
||||
|
||||
LOG(LINFO, ("downloading", curFile.m_fileName, "sized", curFile.m_fileSize, "bytes"));
|
||||
|
||||
downloader::HttpRequest::CallbackT onFinish(bind(&DownloadFileFinished, jni::make_global_ref(observer), _1));
|
||||
downloader::HttpRequest::CallbackT onProgress(bind(&DownloadFileProgress, jni::make_global_ref(observer), _1));
|
||||
|
||||
downloader::HttpRequest::PostJson(GetPlatform().MetaServerUrl(),
|
||||
curFile.m_fileName,
|
||||
bind(&DownloadURLListFinished, _1,
|
||||
onFinish,
|
||||
onProgress));
|
||||
|
||||
return ERR_FILE_IN_PROGRESS;
|
||||
}
|
||||
|
||||
// Move downloaded maps from /sdcard/Android/data/com.mapswithme.maps/files/
|
||||
// to /sdcard/MapsWithMe
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_mapswithme_maps_DownloadResourcesActivity_nativeMoveMaps(JNIEnv * env, jobject thiz,
|
||||
jstring fromPath, jstring toPath)
|
||||
{
|
||||
string from, to;
|
||||
{
|
||||
char const * strFrom = env->GetStringUTFChars(fromPath, 0);
|
||||
if (!strFrom)
|
||||
return;
|
||||
from = strFrom;
|
||||
env->ReleaseStringUTFChars(fromPath, strFrom);
|
||||
|
||||
char const * strTo = env->GetStringUTFChars(toPath, 0);
|
||||
if (!strTo)
|
||||
return;
|
||||
to = strTo;
|
||||
env->ReleaseStringUTFChars(toPath, strTo);
|
||||
}
|
||||
|
||||
Platform & pl = GetPlatform();
|
||||
Platform::FilesList files;
|
||||
// Move *.mwm files
|
||||
pl.GetFilesInDir(from, "*" DATA_FILE_EXTENSION, files);
|
||||
for (size_t i = 0; i < files.size(); ++i)
|
||||
{
|
||||
LOG(LINFO, (from + files[i], to + files[i]));
|
||||
rename((from + files[i]).c_str(), (to + files[i]).c_str());
|
||||
}
|
||||
|
||||
// Delete not finished *.downloading files
|
||||
files.clear();
|
||||
pl.GetFilesInDir(from, "*" DOWNLOADING_FILE_EXTENSION, files);
|
||||
pl.GetFilesInDir(from, "*" RESUME_FILE_EXTENSION, files);
|
||||
for (size_t i = 0; i < files.size(); ++i)
|
||||
remove((from + files[i]).c_str());
|
||||
}
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
package com.mapswithme.maps;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
// MWM resources are zipped in the apk inside /assets folder.
|
||||
// MWM code currently can't randomly read zip files, so they're copied
|
||||
// on the first start to the sdcard and used from there
|
||||
public class CopyResourcesActivity extends Activity
|
||||
{
|
||||
private ProgressDialog m_dialog = null;
|
||||
|
||||
// Error codes, should match the same codes in JNI
|
||||
private static final int ERR_COPIED_SUCCESSFULLY = 0;
|
||||
private static final int ERR_NOT_ENOUGH_MEMORY = -1;
|
||||
private static final int ERR_NOT_ENOUGH_FREE_SPACE = -2;
|
||||
private static final int ERR_STORAGE_DISCONNECTED = -3;
|
||||
|
||||
// Copies assets files to external folder on sdcard in the background
|
||||
public class CopyResourcesTask extends AsyncTask<Void, Integer, Integer>
|
||||
{
|
||||
private final String m_apkPath;
|
||||
private final String m_sdcardPath;
|
||||
|
||||
CopyResourcesTask(String apkPath, String sdcardPath)
|
||||
{
|
||||
m_apkPath = apkPath;
|
||||
m_sdcardPath = sdcardPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute()
|
||||
{
|
||||
// Check if we need to perform any copying
|
||||
final int bytes = nativeGetBytesToCopy(m_apkPath, m_sdcardPath);
|
||||
if (bytes > 0)
|
||||
{
|
||||
// Display copy progress dialog
|
||||
CopyResourcesActivity.this.showDialog(bytes);
|
||||
}
|
||||
else if (bytes == 0)
|
||||
{
|
||||
// All files are in place, continue with UI initialization
|
||||
cancel(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display error dialog in UI, very rare case
|
||||
CopyResourcesActivity.this.onCopyTaskFinished(ERR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result)
|
||||
{
|
||||
CopyResourcesActivity.this.onCopyTaskFinished(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled()
|
||||
{
|
||||
// In our logic cancelled means that files shouldn't be copied,
|
||||
// So we just proceed to main UI initialization
|
||||
CopyResourcesActivity.this.onCopyTaskFinished(ERR_COPIED_SUCCESSFULLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... copiedBytes)
|
||||
{
|
||||
CopyResourcesActivity.this.onCopyResourcesProgress(copiedBytes[0]);
|
||||
}
|
||||
|
||||
// If negative, stores error code
|
||||
// Total number of copied bytes
|
||||
int m_bytesCopied = 0;
|
||||
|
||||
protected void onFileProgress(int size, int pos)
|
||||
{
|
||||
publishProgress(m_bytesCopied + pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... p)
|
||||
{
|
||||
do
|
||||
{
|
||||
m_bytesCopied = nativeCopyNextFile(this);
|
||||
if (m_bytesCopied > 0)
|
||||
publishProgress(m_bytesCopied);
|
||||
else if (m_bytesCopied < 0)
|
||||
return m_bytesCopied;
|
||||
} while (m_bytesCopied != 0);
|
||||
|
||||
return ERR_COPIED_SUCCESSFULLY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
// Set the same layout as for MWMActivity
|
||||
setContentView(R.layout.map);
|
||||
|
||||
final String extPath = MWMActivity.getDataStoragePath();
|
||||
// Create sdcard folder if it doesn't exist
|
||||
new File(extPath).mkdirs();
|
||||
// Used to migrate from v2.0.0 to 2.0.1
|
||||
nativeMoveMaps(MWMActivity.getExtAppDirectoryPath("files"), extPath);
|
||||
// All copy checks are made in the background task
|
||||
new CopyResourcesTask(MWMActivity.getApkPath(this), extPath).execute();
|
||||
}
|
||||
|
||||
public void onCopyTaskFinished(int result)
|
||||
{
|
||||
if (result == ERR_COPIED_SUCCESSFULLY)
|
||||
{
|
||||
// Continue with Main UI initialization (MWMActivity)
|
||||
Intent mwmActivityIntent = new Intent(this, MWMActivity.class);
|
||||
// Disable animation because MWMActivity should appear exactly over this one
|
||||
mwmActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivity(mwmActivityIntent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide loading progress
|
||||
if (m_dialog != null)
|
||||
m_dialog.dismiss();
|
||||
|
||||
int errMsgId;
|
||||
switch (result)
|
||||
{
|
||||
case ERR_NOT_ENOUGH_FREE_SPACE: errMsgId = R.string.not_enough_free_space_on_sdcard; break;
|
||||
case ERR_STORAGE_DISCONNECTED: errMsgId = R.string.disconnect_usb_cable; break;
|
||||
default: errMsgId = R.string.not_enough_memory;
|
||||
}
|
||||
// Display Error dialog with close button
|
||||
new AlertDialog.Builder(this).setMessage(errMsgId)
|
||||
.setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
CopyResourcesActivity.this.finish();
|
||||
CopyResourcesActivity.this.moveTaskToBack(true);
|
||||
}})
|
||||
.create().show();
|
||||
}
|
||||
}
|
||||
|
||||
private String cutProgressString(final String str, int current, int total)
|
||||
{
|
||||
int len = current * str.length() / total;
|
||||
if (len <= 0)
|
||||
len = 0;
|
||||
else if (len > str.length())
|
||||
len = str.length();
|
||||
return str.substring(0, len);
|
||||
}
|
||||
|
||||
private String m_progressString;
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int totalBytesToCopy)
|
||||
{
|
||||
m_progressString = getString(R.string.loading);
|
||||
|
||||
m_dialog = new ProgressDialog(this);
|
||||
m_dialog.setMessage(cutProgressString(m_progressString, 0, totalBytesToCopy));
|
||||
m_dialog.setCancelable(false);
|
||||
m_dialog.setIndeterminate(true);
|
||||
m_dialog.setMax(totalBytesToCopy);
|
||||
return m_dialog;
|
||||
}
|
||||
|
||||
public void onCopyResourcesProgress(int copiedBytes)
|
||||
{
|
||||
if (m_dialog != null)
|
||||
{
|
||||
m_dialog.setMessage(cutProgressString(m_progressString, copiedBytes, m_dialog.getMax()));
|
||||
m_dialog.setProgress(copiedBytes);
|
||||
}
|
||||
}
|
||||
|
||||
private native void nativeMoveMaps(String fromFolder, String toFolder);
|
||||
private native int nativeGetBytesToCopy(String m_apkPath, String m_sdcardPath);
|
||||
private native int nativeCopyNextFile(Object observer);
|
||||
}
|
186
android/src/com/mapswithme/maps/DownloadResourcesActivity.java
Normal file
186
android/src/com/mapswithme/maps/DownloadResourcesActivity.java
Normal file
|
@ -0,0 +1,186 @@
|
|||
package com.mapswithme.maps;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.util.Log;
|
||||
|
||||
public class DownloadResourcesActivity extends Activity
|
||||
{
|
||||
private static final String TAG = "DownloadResourcesActivity";
|
||||
|
||||
private ProgressDialog mDialog = null;
|
||||
|
||||
// Error codes, should match the same codes in JNI
|
||||
|
||||
private static final int ERR_DOWNLOAD_SUCCESS = 0;
|
||||
private static final int ERR_NOT_ENOUGH_MEMORY = -1;
|
||||
private static final int ERR_NOT_ENOUGH_FREE_SPACE = -2;
|
||||
private static final int ERR_STORAGE_DISCONNECTED = -3;
|
||||
private static final int ERR_DOWNLOAD_ERROR = -4;
|
||||
private static final int ERR_NO_MORE_FILES = -5;
|
||||
private static final int ERR_FILE_IN_PROGRESS = -6;
|
||||
|
||||
MWMApplication mApplication;
|
||||
|
||||
protected void prepareFilesDownload()
|
||||
{
|
||||
// Check if we need to perform any downloading
|
||||
final int bytes = nativeGetBytesToDownload(
|
||||
mApplication.getApkPath(),
|
||||
mApplication.getDataStoragePath());
|
||||
|
||||
/// disabling screen
|
||||
disableAutomaticStandby();
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
// Display copy progress dialog
|
||||
Log.w(TAG, "prepareFilesDownload, bytesToDownload:" + bytes);
|
||||
|
||||
showDialog(bytes);
|
||||
|
||||
if (nativeDownloadNextFile(this) == ERR_NO_MORE_FILES)
|
||||
finishFilesDownload(ERR_NO_MORE_FILES);
|
||||
}
|
||||
else if (bytes == 0)
|
||||
{
|
||||
// All files are in place, continue with UI initialization
|
||||
finishFilesDownload(ERR_DOWNLOAD_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display error dialog in UI, very rare case
|
||||
finishFilesDownload(ERR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
private WakeLock mWakeLock = null;
|
||||
|
||||
private void disableAutomaticStandby()
|
||||
{
|
||||
if (mWakeLock == null)
|
||||
{
|
||||
PowerManager pm = (PowerManager) mApplication.getSystemService(
|
||||
android.content.Context.POWER_SERVICE);
|
||||
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG);
|
||||
mWakeLock.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
private void enableAutomaticStandby()
|
||||
{
|
||||
if (mWakeLock != null)
|
||||
{
|
||||
mWakeLock.release();
|
||||
mWakeLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
// Set the same layout as for MWMActivity
|
||||
setContentView(R.layout.map);
|
||||
|
||||
mApplication = (MWMApplication)getApplication();
|
||||
|
||||
// Create sdcard folder if it doesn't exist
|
||||
new File(mApplication.getDataStoragePath()).mkdirs();
|
||||
// Used to migrate from v2.0.0 to 2.0.1
|
||||
nativeMoveMaps(mApplication.getExtAppDirectoryPath("files"),
|
||||
mApplication.getDataStoragePath());
|
||||
|
||||
prepareFilesDownload();
|
||||
}
|
||||
|
||||
public void finishFilesDownload(int result)
|
||||
{
|
||||
enableAutomaticStandby();
|
||||
if (result == ERR_NO_MORE_FILES)
|
||||
{
|
||||
Log.w(TAG, "finished files download");
|
||||
|
||||
// Continue with Main UI initialization (MWMActivity)
|
||||
Intent mwmActivityIntent = new Intent(this, MWMActivity.class);
|
||||
// Disable animation because MWMActivity should appear exactly over this one
|
||||
mwmActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivity(mwmActivityIntent);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hide loading progress
|
||||
if (mDialog != null)
|
||||
mDialog.dismiss();
|
||||
|
||||
int errMsgId;
|
||||
switch (result)
|
||||
{
|
||||
case ERR_NOT_ENOUGH_FREE_SPACE: errMsgId = R.string.not_enough_free_space_on_sdcard; break;
|
||||
case ERR_STORAGE_DISCONNECTED: errMsgId = R.string.disconnect_usb_cable; break;
|
||||
case ERR_DOWNLOAD_ERROR: errMsgId = R.string.download_has_failed; break;
|
||||
default: errMsgId = R.string.not_enough_memory;
|
||||
}
|
||||
// Display Error dialog with close button
|
||||
new AlertDialog.Builder(this).setMessage(errMsgId)
|
||||
.setPositiveButton(R.string.close, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
finish();
|
||||
moveTaskToBack(true);
|
||||
}})
|
||||
.create().show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int totalBytesToDownload)
|
||||
{
|
||||
mDialog = new ProgressDialog(this);
|
||||
|
||||
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
mDialog.setMessage(getString(R.string.loading));
|
||||
mDialog.setCancelable(true);
|
||||
mDialog.setIndeterminate(false);
|
||||
|
||||
Log.w(TAG, "progressMax:" + totalBytesToDownload);
|
||||
|
||||
mDialog.setMax(totalBytesToDownload);
|
||||
|
||||
return mDialog;
|
||||
}
|
||||
|
||||
public void onDownloadProgress(int currentTotal, int currentProgress, int globalTotal, int globalProgress)
|
||||
{
|
||||
Log.w(TAG, "curTotal:" + currentTotal + ", curProgress:" + currentProgress
|
||||
+ ", glbTotal:" + globalTotal + ", glbProgress:" + globalProgress);
|
||||
|
||||
if (mDialog != null)
|
||||
mDialog.setProgress(globalProgress);
|
||||
}
|
||||
|
||||
public void onDownloadFinished(int errorCode)
|
||||
{
|
||||
if (errorCode == ERR_DOWNLOAD_SUCCESS)
|
||||
{
|
||||
int res = nativeDownloadNextFile(this);
|
||||
if (res == ERR_NO_MORE_FILES)
|
||||
finishFilesDownload(res);
|
||||
}
|
||||
else
|
||||
finishFilesDownload(errorCode);
|
||||
}
|
||||
|
||||
private native void nativeMoveMaps(String fromFolder, String toFolder);
|
||||
private native int nativeGetBytesToDownload(String m_apkPath, String m_sdcardPath);
|
||||
private native int nativeDownloadNextFile(Object observer);
|
||||
}
|
9
data/external_resources.txt
Normal file
9
data/external_resources.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
World.mwm 21694121
|
||||
WorldCoasts.mwm 6315418
|
||||
01_dejavusans.ttf 633604
|
||||
02_wqy-microhei.ttf 5177387
|
||||
03_jomolhari-id-a3d.ttf 1817160
|
||||
04_padauk.ttf 248076
|
||||
05_khmeros.ttf 265552
|
||||
06_code2000.ttf 3155104
|
||||
packed_polygons.bin 1854515
|
|
@ -461,4 +461,9 @@ namespace storage
|
|||
bind(&Storage::OnMapDownloadFinished, this, _1),
|
||||
bind(&Storage::OnMapDownloadProgress, this, _1)));
|
||||
}
|
||||
|
||||
int64_t Storage::GetCurrentVersion() const
|
||||
{
|
||||
return m_currentVersion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,6 +146,8 @@ namespace storage
|
|||
void CheckForUpdate();
|
||||
|
||||
void NotifyStatusChanhed(TIndex const & index) const;
|
||||
|
||||
int64_t GetCurrentVersion() const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -8,12 +8,10 @@ DST=../../android/assets
|
|||
rm -rf $DST
|
||||
mkdir $DST
|
||||
|
||||
files=(01_dejavusans.ttf 02_wqy-microhei.ttf 03_jomolhari-id-a3d.ttf 04_padauk.ttf \
|
||||
05_khmeros.ttf 06_code2000.ttf WorldCoasts.mwm about.html \
|
||||
basic_ldpi.skn basic_mdpi.skn basic_hdpi.skn basic_xhdpi.skn categories.txt classificator.txt
|
||||
files=(about.html basic_ldpi.skn basic_mdpi.skn basic_hdpi.skn basic_xhdpi.skn categories.txt classificator.txt
|
||||
types.txt fonts_blacklist.txt fonts_whitelist.txt languages.txt \
|
||||
symbols_ldpi.png symbols_mdpi.png symbols_hdpi.png symbols_xhdpi.png unicode_blocks.txt \
|
||||
visibility.txt drules_proto.txt drules_proto.bin packed_polygons.bin)
|
||||
visibility.txt drules_proto.txt drules_proto.bin external_resources.txt)
|
||||
|
||||
for item in ${files[*]}
|
||||
do
|
||||
|
@ -21,5 +19,4 @@ do
|
|||
done
|
||||
|
||||
# Separate case for World and countries list files without search support
|
||||
ln -s $SRC/World.mwm.nosearch $DST/World.mwm
|
||||
ln -s $SRC/countries.txt.nosearch $DST/countries.txt
|
||||
|
|
Loading…
Add table
Reference in a new issue