First run changes (#809)

* don't request for storage permission on first startup
* app head: download button tweaks
* fix download manager
This commit is contained in:
Akinwale Ariwodola 2019-12-28 16:06:14 +01:00 committed by GitHub
parent d0117b14db
commit 57d6b72f5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 99 deletions

2
app

@ -1 +1 @@
Subproject commit 54b10c818e5c49a74044d076841f9e57a6ad1dc1 Subproject commit d362d9e8dd9e0f87262bcb61f996182633e7f008

View file

@ -242,27 +242,30 @@ public class LbrynetService extends PythonService {
try { try {
JSONObject response = new JSONObject(fileList); JSONObject response = new JSONObject(fileList);
if (!response.has("error")) { if (!response.has("error")) {
JSONArray fileItems = response.optJSONArray("result"); JSONObject result = response.getJSONObject("result");
if (fileItems != null && fileItems.length() > 0) { if (result != null) {
// TODO: Create Java FileItem class JSONArray fileItems = response.optJSONArray("items");
JSONObject item = fileItems.getJSONObject(0); if (fileItems != null && fileItems.length() > 0) {
String downloadPath = item.isNull("download_path") ? null : item.getString("download_path"); // TODO: Create Java FileItem class
if (downloadPath == null || downloadPath.trim().length() == 0) { JSONObject item = fileItems.getJSONObject(0);
return; String downloadPath = item.isNull("download_path") ? null : item.getString("download_path");
} if (downloadPath == null || downloadPath.trim().length() == 0) {
String claimId = item.getString("claim_id"); return;
String claimName = item.getString("claim_name"); }
String uri = String.format("lbry://%s#%s", claimName, claimId); String claimId = item.getString("claim_id");
String claimName = item.getString("claim_name");
String uri = String.format("lbry://%s#%s", claimName, claimId);
if (!downloadManager.isDownloadActive(uri) && !downloadManager.isDownloadCompleted(uri)) { if (!downloadManager.isDownloadActive(uri) && !downloadManager.isDownloadCompleted(uri)) {
File file = new File(downloadPath); File file = new File(downloadPath);
Intent intent = createDownloadEventIntent(uri, outpoint, item.toString()); Intent intent = createDownloadEventIntent(uri, outpoint, item.toString());
intent.putExtra("action", "start"); intent.putExtra("action", "start");
downloadManager.startDownload(uri, file.getName()); downloadManager.startDownload(uri, file.getName());
Context context = getApplicationContext(); Context context = getApplicationContext();
if (context != null) { if (context != null) {
context.sendBroadcast(intent); context.sendBroadcast(intent);
}
} }
} }
} }
@ -287,74 +290,78 @@ public class LbrynetService extends PythonService {
private void handlePollFileResponse(JSONObject response) { private void handlePollFileResponse(JSONObject response) {
Context context = getApplicationContext(); Context context = getApplicationContext();
if (response.has("result")) { if (response.has("result")) {
JSONArray fileItems = response.optJSONArray("result"); JSONObject result = response.optJSONObject("result");
if (fileItems != null) { if (result != null) {
try { JSONArray fileItems = result.optJSONArray("items");
//List<String> itemUris = new ArrayList<String>(); if (fileItems != null) {
for (int i = 0; i < fileItems.length(); i++) { try {
JSONObject item = fileItems.getJSONObject(i); //List<String> itemUris = new ArrayList<String>();
String downloadPath = item.isNull("download_path") ? null : item.getString("download_path"); for (int i = 0; i < fileItems.length(); i++) {
if (downloadPath == null || downloadPath.trim().length() == 0) { JSONObject item = fileItems.getJSONObject(i);
continue; String downloadPath = item.isNull("download_path") ? null : item.getString("download_path");
} if (downloadPath == null || downloadPath.trim().length() == 0) {
String claimId = item.getString("claim_id");
String claimName = item.getString("claim_name");
String uri = String.format("lbry://%s#%s", claimName, claimId);
boolean completed = item.getBoolean("completed");
double writtenBytes = item.optDouble("written_bytes", -1);
double totalBytes = item.optDouble("total_bytes", -1);
String outpoint = item.getString("outpoint");
if (downloadManager.isDownloadActive(uri) && (writtenBytes == -1 || totalBytes == -1)) {
// possibly deleted, abort the download
downloadManager.abortDownload(uri);
continue;
}
File file = new File(downloadPath);
Intent intent = createDownloadEventIntent(uri, outpoint, item.toString());
if (downloadManager.isDownloadActive(uri)) {
if (writtenBytes >= totalBytes || completed) {
// completed download
intent.putExtra("action", "complete");
downloadManager.completeDownload(uri, file.getName(), totalBytes);
} else {
intent.putExtra("action", "update");
intent.putExtra("progress", (writtenBytes / totalBytes) * 100);
downloadManager.updateDownload(uri, file.getName(), writtenBytes, totalBytes);
}
if (context != null) {
context.sendBroadcast(intent);
}
} else {
if (writtenBytes == -1 || writtenBytes >= totalBytes) {
// do not start a download that is considered completed
continue; continue;
} }
if (!completed && downloadPath != null) {
intent.putExtra("action", "start"); String claimId = item.getString("claim_id");
downloadManager.startDownload(uri, file.getName()); String claimName = item.getString("claim_name");
String uri = String.format("lbry://%s#%s", claimName, claimId);
boolean completed = item.getBoolean("completed");
double writtenBytes = item.optDouble("written_bytes", -1);
double totalBytes = item.optDouble("total_bytes", -1);
String outpoint = item.getString("outpoint");
if (downloadManager.isDownloadActive(uri) && (writtenBytes == -1 || totalBytes == -1)) {
// possibly deleted, abort the download
downloadManager.abortDownload(uri);
continue;
}
File file = new File(downloadPath);
Intent intent = createDownloadEventIntent(uri, outpoint, item.toString());
if (downloadManager.isDownloadActive(uri)) {
if (writtenBytes >= totalBytes || completed) {
// completed download
intent.putExtra("action", "complete");
downloadManager.completeDownload(uri, file.getName(), totalBytes);
} else {
intent.putExtra("action", "update");
intent.putExtra("progress", (writtenBytes / totalBytes) * 100);
downloadManager.updateDownload(uri, file.getName(), writtenBytes, totalBytes);
}
if (context != null) { if (context != null) {
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
} else {
if (writtenBytes == -1 || writtenBytes >= totalBytes) {
// do not start a download that is considered completed
continue;
}
if (!completed && downloadPath != null) {
intent.putExtra("action", "start");
downloadManager.startDownload(uri, file.getName());
if (context != null) {
context.sendBroadcast(intent);
}
}
} }
} }
}
// check download manager uris and clear downloads that may have been cancelled / deleted // check download manager uris and clear downloads that may have been cancelled / deleted
/*List<String> activeUris = downloadManager.getActiveDownloads(); /*List<String> activeUris = downloadManager.getActiveDownloads();
for (int i = 0; i < activeUris.size(); i++) { for (int i = 0; i < activeUris.size(); i++) {
String activeUri = activeUris.get(i); String activeUri = activeUris.get(i);
if (!itemUris.contains(activeUri)) { if (!itemUris.contains(activeUri)) {
downloadManager.abortDownload(activeUri); downloadManager.abortDownload(activeUri);
fileListUris.remove(activeUri); // remove URIs from the session that may have been deleted fileListUris.remove(activeUri); // remove URIs from the session that may have been deleted
} }
}*/ }*/
} catch (JSONException ex) { } catch (JSONException ex) {
// pass // pass
Log.e(TAG, ex.getMessage(), ex); Log.e(TAG, ex.getMessage(), ex);
}
} }
} }
} }

View file

@ -38,6 +38,8 @@ import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.ReadableNativeArray;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.modules.core.PermissionAwareActivity; import com.facebook.react.modules.core.PermissionAwareActivity;
import com.facebook.react.modules.core.PermissionListener; import com.facebook.react.modules.core.PermissionListener;
@ -128,14 +130,6 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Request external storage permission on Android version >= 6
checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
STORAGE_PERMISSION_REQ_CODE,
"LBRY requires access to your device storage to be able to download files and media.",
this);
}
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
currentActivity = this; currentActivity = this;
@ -365,6 +359,7 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
@Override @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
switch (requestCode) { switch (requestCode) {
case STORAGE_PERMISSION_REQ_CODE: case STORAGE_PERMISSION_REQ_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
@ -373,22 +368,25 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
Uri.parse("package:" + getPackageName())); Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE); startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
} }
} else { if (reactContext != null) {
// Permission not granted. Show a message and terminate the application reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
Toast.makeText(this, .emit("onStoragePermissionGranted", null);
"LBRY requires access to your device storage to be able to download files and media." + }
" Please enable the storage permission and restart the app.", Toast.LENGTH_LONG).show(); } else {
if (serviceRunning) { // Permission not granted
ServiceHelper.stop(this, LbrynetService.class); /*Toast.makeText(this,
"LBRY requires access to your device storage to be able to download files and media." +
" Please enable the storage permission and restart the app.", Toast.LENGTH_LONG).show();*/
if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("onStoragePermissionRefused", null);
} }
finish();
} }
break; break;
case PHONE_STATE_PERMISSION_REQ_CODE: case PHONE_STATE_PERMISSION_REQ_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted. Emit an onPhoneStatePermissionGranted event // Permission granted. Emit an onPhoneStatePermissionGranted event
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext != null) { if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("onPhoneStatePermissionGranted", null); .emit("onPhoneStatePermissionGranted", null);
@ -403,7 +401,6 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
case RECEIVE_SMS_PERMISSION_REQ_CODE: case RECEIVE_SMS_PERMISSION_REQ_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted. Emit an onPhoneStatePermissionGranted event // Permission granted. Emit an onPhoneStatePermissionGranted event
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext != null) { if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("onReceiveSmsPermissionGranted", null); .emit("onReceiveSmsPermissionGranted", null);
@ -609,6 +606,15 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
true); true);
} }
public static void checkStoragePermission(Context context) {
// Request read phone state permission
checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
STORAGE_PERMISSION_REQ_CODE,
"LBRY requires access to your device storage to be able to download files and media.",
context,
true);
}
private boolean isServiceRunning(Class<?> serviceClass) { private boolean isServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo serviceInfo : manager.getRunningServices(Integer.MAX_VALUE)) { for (ActivityManager.RunningServiceInfo serviceInfo : manager.getRunningServices(Integer.MAX_VALUE)) {

View file

@ -62,6 +62,8 @@ public final class Utils {
public static final String SDK_URL = "http://127.0.0.1:5279"; public static final String SDK_URL = "http://127.0.0.1:5279";
public static final String SP_DOWNLOAD_DIR_KEY = "download_dir";
public static String getAndroidRelease() { public static String getAndroidRelease() {
return android.os.Build.VERSION.RELEASE; return android.os.Build.VERSION.RELEASE;
} }
@ -114,6 +116,16 @@ public final class Utils {
return file.getAbsolutePath(); return file.getAbsolutePath();
} }
public static String getConfiguredDownloadDirectory(Context context) {
// use the default folder (usually [private files]/Download with WRITE_EXTERNAL_STOAGE permission not granted)
// if none is configured or specified
String defaultDirectory = String.format("%s/Download", getInternalStorageDir(context));
SharedPreferences pref = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
String downloadDirectory = pref.getString(SP_DOWNLOAD_DIR_KEY, defaultDirectory);
return downloadDirectory;
}
public static void saveApiSecret(String secret, Context context, KeyStore keyStore) { public static void saveApiSecret(String secret, Context context, KeyStore keyStore) {
try { try {
SharedPreferences pref = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); SharedPreferences pref = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);

View file

@ -207,6 +207,19 @@ public class UtilityModule extends ReactContextBaseJavaModule {
} }
} }
@ReactMethod
public void canReadWriteStorage(final Promise promise) {
promise.resolve(MainActivity.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, MainActivity.getActivity()));
}
@ReactMethod
public void requestStoragePermission() {
MainActivity activity = (MainActivity) MainActivity.getActivity();
if (activity != null) {
MainActivity.checkStoragePermission(activity);
}
}
@ReactMethod @ReactMethod
public void shareLogFile(Callback errorCallback) { public void shareLogFile(Callback errorCallback) {
String logFileName = "lbrynet.log"; String logFileName = "lbrynet.log";
@ -378,6 +391,7 @@ public class UtilityModule extends ReactContextBaseJavaModule {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(LbrynetService.ACTION_QUEUE_DOWNLOAD); intent.setAction(LbrynetService.ACTION_QUEUE_DOWNLOAD);
intent.putExtra("outpoint", outpoint); intent.putExtra("outpoint", outpoint);
if (context != null) { if (context != null) {
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
@ -450,4 +464,10 @@ public class UtilityModule extends ReactContextBaseJavaModule {
promise.resolve(null); promise.resolve(null);
} }
@ReactMethod
public void getDownloadDirectory(Promise promise) {
// This obtains a public default download directory after the storage permission has been granted
promise.resolve(Utils.getConfiguredDownloadDirectory(context));
}
} }

View file

@ -73,10 +73,12 @@ def configure_logging(conf):
def start(): def start():
keyring.set_keyring(LbryAndroidKeyring()) keyring.set_keyring(LbryAndroidKeyring())
private_storage_dir = lbrynet_android_utils.getAppInternalStorageDir(service.getApplicationContext()) private_storage_dir = lbrynet_android_utils.getAppInternalStorageDir(service.getApplicationContext())
configured_download_dir = lbrynet_android_utils.getConfiguredDownloadDirectory(service.getApplicationContext())
print('configured_download_dir={}'.format(configured_download_dir))
conf = Config( conf = Config(
data_dir=f'{private_storage_dir}/lbrynet', data_dir=f'{private_storage_dir}/lbrynet',
wallet_dir=f'{private_storage_dir}/lbryum', wallet_dir=f'{private_storage_dir}/lbryum',
download_dir=f'{lbrynet_android_utils.getInternalStorageDir(service.getApplicationContext())}/Download', download_dir=configured_download_dir,
blob_lru_cache_size=32, blob_lru_cache_size=32,
components_to_skip=[DHT_COMPONENT, HASH_ANNOUNCER_COMPONENT, PEER_PROTOCOL_SERVER_COMPONENT], components_to_skip=[DHT_COMPONENT, HASH_ANNOUNCER_COMPONENT, PEER_PROTOCOL_SERVER_COMPONENT],
save_blobs=False, save_blobs=False,