lbry.tv hybrid mode #869

Merged
akinwale merged 6 commits from lbry-tv-experiment into master 2020-03-20 08:30:35 +01:00
6 changed files with 103 additions and 33 deletions

View file

@ -12,10 +12,6 @@ import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat; import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import io.lbry.browser.receivers.NotificationDeletedReceiver; import io.lbry.browser.receivers.NotificationDeletedReceiver;
import io.lbry.lbrysdk.LbrynetService; import io.lbry.lbrysdk.LbrynetService;

View file

@ -116,7 +116,8 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
} else { } else {
if (!MainActivity.isServiceRunning(this, LbrynetService.class) && if (!MainActivity.isServiceRunning(this, LbrynetService.class) &&
contentTitle != null && contentTitle != null &&
channelUrl != null channelUrl != null &&
!url.startsWith("lbry://?") /* not a special url */
) { ) {
// only enter lite mode when contentTitle and channelUrl are set (and the service isn't running yet) // only enter lite mode when contentTitle and channelUrl are set (and the service isn't running yet)
// cold start // cold start

View file

@ -3,6 +3,7 @@ package io.lbry.browser;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
@ -18,6 +19,7 @@ import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.Manifest; import android.Manifest;
import android.net.Uri; import android.net.Uri;
import android.os.Handler;
import android.provider.DocumentsContract; import android.provider.DocumentsContract;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.provider.Settings; import android.provider.Settings;
@ -62,10 +64,12 @@ import io.lbry.browser.reactpackages.LbryReactPackage;
import io.lbry.browser.reactmodules.BackgroundMediaModule; import io.lbry.browser.reactmodules.BackgroundMediaModule;
import io.lbry.lbrysdk.LbrynetService; import io.lbry.lbrysdk.LbrynetService;
import io.lbry.lbrysdk.ServiceHelper; import io.lbry.lbrysdk.ServiceHelper;
import io.lbry.lbrysdk.Utils;
import java.io.File; import java.io.File;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigInteger; import java.math.BigInteger;
import java.net.ConnectException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -84,51 +88,34 @@ import org.reactnative.camera.RNCameraPackage;
public class MainActivity extends FragmentActivity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { public class MainActivity extends FragmentActivity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
private static Activity currentActivity = null; private static Activity currentActivity = null;
private static final int OVERLAY_PERMISSION_REQ_CODE = 101; private static final int OVERLAY_PERMISSION_REQ_CODE = 101;
private static final int STORAGE_PERMISSION_REQ_CODE = 201; private static final int STORAGE_PERMISSION_REQ_CODE = 201;
private static final int PHONE_STATE_PERMISSION_REQ_CODE = 202; private static final int PHONE_STATE_PERMISSION_REQ_CODE = 202;
private static final int RECEIVE_SMS_PERMISSION_REQ_CODE = 203; private static final int RECEIVE_SMS_PERMISSION_REQ_CODE = 203;
public static final int DOCUMENT_PICKER_RESULT_CODE = 301; public static final int DOCUMENT_PICKER_RESULT_CODE = 301;
public static final String SHARED_PREFERENCES_NAME = "LBRY";
public static final String SALT_KEY = "salt";
public static final String DEVICE_ID_KEY = "deviceId";
public static final String SOURCE_NOTIFICATION_ID_KEY = "sourceNotificationId";
public static final String SETTING_KEEP_DAEMON_RUNNING = "keepDaemonRunning";
public static List<Integer> downloadNotificationIds = new ArrayList<Integer>();
private BroadcastReceiver notificationsReceiver; private BroadcastReceiver notificationsReceiver;
private BroadcastReceiver smsReceiver; private BroadcastReceiver smsReceiver;
private BroadcastReceiver stopServiceReceiver; private BroadcastReceiver stopServiceReceiver;
private BroadcastReceiver downloadEventReceiver; private BroadcastReceiver downloadEventReceiver;
private FirebaseAnalytics firebaseAnalytics; private FirebaseAnalytics firebaseAnalytics;
private ReactRootView mReactRootView; private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager; private ReactInstanceManager mReactInstanceManager;
public static final String SHARED_PREFERENCES_NAME = "LBRY";
public static final String SALT_KEY = "salt";
public static final String DEVICE_ID_KEY = "deviceId";
public static final String SOURCE_NOTIFICATION_ID_KEY = "sourceNotificationId";
public static final String SETTING_KEEP_DAEMON_RUNNING = "keepDaemonRunning";
public static List<Integer> downloadNotificationIds = new ArrayList<Integer>();
/** /**
* Flag which indicates whether or not the service is running. Will be updated in the * Flag which indicates whether or not the service is running. Will be updated in the
* onResume method. * onResume method.
*/ */
private boolean serviceRunning; private boolean serviceRunning;
private CheckSdkReadyTask checkSdkReadyTask;
private boolean lbrySdkReady;
private boolean receivedStopService; private boolean receivedStopService;
private PermissionListener permissionListener; private PermissionListener permissionListener;
protected String getMainComponentName() { protected String getMainComponentName() {
@ -158,12 +145,12 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
// Check the dht setting // Check the dht setting
SharedPreferences sp = getSharedPreferences(MainActivity.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); SharedPreferences sp = getSharedPreferences(MainActivity.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
LbrynetService.setDHTEnabled(sp.getBoolean(UtilityModule.DHT_ENABLED, false)); LbrynetService.setDHTEnabled(sp.getBoolean(UtilityModule.DHT_ENABLED, false));
serviceRunning = isServiceRunning(this, LbrynetService.class); serviceRunning = isServiceRunning(this, LbrynetService.class);
if (!serviceRunning) { if (!serviceRunning) {
CurrentLaunchTiming.setColdStart(true); CurrentLaunchTiming.setColdStart(true);
ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice"); ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice");
} }
checkSdkReady();
if (LbrynetService.serviceInstance != null) { if (LbrynetService.serviceInstance != null) {
// TODO: Add a broadcast receiver to listen for the service started event, so that we can set this properly // TODO: Add a broadcast receiver to listen for the service started event, so that we can set this properly
@ -203,6 +190,22 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
setContentView(mReactRootView); setContentView(mReactRootView);
} }
private void checkSdkReady() {
if (!lbrySdkReady) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (checkSdkReadyTask != null && checkSdkReadyTask.getStatus() != AsyncTask.Status.FINISHED) {
// task already running
return;
}
checkSdkReadyTask = new CheckSdkReadyTask();
checkSdkReadyTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}, 1000);
}
}
private void checkNotificationOpenIntent(Intent intent) { private void checkNotificationOpenIntent(Intent intent) {
if (intent != null) { if (intent != null) {
String notificationName = intent.getStringExtra("notification_name"); String notificationName = intent.getStringExtra("notification_name");
@ -477,10 +480,13 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
super.onResume(); super.onResume();
SharedPreferences sp = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); SharedPreferences sp = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
LbrynetService.setDHTEnabled(sp.getBoolean(UtilityModule.DHT_ENABLED, false));
serviceRunning = isServiceRunning(this, LbrynetService.class); serviceRunning = isServiceRunning(this, LbrynetService.class);
if (!serviceRunning) { if (!serviceRunning) {
ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice"); ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice");
} }
checkSdkReady();
if (mReactInstanceManager != null) { if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this); mReactInstanceManager.onHostResume(this, this);
@ -684,7 +690,6 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
*/ */
@SuppressLint("NewApi") @SuppressLint("NewApi")
public static String getRealPathFromURI_API19(final Context context, final Uri uri) { public static String getRealPathFromURI_API19(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider // DocumentProvider
@ -835,6 +840,51 @@ public class MainActivity extends FragmentActivity implements DefaultHardwareBac
public static boolean isGooglePhotosUri(Uri uri) { public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority()); return "com.google.android.apps.photos.content".equals(uri.getAuthority());
} }
private class CheckSdkReadyTask extends AsyncTask<Void, Void, Boolean> {
public Boolean doInBackground(Void... params) {
boolean sdkReady = false;
try {
String response = Utils.sdkCall("status");
if (response != null) {
JSONObject result = new JSONObject(response);
JSONObject status = result.getJSONObject("result");
// send status response for splash page updates
WritableMap sdkStatus = JSONObjectToMap(status);
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext != null) {
WritableMap evtParams = Arguments.createMap();
evtParams.putMap("status", sdkStatus);
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onSdkStatusResponse", evtParams);
}
JSONObject startupStatus = status.getJSONObject("startup_status");
sdkReady = startupStatus.has("stream_manager") && startupStatus.has("wallet") &&
startupStatus.getBoolean("stream_manager") && startupStatus.getBoolean("wallet") &&
(status.getJSONObject("wallet").getLong("blocks_behind") <= 0);
}
} catch (ConnectException ex) {
// pass
} catch (JSONException ex) {
// pass
}
return sdkReady;
}
protected void onPostExecute(Boolean sdkReady) {
lbrySdkReady = sdkReady;
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (sdkReady && reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onSdkReady", null);
}
if (!sdkReady) {
checkSdkReady();
}
}
}
public static class LaunchTiming { public static class LaunchTiming {
private Date start; private Date start;

View file

@ -34,6 +34,7 @@ import java.io.Closeable;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
@ -93,6 +94,7 @@ public class UtilityModule extends ReactContextBaseJavaModule {
public Map<String, Object> getConstants() { public Map<String, Object> getConstants() {
final Map<String, Object> constants = MapBuilder.newHashMap(); final Map<String, Object> constants = MapBuilder.newHashMap();
constants.put("language", language); constants.put("language", language);
constants.put("dhtEnabled", LbrynetService.isDHTEnabled());
return constants; return constants;
} }
@ -422,13 +424,34 @@ public class UtilityModule extends ReactContextBaseJavaModule {
} }
@ReactMethod @ReactMethod
public void setNativeBooleanSetting(String key, boolean value) { public void setNativeBooleanSetting(String key, final boolean value) {
if (context != null) { if (context != null) {
SharedPreferences sp = context.getSharedPreferences(MainActivity.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); SharedPreferences sp = context.getSharedPreferences(MainActivity.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit(); SharedPreferences.Editor editor = sp.edit();
editor.putBoolean(key, value); editor.putBoolean(key, value);
editor.commit(); editor.commit();
} }
if (DHT_ENABLED.equalsIgnoreCase(key)) {
(new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... params) {
String fileContent = value ? "on" : "off";
String path = String.format("%s/%s", Utils.getAppInternalStorageDir(context), "dht");
PrintStream out = null;
try {
out = new PrintStream(new FileOutputStream(path));
out.print(fileContent);
} catch (Exception ex) {
// pass
} finally {
if (out != null) {
out.close();
}
}
return null;
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
} }
@ReactMethod @ReactMethod