diff --git a/app/build.gradle b/app/build.gradle index f8ad4a6a..319a4e62 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -117,6 +117,7 @@ dependencies { implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.3.1.LTS' + implementation 'org.bitcoinj:bitcoinj-tools:0.14.7' implementation 'org.java-websocket:Java-WebSocket:1.5.1' compileOnly 'org.projectlombok:lombok:1.18.10' diff --git a/app/src/main/java/io/lbry/browser/FirstRunActivity.java b/app/src/main/java/io/lbry/browser/FirstRunActivity.java index ad10a6ef..b6d6eecb 100644 --- a/app/src/main/java/io/lbry/browser/FirstRunActivity.java +++ b/app/src/main/java/io/lbry/browser/FirstRunActivity.java @@ -15,12 +15,22 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.core.text.HtmlCompat; import androidx.preference.PreferenceManager; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; + import io.lbry.browser.exceptions.AuthTokenInvalidatedException; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.LbryAnalytics; import io.lbry.browser.utils.Lbryio; import io.lbry.lbrysdk.LbrynetService; +import io.lbry.lbrysdk.ServiceHelper; +import io.lbry.lbrysdk.Utils; public class FirstRunActivity extends AppCompatActivity { @@ -44,12 +54,7 @@ public class FirstRunActivity extends AppCompatActivity { }); registerAuthReceiver(); - if (!Lbry.SDK_READY) { - findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE); - } else { - authenticate(); - } - + findViewById(R.id.welcome_wait_container).setVisibility(View.VISIBLE); IntentFilter filter = new IntentFilter(); filter.addAction(MainActivity.ACTION_SDK_READY); filter.addAction(LbrynetService.ACTION_STOP_SERVICE); @@ -62,10 +67,38 @@ public class FirstRunActivity extends AppCompatActivity { authenticate(); } else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) { finish(); + if (MainActivity.instance != null) { + MainActivity.instance.finish(); + } } } }; registerReceiver(sdkReceiver, filter); + + CheckInstallIdTask task = new CheckInstallIdTask(this, new CheckInstallIdTask.InstallIdHandler() { + @Override + public void onInstallIdChecked(boolean result) { + // start the sdk from FirstRun + boolean serviceRunning = MainActivity.isServiceRunning(MainActivity.instance, LbrynetService.class); + if (!serviceRunning) { + Lbry.SDK_READY = false; + ServiceHelper.start(MainActivity.instance, "", LbrynetService.class, "lbrynetservice"); + } + + if (result) { + // install_id generated and validated, authenticate now + authenticate(); + return; + } + + // we weren't able to generate the install_id ourselves, depend on the sdk for that + if (Lbry.SDK_READY) { + authenticate(); + return; + } + } + }); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } public void onResume() { @@ -134,6 +167,75 @@ public class FirstRunActivity extends AppCompatActivity { super.onDestroy(); } + private void generateIdAndAuthenticate() { + + } + + private static class CheckInstallIdTask extends AsyncTask { + private Context context; + private InstallIdHandler handler; + public CheckInstallIdTask(Context context, InstallIdHandler handler) { + this.context = context; + this.handler = handler; + } + protected Boolean doInBackground(Void... params) { + // Load the installation id from the file system + String lbrynetDir = String.format("%s/%s", Utils.getAppInternalStorageDir(context), "lbrynet"); + File dir = new File(lbrynetDir); + boolean dirExists = dir.isDirectory(); + if (!dirExists) { + dirExists = dir.mkdirs(); + } + + if (!dirExists) { + return false; + } + + String installIdPath = String.format("%s/install_id", lbrynetDir); + File file = new File(installIdPath); + String installId = null; + if (!file.exists()) { + // generate the install_id + installId = Lbry.generateId(); + BufferedWriter writer = null; + try { + writer = new BufferedWriter(new FileWriter(file)); + writer.write(installId); + android.util.Log.d("LbryMain", "Generated install ID=" + installId); + } catch (IOException ex) { + return false; + } finally { + Helper.closeCloseable(writer); + } + } else { + // read the installation id from the file + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(installIdPath))); + installId = reader.readLine(); + } catch (IOException ex) { + return false; + } finally { + Helper.closeCloseable(reader); + } + } + + if (!Helper.isNullOrEmpty(installId)) { + Lbry.INSTALLATION_ID = installId; + } + return !Helper.isNullOrEmpty(installId); + } + protected void onPostExecute(Boolean result) { + if (handler != null) { + handler.onInstallIdChecked(result); + } + } + + public interface InstallIdHandler { + void onInstallIdChecked(boolean result); + } + } + private static class AuthenticateTask extends AsyncTask { private Context context; public AuthenticateTask(Context context) { diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 110f01a1..bd7a7a26 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -211,6 +211,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener private static final String SPECIAL_URL_PREFIX = "lbry://?"; private static final int REMOTE_NOTIFICATION_REFRESH_TTL = 300000; // 5 minutes public static final String SKU_SKIP = "lbryskip"; + public static MainActivity instance; private boolean shuttingDown; private Date remoteNotifcationsLastLoaded; @@ -393,6 +394,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener @Override protected void onCreate(Bundle savedInstanceState) { + instance = this; // workaround to fix dark theme because https://issuetracker.google.com/issues/37124582 try { new WebView(this); @@ -1140,12 +1142,14 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener checkFirstRun(); checkNowPlaying(); - // check (and start) the LBRY SDK service - serviceRunning = isServiceRunning(this, LbrynetService.class); - if (!serviceRunning) { - Lbry.SDK_READY = false; - //findViewById(R.id.global_sdk_initializing_status).setVisibility(View.VISIBLE); - ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice"); + if (isFirstRunCompleted()) { + // check (and start) the LBRY SDK service + serviceRunning = isServiceRunning(this, LbrynetService.class); + if (!serviceRunning) { + Lbry.SDK_READY = false; + //findViewById(R.id.global_sdk_initializing_status).setVisibility(View.VISIBLE); + ServiceHelper.start(this, "", LbrynetService.class, "lbrynetservice"); + } } checkSdkReady(); showSignedInUser(); @@ -1156,6 +1160,11 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener }*/ } + public boolean isFirstRunCompleted() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + return sp.getBoolean(PREFERENCE_KEY_INTERNAL_FIRST_RUN_COMPLETED, false); + } + private void checkPurchases() { if (billingClient != null) { Purchase.PurchasesResult result = billingClient.queryPurchases(BillingClient.SkuType.INAPP); diff --git a/app/src/main/java/io/lbry/browser/utils/Helper.java b/app/src/main/java/io/lbry/browser/utils/Helper.java index 8fd0b416..e5ac6410 100644 --- a/app/src/main/java/io/lbry/browser/utils/Helper.java +++ b/app/src/main/java/io/lbry/browser/utils/Helper.java @@ -20,7 +20,6 @@ import android.provider.MediaStore; import android.text.method.LinkMovementMethod; import android.view.ContextMenu; import android.view.View; -import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; @@ -32,6 +31,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.gms.common.util.Hex; +import org.bitcoinj.core.Base58; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; diff --git a/app/src/main/java/io/lbry/browser/utils/Lbry.java b/app/src/main/java/io/lbry/browser/utils/Lbry.java index 1d0a7f5c..fb499ffa 100644 --- a/app/src/main/java/io/lbry/browser/utils/Lbry.java +++ b/app/src/main/java/io/lbry/browser/utils/Lbry.java @@ -2,12 +2,15 @@ package io.lbry.browser.utils; import android.util.Log; +import org.bitcoinj.core.Base58; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.security.KeyStore; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -17,6 +20,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.concurrent.TimeUnit; import io.lbry.browser.exceptions.ApiCallException; @@ -522,4 +526,20 @@ public final class Lbry { } } } + + public static String generateId() { + return generateId(64); + } + public static String generateId(int numBytes) { + byte[] arr = new byte[numBytes]; + new Random().nextBytes(arr); + try { + MessageDigest md = MessageDigest.getInstance("SHA-384"); + byte[] hash = md.digest(arr); + return Base58.encode(hash); + } catch (NoSuchAlgorithmException e) { + // pass + return null; + } + } }