diff --git a/.gitignore b/.gitignore index aee079462..93de9b0a1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ app/src/main/jni/transition/testingStuff.c # Built application files *.apk *.ap_ +*/release/*.aab # Files for the Dalvik VM *.dex diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 84a15348f..a622e5d7e 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -60,6 +60,9 @@ add_library( # Specifies the name of the library. src/main/jni/loafwallet-core/BRTransaction.h src/main/jni/loafwallet-core/BRWallet.c src/main/jni/loafwallet-core/BRWallet.h + src/main/jni/loafwallet-core/BRChainParams.h + src/main/jni/loafwallet-core/BRBech32.c + src/main/jni/loafwallet-core/BRBech32.h src/main/jni/transition/core.c src/main/jni/transition/core.h diff --git a/app/build.gradle b/app/build.gradle index 33e43598a..5a629520e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,8 +64,8 @@ android { applicationId = 'com.loafwallet' minSdkVersion 27 targetSdkVersion 32 - versionCode 725 - versionName "v2.8.1" + versionCode 733 + versionName "v2.8.4" multiDexEnabled true archivesBaseName = "${versionName}(${versionCode})" diff --git a/app/loaf/release/v2.4.0(641)-loaf-release.aab b/app/loaf/release/v2.4.0(641)-loaf-release.aab deleted file mode 100644 index 1b59bd083..000000000 Binary files a/app/loaf/release/v2.4.0(641)-loaf-release.aab and /dev/null differ diff --git a/app/loaf/release/v2.4.2(1)-loaf-release.aab b/app/loaf/release/v2.4.2(1)-loaf-release.aab deleted file mode 100644 index a038c9963..000000000 Binary files a/app/loaf/release/v2.4.2(1)-loaf-release.aab and /dev/null differ diff --git a/app/src/main/java/com/breadwallet/BreadApp.java b/app/src/main/java/com/breadwallet/BreadApp.java index 10017e1c3..6039b3d09 100644 --- a/app/src/main/java/com/breadwallet/BreadApp.java +++ b/app/src/main/java/com/breadwallet/BreadApp.java @@ -51,7 +51,7 @@ public void onCreate() { } // setup Timber - Timber.plant(BuildConfig.DEBUG ? new Timber.DebugTree() : new CrashReportingTree()); + Timber.plant(new Timber.DebugTree()); FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enableCrashlytics); AnalyticsManager.init(this); @@ -98,7 +98,7 @@ public static void onStop(final BRActivity app) { public void run() { if (isAppInBackground(app)) { backgroundedTime = System.currentTimeMillis(); - Timber.d("App went in background!"); + Timber.d("timber: App went in background!"); // APP in background, do something isBackgroundChecker.cancel(); fireListeners(); diff --git a/app/src/main/java/com/breadwallet/presenter/activities/BreadActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/BreadActivity.java index 7f8e52d76..b8a6d33ca 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/BreadActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/BreadActivity.java @@ -97,8 +97,8 @@ protected void onCreate(Bundle savedInstanceState) { initializeViews(); setPriceTags(BRSharedPrefs.getPreferredLTC(BreadActivity.this), false); setListeners(); - setUpBarFlipper(); + checkTransactionDatabase(); primaryPrice.setTextSize(PRIMARY_TEXT_SIZE); secondaryPrice.setTextSize(SECONDARY_TEXT_SIZE); @@ -138,7 +138,7 @@ private void showInAppReviewDialogIfNeeded() { // The flow has finished. The API does not indicate whether the user // reviewed or not, or even whether the review dialog was shown. Thus, no // matter the result, we continue our app flow. - Timber.i("In-app LaunchReviewFlow completed successful (%s)", task1.isSuccessful()); + Timber.i("timber: In-app LaunchReviewFlow completed successful (%s)", task1.isSuccessful()); if (task1.isSuccessful()) { BRSharedPrefs.inAppReviewDone(BreadActivity.this); } @@ -281,6 +281,10 @@ private void setPriceTags(boolean ltcPreferred, boolean animate) { mHandler.postDelayed(() -> updateUI(), toolBarConstraintLayout.getLayoutTransition().getDuration(LayoutTransition.CHANGING)); } + private void checkTransactionDatabase() { + + } + private void setUpBarFlipper() { barFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.flipper_enter)); barFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.flipper_exit)); @@ -435,7 +439,7 @@ public void onConnectionChanged(boolean isConnected) { } BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(() -> { final double progress = BRPeerManager.syncProgress(BRSharedPrefs.getStartHeight(BreadActivity.this)); - Timber.d("Sync Progress: %s", progress); + Timber.d("timber: Sync Progress: %s", progress); if (progress < 1 && progress > 0) { SyncManager.getInstance().startSyncingProgressThread(); } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/LoginActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/LoginActivity.java index 51c714138..ca174729c 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/LoginActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/LoginActivity.java @@ -20,6 +20,7 @@ import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import com.breadwallet.BuildConfig; import com.breadwallet.R; import com.breadwallet.presenter.activities.camera.ScanQRActivity; import com.breadwallet.presenter.activities.util.BRActivity; @@ -38,6 +39,7 @@ import com.breadwallet.tools.util.BRConstants; import com.breadwallet.tools.util.BRCurrency; import com.breadwallet.wallet.BRWalletManager; +import com.google.android.material.snackbar.Snackbar; import com.platform.APIClient; import java.math.BigDecimal; @@ -81,7 +83,8 @@ public static LoginActivity getApp() { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_pin); + setContentView(R.layout.activity_pin); + View parentLayout = findViewById(android.R.id.content); String pin = BRKeyStore.getPinCode(this); if (pin.isEmpty() || (pin.length() != 6 && pin.length() != 4)) { Intent intent = new Intent(this, SetPinActivity.class); @@ -169,6 +172,19 @@ public void onCancel() { }, 500); setCurrentLtcPrice(); + + if (BuildConfig.VERSION_NAME == "v2.8.4") { + Snackbar.make(parentLayout, + R.string.release_notes, + Snackbar.LENGTH_INDEFINITE).setAction(R.string.Webview_dismiss, new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }) + .setActionTextColor(getResources().getColor(android.R.color.holo_red_light )) + .show(); + } } private void setCurrentLtcPrice() { @@ -211,11 +227,11 @@ protected void onPause() { private void handleClick(String key) { if (!inputAllowed) { - Timber.d("handleClick: input not allowed"); + Timber.d("timber: handleClick: input not allowed"); return; } if (key == null) { - Timber.d("handleClick: key is null! "); + Timber.d("timber: handleClick: key is null! "); return; } @@ -224,7 +240,7 @@ private void handleClick(String key) { } else if (Character.isDigit(key.charAt(0))) { handleDigitClick(Integer.parseInt(key.substring(0, 1))); } else { - Timber.d("handleClick: oops: %s", key); + Timber.d("timber: handleClick: oops: %s", key); } } @@ -313,7 +329,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis // permission was granted, yay! Do the // contacts-related task you need to do. } else { - Timber.i("onRequestPermissionsResult: permission isn't granted for: %s", requestCode); + Timber.i("timber: onRequestPermissionsResult: permission isn't granted for: %s", requestCode); // permission denied, boo! Disable the // functionality that depends on this permission. } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/ReEnterPinActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/ReEnterPinActivity.java index 77c7f3bf0..b1957deae 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/ReEnterPinActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/ReEnterPinActivity.java @@ -95,7 +95,7 @@ protected void onPause() { private void handleClick(String key) { if (!isPressAllowed) return; if (key == null) { - Timber.d("handleClick: key is null! "); + Timber.d("timber: handleClick: key is null! "); return; } @@ -104,7 +104,7 @@ private void handleClick(String key) { } else if (Character.isDigit(key.charAt(0))) { handleDigitClick(Integer.parseInt(key.substring(0, 1))); } else { - Timber.d("handleClick: oops: %s", key); + Timber.d("timber: handleClick: oops: %s", key); } } @@ -171,7 +171,7 @@ public void onComplete() { } } else { AuthManager.getInstance().authFail(this); - Timber.d("verifyPin: FAIL: firs: %s, reEnter: %s ", firstPIN, pin); + Timber.d("timber: verifyPin: FAIL: firs: %s, reEnter: %s ", firstPIN, pin); SpringAnimator.failShakeAnimation(this, pinLayout); pin = new StringBuilder(); } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/SetPinActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/SetPinActivity.java index 28becfaaa..e3c3f9097 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/SetPinActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/SetPinActivity.java @@ -44,10 +44,10 @@ protected void onCreate(Bundle savedInstanceState) { keyboard = (BRKeyboard) findViewById(R.id.brkeyboard); title = (TextView) findViewById(R.id.title); + //TODO: all views are using the layout of this button. Views should be refactored without it // Hiding until layouts are built. faq = (ImageButton) findViewById(R.id.faq_button); - dot1 = findViewById(R.id.dot1); dot2 = findViewById(R.id.dot2); dot3 = findViewById(R.id.dot3); @@ -82,7 +82,7 @@ protected void onPause() { private void handleClick(String key) { if (key == null) { - Timber.d("handleClick: key is null! "); + Timber.d("timber: handleClick: key is null! "); return; } @@ -91,7 +91,7 @@ private void handleClick(String key) { } else if (Character.isDigit(key.charAt(0))) { handleDigitClick(Integer.parseInt(key.substring(0, 1))); } else { - Timber.d("handleClick: oops: %s", key); + Timber.d("timber: handleClick: oops: %s", key); } } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/UpdatePinActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/UpdatePinActivity.java index 62c6f3b5e..5d57868ee 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/UpdatePinActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/UpdatePinActivity.java @@ -95,7 +95,7 @@ protected void onPause() { private void handleClick(String key) { if (key == null) { - Timber.d("handleClick: key is null! "); + Timber.d("timber: handleClick: key is null! "); return; } @@ -104,7 +104,7 @@ private void handleClick(String key) { } else if (Character.isDigit(key.charAt(0))) { handleDigitClick(Integer.parseInt(key.substring(0, 1))); } else { - Timber.d("handleClick: oops: %s", key); + Timber.d("timber: handleClick: oops: %s", key); } } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/camera/CameraActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/camera/CameraActivity.java index 16deec487..d7fed45ac 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/camera/CameraActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/camera/CameraActivity.java @@ -391,7 +391,7 @@ private static Size chooseOptimalSize(Size[] choices, int textureViewWidth, } else if (notBigEnough.size() > 0) { return Collections.max(notBigEnough, new CompareSizesByArea()); } else { - Timber.d("Couldn't find any suitable preview size"); + Timber.d("timber: Couldn't find any suitable preview size"); return choices[0]; } } @@ -473,7 +473,7 @@ private void setUpCameraOutputs(int width, int height) { } break; default: - Timber.d("Display rotation is invalid: %s", displayRotation); + Timber.d("timber: Display rotation is invalid: %s", displayRotation); } Point displaySize = new Point(); diff --git a/app/src/main/java/com/breadwallet/presenter/activities/camera/ScanQRActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/camera/ScanQRActivity.java index a99097726..fd25dc49c 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/camera/ScanQRActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/camera/ScanQRActivity.java @@ -51,7 +51,7 @@ protected void onCreate(final Bundle savedInstanceState) { == PackageManager.PERMISSION_GRANTED) { initQRCodeReaderView(); } else { - Timber.d("onCreate: Permissions needed? HUH?"); + Timber.d("timber: onCreate: Permissions needed? HUH?"); } new Handler().postDelayed(new Runnable() { diff --git a/app/src/main/java/com/breadwallet/presenter/activities/intro/IntroActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/intro/IntroActivity.java index 948e824fd..c00950170 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/intro/IntroActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/intro/IntroActivity.java @@ -2,13 +2,13 @@ package com.breadwallet.presenter.activities.intro; import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.graphics.Point; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; +import android.widget.Toast; +import com.google.android.material.snackbar.Snackbar; import com.breadwallet.BuildConfig; import com.breadwallet.R; @@ -26,7 +26,6 @@ import com.platform.APIClient; import java.io.Serializable; -import java.util.Locale; import timber.log.Timber; @@ -38,7 +37,6 @@ public class IntroActivity extends BRActivity implements Serializable { private static IntroActivity app; private TextView versionText; - public static IntroActivity getApp() { return app; } @@ -57,10 +55,10 @@ protected void onCreate(Bundle savedInstanceState) { newWalletButton = (Button) findViewById(R.id.button_new_wallet); recoverWalletButton = (Button) findViewById(R.id.button_recover_wallet); versionText = findViewById(R.id.version_text); + View parentLayout = findViewById(android.R.id.content); + setListeners(); updateBundles(); -// SyncManager.getInstance().updateAlarms(this); - if (!BuildConfig.DEBUG && BRKeyStore.AUTH_DURATION_SEC != 300) { RuntimeException ex = new RuntimeException("onCreate: AUTH_DURATION_SEC should be 300"); Timber.e(ex); @@ -77,12 +75,28 @@ protected void onCreate(Bundle savedInstanceState) { byte[] masterPubKey = BRKeyStore.getMasterPublicKey(this); boolean isFirstAddressCorrect = false; if (masterPubKey != null && masterPubKey.length != 0) { + Timber.d("timber: masterPubkey exists"); + isFirstAddressCorrect = SmartValidator.checkFirstAddress(this, masterPubKey); } if (!isFirstAddressCorrect) { + Timber.d("timber: Calling wipeWalletButKeyStore"); BRWalletManager.getInstance().wipeWalletButKeystore(this); } + if (BuildConfig.VERSION_NAME == "v2.8.4") { + Snackbar.make(parentLayout, + R.string.release_notes, + Snackbar.LENGTH_INDEFINITE).setAction(R.string.Webview_dismiss, new View.OnClickListener() { + @Override + public void onClick(View view) { + + } + }) + .setActionTextColor(getResources().getColor(android.R.color.holo_red_light )) + .show(); + } + PostAuth.getInstance().onCanaryCheck(this, false); } @@ -94,7 +108,7 @@ public void run() { final long startTime = System.currentTimeMillis(); APIClient apiClient = APIClient.getInstance(IntroActivity.this); long endTime = System.currentTimeMillis(); - Timber.d("updateBundle DONE in %sms",endTime - startTime); + Timber.d("timber: updateBundle DONE in %sms",endTime - startTime); } }); } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/settings/AboutActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/settings/AboutActivity.java index caacc05e1..7bdd01df8 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/settings/AboutActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/settings/AboutActivity.java @@ -21,9 +21,8 @@ public class AboutActivity extends BRActivity { private static final String TAG = AboutActivity.class.getName(); -// private TextView termsText; private TextView policyText; - private TextView infoText; + private TextView versionText; private ImageView instagramShare; private ImageView twitterShare; @@ -45,13 +44,12 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); - infoText = (TextView) findViewById(R.id.info_text); + versionText = (TextView) findViewById(R.id.info_text); policyText = (TextView) findViewById(R.id.policy_text); instagramShare = (ImageView) findViewById(R.id.instagram_share_button); twitterShare = (ImageView) findViewById(R.id.twitter_share_button); blogShare = (ImageView) findViewById(R.id.blog_share_button); - - infoText.setText(BRConstants.APP_VERSION_NAME_CODE); + versionText.setText(BRConstants.APP_VERSION_NAME_CODE); instagramShare.setOnClickListener(new View.OnClickListener() { @Override @@ -86,14 +84,6 @@ public void onClick(View v) { app.overridePendingTransition(R.anim.enter_from_bottom, R.anim.empty_300); } }); -// termsText.setOnClickListener(new View.OnClickListener() { -// @Override -// public void onClick(View v) { -// Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://breadapp.com/privacy-policy")); -// startActivity(browserIntent); -// app.overridePendingTransition(R.anim.enter_from_bottom, R.anim.empty_300); -// } -// }); } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/settings/FingerprintActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/settings/FingerprintActivity.java index cac784455..962a6b5d3 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/settings/FingerprintActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/settings/FingerprintActivity.java @@ -72,7 +72,7 @@ protected void onCreate(Bundle savedInstanceState) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Activity app = FingerprintActivity.this; if (isChecked && !Utils.isFingerprintEnrolled(app)) { - Timber.d("onCheckedChanged: fingerprint not setup"); + Timber.d("timber: onCheckedChanged: fingerprint not setup"); BRDialog.showCustomDialog(app, getString(R.string.TouchIdSettings_disabledWarning_title_android), getString(R.string.TouchIdSettings_disabledWarning_body_android), getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @Override public void onClick(BRDialogView brDialogView) { diff --git a/app/src/main/java/com/breadwallet/presenter/activities/settings/SettingsActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/settings/SettingsActivity.java index 715783336..3ad153757 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/settings/SettingsActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/settings/SettingsActivity.java @@ -23,6 +23,7 @@ import com.breadwallet.tools.manager.BRSharedPrefs; import com.breadwallet.tools.security.AuthManager; import com.platform.APIClient; +import com.breadwallet.tools.animation.BRAnimator; import java.util.ArrayList; import java.util.List; @@ -126,6 +127,11 @@ private void populateItems() { }, false)); + /*Show Seed Phrase*/ + items.add(new BRSettingsItem(getString(R.string.settings_show_seed), "", v -> { + BRAnimator.showBalanceSeedFragment(this); + }, false)); + /*Wipe Start_Recover Wallet*/ items.add(new BRSettingsItem(getString(R.string.Settings_wipe), "", v -> { Intent intent = new Intent(SettingsActivity.this, WipeActivity.class); diff --git a/app/src/main/java/com/breadwallet/presenter/activities/settings/SpendLimitActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/settings/SpendLimitActivity.java index d86b126ba..ace423d24 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/settings/SpendLimitActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/settings/SpendLimitActivity.java @@ -72,7 +72,7 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - Timber.d("onItemClick: %s", position); + Timber.d("timber: onItemClick: %s", position); int limit = adapter.getItem(position); BRKeyStore.putSpendLimit(limit, app); diff --git a/app/src/main/java/com/breadwallet/presenter/activities/settings/SyncBlockchainActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/settings/SyncBlockchainActivity.java index fb6a10fa7..3449d1ece 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/settings/SyncBlockchainActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/settings/SyncBlockchainActivity.java @@ -1,11 +1,15 @@ package com.breadwallet.presenter.activities.settings; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; +import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageButton; +import android.widget.RadioGroup; +import android.widget.TextView; import com.breadwallet.R; import com.breadwallet.presenter.activities.util.ActivityUTILS; @@ -20,30 +24,89 @@ import com.breadwallet.wallet.BRPeerManager; + + public class SyncBlockchainActivity extends BRActivity { + private static final String TAG = SyncBlockchainActivity.class.getName(); private Button scanButton; + private Button lowPrivacyButton; + private Button semiPrivateButton; + private Button anonymousButton; + + private RadioGroup syncRadioGroup; + public static boolean appVisible = false; - private static SyncBlockchainActivity app; + private static TextView syncPreferenceTextView; + private ImageButton fingerPrint; + private static SyncBlockchainActivity app; public static SyncBlockchainActivity getApp() { return app; } - @Override protected void onSaveInstanceState(Bundle outState) { } + private void updateSyncPreference() { + float fprate = BRSharedPrefs.getFalsePositivesRate(SyncBlockchainActivity.this); + String rateAsString = String.format("%1.5f",fprate); + syncPreferenceTextView.setText(getString(R.string.sync_preferences, rateAsString)); + + if (fprate == BRConstants.FALSE_POS_RATE_LOW_PRIVACY) { + syncRadioGroup.check(R.id.radio_low_privacy); + } + else if (fprate == BRConstants.FALSE_POS_RATE_SEMI_PRIVACY) { + syncRadioGroup.check(R.id.radio_semi_private); + }else { + ///Assumed the Anon option is preferred + syncRadioGroup.check(R.id.radio_anonymous); + } + } + @SuppressLint("StringFormatInvalid") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sync_blockchain); - ImageButton faq = (ImageButton) findViewById(R.id.faq_button); - //TODO: all views are using the layout of this button. Views should be refactored without it - // Hiding until layouts are built. + syncRadioGroup = (RadioGroup) findViewById(R.id.sync_radio_group); + ImageButton faq = (ImageButton) findViewById(R.id.faq_button); + syncPreferenceTextView = (TextView) findViewById(R.id.sync_preferences); scanButton = (Button) findViewById(R.id.button_scan); + lowPrivacyButton = (Button) findViewById(R.id.radio_low_privacy); + semiPrivateButton = (Button) findViewById(R.id.radio_semi_private); + anonymousButton = (Button) findViewById(R.id.radio_anonymous); + + lowPrivacyButton.setText(getString(R.string.radio_low_privacy)); + semiPrivateButton.setText(getString(R.string.radio_semi_private)); + anonymousButton.setText(getString(R.string.radio_anonymous)); + + updateSyncPreference(); + + lowPrivacyButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + BRSharedPrefs.putFalsePositivesRate(SyncBlockchainActivity.this, BRConstants.FALSE_POS_RATE_LOW_PRIVACY); + updateSyncPreference(); + } + }); + + semiPrivateButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + BRSharedPrefs.putFalsePositivesRate(SyncBlockchainActivity.this, BRConstants.FALSE_POS_RATE_SEMI_PRIVACY); + updateSyncPreference(); + } + }); + anonymousButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + BRSharedPrefs.putFalsePositivesRate(SyncBlockchainActivity.this, BRConstants.FALSE_POS_RATE_ANONYMOUS); + updateSyncPreference(); + } + }); + scanButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -76,6 +139,8 @@ public void onClick(BRDialogView brDialogView) { } + + @Override protected void onResume() { super.onResume(); diff --git a/app/src/main/java/com/breadwallet/presenter/activities/util/ActivityUTILS.java b/app/src/main/java/com/breadwallet/presenter/activities/util/ActivityUTILS.java index 84328585e..f9eab9b3d 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/util/ActivityUTILS.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/util/ActivityUTILS.java @@ -29,7 +29,7 @@ public static void showWalletDisabled(Activity app) { Intent intent = new Intent(app, DisabledActivity.class); app.startActivity(intent); app.overridePendingTransition(R.anim.fade_up, R.anim.fade_down); - Timber.d("showWalletDisabled: %s", app.getClass().getName()); + Timber.d("timber: showWalletDisabled: %s", app.getClass().getName()); } public static boolean isLast(Activity app) { @@ -47,7 +47,7 @@ public static boolean isLast(Activity app) { public static boolean isMainThread() { boolean isMain = Looper.myLooper() == Looper.getMainLooper(); if (isMain) { - Timber.d("IS MAIN UI THREAD!"); + Timber.d("timber: IS MAIN UI THREAD!"); } return isMain; } diff --git a/app/src/main/java/com/breadwallet/presenter/activities/util/BRActivity.java b/app/src/main/java/com/breadwallet/presenter/activities/util/BRActivity.java index 46ee1d612..fe983077a 100644 --- a/app/src/main/java/com/breadwallet/presenter/activities/util/BRActivity.java +++ b/app/src/main/java/com/breadwallet/presenter/activities/util/BRActivity.java @@ -113,7 +113,7 @@ public void run() { if (BitcoinUrlHandler.isBitcoinUrl(result)) BitcoinUrlHandler.processRequest(BRActivity.this, result); else - Timber.i("onActivityResult: not litecoin address NOR bitID"); + Timber.i("timber: onActivityResult: not litecoin address NOR bitID"); } }, 500); @@ -124,7 +124,7 @@ public void run() { if (resultCode == RESULT_OK) { PostAuth.getInstance().onCreateWalletAuth(this, true); } else { - Timber.d("WARNING: resultCode != RESULT_OK"); + Timber.d("timber: WARNING: resultCode != RESULT_OK"); BRWalletManager m = BRWalletManager.getInstance(); m.wipeWalletButKeystore(this); finish(); diff --git a/app/src/main/java/com/breadwallet/presenter/customviews/BRButton.java b/app/src/main/java/com/breadwallet/presenter/customviews/BRButton.java index 203f05ef9..876521843 100644 --- a/app/src/main/java/com/breadwallet/presenter/customviews/BRButton.java +++ b/app/src/main/java/com/breadwallet/presenter/customviews/BRButton.java @@ -133,7 +133,7 @@ private void correctTextSizeIfNeeded() { setTextSize(TypedValue.COMPLEX_UNIT_PX, px); lines = getLineCount(); if (limit <= 0) { - Timber.d("correctTextSizeIfNeeded: Failed to rescale, limit reached, final: %s", px); + Timber.d("timber: correctTextSizeIfNeeded: Failed to rescale, limit reached, final: %s", px); break; } } diff --git a/app/src/main/java/com/breadwallet/presenter/customviews/BRDialogView.java b/app/src/main/java/com/breadwallet/presenter/customviews/BRDialogView.java index a4abff5a0..5229c3270 100644 --- a/app/src/main/java/com/breadwallet/presenter/customviews/BRDialogView.java +++ b/app/src/main/java/com/breadwallet/presenter/customviews/BRDialogView.java @@ -73,7 +73,7 @@ public void onClick(View v) { } }); if (Utils.isNullOrEmpty(negButton)) { - Timber.e("onCreateDialog: removing negative button"); + Timber.e("timber:onCreateDialog: removing negative button"); buttonsLayout.removeView(negativeButton); buttonsLayout.requestLayout(); } diff --git a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentBalanceSeedReminder.kt b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentBalanceSeedReminder.kt new file mode 100644 index 000000000..1394c3e2f --- /dev/null +++ b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentBalanceSeedReminder.kt @@ -0,0 +1,82 @@ +package com.breadwallet.presenter.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewTreeObserver.OnGlobalLayoutListener +import android.widget.* +import androidx.fragment.app.Fragment +import com.breadwallet.R +import com.breadwallet.tools.animation.BRAnimator +import com.breadwallet.tools.security.BRKeyStore +import com.breadwallet.tools.util.BRConstants +import com.breadwallet.wallet.BRWalletManager +import java.util.* + + +class FragmentBalanceSeedReminder : Fragment() { + private lateinit var backgroundLayout: ScrollView + private lateinit var signalLayout: LinearLayout + private lateinit var showSeedButton: Button + private lateinit var seedPhraseTextView: TextView + private lateinit var closeButton: View + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + val rootView = inflater.inflate(R.layout.fragment_balance_seed_reminder, container, false) + backgroundLayout = rootView.findViewById(R.id.background_layout) + signalLayout = rootView.findViewById(R.id.signal_layout) + signalLayout = rootView.findViewById(R.id.signal_layout) as LinearLayout + seedPhraseTextView = rootView.findViewById(R.id.seed_phrase) + closeButton = rootView.findViewById(R.id.close_button) + showSeedButton = rootView.findViewById(R.id.show_seed_button) + return rootView + } + + private fun setListeners() { + + showSeedButton.setOnClickListener { + seedPhraseTextView.visibility = View.VISIBLE + } + + closeButton.setOnClickListener { + animateClose() + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val observer = signalLayout.viewTreeObserver + observer.addOnGlobalLayoutListener(object : OnGlobalLayoutListener { + override fun onGlobalLayout() { + if (observer.isAlive) { + observer.removeOnGlobalLayoutListener(this) + } + BRAnimator.animateBackgroundDim(backgroundLayout, false) + BRAnimator.animateSignalSlide(signalLayout, false) { + } + } + }) + setListeners() + fetchSeedPhrase() + } + fun fetchSeedPhrase() { + seedPhraseTextView.text = String(BRKeyStore.getPhrase(context, 0)) + } + + private fun animateClose() { + BRAnimator.animateBackgroundDim(backgroundLayout, true) + BRAnimator.animateSignalSlide(signalLayout, true) { close() } + } + + private fun close() { + if (activity != null && activity?.isFinishing != true) { + activity?.onBackPressed() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentBuy.java b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentBuy.java index b86e57f9c..7b12b232c 100644 --- a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentBuy.java +++ b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentBuy.java @@ -129,7 +129,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa String bitrefillUrl = String.format( BRConstants.BITREFILL_AFFILIATE_LINK + "/embed/?paymentMethod=litecoin&ref=%s&utm_source=%s", bitrefillRef,utmSource); String buyUrl = partner == Partner.BITREFILL ? bitrefillUrl : url(getContext(), partner, currency); - Timber.d("URL %s", buyUrl); + Timber.d("timber: URL %s", buyUrl); webView.loadUrl(buyUrl); return rootView; @@ -187,7 +187,7 @@ public void onProgressChanged(WebView view, int newProgress) { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { String url = request.getUrl().toString(); - Timber.d("shouldOverrideUrlLoading: URL=%s\nMethod=%s", url, request.getMethod()); + Timber.d("timber: shouldOverrideUrlLoading: URL=%s\nMethod=%s", url, request.getMethod()); if (url.equalsIgnoreCase(onCloseUrl)) { closePayment(); onCloseUrl = null; @@ -202,7 +202,7 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - Timber.d("onPageStarted: %s", url); + Timber.d("timber: onPageStarted: %s", url); super.onPageStarted(view, url, favicon); progress.setVisibility(View.VISIBLE); } @@ -210,7 +210,7 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); - Timber.d("onPageFinished %s", url); + Timber.d("timber: onPageFinished %s", url); progress.setVisibility(View.GONE); } }; diff --git a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentPin.java b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentPin.java index e080ac364..e091ec74f 100644 --- a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentPin.java +++ b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentPin.java @@ -131,7 +131,7 @@ public void onResume() { private void handleClick(String key) { if (key == null) { - Timber.d("handleClick: key is null! "); + Timber.d("timber: handleClick: key is null! "); return; } @@ -140,7 +140,7 @@ private void handleClick(String key) { } else if (Character.isDigit(key.charAt(0))) { handleDigitClick(Integer.parseInt(key.substring(0, 1))); } else { - Timber.d("handleClick: oops: %s", key); + Timber.d("timber: handleClick: oops: %s", key); } } diff --git a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentRequestAmount.java b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentRequestAmount.java index ff35f1eeb..3a09a41b8 100644 --- a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentRequestAmount.java +++ b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentRequestAmount.java @@ -255,7 +255,7 @@ public void run() { private void handleClick(String key) { if (key == null) { - Timber.d("handleClick: key is null! "); + Timber.d("timber: handleClick: key is null! "); return; } diff --git a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentSend.kt b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentSend.kt index bc1166ac8..63608cdd4 100644 --- a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentSend.kt +++ b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentSend.kt @@ -287,7 +287,7 @@ class FragmentSend : Fragment() { if (BRWalletManager.validateAddress(address)) { val app: Activity? = activity if (app == null) { - Timber.e("paste onClick: app is null") + Timber.e("timber:paste onClick: app is null") return@OnClickListener } BRExecutor.getInstance().forLightWeightBackgroundTasks().execute { @@ -531,7 +531,7 @@ class FragmentSend : Fragment() { private fun handleClick(key: String?) { if (key == null) { - Timber.d("handleClick: key is null! ") + Timber.d("timber: handleClick: key is null! ") return } when { @@ -606,7 +606,7 @@ class FragmentSend : Fragment() { BigDecimal(tmpAmount) ).toLong() val balanceForISO = BRExchange.getAmountFromSatoshis(activity, iso, BigDecimal(curBalance)) - Timber.d("updateText: balanceForISO: %s", balanceForISO) + Timber.d("timber: updateText: balanceForISO: %s", balanceForISO) //formattedBalance val formattedBalance = BRCurrency.getFormattedCurrencyString(activity, iso, balanceForISO) @@ -617,7 +617,7 @@ class FragmentSend : Fragment() { } else { fee = BRWalletManager.getInstance().feeForTransactionAmount(satoshis).toLong() if (fee == 0L) { - Timber.i("updateText: fee is 0, trying the estimate") + Timber.i("timber: updateText: fee is 0, trying the estimate") fee = BRWalletManager.getInstance() .feeForTransaction(addressEdit.text.toString(), satoshis).toLong() } @@ -627,10 +627,10 @@ class FragmentSend : Fragment() { iso, BigDecimal(if (curBalance == 0L) 0 else fee) ) - Timber.d("updateText: feeForISO: %s", feeForISO) + Timber.d("timber: updateText: feeForISO: %s", feeForISO) //formattedBalance val aproxFee = BRCurrency.getFormattedCurrencyString(activity, iso, feeForISO) - Timber.d("updateText: aproxFee: %s", aproxFee) + Timber.d("timber: updateText: aproxFee: %s", aproxFee) if (BigDecimal( if (tmpAmount.isEmpty() || tmpAmount.equals( ".", @@ -708,10 +708,10 @@ class FragmentSend : Fragment() { // Checks whether a hardware keyboard is available if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { - Timber.d("onConfigurationChanged: hidden") + Timber.d("timber: onConfigurationChanged: hidden") showKeyboard(true) } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { - Timber.d("onConfigurationChanged: shown") + Timber.d("timber: onConfigurationChanged: shown") showKeyboard(false) } } diff --git a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionDetails.java b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionDetails.java index f70f9a7f0..fd623e708 100644 --- a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionDetails.java +++ b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionDetails.java @@ -85,7 +85,7 @@ public void close() { if (app != null && !app.isFinishing()) app.getFragmentManager().popBackStack(); else - Timber.d("onAnimationEnd: app is null"); + Timber.d("timber: onAnimationEnd: app is null"); }); } diff --git a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionItem.java b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionItem.java index 3079be604..752313b42 100644 --- a/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionItem.java +++ b/app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionItem.java @@ -128,7 +128,7 @@ private void fillTexts() { mTxHashLink.setOnClickListener(view -> { close(); String txUrl = BRConstants.BLOCK_EXPLORER_BASE_URL + item.getTxHashHexReversed(); - Timber.d("txUrl = %s", txUrl); + Timber.d("timber: txUrl = %s", txUrl); Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(txUrl)); startActivity(browserIntent); getActivity().overridePendingTransition(R.anim.enter_from_bottom, R.anim.empty_300); @@ -164,7 +164,7 @@ private void fillTexts() { } boolean removeView = sent || !availableForSpend; - Timber.d("fillTexts: removeView : %s", removeView); + Timber.d("timber: fillTexts: removeView : %s", removeView); if (!removeView) { mAvailableSpend.setText(getString(R.string.Transaction_available)); } else { diff --git a/app/src/main/java/com/breadwallet/tools/adapter/TransactionListAdapter.java b/app/src/main/java/com/breadwallet/tools/adapter/TransactionListAdapter.java index 128659531..357b5fae7 100644 --- a/app/src/main/java/com/breadwallet/tools/adapter/TransactionListAdapter.java +++ b/app/src/main/java/com/breadwallet/tools/adapter/TransactionListAdapter.java @@ -86,7 +86,7 @@ public void run() { item.txReversed = Utils.reverseHex(Utils.bytesToHex(item.getTxHash())); } backUpFeed = newItems; - Timber.d("updateData: newItems: %d, took: %s", newItems.size(), System.currentTimeMillis() - s); + Timber.d("timber: updateData: newItems: %d, took: %s", newItems.size(), System.currentTimeMillis() - s); updatingData = false; } }); @@ -262,7 +262,7 @@ else if (confirms == 3) } private void setPrompt(final PromptHolder prompt) { - Timber.d("setPrompt: %s", TxManager.getInstance().promptInfo.title); + Timber.d("timber: setPrompt: %s", TxManager.getInstance().promptInfo.title); if (TxManager.getInstance().promptInfo == null) { throw new RuntimeException("can't happen, showing prompt with null PromptInfo"); } @@ -350,7 +350,7 @@ private void filter(final String query, final boolean[] switches) { itemFeed = filteredList; notifyDataSetChanged(); - Timber.d("filter: %s took: %s", query, System.currentTimeMillis() - start); + Timber.d("timber: filter: %s took: %s", query, System.currentTimeMillis() - start); } private class TxHolder extends RecyclerView.ViewHolder { diff --git a/app/src/main/java/com/breadwallet/tools/animation/BRAnimator.java b/app/src/main/java/com/breadwallet/tools/animation/BRAnimator.java index 9263197c5..5c9a3cffe 100644 --- a/app/src/main/java/com/breadwallet/tools/animation/BRAnimator.java +++ b/app/src/main/java/com/breadwallet/tools/animation/BRAnimator.java @@ -18,6 +18,7 @@ import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.view.animation.OvershootInterpolator; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -28,10 +29,12 @@ import com.breadwallet.R; import com.breadwallet.presenter.activities.BreadActivity; import com.breadwallet.presenter.activities.LoginActivity; +import com.breadwallet.presenter.activities.camera.CameraActivity; import com.breadwallet.presenter.activities.camera.ScanQRActivity; import com.breadwallet.presenter.customviews.BRDialogView; import com.breadwallet.presenter.entities.TxItem; import com.breadwallet.presenter.fragments.DynamicDonationFragment; +import com.breadwallet.presenter.fragments.FragmentBalanceSeedReminder; import com.breadwallet.presenter.fragments.FragmentBuy; import com.breadwallet.presenter.fragments.FragmentGreetings; import com.breadwallet.presenter.fragments.FragmentMenu; @@ -71,9 +74,30 @@ public static void showBreadSignal(Activity activity, String title, String iconD transaction.commit(); } + + public static void showBalanceSeedFragment(@NonNull FragmentActivity app) { + Timber.d("timber: fetched info"); + + androidx.fragment.app.FragmentManager fragmentManager = app.getSupportFragmentManager(); + FragmentBalanceSeedReminder fragmentBalanceSeedReminder = (FragmentBalanceSeedReminder) fragmentManager.findFragmentByTag(FragmentBalanceSeedReminder.class.getName()); + if (fragmentBalanceSeedReminder != null) { + fragmentBalanceSeedReminder.fetchSeedPhrase(); + Timber.d("timber: fetched seed phrase"); + return; + } + + try { + fragmentBalanceSeedReminder = new FragmentBalanceSeedReminder(); + fragmentManager.beginTransaction() + .setCustomAnimations(0, 0, 0, R.animator.plain_300) + .add(android.R.id.content, fragmentBalanceSeedReminder, FragmentBalanceSeedReminder.class.getName()) + .addToBackStack(FragmentBalanceSeedReminder.class.getName()).commit(); + } finally { + } + } public static void showSendFragment(FragmentActivity app, final String bitcoinUrl) { if (app == null) { - Timber.i("showSendFragment: app is null"); + Timber.i("timber: showSendFragment: app is null"); return; } androidx.fragment.app.FragmentManager fragmentManager = app.getSupportFragmentManager(); @@ -115,13 +139,13 @@ public static void popBackStackTillEntry(Activity app, int entryIndex) { public static void showTransactionPager(Activity app, List items, int position) { if (app == null) { - Timber.i("showSendFragment: app is null"); + Timber.i("timber: showSendFragment: app is null"); return; } FragmentTransactionDetails fragmentTransactionDetails = (FragmentTransactionDetails) app.getFragmentManager().findFragmentByTag(FragmentTransactionDetails.class.getName()); if (fragmentTransactionDetails != null && fragmentTransactionDetails.isAdded()) { fragmentTransactionDetails.setItems(items); - Timber.i("showTransactionPager: Already showing"); + Timber.i("timber: showTransactionPager: Already showing"); return; } fragmentTransactionDetails = new FragmentTransactionDetails(); @@ -193,11 +217,11 @@ public static LayoutTransition getDefaultTransition() { public static void showRequestFragment(Activity app, String address) { if (app == null) { - Timber.i("showRequestFragment: app is null"); + Timber.i("timber: showRequestFragment: app is null"); return; } if (Utils.isNullOrEmpty(address)) { - Timber.i("showRequestFragment: address is empty"); + Timber.i("timber: showRequestFragment: address is empty"); return; } @@ -219,7 +243,7 @@ public static void showRequestFragment(Activity app, String address) { //isReceive tells the Animator that the Receive fragment is requested, not My Address public static void showReceiveFragment(Activity app, boolean isReceive) { if (app == null) { - Timber.i("showReceiveFragment: app is null"); + Timber.i("timber: showReceiveFragment: app is null"); return; } FragmentReceive fragmentReceive = (FragmentReceive) app.getFragmentManager().findFragmentByTag(FragmentReceive.class.getName()); @@ -239,7 +263,7 @@ public static void showReceiveFragment(Activity app, boolean isReceive) { public static void showBuyFragment(FragmentActivity app, String currency, FragmentBuy.Partner partner) { if (app == null) { - Timber.i("showBuyFragment: app is null"); + Timber.i("timber: showBuyFragment: app is null"); return; } app.getSupportFragmentManager() @@ -260,7 +284,7 @@ public static void showDynamicDonationFragment(@NonNull FragmentActivity app) { public static void showMenuFragment(Activity app) { if (app == null) { - Timber.i("showReceiveFragment: app is null"); + Timber.i("timber: showReceiveFragment: app is null"); return; } FragmentTransaction transaction = app.getFragmentManager().beginTransaction(); @@ -272,7 +296,7 @@ public static void showMenuFragment(Activity app) { public static void showGreetingsMessage(Activity app) { if (app == null) { - Timber.i("showGreetingsMessage: app is null"); + Timber.i("timber: showGreetingsMessage: app is null"); return; } FragmentTransaction transaction = app.getFragmentManager().beginTransaction(); @@ -312,7 +336,7 @@ public static void startBreadIfNotStarted(Activity app) { public static void startBreadActivity(Activity from, boolean auth) { if (from == null) return; - Timber.i("startBreadActivity: %s", from.getClass().getName()); + Timber.i("timber: startBreadActivity: %s", from.getClass().getName()); Class toStart = auth ? LoginActivity.class : BreadActivity.class; Intent intent = new Intent(from, toStart); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); diff --git a/app/src/main/java/com/breadwallet/tools/animation/BRDialog.java b/app/src/main/java/com/breadwallet/tools/animation/BRDialog.java index da8699fec..f84035ec5 100644 --- a/app/src/main/java/com/breadwallet/tools/animation/BRDialog.java +++ b/app/src/main/java/com/breadwallet/tools/animation/BRDialog.java @@ -24,7 +24,7 @@ public static void showCustomDialog(@NonNull final Context app, @NonNull final S @NonNull final String posButton, final String negButton, final BRDialogView.BROnClickListener posListener, final BRDialogView.BROnClickListener negListener, final DialogInterface.OnDismissListener dismissListener, final int iconRes) { if (((Activity) app).isDestroyed()) { - Timber.d("showCustomDialog: FAILED, context is destroyed"); + Timber.d("timber: showCustomDialog: FAILED, context is destroyed"); return; } @@ -51,7 +51,7 @@ public static void showCustomDialog(@NonNull final Context app, @NonNull final S @NonNull final String posButton, final String negButton, final BRDialogView.BROnClickListener posListener, final BRDialogView.BROnClickListener negListener, final DialogInterface.OnDismissListener dismissListener, final int iconRes) { if (((Activity) app).isDestroyed()) { - Timber.d("showCustomDialog: FAILED, context is destroyed"); + Timber.d("timber: showCustomDialog: FAILED, context is destroyed"); return; } diff --git a/app/src/main/java/com/breadwallet/tools/manager/BRApiManager.java b/app/src/main/java/com/breadwallet/tools/manager/BRApiManager.java index 7d9c383b1..3a90507f0 100644 --- a/app/src/main/java/com/breadwallet/tools/manager/BRApiManager.java +++ b/app/src/main/java/com/breadwallet/tools/manager/BRApiManager.java @@ -82,7 +82,7 @@ private Set getCurrencies(Activity context) { set.add(tmp); } } else { - Timber.d("getCurrencies: failed to get currencies"); + Timber.d("timber: getCurrencies: failed to get currencies"); } } catch (Exception e) { Timber.e(e); @@ -103,7 +103,7 @@ public void run() { @Override public void run() { if (!BreadApp.isAppInBackground(context)) { - Timber.d("doInBackground: Stopping timer, no activity on."); + Timber.d("timber: doInBackground: Stopping timer, no activity on."); BRApiManager.getInstance().stopTimerTask(); } Set tmp = getCurrencies((Activity) context); @@ -198,13 +198,13 @@ private static String createGETRequestURL(Context app, String myURL) { try { if (resp == null) { - Timber.i("urlGET: %s resp is null", myURL); + Timber.i("timber: urlGET: %s resp is null", myURL); return null; } response = resp.body().string(); String strDate = resp.header("date"); if (strDate == null) { - Timber.i("urlGET: strDate is null!"); + Timber.i("timber: urlGET: strDate is null!"); return response; } SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); diff --git a/app/src/main/java/com/breadwallet/tools/manager/BREventManager.java b/app/src/main/java/com/breadwallet/tools/manager/BREventManager.java index 0bfd8a45c..1f365fb30 100644 --- a/app/src/main/java/com/breadwallet/tools/manager/BREventManager.java +++ b/app/src/main/java/com/breadwallet/tools/manager/BREventManager.java @@ -46,20 +46,20 @@ public static BREventManager getInstance() { } public void pushEvent(String eventName, Map attributes) { - Timber.d("pushEvent: %s", eventName); + Timber.d("timber: pushEvent: %s", eventName); Event event = new Event(sessionId, System.currentTimeMillis() * 1000, eventName, attributes); events.add(event); } public void pushEvent(String eventName) { - Timber.d("pushEvent: %s", eventName); + Timber.d("timber: pushEvent: %s", eventName); Event event = new Event(sessionId, System.currentTimeMillis() * 1000, eventName, null); events.add(event); } @Override public void onBackgrounded() { - Timber.d("onBackgrounded: "); + Timber.d("timber: onBackgrounded: "); saveEvents(); pushToServer(); } @@ -89,7 +89,7 @@ private void saveEvents() { String fileName = app.getFilesDir().getAbsolutePath() + "/events/" + UUID.randomUUID().toString(); writeEventsToDisk(fileName, array.toString()); } else { - Timber.i("saveEvents: FAILED TO WRITE EVENTS TO FILE: app is null"); + Timber.i("timber: saveEvents: FAILED TO WRITE EVENTS TO FILE: app is null"); } } @@ -127,7 +127,7 @@ private void pushToServer() { if (response != null) response.close(); } if (Utils.isNullOrEmpty(strResponse)) { - Timber.i("pushToServer: response is empty"); + Timber.i("timber: pushToServer: response is empty"); fails++; } } catch (JSONException e) { @@ -144,18 +144,18 @@ private void pushToServer() { new File(dir, children[i]).delete(); } } else { - Timber.i("pushToServer: missing events directory"); + Timber.i("timber: pushToServer: missing events directory"); } } else { - Timber.i("pushToServer: FAILED with: %s fails", fails); + Timber.i("timber: pushToServer: FAILED with: %s fails", fails); } } else { - Timber.i("pushToServer: Failed to push, app is null"); + Timber.i("timber: pushToServer: Failed to push, app is null"); } } private boolean writeEventsToDisk(String fileName, String json) { - Timber.d("saveEvents: eventsFile: %s,\njson: %s", fileName, json); + Timber.d("timber: saveEvents: eventsFile: %s,\njson: %s", fileName, json); try { FileWriter file = new FileWriter(fileName); file.write(json); @@ -163,7 +163,7 @@ private boolean writeEventsToDisk(String fileName, String json) { file.close(); return true; } catch (IOException e) { - Timber.e(e, "Error in Writing"); + Timber.e(e, "timber:Error in Writing"); } return false; } @@ -176,7 +176,7 @@ private static List getEventsFromDisk(Context context) { for (File f : dir.listFiles()) { if (f.isFile()) { String name = f.getName(); - Timber.d("getEventsFromDisk: name:%s", name); + Timber.d("timber: getEventsFromDisk: name:%s", name); try { JSONArray arr = new JSONArray(readFile(name)); result.add(arr); @@ -184,7 +184,7 @@ private static List getEventsFromDisk(Context context) { Timber.e(e); } } else { - Timber.i("getEventsFromDisk: Unexpected directory where file is expected: %s", f.getName()); + Timber.i("timber: getEventsFromDisk: Unexpected directory where file is expected: %s", f.getName()); } } return result; @@ -201,7 +201,7 @@ private static String readFile(String fileName) { is.close(); return new String(buffer); } catch (IOException e) { - Timber.e(e, "Error in Reading"); + Timber.e(e, "timber:Error in Reading"); return null; } } diff --git a/app/src/main/java/com/breadwallet/tools/manager/BRSharedPrefs.java b/app/src/main/java/com/breadwallet/tools/manager/BRSharedPrefs.java index b70fc8492..33c0e9a4d 100644 --- a/app/src/main/java/com/breadwallet/tools/manager/BRSharedPrefs.java +++ b/app/src/main/java/com/breadwallet/tools/manager/BRSharedPrefs.java @@ -24,6 +24,8 @@ public class BRSharedPrefs { public static final String SEND_TRANSACTION_COUNT = "send_transaction_count"; public static final String IN_APP_REVIEW_DONE = "in_app_review_done"; + public static final String PREFERRED_FPRATE = "preferredFalsePositiveRate"; + public interface OnIsoChangedListener { void onIsoChanged(String iso); } @@ -203,7 +205,7 @@ public static List getBitIdNonces(Context activity, String key) { JSONArray arr = new JSONArray(result); for (int i = 0; i < arr.length(); i++) { int a = arr.getInt(i); - Timber.d("found a nonce: %s", a); + Timber.d("timber: found a nonce: %s", a); list.add(a); } } catch (Exception e) { @@ -241,7 +243,7 @@ public static boolean getPreferredLTC(Context activity) { //if the user prefers all in litecoin units, not other currencies public static void putPreferredLTC(Context activity, boolean b) { - Timber.d("putPreferredLTC: %s", b); + Timber.d("timber: putPreferredLTC: %s", b); SharedPreferences prefs = activity.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean("priceSetToLitecoin", b); @@ -438,4 +440,16 @@ public static void inAppReviewDone(Context context) { context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE) .edit().putBoolean(IN_APP_REVIEW_DONE, true).apply(); } -} \ No newline at end of file + + public static float getFalsePositivesRate(Context context) { + return context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE).getFloat(PREFERRED_FPRATE, BRConstants.FALSE_POS_RATE_LOW_PRIVACY); + } + + public static void putFalsePositivesRate(Context context, float preferredRate) { + SharedPreferences prefs = context.getSharedPreferences(BRConstants.PREFS_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putFloat(PREFERRED_FPRATE, preferredRate); + editor.apply(); + } +} + diff --git a/app/src/main/java/com/breadwallet/tools/manager/InternetManager.java b/app/src/main/java/com/breadwallet/tools/manager/InternetManager.java index f601048ee..6598d7356 100644 --- a/app/src/main/java/com/breadwallet/tools/manager/InternetManager.java +++ b/app/src/main/java/com/breadwallet/tools/manager/InternetManager.java @@ -52,7 +52,7 @@ public void onReceive(final Context context, final Intent intent) { for (ConnectionReceiverListener listener : connectionReceiverListeners) { listener.onConnectionChanged(connected); } - Timber.d("onReceive: %s", connected); + Timber.d("timber: onReceive: %s", connected); } } diff --git a/app/src/main/java/com/breadwallet/tools/manager/SyncManager.java b/app/src/main/java/com/breadwallet/tools/manager/SyncManager.java index 2739b7135..d139e396f 100644 --- a/app/src/main/java/com/breadwallet/tools/manager/SyncManager.java +++ b/app/src/main/java/com/breadwallet/tools/manager/SyncManager.java @@ -45,12 +45,12 @@ public synchronized void updateAlarms(Context app) { } public synchronized void startSyncingProgressThread() { - Timber.d("startSyncingProgressThread:%s", Thread.currentThread().getName()); + Timber.d("timber: startSyncingProgressThread:%s", Thread.currentThread().getName()); try { if (syncTask != null) { if (running) { - Timber.d("startSyncingProgressThread: syncTask.running == true, returning"); + Timber.d("timber: startSyncingProgressThread: syncTask.running == true, returning"); return; } syncTask.interrupt(); @@ -64,10 +64,10 @@ public synchronized void startSyncingProgressThread() { } public synchronized void stopSyncingProgressThread() { - Timber.d("stopSyncingProgressThread"); + Timber.d("timber: stopSyncingProgressThread"); final BreadActivity ctx = BreadActivity.getApp(); if (ctx == null) { - Timber.i("stopSyncingProgressThread: ctx is null"); + Timber.i("timber: stopSyncingProgressThread: ctx is null"); return; } try { @@ -95,7 +95,7 @@ public void run() { app = BreadActivity.getApp(); progressStatus = 0; running = true; - Timber.d("run: starting: %s", progressStatus); + Timber.d("timber: run: starting: %s", progressStatus); if (app != null) { final long lastBlockTimeStamp = BRPeerManager.getInstance().getLastBlockTimestamp() * 1000; @@ -124,7 +124,7 @@ public void run() { public void run() { if (TxManager.getInstance().currentPrompt != PromptManager.PromptItem.SYNCING) { - Timber.d("run: currentPrompt != SYNCING, showPrompt(SYNCING) ...."); + Timber.d("timber: run: currentPrompt != SYNCING, showPrompt(SYNCING) ...."); TxManager.getInstance().showPrompt(app, PromptManager.PromptItem.SYNCING); } @@ -142,10 +142,10 @@ public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { - Timber.e(e, "run: Thread.sleep was Interrupted:%s", Thread.currentThread().getName()); + Timber.e(e, "timber:run: Thread.sleep was Interrupted:%s", Thread.currentThread().getName()); } } - Timber.d("run: SyncProgress task finished:%s", Thread.currentThread().getName()); + Timber.d("timber: run: SyncProgress task finished:%s", Thread.currentThread().getName()); } finally { running = false; progressStatus = 0; diff --git a/app/src/main/java/com/breadwallet/tools/manager/TxManager.java b/app/src/main/java/com/breadwallet/tools/manager/TxManager.java index f7a1ddb1c..ebf2fcfd8 100644 --- a/app/src/main/java/com/breadwallet/tools/manager/TxManager.java +++ b/app/src/main/java/com/breadwallet/tools/manager/TxManager.java @@ -142,12 +142,12 @@ private void showNextPrompt(Activity app) { crashIfNotMain(); PromptManager.PromptItem toShow = PromptManager.getInstance().nextPrompt(app); if (toShow != null) { - Timber.d("showNextPrompt: %s", toShow); + Timber.d("timber: showNextPrompt: %s", toShow); currentPrompt = toShow; promptInfo = PromptManager.getInstance().promptInfo(app, currentPrompt); updateCard(app); } else { - Timber.d("showNextPrompt: nothing to show"); + Timber.d("timber: showNextPrompt: nothing to show"); } } @@ -159,7 +159,7 @@ public synchronized void updateTxList(final Context app) { long took = (System.currentTimeMillis() - start); if (took > 500) - Timber.d("updateTxList: took: %s", took); + Timber.d("timber: updateTxList: took: %s", took); if (adapter != null) { ((Activity) app).runOnUiThread(new Runnable() { @Override @@ -167,7 +167,7 @@ public void run() { adapter.setItems(items); txList.setAdapter(adapter); adapter.notifyDataSetChanged(); - Timber.d("updateTxList: %s", currentPrompt); + Timber.d("timber: updateTxList: %s", currentPrompt); } }); } diff --git a/app/src/main/java/com/breadwallet/tools/qrcode/QRCodeReaderView.java b/app/src/main/java/com/breadwallet/tools/qrcode/QRCodeReaderView.java index 8eab3749b..4fbb066cb 100755 --- a/app/src/main/java/com/breadwallet/tools/qrcode/QRCodeReaderView.java +++ b/app/src/main/java/com/breadwallet/tools/qrcode/QRCodeReaderView.java @@ -211,13 +211,13 @@ public void onDetachedFromWindow() { @Override public void surfaceCreated(SurfaceHolder holder) { - Timber.d("surfaceCreated"); + Timber.d("timber: surfaceCreated"); try { // Indicate camera, our View dimensions mCameraManager.openDriver(holder, this.getWidth(), this.getHeight()); } catch (IOException | RuntimeException e) { - Timber.e(e, "Can not openDriver"); + Timber.e(e, "timber:Can not openDriver"); mCameraManager.closeDriver(); } @@ -225,22 +225,22 @@ public void surfaceCreated(SurfaceHolder holder) { mQRCodeReader = new QRCodeReader(); mCameraManager.startPreview(); } catch (Exception e) { - Timber.e(e, "Exception"); + Timber.e(e, "timber:Exception"); mCameraManager.closeDriver(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Timber.d("surfaceChanged"); + Timber.d("timber: surfaceChanged"); if (holder.getSurface() == null) { - Timber.d("Error: preview surface does not exist"); + Timber.d("timber: Error: preview surface does not exist"); return; } if (mCameraManager.getPreviewSize() == null) { - Timber.d("Error: preview size does not exist"); + Timber.d("timber: Error: preview size does not exist"); return; } @@ -258,7 +258,7 @@ public void surfaceChanged(SurfaceHolder holder, int format, int width, int heig @Override public void surfaceDestroyed(SurfaceHolder holder) { - Timber.d("surfaceDestroyed"); + Timber.d("timber: surfaceDestroyed"); mCameraManager.setPreviewCallback(null); mCameraManager.stopPreview(); @@ -366,11 +366,11 @@ protected Result doInBackground(byte[]... params) { try { return view.mQRCodeReader.decode(bitmap, hintsRef.get()); } catch (ChecksumException e) { - Timber.e(e, "ChecksumException"); + Timber.e(e, "timber:ChecksumException"); } catch (NotFoundException e) { - Timber.e(e, "No QR Code found"); + Timber.e(e, "timber:No QR Code found"); } catch (FormatException e) { - Timber.e(e, "FormatException"); + Timber.e(e, "timber:FormatException"); } finally { view.mQRCodeReader.reset(); } diff --git a/app/src/main/java/com/breadwallet/tools/qrcode/QRUtils.java b/app/src/main/java/com/breadwallet/tools/qrcode/QRUtils.java index ad84bfba5..5b68dc173 100644 --- a/app/src/main/java/com/breadwallet/tools/qrcode/QRUtils.java +++ b/app/src/main/java/com/breadwallet/tools/qrcode/QRUtils.java @@ -98,7 +98,7 @@ private static String guessAppropriateEncoding(CharSequence contents) { public static void share(String via, Activity app, String bitcoinUri) { if (app == null) { - Timber.d("share: app is null"); + Timber.d("timber: share: app is null"); return; } @@ -112,7 +112,7 @@ public static void share(String via, Activity app, String bitcoinUri) { private static File saveToExternalStorage(Bitmap bitmapImage, Activity app) { if (app == null) { - Timber.d("saveToExternalStorage: app is null"); + Timber.d("timber: saveToExternalStorage: app is null"); return null; } @@ -124,11 +124,11 @@ private static File saveToExternalStorage(Bitmap bitmapImage, Activity app) { f.setReadable(true, false); try { boolean a = f.createNewFile(); - if(!a) Timber.d("saveToExternalStorage: createNewFile: failed"); + if(!a) Timber.d("timber: saveToExternalStorage: createNewFile: failed"); } catch (IOException e) { Timber.e(e); } - Timber.d("saveToExternalStorage: " + f.getAbsolutePath()); + Timber.d("timber: saveToExternalStorage: " + f.getAbsolutePath()); if (f.exists()) f.delete(); try { diff --git a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/AutoFocusManager.java b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/AutoFocusManager.java index d98984b8b..a2d203c3f 100755 --- a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/AutoFocusManager.java +++ b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/AutoFocusManager.java @@ -63,7 +63,7 @@ final class AutoFocusManager implements Camera.AutoFocusCallback { this.camera = camera; String currentFocusMode = camera.getParameters().getFocusMode(); useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode); - Timber.d("Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus); + Timber.d("timber: Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus); start(); } diff --git a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraConfigurationManager.java b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraConfigurationManager.java index 4a236ab01..66d647ead 100755 --- a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraConfigurationManager.java +++ b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraConfigurationManager.java @@ -89,34 +89,34 @@ void initFromCameraParameters(OpenCamera camera, int width, int height) { throw new IllegalArgumentException("Bad rotation: " + displayRotation); } } - Timber.d("Display at: %s", cwRotationFromNaturalToDisplay); + Timber.d("timber: Display at: %s", cwRotationFromNaturalToDisplay); int cwRotationFromNaturalToCamera = camera.getOrientation(); - Timber.d("Camera at: %s", cwRotationFromNaturalToCamera); + Timber.d("timber: Camera at: %s", cwRotationFromNaturalToCamera); // Still not 100% sure about this. But acts like we need to flip this: if (camera.getFacing() == CameraFacing.FRONT) { cwRotationFromNaturalToCamera = (360 - cwRotationFromNaturalToCamera) % 360; - Timber.d("Front camera overriden to: %s", cwRotationFromNaturalToCamera); + Timber.d("timber: Front camera overriden to: %s", cwRotationFromNaturalToCamera); } cwRotationFromDisplayToCamera = (360 + cwRotationFromNaturalToCamera - cwRotationFromNaturalToDisplay) % 360; - Timber.d("Final display orientation: %s", cwRotationFromDisplayToCamera); + Timber.d("timber: Final display orientation: %s", cwRotationFromDisplayToCamera); if (camera.getFacing() == CameraFacing.FRONT) { - Timber.d("Compensating rotation for front camera"); + Timber.d("timber: Compensating rotation for front camera"); cwNeededRotation = (360 - cwRotationFromDisplayToCamera) % 360; } else { cwNeededRotation = cwRotationFromDisplayToCamera; } - Timber.d("Clockwise rotation from display to camera: %s", cwNeededRotation); + Timber.d("timber: Clockwise rotation from display to camera: %s", cwNeededRotation); resolution = new Point(width, height); - Timber.d("Screen resolution in current orientation: %s", resolution); + Timber.d("timber: Screen resolution in current orientation: %s", resolution); cameraResolution = findBestPreviewSizeValue(parameters, resolution); - Timber.d("Camera resolution: %s", cameraResolution); + Timber.d("timber: Camera resolution: %s", cameraResolution); bestPreviewSize = findBestPreviewSizeValue(parameters, resolution); - Timber.d("Best available preview size: %s", bestPreviewSize); + Timber.d("timber: Best available preview size: %s", bestPreviewSize); boolean isScreenPortrait = resolution.x < resolution.y; boolean isPreviewSizePortrait = bestPreviewSize.x < bestPreviewSize.y; @@ -126,7 +126,7 @@ void initFromCameraParameters(OpenCamera camera, int width, int height) { } else { previewSizeOnScreen = new Point(bestPreviewSize.y, bestPreviewSize.x); } - Timber.d("Preview size on screen: %s", previewSizeOnScreen); + Timber.d("timber: Preview size on screen: %s", previewSizeOnScreen); } void setDesiredCameraParameters(OpenCamera camera, boolean safeMode) { @@ -135,14 +135,14 @@ void setDesiredCameraParameters(OpenCamera camera, boolean safeMode) { Camera.Parameters parameters = theCamera.getParameters(); if (parameters == null) { - Timber.d("Device error: no camera parameters are available. Proceeding without configuration."); + Timber.d("timber: Device error: no camera parameters are available. Proceeding without configuration."); return; } - Timber.d("Initial camera parameters: %s", parameters.flatten()); + Timber.d("timber: Initial camera parameters: %s", parameters.flatten()); if (safeMode) { - Timber.d("In camera config safe mode -- most settings will not be honored"); + Timber.d("timber: In camera config safe mode -- most settings will not be honored"); } // Maybe selected auto-focus but not available, so fall through here: @@ -194,7 +194,7 @@ public Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screen List rawSupportedSizes = parameters.getSupportedPreviewSizes(); if (rawSupportedSizes == null) { - Timber.d("Device returned no supported preview sizes; using default"); + Timber.d("timber: Device returned no supported preview sizes; using default"); Camera.Size defaultSize = parameters.getPreviewSize(); return new Point(defaultSize.width, defaultSize.height); } @@ -223,7 +223,7 @@ public int compare(Camera.Size a, Camera.Size b) { .append(supportedPreviewSize.height) .append(' '); } - Timber.d("Supported preview sizes: %s", previewSizesString); + Timber.d("timber: Supported preview sizes: %s", previewSizesString); Point bestSize = null; float screenAspectRatio = (float) screenResolution.x / (float) screenResolution.y; @@ -244,7 +244,7 @@ public int compare(Camera.Size a, Camera.Size b) { if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) { Point exactPoint = new Point(realWidth, realHeight); - Timber.d("Found preview size exactly matching screen size: %s", exactPoint); + Timber.d("timber: Found preview size exactly matching screen size: %s", exactPoint); return exactPoint; } float aspectRatio = (float) maybeFlippedWidth / (float) maybeFlippedHeight; @@ -258,26 +258,26 @@ public int compare(Camera.Size a, Camera.Size b) { if (bestSize == null) { Camera.Size defaultSize = parameters.getPreviewSize(); bestSize = new Point(defaultSize.width, defaultSize.height); - Timber.d("No suitable preview sizes, using default: %s", bestSize); + Timber.d("timber: No suitable preview sizes, using default: %s", bestSize); } - Timber.d("Found best approximate preview size: %s", bestSize); + Timber.d("timber: Found best approximate preview size: %s", bestSize); return bestSize; } private static String findSettableValue(String name, Collection supportedValues, String... desiredValues) { - Timber.d("Requesting " + name + " value from among: " + Arrays.toString(desiredValues)); - Timber.d("Supported " + name + " values: " + supportedValues); + Timber.d("timber: Requesting " + name + " value from among: " + Arrays.toString(desiredValues)); + Timber.d("timber: Supported " + name + " values: " + supportedValues); if (supportedValues != null) { for (String desiredValue : desiredValues) { if (supportedValues.contains(desiredValue)) { - Timber.d("Can set " + name + " to: " + desiredValue); + Timber.d("timber: Can set " + name + " to: " + desiredValue); return desiredValue; } } } - Timber.d("No supported values match"); + Timber.d("timber: No supported values match"); return null; } @@ -320,9 +320,9 @@ public static void setTorchEnabled(Camera.Parameters parameters, boolean enabled } if (flashMode != null) { if (flashMode.equals(parameters.getFlashMode())) { - Timber.d("Flash mode already set to %s", flashMode); + Timber.d("timber: Flash mode already set to %s", flashMode); } else { - Timber.d("Setting flash mode to %s", flashMode); + Timber.d("timber: Setting flash mode to %s", flashMode); parameters.setFlashMode(flashMode); } } @@ -341,14 +341,14 @@ public static void setBestExposure(Camera.Parameters parameters, boolean lightOn // Clamp value: compensationSteps = Math.max(Math.min(compensationSteps, maxExposure), minExposure); if (parameters.getExposureCompensation() == compensationSteps) { - Timber.d("Exposure compensation already set to " + compensationSteps + " / " + Timber.d("timber: Exposure compensation already set to " + compensationSteps + " / " + actualCompensation); } else { - Timber.d("Setting exposure compensation to " + compensationSteps + " / " + actualCompensation); + Timber.d("timber: Setting exposure compensation to " + compensationSteps + " / " + actualCompensation); parameters.setExposureCompensation(compensationSteps); } } else { - Timber.d("Camera does not support exposure compensation"); + Timber.d("timber: Camera does not support exposure compensation"); } } } diff --git a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraManager.java b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraManager.java index 5f455b737..728f47e70 100755 --- a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraManager.java +++ b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/CameraManager.java @@ -125,8 +125,8 @@ public synchronized void openDriver(SurfaceHolder holder, int width, int height) configManager.setDesiredCameraParameters(theCamera, false); } catch (RuntimeException re) { // Driver failed - Timber.d("Camera rejected parameters. Setting only minimal safe-mode parameters"); - Timber.d("Resetting to saved camera params: %s", parametersFlattened); + Timber.d("timber: Camera rejected parameters. Setting only minimal safe-mode parameters"); + Timber.d("timber: Resetting to saved camera params: %s", parametersFlattened); // Reset: if (parametersFlattened != null) { parameters = cameraObject.getParameters(); diff --git a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/open/OpenCameraInterface.java b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/open/OpenCameraInterface.java index 24d90124e..a6a000806 100755 --- a/app/src/main/java/com/breadwallet/tools/qrcode/xzing/open/OpenCameraInterface.java +++ b/app/src/main/java/com/breadwallet/tools/qrcode/xzing/open/OpenCameraInterface.java @@ -46,7 +46,7 @@ public static OpenCamera open(int cameraId) { int numCameras = Camera.getNumberOfCameras(); if (numCameras == 0) { - Timber.d("No cameras!"); + Timber.d("timber: No cameras!"); return null; } @@ -74,14 +74,14 @@ public static OpenCamera open(int cameraId) { Camera camera; if (index < numCameras) { - Timber.d("Opening camera #%s", index); + Timber.d("timber: Opening camera #%s", index); camera = Camera.open(index); } else { if (explicitRequest) { - Timber.d("Requested camera does not exist: %s", cameraId); + Timber.d("timber: Requested camera does not exist: %s", cameraId); camera = null; } else { - Timber.d("No camera facing " + CameraFacing.BACK + "; returning camera #0"); + Timber.d("timber: No camera facing " + CameraFacing.BACK + "; returning camera #0"); camera = Camera.open(0); selectedCameraInfo = new Camera.CameraInfo(); Camera.getCameraInfo(0, selectedCameraInfo); diff --git a/app/src/main/java/com/breadwallet/tools/security/AuthManager.java b/app/src/main/java/com/breadwallet/tools/security/AuthManager.java index 75b62097b..3d0d2ac28 100644 --- a/app/src/main/java/com/breadwallet/tools/security/AuthManager.java +++ b/app/src/main/java/com/breadwallet/tools/security/AuthManager.java @@ -41,7 +41,7 @@ public static AuthManager getInstance() { } public boolean checkAuth(CharSequence passSequence, Context context) { - Timber.d("checkAuth: "); + Timber.d("timber: checkAuth: "); String tempPass = passSequence.toString(); if (!previousTry.equals(tempPass)) { int failCount = BRKeyStore.getFailCount(context); @@ -175,7 +175,7 @@ public void run() { public void authPrompt(final Context context, String title, String message, boolean forcePin, boolean forceFingerprint, BRAuthCompletion completion) { if (context == null || !(context instanceof Activity)) { - Timber.i("authPrompt: context is null or not Activity: %s", context); + Timber.i("timber: authPrompt: context is null or not Activity: %s", context); return; } KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Activity.KEYGUARD_SERVICE); diff --git a/app/src/main/java/com/breadwallet/tools/security/BRKeyStore.java b/app/src/main/java/com/breadwallet/tools/security/BRKeyStore.java index 8f6df2724..ceb33ed9b 100644 --- a/app/src/main/java/com/breadwallet/tools/security/BRKeyStore.java +++ b/app/src/main/java/com/breadwallet/tools/security/BRKeyStore.java @@ -157,7 +157,7 @@ private synchronized static boolean _setData(Context context, byte[] data, Strin inCipher.init(Cipher.ENCRYPT_MODE, secretKey); } else { - Timber.d("KeyStore: is initialized"); + Timber.d("timber: KeyStore: is initialized"); //see if the key is old format, create a new one if it is try { @@ -167,7 +167,7 @@ private synchronized static boolean _setData(Context context, byte[] data, Strin if (ignored instanceof UserNotAuthenticatedException) { throw ignored; } - Timber.d("_setData: OLD KEY PRESENT: %s", alias); + Timber.d("timber: _setData: OLD KEY PRESENT: %s", alias); //create new key and reinitialize the cipher secretKey = createKeys(alias, auth_required); inCipher.init(Cipher.ENCRYPT_MODE, secretKey); @@ -191,7 +191,7 @@ private synchronized static boolean _setData(Context context, byte[] data, Strin storeEncryptedData(context, encryptedData, alias); return true; } catch (UserNotAuthenticatedException e) { - Timber.e(e, "_setData: showAuthenticationScreen: %s", alias); + Timber.e(e, "timber:_setData: showAuthenticationScreen: %s", alias); showAuthenticationScreen(context, request_code, alias); throw e; } catch (InvalidKeyException ex) { @@ -234,6 +234,7 @@ private synchronized static byte[] _getData(final Context context, String alias, lock.lock(); keyStore = KeyStore.getInstance(ANDROID_KEY_STORE); keyStore.load(null); + Timber.d("timber: BRKeyStore size: %d", keyStore.size()); SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null); byte[] encryptedData = retrieveEncryptedData(context, alias); @@ -313,11 +314,11 @@ private synchronized static byte[] _getData(final Context context, String alias, } catch (InvalidKeyException e) { if (e instanceof UserNotAuthenticatedException) { /** user not authenticated, ask the system for authentication */ - Timber.e(e, "_getData: showAuthenticationScreen: %s", alias); + Timber.e(e, "timber:_getData: showAuthenticationScreen: %s", alias); showAuthenticationScreen(context, request_code, alias); throw (UserNotAuthenticatedException) e; } else { - Timber.e(e, "_getData: InvalidKeyException"); + Timber.e(e, "timber:_getData: InvalidKeyException"); if (e instanceof KeyPermanentlyInvalidatedException) showKeyInvalidated(context); throw new UserNotAuthenticatedException(); //just to not go any further @@ -334,7 +335,7 @@ private synchronized static byte[] _getData(final Context context, String alias, } } catch (UnrecoverableKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException e) { /** if for any other reason the keystore fails, crash! */ - Timber.e(e, "getData: error"); + Timber.e(e, "timber:getData: error"); throw new RuntimeException(e.getMessage()); } catch (BadPaddingException | IllegalBlockSizeException | NoSuchProviderException e) { Timber.e(e); @@ -553,7 +554,7 @@ public synchronized static String getPinCode(final Context context) { try { Integer.parseInt(pinCode); } catch (Exception e) { - Timber.e(e, "getPinCode: WARNING passcode isn't a number"); + Timber.e(e, "timber:getPinCode: WARNING passcode isn't a number"); pinCode = ""; putPinCode(pinCode, context); putFailCount(0, context); @@ -701,7 +702,7 @@ public synchronized static boolean resetWalletKeyStore(Context context) { destroyEncryptedData(context, alias); count++; } - Timber.d("resetWalletKeyStore: removed:%s", count); + Timber.d("timber: resetWalletKeyStore: removed:%s", count); } catch (NoSuchAlgorithmException | KeyStoreException | IOException e) { Timber.e(e); return false; @@ -797,7 +798,7 @@ public synchronized static boolean _setOldData(Context context, byte[] data, Str try { validateSet(data, alias, alias_file, alias_iv, auth_required); } catch (Exception e) { - Timber.e(e, "_setData: "); + Timber.e(e, "timber:_setData: "); } KeyStore keyStore; @@ -827,7 +828,7 @@ public synchronized static boolean _setOldData(Context context, byte[] data, Str SecretKey secret = (SecretKey) keyStore.getKey(alias, null); if (secret == null) { - Timber.d("_setOldData: " + "secret is null on _setData: " + alias); + Timber.d("timber: _setOldData: " + "secret is null on _setData: " + alias); return false; } Cipher inCipher = Cipher.getInstance(CIPHER_ALGORITHM); @@ -836,7 +837,7 @@ public synchronized static boolean _setOldData(Context context, byte[] data, Str String path = getFilePath(alias_iv, context); boolean success = writeBytesToFile(path, iv); if (!success) { - Timber.d("_setOldData: " + "failed to writeBytesToFile: " + alias); + Timber.d("timber: _setOldData: " + "failed to writeBytesToFile: " + alias); BRDialog.showCustomDialog(context, context.getString(R.string.Alert_keystore_title_android), "Failed to save the iv file for: " + alias, "close", null, new BRDialogView.BROnClickListener() { @Override public void onClick(BRDialogView brDialogView) { @@ -858,11 +859,11 @@ public void onClick(BRDialogView brDialogView) { } return true; } catch (UserNotAuthenticatedException e) { - Timber.e(e, "_setOldData: showAuthenticationScreen: " + alias); + Timber.e(e, "timber:_setOldData: showAuthenticationScreen: " + alias); showAuthenticationScreen(context, request_code, alias); throw e; } catch (Exception e) { - Timber.e(e, "_setOldData: "); + Timber.e(e, "timber:_setOldData: "); return false; } } @@ -873,7 +874,7 @@ public synchronized static byte[] _getOldData(final Context context, String alia try { validateGet(alias, alias_file, alias_iv); } catch (Exception e) { - Timber.e(e, "_getOldData"); + Timber.e(e, "timber:_getOldData"); } KeyStore keyStore; @@ -889,7 +890,7 @@ public synchronized static byte[] _getOldData(final Context context, String alia if (!fileExists) { return null;/* file also not there, fine then */ } - Timber.i("_getOldData: file is present but the key is gone: %s", alias); + Timber.i("timber: _getOldData: file is present but the key is gone: %s", alias); return null; } @@ -899,10 +900,10 @@ public synchronized static byte[] _getOldData(final Context context, String alia removeAliasAndFiles(keyStore, alias, context); //report it if one exists and not the other. if (ivExists != aliasExists) { - Timber.d("_getOldData: " + "alias or iv isn't on the disk: " + alias + ", aliasExists:" + aliasExists); + Timber.d("timber: _getOldData: " + "alias or iv isn't on the disk: " + alias + ", aliasExists:" + aliasExists); return null; } else { - Timber.d("_getOldData: " + "!ivExists && !aliasExists: " + alias); + Timber.d("timber: _getOldData: " + "!ivExists && !aliasExists: " + alias); return null; } } @@ -918,20 +919,20 @@ public synchronized static byte[] _getOldData(final Context context, String alia } catch (InvalidKeyException e) { if (e instanceof UserNotAuthenticatedException) { /** user not authenticated, ask the system for authentication */ - Timber.e(e, "_getOldData: showAuthenticationScreen: %s", alias); + Timber.e(e, "timber:_getOldData: showAuthenticationScreen: %s", alias); showAuthenticationScreen(context, request_code, alias); throw (UserNotAuthenticatedException) e; } else { - Timber.e(e, "_getOldData: InvalidKeyException"); + Timber.e(e, "timber:_getOldData: InvalidKeyException"); return null; } } catch (IOException | CertificateException | KeyStoreException e) { /** keyStore.load(null) threw the Exception, meaning the keystore is unavailable */ - Timber.e(e, "_getOldData: keyStore.load(null) threw the Exception, meaning the keystore is unavailable"); + Timber.e(e, "timber:_getOldData: keyStore.load(null) threw the Exception, meaning the keystore is unavailable"); return null; } catch (UnrecoverableKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException e) { /** if for any other reason the keystore fails, crash! */ - Timber.e(e, "getData: error"); + Timber.e(e, "timber:getData: error"); return null; } } @@ -939,14 +940,14 @@ public synchronized static byte[] _getOldData(final Context context, String alia private static void showLoopBugMessage(final Context app) { if (bugMessageShowing) return; bugMessageShowing = true; - Timber.d("showLoopBugMessage: "); + Timber.d("timber: showLoopBugMessage: "); String mess = app.getString(R.string.ErrorMessages_loopingLockScreen_android); SpannableString ss = new SpannableString(mess.replace("[", "").replace("]", "")); ClickableSpan clickableSpan = new ClickableSpan() { @Override public void onClick(View textView) { - Timber.d("onClick: clicked on span!"); + Timber.d("timber: onClick: clicked on span!"); BRExecutor.getInstance().forMainThreadTasks().execute(new Runnable() { @Override public void run() { diff --git a/app/src/main/java/com/breadwallet/tools/security/BRSender.java b/app/src/main/java/com/breadwallet/tools/security/BRSender.java index d3f22d41e..b64c92eea 100644 --- a/app/src/main/java/com/breadwallet/tools/security/BRSender.java +++ b/app/src/main/java/com/breadwallet/tools/security/BRSender.java @@ -73,7 +73,7 @@ public void run() { //if the fee is STILL out of date then fail with network problem message long time = BRSharedPrefs.getFeeTime(app); if (time <= 0 || now - time >= FEE_EXPIRATION_MILLIS) { - Timber.d("sendTransaction: fee out of date even after fetching..."); + Timber.d("timber: sendTransaction: fee out of date even after fetching..."); AnalyticsManager.logCustomEvent(BRConstants._20200111_FNI); @@ -143,7 +143,7 @@ public void onClick(BRDialogView brDialogView) { private void tryPay(final Context app, final PaymentItem paymentRequest) throws InsufficientFundsException, AmountSmallerThanMinException, SpendingNotAllowed, FeeNeedsAdjust { if (paymentRequest == null || paymentRequest.addresses == null) { - Timber.d("handlePay: WRONG PARAMS"); + Timber.d("timber: handlePay: WRONG PARAMS"); String message = paymentRequest == null ? "paymentRequest is null" : "addresses is null"; RuntimeException ex = new RuntimeException("paymentRequest is malformed: " + message); @@ -242,7 +242,7 @@ public void onClick(BRDialogView brDialogView) { private void confirmPay(final Context ctx, final PaymentItem request) { if (ctx == null) { - Timber.i("confirmPay: context is null"); + Timber.i("timber: confirmPay: context is null"); return; } @@ -276,10 +276,10 @@ public void onClick(BRDialogView brDialogView) { } boolean forcePin = false; - Timber.d("confirmPay: totalSent: %s", BRWalletManager.getInstance().getTotalSent()); - Timber.d("confirmPay: request.amount: %s", request.amount); - Timber.d("confirmPay: total limit: %s", AuthManager.getInstance().getTotalLimit(ctx)); - Timber.d("confirmPay: limit: %s", BRKeyStore.getSpendLimit(ctx)); + Timber.d("timber: confirmPay: totalSent: %s", BRWalletManager.getInstance().getTotalSent()); + Timber.d("timber: confirmPay: request.amount: %s", request.amount); + Timber.d("timber: confirmPay: total limit: %s", AuthManager.getInstance().getTotalLimit(ctx)); + Timber.d("timber: confirmPay: limit: %s", BRKeyStore.getSpendLimit(ctx)); if (BRWalletManager.getInstance().getTotalSent() + request.amount > AuthManager.getInstance().getTotalLimit(ctx)) { forcePin = true; @@ -381,7 +381,7 @@ private boolean notEnoughForFee(PaymentItem paymentRequest) { } private static void showSpendNotAllowed(final Context app) { - Timber.d("showSpendNotAllowed"); + Timber.d("timber: showSpendNotAllowed"); ((Activity) app).runOnUiThread(new Runnable() { @Override public void run() { diff --git a/app/src/main/java/com/breadwallet/tools/security/BitcoinUrlHandler.java b/app/src/main/java/com/breadwallet/tools/security/BitcoinUrlHandler.java index e68223bdb..803dd0cd3 100644 --- a/app/src/main/java/com/breadwallet/tools/security/BitcoinUrlHandler.java +++ b/app/src/main/java/com/breadwallet/tools/security/BitcoinUrlHandler.java @@ -28,7 +28,7 @@ public class BitcoinUrlHandler { public static synchronized boolean processRequest(FragmentActivity app, String url) { if (url == null) { - Timber.d("processRequest: url is null"); + Timber.d("timber: processRequest: url is null"); return false; } diff --git a/app/src/main/java/com/breadwallet/tools/security/PostAuth.java b/app/src/main/java/com/breadwallet/tools/security/PostAuth.java index d6586bfff..c9141515d 100644 --- a/app/src/main/java/com/breadwallet/tools/security/PostAuth.java +++ b/app/src/main/java/com/breadwallet/tools/security/PostAuth.java @@ -63,7 +63,7 @@ public void onCreateWalletAuth(Activity app, boolean authAsked) { app.overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left); } else { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } @@ -83,7 +83,7 @@ public void onPhraseCheckAuth(Activity app, boolean authAsked) { cleanPhrase = new String(raw); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } @@ -101,7 +101,7 @@ public void onPhraseProveAuth(Activity app, boolean authAsked) { cleanPhrase = new String(BRKeyStore.getPhrase(app, BRConstants.PROVE_PHRASE_REQUEST)); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } @@ -127,7 +127,7 @@ public void onRecoverWalletAuth(Activity app, boolean authAsked) { app, BRConstants.PUT_PHRASE_RECOVERY_WALLET_REQUEST_CODE); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.e("%s: WARNING!!!! LOOP", new Object() { + Timber.e("timber:%s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } @@ -136,11 +136,12 @@ public void onRecoverWalletAuth(Activity app, boolean authAsked) { if (!success) { if (authAsked) { - Timber.d("onRecoverWalletAuth,!success && authAsked"); + Timber.d("timber: onRecoverWalletAuth,!success && authAsked"); } } else { if (phraseForKeyStore.length() != 0) { BRSharedPrefs.putPhraseWroteDown(app, true); + Timber.d("timber: BRSharedPrefs.putPhraseWroteDown was set to true"); bytePhrase = TypesConverter.getNullTerminatedPhrase(phraseForKeyStore.getBytes()); byte[] seed = BRWalletManager.getSeedFromPhrase(bytePhrase); byte[] authKey = BRWalletManager.getAuthPrivKeyForAPI(seed); @@ -173,7 +174,7 @@ public void onPublishTxAuth(final Context app, boolean authAsked) { rawSeed = BRKeyStore.getPhrase(app, BRConstants.PAY_REQUEST_CODE); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } @@ -185,12 +186,10 @@ public void onPublishTxAuth(final Context app, boolean authAsked) { if (seed.length != 0) { if (paymentItem != null && paymentItem.serializedTx != null) { byte[] txHash = walletManager.publishSerializedTransaction(paymentItem.serializedTx, seed); - Timber.d("onPublishTxAuth: txhash:" + Arrays.toString(txHash)); + Timber.d("timber: onPublishTxAuth: txhash:" + Arrays.toString(txHash)); if (Utils.isNullOrEmpty(txHash)) { - Timber.d("onPublishTxAuth: publishSerializedTransaction returned FALSE"); - //todo fix this -// BRWalletManager.getInstance().offerToChangeTheAmount(app, new PaymentItem(paymentRequest.addresses, paymentItem.serializedTx, paymentRequest.amount, null, paymentRequest.isPaymentRequest)); - } else { + Timber.d("timber: onPublishTxAuth: publishSerializedTransaction returned FALSE"); + } else { TxMetaData txMetaData = new TxMetaData(); txMetaData.comment = paymentItem.comment; KVStoreManager.getInstance().putTxMetaData(app, txMetaData, txHash); @@ -200,7 +199,7 @@ public void onPublishTxAuth(final Context app, boolean authAsked) { throw new NullPointerException("payment item is null"); } } else { - Timber.d("onPublishTxAuth: seed length is 0!"); + Timber.d("timber: onPublishTxAuth: seed length is 0!"); return; } } finally { @@ -215,14 +214,14 @@ public void onPaymentProtocolRequest(Activity app, boolean authAsked) { rawSeed = BRKeyStore.getPhrase(app, BRConstants.PAYMENT_PROTOCOL_REQUEST_CODE); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } return; } if (rawSeed == null || rawSeed.length < 10 || paymentRequest.serializedTx == null) { - Timber.d("onPaymentProtocolRequest() returned: rawSeed is malformed: %s", Arrays.toString(rawSeed)); + Timber.d("timber: onPaymentProtocolRequest() returned: rawSeed is malformed: %s", Arrays.toString(rawSeed)); return; } @@ -259,7 +258,7 @@ public void onCanaryCheck(final Activity app, boolean authAsked) { canary = BRKeyStore.getCanary(app, BRConstants.CANARY_REQUEST_CODE); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } @@ -271,7 +270,7 @@ public void onCanaryCheck(final Activity app, boolean authAsked) { phrase = BRKeyStore.getPhrase(app, BRConstants.CANARY_REQUEST_CODE); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } @@ -284,12 +283,12 @@ public void onCanaryCheck(final Activity app, boolean authAsked) { m.wipeKeyStore(app); m.wipeWalletButKeystore(app); } else { - Timber.d("onCanaryCheck: Canary wasn't there, but the phrase persists, adding canary to keystore."); + Timber.d("timber: onCanaryCheck: Canary wasn't there, but the phrase persists, adding canary to keystore."); try { BRKeyStore.putCanary(BRConstants.CANARY_STRING, app, 0); } catch (UserNotAuthenticatedException e) { if (authAsked) { - Timber.d("%s: WARNING!!!! LOOP", new Object() { + Timber.d("timber: %s: WARNING!!!! LOOP", new Object() { }.getClass().getEnclosingMethod().getName()); isStuckWithAuthLoop = true; } diff --git a/app/src/main/java/com/breadwallet/tools/security/SmartValidator.java b/app/src/main/java/com/breadwallet/tools/security/SmartValidator.java index 9b1cf13eb..d430db194 100644 --- a/app/src/main/java/com/breadwallet/tools/security/SmartValidator.java +++ b/app/src/main/java/com/breadwallet/tools/security/SmartValidator.java @@ -68,7 +68,7 @@ public static boolean checkFirstAddress(Activity app, byte[] mpk) { String addressFromPrefs = BRSharedPrefs.getFirstAddress(app); String generatedAddress = BRWalletManager.getFirstAddress(mpk); if (!addressFromPrefs.equalsIgnoreCase(generatedAddress) && addressFromPrefs.length() != 0 && generatedAddress.length() != 0) { - Timber.d("checkFirstAddress: WARNING, addresses don't match: Prefs:" + addressFromPrefs + ", gen:" + generatedAddress); + Timber.d("timber: checkFirstAddress: WARNING, addresses don't match: Prefs:" + addressFromPrefs + ", gen:" + generatedAddress); } return addressFromPrefs.equals(generatedAddress); } @@ -78,10 +78,10 @@ public static String cleanPaperKey(Context activity, String phraseToCheck) { } public static boolean isWordValid(Context ctx, String word) { - Timber.d("isWordValid: word:" + word + ":" + word.length()); + Timber.d("timber: isWordValid: word:" + word + ":" + word.length()); if (list == null) list = Bip39Reader.bip39List(ctx, null); String cleanWord = Bip39Reader.cleanWord(word); - Timber.d("isWordValid: cleanWord:" + cleanWord + ":" + cleanWord.length()); + Timber.d("timber: isWordValid: cleanWord:" + cleanWord + ":" + cleanWord.length()); return list.contains(cleanWord); } } diff --git a/app/src/main/java/com/breadwallet/tools/sqlite/BRSQLiteHelper.java b/app/src/main/java/com/breadwallet/tools/sqlite/BRSQLiteHelper.java index f381338ca..51e6c57ab 100644 --- a/app/src/main/java/com/breadwallet/tools/sqlite/BRSQLiteHelper.java +++ b/app/src/main/java/com/breadwallet/tools/sqlite/BRSQLiteHelper.java @@ -4,6 +4,8 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import java.util.Date; + import timber.log.Timber; public class BRSQLiteHelper extends SQLiteOpenHelper { @@ -21,7 +23,7 @@ public static BRSQLiteHelper getInstance(Context context) { } private static final String DATABASE_NAME = "loafwallet.db"; - private static final int DATABASE_VERSION = 12; + private static final int DATABASE_VERSION = 13; /** * MerkleBlock table @@ -91,8 +93,19 @@ public void onCreate(SQLiteDatabase database) { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Timber.e("Upgrading database from version " + oldVersion + " to " + + Timber.e("timber: Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); - onCreate(db); + + // Clear DB tables to enable Bech32 features + if (oldVersion == 12 && newVersion == 13) { + Timber.e("timber: Delete start %s", new Date().toString()); + db.execSQL("DELETE FROM " + MB_TABLE_NAME); + db.execSQL("DELETE FROM " + TX_TABLE_NAME); + db.execSQL("DELETE FROM " + PEER_TABLE_NAME); + db.execSQL("DELETE FROM " + CURRENCY_TABLE_NAME); + Timber.e("timber: Delete Finish %s", new Date().toString()); + + } } } diff --git a/app/src/main/java/com/breadwallet/tools/sqlite/MerkleBlockDataSource.java b/app/src/main/java/com/breadwallet/tools/sqlite/MerkleBlockDataSource.java index 3a1c3bbfc..b1af827a9 100644 --- a/app/src/main/java/com/breadwallet/tools/sqlite/MerkleBlockDataSource.java +++ b/app/src/main/java/com/breadwallet/tools/sqlite/MerkleBlockDataSource.java @@ -75,7 +75,7 @@ public void deleteMerkleBlock(BRMerkleBlockEntity merkleBlock) { try { database = openDatabase(); long id = merkleBlock.getId(); - Timber.d("MerkleBlock deleted with id: %s", id); + Timber.d("timber: MerkleBlock deleted with id: %s", id); database.delete(BRSQLiteHelper.MB_TABLE_NAME, BRSQLiteHelper.MB_COLUMN_ID + " = " + id, null); } finally { @@ -98,7 +98,7 @@ public List getAllMerkleBlocks() { merkleBlocks.add(merkleBlockEntity); cursor.moveToNext(); } - Timber.d("merkleBlocks: %s", merkleBlocks.size()); + Timber.d("timber: merkleBlocks: %s", merkleBlocks.size()); } finally { closeDatabase(); if (cursor != null) cursor.close(); diff --git a/app/src/main/java/com/breadwallet/tools/sqlite/PeerDataSource.java b/app/src/main/java/com/breadwallet/tools/sqlite/PeerDataSource.java index beca2cbe3..f45d5bf1b 100644 --- a/app/src/main/java/com/breadwallet/tools/sqlite/PeerDataSource.java +++ b/app/src/main/java/com/breadwallet/tools/sqlite/PeerDataSource.java @@ -52,7 +52,7 @@ public void putPeers(PeerEntity[] peerEntities) { database = openDatabase(); database.beginTransaction(); for (PeerEntity p : peerEntities) { - Timber.d("SQLite peer saved: %s", Arrays.toString(p.getPeerTimeStamp())); + Timber.d("timber: SQLite peer saved: %s", Arrays.toString(p.getPeerTimeStamp())); ContentValues values = new ContentValues(); values.put(BRSQLiteHelper.PEER_ADDRESS, p.getPeerAddress()); values.put(BRSQLiteHelper.PEER_PORT, p.getPeerPort()); @@ -74,7 +74,7 @@ public void deletePeer(BRPeerEntity peerEntity) { try { database = openDatabase(); long id = peerEntity.getId(); - Timber.d("Peer deleted with id: %s", id); + Timber.d("timber: Peer deleted with id: %s", id); database.delete(BRSQLiteHelper.PEER_TABLE_NAME, BRSQLiteHelper.PEER_COLUMN_ID + " = " + id, null); } finally { @@ -111,7 +111,7 @@ public List getAllPeers() { cursor.close(); closeDatabase(); } - Timber.d("peers: %s", peers.size()); + Timber.d("timber: peers: %s", peers.size()); return peers; } diff --git a/app/src/main/java/com/breadwallet/tools/sqlite/TransactionDataSource.java b/app/src/main/java/com/breadwallet/tools/sqlite/TransactionDataSource.java index 19fd77307..961967b02 100644 --- a/app/src/main/java/com/breadwallet/tools/sqlite/TransactionDataSource.java +++ b/app/src/main/java/com/breadwallet/tools/sqlite/TransactionDataSource.java @@ -131,7 +131,7 @@ private BRTransactionEntity cursorToTransaction(Cursor cursor) { public void updateTxBlockHeight(String hash, int blockHeight, int timeStamp) { try { database = openDatabase(); - Timber.d("transaction updated with id: %s", hash); + Timber.d("timber: transaction updated with id: %s", hash); String strFilter = "_id=\'" + hash + "\'"; ContentValues args = new ContentValues(); args.put(BRSQLiteHelper.TX_BLOCK_HEIGHT, blockHeight); @@ -146,7 +146,7 @@ public void updateTxBlockHeight(String hash, int blockHeight, int timeStamp) { public void deleteTxByHash(String hash) { try { database = openDatabase(); - Timber.d("transaction deleted with id: %s", hash); + Timber.d("timber: transaction deleted with id: %s", hash); database.delete(BRSQLiteHelper.TX_TABLE_NAME, BRSQLiteHelper.TX_COLUMN_ID + " = \'" + hash + "\'", null); } finally { diff --git a/app/src/main/java/com/breadwallet/tools/threads/BRExecutor.java b/app/src/main/java/com/breadwallet/tools/threads/BRExecutor.java index 6aeb022af..537f6f02b 100644 --- a/app/src/main/java/com/breadwallet/tools/threads/BRExecutor.java +++ b/app/src/main/java/com/breadwallet/tools/threads/BRExecutor.java @@ -130,6 +130,6 @@ public Executor forMainThreadTasks() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - Timber.d("rejectedExecution: "); + Timber.d("timber: rejectedExecution: "); } } \ No newline at end of file diff --git a/app/src/main/java/com/breadwallet/tools/threads/ImportPrivKeyTask.java b/app/src/main/java/com/breadwallet/tools/threads/ImportPrivKeyTask.java index 7362809fd..ac2568180 100644 --- a/app/src/main/java/com/breadwallet/tools/threads/ImportPrivKeyTask.java +++ b/app/src/main/java/com/breadwallet/tools/threads/ImportPrivKeyTask.java @@ -36,7 +36,7 @@ public class ImportPrivKeyTask extends AsyncTask { public ImportPrivKeyTask(Activity activity) { app = activity; - UNSPENT_URL = BuildConfig.LITECOIN_TESTNET ? "https://testnet.litecore.io/api/addrs/" : "https://insight.litecore.io/api/addrs/"; + UNSPENT_URL = BuildConfig.LITECOIN_TESTNET ? "https://chain.so/tx/LTCTEST/" : "https://blockchair.com/litecoin/transaction/"; } @Override diff --git a/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolPostPaymentTask.java b/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolPostPaymentTask.java index 8469c615f..fa0e14777 100644 --- a/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolPostPaymentTask.java +++ b/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolPostPaymentTask.java @@ -65,12 +65,12 @@ protected String doInBackground(String... uri) { in = urlConnection.getInputStream(); if (in == null) { - Timber.i("The inputStream is null!"); + Timber.i("timber: The inputStream is null!"); return null; } byte[] serializedBytes = BytesUtil.readBytesFromStream(in); if (serializedBytes == null || serializedBytes.length == 0) { - Timber.d("serializedBytes are null!!!"); + Timber.d("timber: serializedBytes are null!!!"); return null; } diff --git a/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolTask.java b/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolTask.java index e3789aa35..308704dd1 100644 --- a/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolTask.java +++ b/app/src/main/java/com/breadwallet/tools/threads/PaymentProtocolTask.java @@ -47,7 +47,7 @@ protected String doInBackground(String... params) { app = (Activity) BreadApp.getBreadContext(); InputStream in; try { - Timber.d("the uri: %s", params[0]); + Timber.d("timber: the uri: %s", params[0]); URL url = new URL(params[0]); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestProperty("Accept", "application/litecoin-paymentrequest"); @@ -57,19 +57,19 @@ protected String doInBackground(String... params) { in = urlConnection.getInputStream(); if (in == null) { - Timber.i("The inputStream is null!"); + Timber.i("timber: The inputStream is null!"); return null; } byte[] serializedBytes = BytesUtil.readBytesFromStream(in); if (serializedBytes == null || serializedBytes.length == 0) { - Timber.i("serializedBytes are null!!!"); + Timber.i("timber: serializedBytes are null!!!"); return null; } paymentRequest = BitcoinUrlHandler.parsePaymentRequest(serializedBytes); if (paymentRequest == null || paymentRequest.error == PaymentRequestWrapper.INVALID_REQUEST_ERROR) { - Timber.i("paymentRequest is null!!!"); + Timber.i("timber: paymentRequest is null!!!"); BRDialog.showCustomDialog(app, "", app.getString(R.string.Send_remoteRequestError), app.getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @Override public void onClick(BRDialogView brDialogView) { @@ -79,7 +79,7 @@ public void onClick(BRDialogView brDialogView) { paymentRequest = null; return null; } else if (paymentRequest.error == PaymentRequestWrapper.INSUFFICIENT_FUNDS_ERROR) { - Timber.i("insufficient amount!!!"); + Timber.i("timber: insufficient amount!!!"); BRDialog.showCustomDialog(app, "", app.getString(R.string.Alerts_sendFailure), app.getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @Override public void onClick(BRDialogView brDialogView) { @@ -89,7 +89,7 @@ public void onClick(BRDialogView brDialogView) { paymentRequest = null; return null; } else if (paymentRequest.error == PaymentRequestWrapper.SIGNING_FAILED_ERROR) { - Timber.i("failed to sign tx!!! \n insufficient amount!!!"); + Timber.i("timber: failed to sign tx!!! \n insufficient amount!!!"); BRDialog.showCustomDialog(app, "", app.getString(R.string.Import_Error_signing), app.getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @Override public void onClick(BRDialogView brDialogView) { @@ -99,7 +99,7 @@ public void onClick(BRDialogView brDialogView) { paymentRequest = null; return null; } else if (paymentRequest.error == PaymentRequestWrapper.REQUEST_TOO_LONG_ERROR) { - Timber.i("failed to sign tx!!!"); + Timber.i("timber: failed to sign tx!!!"); BRDialog.showCustomDialog(app, app.getString(R.string.PaymentProtocol_Errors_badPaymentRequest), "Too long", app.getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @Override public void onClick(BRDialogView brDialogView) { @@ -109,7 +109,7 @@ public void onClick(BRDialogView brDialogView) { paymentRequest = null; return null; } else if (paymentRequest.error == PaymentRequestWrapper.AMOUNTS_ERROR) { - Timber.i("failed to sign tx!!!"); + Timber.i("timber: failed to sign tx!!!"); BRDialog.showCustomDialog(app, "", app.getString(R.string.PaymentProtocol_Errors_badPaymentRequest), app.getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @Override public void onClick(BRDialogView brDialogView) { @@ -148,7 +148,7 @@ public void onClick(BRDialogView brDialogView) { "amount", String.valueOf(paymentRequest.amount)); //end logging if (paymentRequest.expires != 0 && paymentRequest.time > paymentRequest.expires) { - Timber.i("Request is expired"); + Timber.i("timber: Request is expired"); if (app != null) BRDialog.showCustomDialog(app, app.getString(R.string.Alert_error), app.getString(R.string.PaymentProtocol_Errors_requestExpired), app.getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @Override @@ -190,7 +190,7 @@ public void onClick(BRDialogView brDialogView) { }, null, null, 0); paymentRequest = null; } else if (e instanceof CertificateChainNotFound) { - Timber.e(e, "No certificates!"); + Timber.e(e, "timber:No certificates!"); } else { if (app != null) BRDialog.showCustomDialog(app, app.getString(R.string.JailbreakWarnings_title), app.getString(R.string.PaymentProtocol_Errors_badPaymentRequest) + ":" + e.getMessage(), app.getString(R.string.Button_ok), null, new BRDialogView.BROnClickListener() { @@ -329,7 +329,7 @@ public void onComplete() { @Override public void onCancel() { - Timber.d("onCancel: "); + Timber.d("timber: onCancel: "); } }); } diff --git a/app/src/main/java/com/breadwallet/tools/util/BRConstants.java b/app/src/main/java/com/breadwallet/tools/util/BRConstants.java index 9fe61048b..e465c236c 100644 --- a/app/src/main/java/com/breadwallet/tools/util/BRConstants.java +++ b/app/src/main/java/com/breadwallet/tools/util/BRConstants.java @@ -101,7 +101,7 @@ private BRConstants() { public static final String INSTAGRAM_LINK = "https://www.instagram.com/litewallet.app"; public static final String WEB_LINK = "https://litewallet.io"; - public static final String TOS_LINK = "https://litewallet.io/privacy/policy.html"; + public static final String TOS_LINK = "https://litewallet.io/privacy"; public static String CUSTOMER_SUPPORT_LINK = "https://support.litewallet.io"; public static String BITREFILL_AFFILIATE_LINK = "https://www.bitrefill.com/"; @@ -114,8 +114,7 @@ private BRConstants() { public static final String LW_API_HOST = "https://api-prod.lite-wallet.org"; public static final String LW_BACKUP_API_HOST = "https://api-dev.lite-wallet.org"; - public static final String BLOCK_EXPLORER_BASE_URL = BuildConfig.LITECOIN_TESTNET ? "https://testnet.litecore.io/tx/" : "https://insight.litecore.io/tx/"; - + public static final String BLOCK_EXPLORER_BASE_URL = BuildConfig.LITECOIN_TESTNET ? "https://chain.so/tx/LTCTEST/" : "https://blockchair.com/litecoin/transaction/"; public static final String RESET_CARD_PWD_LINK = "https://litecoin.dashboard.getblockcard.com/password/forgot"; @@ -144,6 +143,7 @@ private BRConstants() { public static final String _20201121_FRIA = "failed_resolve_IPFS_address"; public static final String _20230113_BAC = "backup_apiserver_called"; + public static final String _20230407_DCS = "did_complete_sync"; ///Dev: These events not yet used public static final String _20200207_DTHB = "did_tap_header_balance"; public static final String _20210405_TAWDF = "ternio_api_wallet_details_failure"; @@ -190,7 +190,8 @@ private BRConstants() { _20210804_TAULO, _20210427_HCIEEH, _20220822_UTOU, - _20230131_NENR + _20230131_NENR, + _20230407_DCS }) public @interface Event { } @@ -204,4 +205,11 @@ private BRConstants() { public static final String SUCCESS_TIME = "success_time"; public static final String FAILURE_TIME = "failure_time"; public static final String ERROR = "error"; + + /** + * False Positive rate keys + */ + public static final float FALSE_POS_RATE_LOW_PRIVACY = 0.00005F; + public static final float FALSE_POS_RATE_SEMI_PRIVACY = 0.00008F; + public static final float FALSE_POS_RATE_ANONYMOUS = 0.0005F; } diff --git a/app/src/main/java/com/breadwallet/tools/util/Utils.java b/app/src/main/java/com/breadwallet/tools/util/Utils.java index 703a10a8a..350bf88c0 100644 --- a/app/src/main/java/com/breadwallet/tools/util/Utils.java +++ b/app/src/main/java/com/breadwallet/tools/util/Utils.java @@ -57,11 +57,11 @@ public static boolean isUsingCustomInputMethod(Activity context) { @SuppressWarnings("deprecation") public static void printPhoneSpecs() { - Timber.d("***************************PHONE SPECS***************************"); - Timber.d("* screen X: %d , screen Y: %s", IntroActivity.screenParametersPoint.x, IntroActivity.screenParametersPoint.y); - Timber.d("* Build.CPU_ABI: %s", Build.CPU_ABI); - Timber.d("* maxMemory:%s", Runtime.getRuntime().maxMemory()); - Timber.d("----------------------------PHONE SPECS----------------------------"); + Timber.d("timber: ***************************PHONE SPECS***************************"); + Timber.d("timber: * screen X: %d , screen Y: %s", IntroActivity.screenParametersPoint.x, IntroActivity.screenParametersPoint.y); + Timber.d("timber: * Build.CPU_ABI: %s", Build.CPU_ABI); + Timber.d("timber: * maxMemory:%s", Runtime.getRuntime().maxMemory()); + Timber.d("timber: ----------------------------PHONE SPECS----------------------------"); } public static boolean isEmulatorOrDebug(Context app) { diff --git a/app/src/main/java/com/breadwallet/wallet/BRPeerManager.java b/app/src/main/java/com/breadwallet/wallet/BRPeerManager.java index 27b0a5f95..f68347742 100644 --- a/app/src/main/java/com/breadwallet/wallet/BRPeerManager.java +++ b/app/src/main/java/com/breadwallet/wallet/BRPeerManager.java @@ -1,22 +1,28 @@ package com.breadwallet.wallet; +import static java.lang.Math.abs; + import android.content.Context; import androidx.annotation.WorkerThread; +import android.os.Bundle; import android.util.Log; import com.breadwallet.BreadApp; import com.breadwallet.presenter.entities.BlockEntity; import com.breadwallet.presenter.entities.PeerEntity; +import com.breadwallet.tools.manager.AnalyticsManager; import com.breadwallet.tools.manager.BRSharedPrefs; import com.breadwallet.tools.manager.SyncManager; import com.breadwallet.tools.sqlite.MerkleBlockDataSource; import com.breadwallet.tools.sqlite.PeerDataSource; import com.breadwallet.tools.threads.BRExecutor; +import com.breadwallet.tools.util.BRConstants; import com.breadwallet.tools.util.TrustedNode; import java.util.ArrayList; +import java.util.Date; import java.util.List; import timber.log.Timber; @@ -27,6 +33,9 @@ public class BRPeerManager { private static final List statusUpdateListeners = new ArrayList<>(); private static OnSyncSucceeded onSyncFinished; + static long syncStartDate = new Date().getTime(); + static long syncCompletedDate = new Date().getTime(); + private BRPeerManager() { } @@ -49,8 +58,9 @@ public static BRPeerManager getInstance() { */ public static void syncStarted() { - Timber.d("syncStarted: %s", Thread.currentThread().getName()); -// BRPeerManager.getInstance().refreshConnection(); + syncStartDate = new Date().getTime(); + long syncCompletedDate = new Date().getTime(); + Timber.d("timber: syncStarted (unix epoch ms): %s startDate: %s", Thread.currentThread().getName(), syncStartDate); Context ctx = BreadApp.getBreadContext(); int startHeight = BRSharedPrefs.getStartHeight(ctx); int lastHeight = BRSharedPrefs.getLastBlockHeight(ctx); @@ -59,13 +69,29 @@ public static void syncStarted() { } public static void syncSucceeded() { - Timber.d("syncSucceeded"); + syncCompletedDate = new Date().getTime(); + Timber.d("timber: sync started(unix epoch ms): %s, completed(unix epoch ms): %s", syncStartDate, syncCompletedDate); final Context app = BreadApp.getBreadContext(); if (app == null) return; BRSharedPrefs.putLastSyncTime(app, System.currentTimeMillis()); SyncManager.getInstance().updateAlarms(app); BRSharedPrefs.putAllowSpend(app, true); SyncManager.getInstance().stopSyncingProgressThread(); + + long syncTimeElapsed = abs(syncCompletedDate - syncStartDate) / 1000; + float userFalsePositiveRate = BRSharedPrefs.getFalsePositivesRate(app); + Timber.d("timber: syncTimeElapsed duration (seconds): %s", syncTimeElapsed); + + /// Need to filter partial syncs to properly track averages + /// this will filter out any syncs from 19 minutes to 120 minutes + /// The assumption is daily normal syncs are not problematic and quick + /// and any syncs past 120 minutes are errorneous in terms of data collection and testing + if (syncTimeElapsed > 19 * 60 && syncTimeElapsed > 120 * 60 ) { + Bundle params = new Bundle(); + params.putLong("sync_time_elapsed", syncTimeElapsed); + params.putFloat("user_preferred_fprate", userFalsePositiveRate); + AnalyticsManager.logCustomEventWithParams(BRConstants._20230407_DCS, params); + } BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override public void run() { @@ -76,18 +102,18 @@ public void run() { } public static void syncFailed() { - Timber.d("syncFailed"); + Timber.d("timber: syncFailed"); SyncManager.getInstance().stopSyncingProgressThread(); Context ctx = BreadApp.getBreadContext(); if (ctx == null) return; - Timber.d("Network Not Available, showing not connected bar"); + Timber.d("timber: Network Not Available, showing not connected bar"); SyncManager.getInstance().stopSyncingProgressThread(); if (onSyncFinished != null) onSyncFinished.onFinished(); } public static void txStatusUpdate() { - Timber.d("txStatusUpdate"); + Timber.d("timber: txStatusUpdate"); for (OnTxStatusUpdate listener : statusUpdateListeners) { if (listener != null) listener.onStatusUpdate(); @@ -101,7 +127,7 @@ public void run() { } public static void saveBlocks(final BlockEntity[] blockEntities, final boolean replace) { - Timber.d("saveBlocks: %s", blockEntities.length); + Timber.d("timber: saveBlocks: %s", blockEntities.length); final Context ctx = BreadApp.getBreadContext(); if (ctx == null) return; @@ -116,7 +142,7 @@ public void run() { } public static void savePeers(final PeerEntity[] peerEntities, final boolean replace) { - Timber.d("savePeers: %s", peerEntities.length); + Timber.d("timber: savePeers: %s", peerEntities.length); final Context ctx = BreadApp.getBreadContext(); if (ctx == null) return; BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @@ -129,12 +155,12 @@ public void run() { } public static boolean networkIsReachable() { - Timber.d("networkIsReachable"); + Timber.d("timber: networkIsReachable"); return BRWalletManager.getInstance().isNetworkAvailable(BreadApp.getBreadContext()); } public static void deleteBlocks() { - Timber.d("deleteBlocks"); + Timber.d("timber: deleteBlocks"); final Context ctx = BreadApp.getBreadContext(); if (ctx == null) return; BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @@ -146,7 +172,7 @@ public void run() { } public static void deletePeers() { - Timber.d("deletePeers"); + Timber.d("timber: deletePeers"); final Context ctx = BreadApp.getBreadContext(); if (ctx == null) return; BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @@ -163,9 +189,9 @@ public void updateFixedPeer(Context ctx) { int port = TrustedNode.getNodePort(node); boolean success = setFixedPeer(host, port); if (!success) { - Timber.i("updateFixedPeer: Failed to updateFixedPeer with input: %s", node); + Timber.i("timber: updateFixedPeer: Failed to updateFixedPeer with input: %s", node); } else { - Timber.d("updateFixedPeer: succeeded"); + Timber.d("timber: updateFixedPeer: succeeded"); } connect(); } @@ -209,7 +235,7 @@ public static void updateLastBlockHeight(int blockHeight) { public native String getCurrentPeerName(); - public native void create(int earliestKeyTime, int blockCount, int peerCount); + public native void create(int earliestKeyTime, int blockCount, int peerCount, double fpRate); public native void connect(); diff --git a/app/src/main/java/com/breadwallet/wallet/BRWalletManager.java b/app/src/main/java/com/breadwallet/wallet/BRWalletManager.java index 8a88f3d32..22aac2f7e 100644 --- a/app/src/main/java/com/breadwallet/wallet/BRWalletManager.java +++ b/app/src/main/java/com/breadwallet/wallet/BRWalletManager.java @@ -19,6 +19,7 @@ import android.widget.Toast; import androidx.annotation.WorkerThread; +import androidx.fragment.app.FragmentActivity; import com.breadwallet.BreadApp; import com.breadwallet.R; @@ -37,7 +38,6 @@ import com.breadwallet.tools.animation.BRDialog; import com.breadwallet.tools.animation.SpringAnimator; import com.breadwallet.tools.manager.AnalyticsManager; -import com.google.firebase.analytics.FirebaseAnalytics; import com.breadwallet.tools.manager.BRNotificationManager; import com.breadwallet.tools.manager.BRSharedPrefs; import com.breadwallet.tools.manager.FeeManager; @@ -54,7 +54,8 @@ import com.breadwallet.tools.util.TypesConverter; import com.breadwallet.tools.util.Utils; import com.platform.entities.WalletInfo; -import com.platform.tools.KVStoreManager; + +import org.jetbrains.annotations.Nullable; import java.math.BigDecimal; import java.security.SecureRandom; @@ -72,7 +73,7 @@ public class BRWalletManager { public void setBalance(final Context context, long balance) { if (context == null) { - Timber.i("setBalance: FAILED TO SET THE BALANCE NULL context"); + Timber.i("timber: setBalance: FAILED TO SET THE BALANCE NULL context"); return; } BRSharedPrefs.putCatchedBalance(context, balance); @@ -88,7 +89,7 @@ public void refreshBalance(Activity app) { if (nativeBalance != -1) { setBalance(app, nativeBalance); } else { - Timber.i("UpdateUI, nativeBalance is -1 meaning _wallet was null!"); + Timber.i("timber: UpdateUI, nativeBalance is -1 meaning _wallet was null!"); } } @@ -180,7 +181,7 @@ public void run() { } public boolean wipeKeyStore(Context context) { - Timber.d("wipeKeyStore"); + Timber.d("timber: wipeKeyStore"); return BRKeyStore.resetWalletKeyStore(context); } @@ -229,7 +230,7 @@ public boolean isNetworkAvailable(Context ctx) { public static boolean refreshAddress(Context ctx) { String address = getReceiveAddress(); if (Utils.isNullOrEmpty(address)) { - Timber.d("refreshAddress: WARNING, retrieved address:%s", address); + Timber.d("timber: refreshAddress: WARNING, retrieved address:%s", address); return false; } BRSharedPrefs.putReceiveAddress(ctx, address); @@ -237,10 +238,11 @@ public static boolean refreshAddress(Context ctx) { } public void wipeWalletButKeystore(final Context ctx) { - Timber.d("wipeWalletButKeystore"); + Timber.d("timber: wipeWalletButKeystore"); BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override public void run() { + Timber.d("timber: Running peerManagerFreeEverything"); BRPeerManager.getInstance().peerManagerFreeEverything(); walletFreeEverything(); TransactionDataSource.getInstance(ctx).deleteAllTransactions(); @@ -259,7 +261,7 @@ public void wipeAll(Context app) { public boolean confirmSweep(final Context ctx, final String privKey) { if (ctx == null) return false; if (isValidBitcoinBIP38Key(privKey)) { - Timber.d("isValidBitcoinBIP38Key true"); + Timber.d("timber: isValidBitcoinBIP38Key true"); ((Activity) ctx).runOnUiThread(new Runnable() { @Override public void run() { @@ -293,17 +295,17 @@ public void run() { } }); if (editText == null) { - Timber.d("onClick: edit text is null!"); + Timber.d("timber: onClick: edit text is null!"); return; } final String pass = editText.getText().toString(); - Timber.d("onClick: before"); + Timber.d("timber: onClick: before"); BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override public void run() { String decryptedKey = decryptBip38Key(privKey, pass); - Timber.d("onClick: after"); + Timber.d("timber: onClick: after"); if (decryptedKey.equals("")) { SpringAnimator.springView(input); @@ -328,11 +330,11 @@ public void onClick(DialogInterface dialog, int which) { }); return true; } else if (isValidBitcoinPrivateKey(privKey)) { - Timber.d("isValidBitcoinPrivateKey true"); + Timber.d("timber: isValidBitcoinPrivateKey true"); new ImportPrivKeyTask(((Activity) ctx)).execute(privKey); return true; } else { - Timber.d("confirmSweep: !isValidBitcoinPrivateKey && !isValidBitcoinBIP38Key"); + Timber.d("timber: confirmSweep: !isValidBitcoinPrivateKey && !isValidBitcoinBIP38Key"); return false; } } @@ -342,7 +344,7 @@ public void onClick(DialogInterface dialog, int which) { * Wallet callbacks */ public static void publishCallback(final String message, final int error, byte[] txHash) { - Timber.d("publishCallback: " + message + ", err:" + error + ", txHash: " + Arrays.toString(txHash)); + Timber.d("timber: publishCallback: " + message + ", err:" + error + ", txHash: " + Arrays.toString(txHash)); final Context app = BreadApp.getBreadContext(); BRExecutor.getInstance().forMainThreadTasks().execute(new Runnable() { @Override @@ -367,14 +369,14 @@ public void onComplete() { } public static void onBalanceChanged(final long balance) { - Timber.d("onBalanceChanged: " + balance); + Timber.d("timber: onBalanceChanged: " + balance); Context app = BreadApp.getBreadContext(); BRWalletManager.getInstance().setBalance(app, balance); } public static void onTxAdded(byte[] tx, int blockHeight, long timestamp, final long amount, String hash) { - Timber.d("onTxAdded: " + String.format("tx.length: %d, blockHeight: %d, timestamp: %d, amount: %d, hash: %s", tx.length, blockHeight, timestamp, amount, hash)); + Timber.d("timber: onTxAdded: " + String.format("tx.length: %d, blockHeight: %d, timestamp: %d, amount: %d, hash: %s", tx.length, blockHeight, timestamp, amount, hash)); final Context ctx = BreadApp.getBreadContext(); if (amount > 0) { @@ -392,7 +394,7 @@ public void run() { if (ctx != null) TransactionDataSource.getInstance(ctx).putTransaction(new BRTransactionEntity(tx, blockHeight, timestamp, hash)); else - Timber.i("onTxAdded: ctx is null!"); + Timber.i("timber: onTxAdded: ctx is null!"); } private static void showToastWithMessage(Context ctx, final String message) { @@ -423,28 +425,28 @@ public void run() { } else { - Timber.i("showToastWithMessage: failed, ctx is null"); + Timber.i("timber: showToastWithMessage: failed, ctx is null"); } } public static void onTxUpdated(String hash, int blockHeight, int timeStamp) { - Timber.d("onTxUpdated: " + String.format("hash: %s, blockHeight: %d, timestamp: %d", hash, blockHeight, timeStamp)); + Timber.d("timber: onTxUpdated: " + String.format("hash: %s, blockHeight: %d, timestamp: %d", hash, blockHeight, timeStamp)); Context ctx = BreadApp.getBreadContext(); if (ctx != null) { TransactionDataSource.getInstance(ctx).updateTxBlockHeight(hash, blockHeight, timeStamp); } else { - Timber.i("onTxUpdated: Failed, ctx is null"); + Timber.i("timber: onTxUpdated: Failed, ctx is null"); } } public static void onTxDeleted(String hash, int notifyUser, final int recommendRescan) { - Timber.d("onTxDeleted: " + String.format("hash: %s, notifyUser: %d, recommendRescan: %d", hash, notifyUser, recommendRescan)); + Timber.d("timber: onTxDeleted: " + String.format("hash: %s, notifyUser: %d, recommendRescan: %d", hash, notifyUser, recommendRescan)); final Context ctx = BreadApp.getBreadContext(); if (ctx != null) { BRSharedPrefs.putScanRecommended(ctx, true); } else { - Timber.i("onTxDeleted: Failed! ctx is null"); + Timber.i("timber: onTxDeleted: Failed! ctx is null"); } } @@ -485,75 +487,81 @@ public void initWallet(final Context ctx) { itInitiatingWallet = true; try { - Timber.d("initWallet:%s", Thread.currentThread().getName()); + Timber.d("timber: initWallet:%s", Thread.currentThread().getName()); if (ctx == null) { - Timber.i("initWallet: ctx is null"); + Timber.i("timber: initWallet: ctx is null"); return; } BRWalletManager m = BRWalletManager.getInstance(); final BRPeerManager pm = BRPeerManager.getInstance(); + double fpRate = BRSharedPrefs.getFalsePositivesRate(ctx); + + Timber.d("timber: Showing seed fragment"); - if (!m.isCreated()) { - List transactions = TransactionDataSource.getInstance(ctx).getAllTransactions(); - int transactionsCount = transactions.size(); - if (transactionsCount > 0) { - m.createTxArrayWithCount(transactionsCount); - for (BRTransactionEntity entity : transactions) { - m.putTransaction(entity.getBuff(), entity.getBlockheight(), entity.getTimestamp()); + if (!m.isCreated()) { + List transactions = TransactionDataSource.getInstance(ctx).getAllTransactions(); + int transactionsCount = transactions.size(); + if (transactionsCount > 0) { + m.createTxArrayWithCount(transactionsCount); + for (BRTransactionEntity entity : transactions) { + m.putTransaction(entity.getBuff(), entity.getBlockheight(), entity.getTimestamp()); + } } - } - byte[] pubkeyEncoded = BRKeyStore.getMasterPublicKey(ctx); - if (Utils.isNullOrEmpty(pubkeyEncoded)) { - Timber.i("initWallet: pubkey is missing"); - return; - } - //Save the first address for future check - m.createWallet(transactionsCount, pubkeyEncoded); - String firstAddress = BRWalletManager.getFirstAddress(pubkeyEncoded); - BRSharedPrefs.putFirstAddress(ctx, firstAddress); - FeeManager feeManager = FeeManager.getInstance(); - if (feeManager.isRegularFee()) { - Fee fees = feeManager.getFees(); - BRWalletManager.getInstance().setFeePerKb(fees.regular); + byte[] pubkeyEncoded = BRKeyStore.getMasterPublicKey(ctx); + if (Utils.isNullOrEmpty(pubkeyEncoded)) { + Timber.i("timber: initWallet: pubkey is missing"); + return; + } + //Save the first address for future check + m.createWallet(transactionsCount, pubkeyEncoded); + String firstAddress = BRWalletManager.getFirstAddress(pubkeyEncoded); + BRSharedPrefs.putFirstAddress(ctx, firstAddress); + FeeManager feeManager = FeeManager.getInstance(); + if (feeManager.isRegularFee()) { + Fee fees = feeManager.getFees(); + BRWalletManager.getInstance().setFeePerKb(fees.regular); + } } - } - if (!pm.isCreated()) { - List blocks = MerkleBlockDataSource.getInstance(ctx).getAllMerkleBlocks(); - List peers = PeerDataSource.getInstance(ctx).getAllPeers(); - final int blocksCount = blocks.size(); - final int peersCount = peers.size(); - if (blocksCount > 0) { - pm.createBlockArrayWithCount(blocksCount); - for (BRMerkleBlockEntity entity : blocks) { - pm.putBlock(entity.getBuff(), entity.getBlockHeight()); + if (!pm.isCreated()) { + List blocks = MerkleBlockDataSource.getInstance(ctx).getAllMerkleBlocks(); + List peers = PeerDataSource.getInstance(ctx).getAllPeers(); + final int blocksCount = blocks.size(); + final int peersCount = peers.size(); + if (blocksCount > 0) { + pm.createBlockArrayWithCount(blocksCount); + for (BRMerkleBlockEntity entity : blocks) { + pm.putBlock(entity.getBuff(), entity.getBlockHeight()); + } } - } - if (peersCount > 0) { - pm.createPeerArrayWithCount(peersCount); - for (BRPeerEntity entity : peers) { - pm.putPeer(entity.getAddress(), entity.getPort(), entity.getTimeStamp()); + if (peersCount > 0) { + pm.createPeerArrayWithCount(peersCount); + for (BRPeerEntity entity : peers) { + pm.putPeer(entity.getAddress(), entity.getPort(), entity.getTimeStamp()); + } } + Timber.d("timber: blocksCount before connecting: %s", blocksCount); + Timber.d("timber: peersCount before connecting: %s", peersCount); + + int walletTime = BRKeyStore.getWalletCreationTime(ctx); + + Timber.d("timber: initWallet: walletTime: %s user preferred fpRate: %f", walletTime, fpRate); + pm.create(walletTime, blocksCount, peersCount, fpRate); + BRPeerManager.getInstance().updateFixedPeer(ctx); } - Timber.d("blocksCount before connecting: %s", blocksCount); - Timber.d("peersCount before connecting: %s", peersCount); - int walletTime = BRKeyStore.getWalletCreationTime(ctx); + pm.connect(); + if (BRSharedPrefs.getStartHeight(ctx) == 0) { + BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { + @Override + public void run() { + BRSharedPrefs.putStartHeight(ctx, BRPeerManager.getCurrentBlockHeight()); + } + }); + } - Timber.d("initWallet: walletTime: %s", walletTime); - pm.create(walletTime, blocksCount, peersCount); - BRPeerManager.getInstance().updateFixedPeer(ctx); - } - pm.connect(); - if (BRSharedPrefs.getStartHeight(ctx) == 0) - BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { - @Override - public void run() { - BRSharedPrefs.putStartHeight(ctx, BRPeerManager.getCurrentBlockHeight()); - } - }); } finally { itInitiatingWallet = false; } @@ -568,6 +576,16 @@ public void removeListener(OnBalanceChanged listener) { balanceListeners.remove(listener); } + public String getSeedPhrase(Context context) { + byte[] phraseBytes; + try { + phraseBytes = BRKeyStore.getPhrase(context, BRConstants.PUT_PHRASE_NEW_WALLET_REQUEST_CODE); + } catch (UserNotAuthenticatedException e) { + phraseBytes = new byte[0]; + } + return new String(phraseBytes); + } + public interface OnBalanceChanged { void onBalanceChanged(long balance); } diff --git a/app/src/main/java/com/platform/APIClient.java b/app/src/main/java/com/platform/APIClient.java index ce1ad887c..40befa88c 100644 --- a/app/src/main/java/com/platform/APIClient.java +++ b/app/src/main/java/com/platform/APIClient.java @@ -113,7 +113,7 @@ public Response sendRequest(Request locRequest, boolean needsAuth, int retryCoun byte[] data = new byte[0]; try { OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).connectTimeout(60, TimeUnit.SECONDS)/*.addInterceptor(new LoggingInterceptor())*/.build(); - Timber.d("sendRequest: headers for : %s \n %s", request.url(), request.headers()); + Timber.d("timber: sendRequest: headers for : %s \n %s", request.url(), request.headers()); String agent = Utils.getAgentString(ctx, "OkHttp/3.4.1"); request = request.newBuilder().header("User-agent", agent).build(); response = client.newCall(request).execute(); @@ -127,11 +127,11 @@ public Response sendRequest(Request locRequest, boolean needsAuth, int retryCoun String newLocation = request.url().scheme() + "://" + request.url().host() + response.header("location"); Uri newUri = Uri.parse(newLocation); if (newUri == null) { - Timber.d("sendRequest: redirect uri is null"); + Timber.d("timber: sendRequest: redirect uri is null"); } else if (!newUri.getHost().equalsIgnoreCase(BreadApp.HOST) || !newUri.getScheme().equalsIgnoreCase(PROTO)) { - Timber.d("sendRequest: WARNING: redirect is NOT safe: %s", newLocation); + Timber.d("timber: sendRequest: WARNING: redirect is NOT safe: %s", newLocation); } else { - Timber.d("redirecting: %s >>> %s", request.url(), newLocation); + Timber.d("timber: redirecting: %s >>> %s", request.url(), newLocation); response.close(); return sendRequest(new Request.Builder().url(newLocation).get().build(), needsAuth, 0); } @@ -143,11 +143,11 @@ public Response sendRequest(Request locRequest, boolean needsAuth, int retryCoun } if (response.header("content-encoding") != null && response.header("content-encoding").equalsIgnoreCase("gzip")) { - Timber.d("sendRequest: the content is gzip, unzipping"); + Timber.d("timber: sendRequest: the content is gzip, unzipping"); byte[] decompressed = gZipExtract(data); postReqBody = ResponseBody.create(null, decompressed); try { - Timber.d("sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), + Timber.d("timber: sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), request.url(), response.code(), response.message(), new String(decompressed, "utf-8")); } catch (UnsupportedEncodingException e) { Timber.e(e); @@ -155,7 +155,7 @@ public Response sendRequest(Request locRequest, boolean needsAuth, int retryCoun return response.newBuilder().body(postReqBody).build(); } else { try { - Timber.d("sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), + Timber.d("timber: sendRequest: (%s)%s, code (%d), mess (%s), body (%s)", request.method(), request.url(), response.code(), response.message(), new String(data, "utf-8")); } catch (UnsupportedEncodingException e) { Timber.e(e); @@ -174,7 +174,7 @@ public String buildUrl(String path) { private void itemFinished() { int items = itemsLeftToUpdate.incrementAndGet(); if (items >= 4) { - Timber.d("PLATFORM ALL UPDATED: %s", items); + Timber.d("timber: PLATFORM ALL UPDATED: %s", items); platformUpdating = false; itemsLeftToUpdate.set(0); } diff --git a/app/src/main/java/com/platform/kvstore/RemoteKVStore.java b/app/src/main/java/com/platform/kvstore/RemoteKVStore.java index b5ebeda5a..9fc68064c 100644 --- a/app/src/main/java/com/platform/kvstore/RemoteKVStore.java +++ b/app/src/main/java/com/platform/kvstore/RemoteKVStore.java @@ -48,12 +48,12 @@ public CompletionObject ver(String key) { res = apiClient.sendRequest(request, true, retryCount); if (res == null) { - Timber.i("ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); return new CompletionObject(0, 0, unknown); } if (!res.isSuccessful()) { - Timber.i("ver: [KV] PUT key=" + key + ", err=" + (res.code())); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err=" + (res.code())); return new CompletionObject(0, 0, unknown); } v = extractVersion(res); @@ -83,12 +83,12 @@ public CompletionObject put(String key, byte[] value, long version) { try { res = apiClient.sendRequest(request, true, retryCount); if (res == null) { - Timber.i("ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); return new CompletionObject(0, 0, unknown); } if (!res.isSuccessful()) { - Timber.i("ver: [KV] PUT key=" + key + ", err=" + (res.code())); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err=" + (res.code())); return new CompletionObject(0, 0, unknown); } v = extractVersion(res); @@ -114,12 +114,12 @@ public CompletionObject del(String key, long version) { try { res = apiClient.sendRequest(request, true, retryCount); if (res == null) { - Timber.i("ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); return new CompletionObject(0, 0, unknown); } if (!res.isSuccessful()) { - Timber.i("ver: [KV] PUT key=" + key + ", err=" + (res.code())); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err=" + (res.code())); return new CompletionObject(0, 0, unknown); } v = extractVersion(res); @@ -145,12 +145,12 @@ public CompletionObject get(String key, long version) { try { res = apiClient.sendRequest(request, true, retryCount); if (res == null) { - Timber.i("ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); return new CompletionObject(0, 0, unknown); } if (!res.isSuccessful()) { - Timber.i("ver: [KV] PUT key=" + key + ", err=" + (res.code())); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err=" + (res.code())); return new CompletionObject(0, 0, unknown); } v = extractVersion(res); @@ -177,12 +177,12 @@ public CompletionObject keys() { try { res = apiClient.sendRequest(request, true, retryCount); if (res == null) { - Timber.i("ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err= response is null (maybe auth challenge)"); return new CompletionObject(0, 0, unknown); } if (!res.isSuccessful()) { - Timber.i("ver: [KV] PUT key=" + key + ", err=" + (res.code())); + Timber.i("timber: ver: [KV] PUT key=" + key + ", err=" + (res.code())); return new CompletionObject(0, 0, unknown); } byte[] reqData; diff --git a/app/src/main/java/com/platform/kvstore/ReplicatedKVStore.java b/app/src/main/java/com/platform/kvstore/ReplicatedKVStore.java index 28ff6f3db..cf93e2dbf 100644 --- a/app/src/main/java/com/platform/kvstore/ReplicatedKVStore.java +++ b/app/src/main/java/com/platform/kvstore/ReplicatedKVStore.java @@ -123,7 +123,7 @@ public CompletionObject set(KVItem kv) { if (syncImmediately && obj.err == null) { if (!syncRunning) { syncKey(kv.key, 0, 0, null); - Timber.d("set: key synced: " + kv.key); + Timber.d("timber: set: key synced: " + kv.key); } } return obj; @@ -141,7 +141,7 @@ public void set(KVItem[] kvEntities) { } private synchronized CompletionObject _set(KVItem kv) throws Exception { - Timber.d("_set: " + kv.key); + Timber.d("timber: _set: " + kv.key); long localVer = kv.version; long newVer = 0; long time = System.currentTimeMillis(); @@ -149,7 +149,7 @@ private synchronized CompletionObject _set(KVItem kv) throws Exception { long curVer = _localVersion(key).version; if (curVer != localVer) { - Timber.d("set key %s conflict: version %d != current version %d", key, localVer, curVer); + Timber.d("timber: set key %s conflict: version %d != current version %d", key, localVer, curVer); return new CompletionObject(CompletionObject.RemoteKVStoreError.conflict); } newVer = curVer + 1; @@ -161,7 +161,7 @@ private synchronized CompletionObject _set(KVItem kv) throws Exception { if (!success) return new CompletionObject(CompletionObject.RemoteKVStoreError.unknown); db.setTransactionSuccessful(); } catch (Exception e) { - Timber.e(e, "_set: "); + Timber.e(e, "timber:_set: "); } finally { db.endTransaction(); closeDB(); @@ -233,7 +233,7 @@ public CompletionObject get(String key, long version) { kv.value = encrypted ? decrypt(val, mContext) : val; if (val != null && Utils.isNullOrEmpty(kv.value)) { //decrypting failed - Timber.d("get: Decrypting failed for key: " + key + ", deleting the kv"); + Timber.d("timber: get: Decrypting failed for key: " + key + ", deleting the kv"); delete(key, curVer); } } @@ -256,7 +256,7 @@ public CompletionObject localVersion(String key) { if (isKeyValid(key)) { return _localVersion(key); } else { - Timber.d("Key is invalid: %s", key); + Timber.d("timber: Key is invalid: %s", key); } return new CompletionObject(CompletionObject.RemoteKVStoreError.notFound); } @@ -406,7 +406,7 @@ public void syncKey(final String key, final long remoteVersion, final long remot try { if (remoteVersion == 0 || remoteTime == 0) { final CompletionObject completionObject = remoteKvStore.ver(key); - Timber.d("syncKey: completionObject: version: %d, value: %s, err: %s, time: %d", + Timber.d("timber: syncKey: completionObject: version: %d, value: %s, err: %s, time: %d", completionObject.version, Arrays.toString(completionObject.value), completionObject.err, completionObject.time); _syncKey(key, completionObject.version, completionObject.time, completionObject.err); } else { @@ -459,50 +459,50 @@ private boolean _syncKey(String key, long remoteVersion, long remoteTime, Comple if (localKv.deleted > 0 && err == CompletionObject.RemoteKVStoreError.tombstone) { // was removed on both server and locally - Timber.i("Local key %s was deleted, and so was the remote key", key); + Timber.i("timber: Local key %s was deleted, and so was the remote key", key); return setRemoteVersion(key, localKv.version, localKv.remoteVersion).err == null; } if (localKv.time >= remoteTime) {// local is newer (or a tiebreaker) if (localKv.deleted > 0) { - Timber.i("Local key %s was deleted, removing remotely...", key); + Timber.i("timber: Local key %s was deleted, removing remotely...", key); CompletionObject obj = remoteKvStore.del(key, remoteVersion); if (obj.err == CompletionObject.RemoteKVStoreError.notFound) { - Timber.i("Local key %s was already missing on the server. Ignoring", key); + Timber.i("timber: Local key %s was already missing on the server. Ignoring", key); return true; } if (obj.err != null) { - Timber.d("Error deleting remote version for key %s, error: %s", key, err); + Timber.d("timber: Error deleting remote version for key %s, error: %s", key, err); return false; } boolean success = setRemoteVersion(key, localKv.version, obj.version).err == null; if (!success) return false; } else { - Timber.i("Local key %s is newer, updating remotely...", key); + Timber.i("timber: Local key %s is newer, updating remotely...", key); // if the remote version is zero it means it doesnt yet exist on the server. set the remote version // to "1" to create the key on the server long useRemoteVer = (remoteVersion == 0 || remoteVersion < recorderRemoteVersion) ? 1 : remoteVersion; byte[] val = localKv.value; if (Utils.isNullOrEmpty(val)) { - Timber.d("_syncKey: encrypting value before sending to remote failed"); + Timber.d("timber: _syncKey: encrypting value before sending to remote failed"); return false; } CompletionObject obj = remoteKvStore.put(key, val, useRemoteVer); if (obj.err != null) { - Timber.d("Error updating remote version for key %s, error: %s", key, err); + Timber.d("timber: Error updating remote version for key %s, error: %s", key, err); return false; } boolean success = setRemoteVersion(key, localKv.version, obj.version).err == null; - Timber.i("Local key %s updated on server", key); + Timber.i("timber: Local key %s updated on server", key); if (!success) return false; } } else { // local is out-of-date if (err == CompletionObject.RemoteKVStoreError.tombstone) { // remote is deleted - Timber.i("Remote key %s deleted, removing locally", key); + Timber.i("timber: Remote key %s deleted, removing locally", key); CompletionObject obj = new CompletionObject(CompletionObject.RemoteKVStoreError.unknown); try { obj = _delete(key, localKv.version); @@ -512,25 +512,25 @@ private boolean _syncKey(String key, long remoteVersion, long remoteTime, Comple if (obj.version != 0) { boolean success = setRemoteVersion(key, obj.version, remoteVersion).err == null; if (!success) return false; - Timber.i("Remote key %s was removed locally", key); + Timber.i("timber: Remote key %s was removed locally", key); } } else { - Timber.i("Remote key %s is newer, fetching...", key); + Timber.i("timber: Remote key %s is newer, fetching...", key); CompletionObject remoteGet = remoteKvStore.get(key, remoteVersion); if (remoteGet.err != null) { - Timber.d("Error fetching the remote value for key %s, error: %s", key, err); + Timber.d("timber: Error fetching the remote value for key %s, error: %s", key, err); return false; } byte[] val = remoteGet.value; if (Utils.isNullOrEmpty(val)) { - Timber.d("_syncKey: key: " + key + " ,from the remote, is empty"); + Timber.d("timber: _syncKey: key: " + key + " ,from the remote, is empty"); return false; } byte[] decryptedValue = encryptedReplication ? decrypt(val, mContext) : val; if (Utils.isNullOrEmpty(decryptedValue)) { - Timber.d("_syncKey: failed to decrypt the value from remote for key: %s", key); + Timber.d("timber: _syncKey: failed to decrypt the value from remote for key: %s", key); return false; } @@ -547,7 +547,7 @@ private boolean _syncKey(String key, long remoteVersion, long remoteTime, Comple } } } else { - Timber.d("Error fetching remote version for key %s, error: %s", key, err); + Timber.d("timber: Error fetching remote version for key %s, error: %s", key, err); return false; } return true; @@ -564,7 +564,7 @@ public boolean syncAllKeys() { // 3. for kvs that we do have, sync em // 4. for kvs that they don't have that we do, upload em if (syncRunning) { - Timber.d("syncAllKeys: already syncing"); + Timber.d("timber: syncAllKeys: already syncing"); return false; } syncRunning = true; @@ -573,7 +573,7 @@ public boolean syncAllKeys() { try { CompletionObject obj = remoteKvStore.keys(); if (obj.err != null) { - Timber.i("Error fetching remote key data: %s", obj.err); + Timber.i("timber: Error fetching remote key data: %s", obj.err); syncRunning = false; return false; } @@ -589,13 +589,13 @@ public boolean syncAllKeys() { allKvs.add(new KVItem(0, 0, kv.key, null, 0, 0)); } - Timber.d("Syncing %d kvs", allKvs.size()); + Timber.d("timber: Syncing %d kvs", allKvs.size()); int failures = 0; for (KVItem k : allKvs) { boolean success = _syncKey(k.key, k.remoteVersion == -1 ? k.version : k.remoteVersion, k.time, k.err); if (!success) failures++; } - Timber.d("Finished syncing in %d, with failures: %d", System.currentTimeMillis() - startTime, failures); + Timber.d("timber: Finished syncing in %d, with failures: %d", System.currentTimeMillis() - startTime, failures); return true; } catch (Exception ex) { Timber.e(ex); @@ -633,7 +633,7 @@ public long remoteVersion(String key) { if (cursor.moveToNext()) version = cursor.getLong(0); else - Timber.i("remoteVersion: cursor is null for: %s", selectQuery); + Timber.i("timber: remoteVersion: cursor is null for: %s", selectQuery); } catch (Exception e) { Timber.e(e); } finally { @@ -642,7 +642,7 @@ public long remoteVersion(String key) { closeDB(); } } else { - Timber.i("Key is invalid: %s", key); + Timber.i("timber: Key is invalid: %s", key); } } finally { if (cursor != null) cursor.close(); @@ -669,7 +669,7 @@ public synchronized CompletionObject setRemoteVersion(String key, long localVer, long curVer = _localVersion(key).version; if (curVer != localVer) { - Timber.d("set remote version key %s conflict: version %d != current version %d", key, localVer, curVer); + Timber.d("timber: set remote version key %s conflict: version %d != current version %d", key, localVer, curVer); return new CompletionObject(CompletionObject.RemoteKVStoreError.conflict); } @@ -704,7 +704,7 @@ public synchronized CompletionObject setRemoteVersion(String key, long localVer, closeDB(); } } else { - Timber.i("Key is invalid: %s", key); + Timber.i("timber: Key is invalid: %s", key); } return new CompletionObject(CompletionObject.RemoteKVStoreError.unknown); } @@ -715,7 +715,7 @@ public synchronized CompletionObject setRemoteVersion(String key, long localVer, */ public CompletionObject delete(String key, long localVersion) { try { - Timber.d("kv deleted with key: %s", key); + Timber.d("timber: kv deleted with key: %s", key); if (isKeyValid(key)) { CompletionObject obj = new CompletionObject(CompletionObject.RemoteKVStoreError.unknown); try { @@ -726,7 +726,7 @@ public CompletionObject delete(String key, long localVersion) { if (syncImmediately && obj.err == null) { if (!syncRunning) { syncKey(key, 0, 0, null); - Timber.d("set: key synced: %s", key); + Timber.d("timber: set: key synced: %s", key); } } return obj; @@ -746,13 +746,13 @@ private synchronized CompletionObject _delete(String key, long localVersion) thr try { long curVer = _localVersion(key).version; if (curVer != localVersion) { - Timber.d("del key %s conflict: version %d != current version %d", key, localVersion, curVer); + Timber.d("timber: del key %s conflict: version %d != current version %d", key, localVersion, curVer); return new CompletionObject(CompletionObject.RemoteKVStoreError.conflict); } SQLiteDatabase db = getWritable(); try { db.beginTransaction(); - Timber.d("DEL key: %s ver: %d", key, curVer); + Timber.d("timber: DEL key: %s ver: %d", key, curVer); newVer = curVer + 1; cursor = db.query(KV_STORE_TABLE_NAME, new String[]{PlatformSqliteHelper.KV_VALUE}, "key = ? AND version = ?", new String[]{key, String.valueOf(localVersion)}, @@ -800,28 +800,28 @@ public static byte[] getNonce() { */ public static byte[] encrypt(byte[] data, Context app) { if (data == null) { - Timber.i("encrypt: data is null"); + Timber.i("timber: encrypt: data is null"); return null; } if (app == null) app = BreadApp.getBreadContext(); if (app == null) { - Timber.i("encrypt: app is null"); + Timber.i("timber: encrypt: app is null"); return null; } if (tempAuthKey == null) retrieveAuthKey(app); if (Utils.isNullOrEmpty(tempAuthKey)) { - Timber.i("encrypt: authKey is empty: %s", tempAuthKey == null ? null : tempAuthKey.length); + Timber.i("timber: encrypt: authKey is empty: %s", tempAuthKey == null ? null : tempAuthKey.length); return null; } BRKey key = new BRKey(tempAuthKey); byte[] nonce = getNonce(); if (Utils.isNullOrEmpty(nonce) || nonce.length != 12) { - Timber.i("encrypt: nonce is invalid: %s", nonce == null ? null : nonce.length); + Timber.i("timber: encrypt: nonce is invalid: %s", nonce == null ? null : nonce.length); return null; } byte[] encryptedData = key.encryptNative(data, nonce); if (Utils.isNullOrEmpty(encryptedData)) { - Timber.i("encrypt: encryptNative failed: %s", encryptedData == null ? null : encryptedData.length); + Timber.i("timber: encrypt: encryptNative failed: %s", encryptedData == null ? null : encryptedData.length); return null; } //result is nonce + encryptedData @@ -836,7 +836,7 @@ public static byte[] encrypt(byte[] data, Context app) { */ public static byte[] decrypt(byte[] data, Context app) { if (data == null || data.length <= 12) { - Timber.i("decrypt: failed to decrypt: %s", data == null ? null : data.length); + Timber.i("timber: decrypt: failed to decrypt: %s", data == null ? null : data.length); return null; } if (app == null) app = BreadApp.getBreadContext(); @@ -852,7 +852,7 @@ public static byte[] decrypt(byte[] data, Context app) { private static void retrieveAuthKey(Context context) { if (Utils.isNullOrEmpty(tempAuthKey)) { tempAuthKey = BRKeyStore.getAuthKey(context); - if (tempAuthKey == null) Timber.d("retrieveAuthKey: FAILED, still null!"); + if (tempAuthKey == null) Timber.d("timber: retrieveAuthKey: FAILED, still null!"); BRExecutor.getInstance().forLightWeightBackgroundTasks().execute(new Runnable() { @Override public void run() { @@ -878,7 +878,7 @@ private boolean isKeyValid(String key) { if (matcher.find()) { return true; } - Timber.d("checkKey: found illegal patterns, key: %s", key); + Timber.d("timber: checkKey: found illegal patterns, key: %s", key); return false; } diff --git a/app/src/main/java/com/platform/sqlite/KVItem.java b/app/src/main/java/com/platform/sqlite/KVItem.java index 4594a0afd..ac75194c6 100644 --- a/app/src/main/java/com/platform/sqlite/KVItem.java +++ b/app/src/main/java/com/platform/sqlite/KVItem.java @@ -33,7 +33,7 @@ public KVItem(long version, long remoteVersion, String key, byte[] value, long t } public void printValues() { - Timber.d("KVItem values: \nversion: %s\nremoteVersion: %s\nkey: %s\nvalue.length: %s\ntime: %s\ndeleted: %s" + Timber.d("timber: KVItem values: \nversion: %s\nremoteVersion: %s\nkey: %s\nvalue.length: %s\ntime: %s\ndeleted: %s" , version , remoteVersion , key diff --git a/app/src/main/java/com/platform/sqlite/PlatformSqliteHelper.java b/app/src/main/java/com/platform/sqlite/PlatformSqliteHelper.java index 834a0d7a9..221111c4a 100644 --- a/app/src/main/java/com/platform/sqlite/PlatformSqliteHelper.java +++ b/app/src/main/java/com/platform/sqlite/PlatformSqliteHelper.java @@ -54,13 +54,13 @@ private PlatformSqliteHelper(Context context) { @Override public void onCreate(SQLiteDatabase database) { - Timber.d("onCreate: %s", KV_DATABASE_CREATE); + Timber.d("timber: onCreate: %s", KV_DATABASE_CREATE); database.execSQL(KV_DATABASE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Timber.d("Upgrading database from version %d to %d, which will destroy all old data", oldVersion, newVersion); + Timber.d("timber: Upgrading database from version %d to %d, which will destroy all old data", oldVersion, newVersion); db.execSQL("DROP TABLE IF EXISTS " + KV_STORE_TABLE_NAME); //recreate the dbs onCreate(db); diff --git a/app/src/main/java/com/platform/tools/KVStoreManager.java b/app/src/main/java/com/platform/tools/KVStoreManager.java index 62e5423ff..8deca2a37 100644 --- a/app/src/main/java/com/platform/tools/KVStoreManager.java +++ b/app/src/main/java/com/platform/tools/KVStoreManager.java @@ -38,7 +38,7 @@ public static KVStoreManager getInstance() { } public WalletInfo getWalletInfo(Context app) { - Timber.i("Never initialized always null until WalletInfo struct to be removed"); + Timber.i("timber: Never initialized always null until WalletInfo struct to be removed"); return null; } @@ -75,14 +75,14 @@ public TxMetaData valueToMetaData(byte[] value) { TxMetaData result = new TxMetaData(); JSONObject json; if (value == null) { - Timber.d("valueToMetaData: value is null!"); + Timber.d("timber: valueToMetaData: value is null!"); AnalyticsManager.logCustomEvent(BRConstants._20200111_TNI); return null; } try { byte[] decompressed = BRCompressor.bz2Extract(value); if (decompressed == null) { - Timber.d("getTxMetaData: decompressed value is null"); + Timber.d("timber: getTxMetaData: decompressed value is null"); return null; } json = new JSONObject(new String(decompressed)); @@ -121,19 +121,19 @@ public void putTxMetaData(Context app, TxMetaData data, byte[] txHash) { } else if (data != null) { String finalExchangeCurrency = getFinalValue(data.exchangeCurrency, old.exchangeCurrency); if (finalExchangeCurrency != null) { - Timber.d("putTxMetaData: finalExchangeCurrency:%s", finalExchangeCurrency); + Timber.d("timber: putTxMetaData: finalExchangeCurrency:%s", finalExchangeCurrency); old.exchangeCurrency = finalExchangeCurrency; needsUpdate = true; } String finalDeviceId = getFinalValue(data.deviceId, old.deviceId); if (finalDeviceId != null) { - Timber.d("putTxMetaData: finalDeviceId:%s", finalDeviceId); + Timber.d("timber: putTxMetaData: finalDeviceId:%s", finalDeviceId); old.deviceId = finalDeviceId; needsUpdate = true; } String finalComment = getFinalValue(data.comment, old.comment); if (finalComment != null) { - Timber.d("putTxMetaData: comment:%s", finalComment); + Timber.d("timber: putTxMetaData: comment:%s", finalComment); old.comment = finalComment; needsUpdate = true; } @@ -171,7 +171,7 @@ public void putTxMetaData(Context app, TxMetaData data, byte[] txHash) { if (!needsUpdate) return; - Timber.d("putTxMetaData: updating txMetadata for : %s", key); + Timber.d("timber: putTxMetaData: updating txMetadata for : %s", key); byte[] result; try { @@ -192,7 +192,7 @@ public void putTxMetaData(Context app, TxMetaData data, byte[] txHash) { } if (result.length == 0) { - Timber.d("putTxMetaData: FAILED: result is empty"); + Timber.d("timber: putTxMetaData: FAILED: result is empty"); return; } byte[] compressed; @@ -208,7 +208,7 @@ public void putTxMetaData(Context app, TxMetaData data, byte[] txHash) { long removeVer = kvStore.remoteVersion(key); CompletionObject compObj = kvStore.set(localVer, removeVer, key, compressed, System.currentTimeMillis(), 0); if (compObj.err != null) { - Timber.d("putTxMetaData: Error setting value for key: " + key + ", err: " + compObj.err); + Timber.d("timber: putTxMetaData: Error setting value for key: " + key + ", err: " + compObj.err); } } diff --git a/app/src/main/jni/loafwallet-core b/app/src/main/jni/loafwallet-core index 2ea83a2ab..1a15ac045 160000 --- a/app/src/main/jni/loafwallet-core +++ b/app/src/main/jni/loafwallet-core @@ -1 +1 @@ -Subproject commit 2ea83a2abb82c208900cd098dcb4239cd5a90d7d +Subproject commit 1a15ac045ab96330afbf59be99b7d6d2e8712542 diff --git a/app/src/main/jni/transition/PeerManager.c b/app/src/main/jni/transition/PeerManager.c index 4e085aea0..79117cef8 100644 --- a/app/src/main/jni/transition/PeerManager.c +++ b/app/src/main/jni/transition/PeerManager.c @@ -13,9 +13,16 @@ #include #include #include +#include #define fprintf(...) __android_log_print(ANDROID_LOG_ERROR, "bread", _va_rest(__VA_ARGS__, NULL)) +#if LITECOIN_TESTNET +#define BR_CHAIN_PARAMS BRTestNetParams +#else +#define BR_CHAIN_PARAMS BRMainNetParams +#endif + static BRMerkleBlock **_blocks; BRPeerManager *_peerManager; static JavaVM *_jvmPM; @@ -237,7 +244,8 @@ JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_rescan(JNIEnv * JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_create(JNIEnv *env, jobject thiz, int earliestKeyTime, - int blocksCount, int peersCount) { + int blocksCount, int peersCount, + double fpRate) { __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "create| blocksCount: %d, peersCount: %d, earliestKeyTime: %d", blocksCount, peersCount, earliestKeyTime); @@ -268,9 +276,9 @@ Java_com_breadwallet_wallet_BRPeerManager_create(JNIEnv *env, jobject thiz, if (earliestKeyTime < BIP39_CREATION_TIME) earliestKeyTime = BIP39_CREATION_TIME; __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "earliestKeyTime: %d", earliestKeyTime); - _peerManager = BRPeerManagerNew(_wallet, (uint32_t) earliestKeyTime, _blocks, + _peerManager = BRPeerManagerNew(&BR_CHAIN_PARAMS, _wallet, (uint32_t) earliestKeyTime, _blocks, (size_t) blocksCount, - _peers, (size_t) peersCount); + _peers, (size_t) peersCount, (double) fpRate); BRPeerManagerSetCallbacks(_peerManager, NULL, syncStarted, syncStopped, txStatusUpdate, saveBlocks, savePeers, networkIsReachable, threadCleanup); @@ -321,7 +329,7 @@ Java_com_breadwallet_wallet_BRPeerManager_putBlock(JNIEnv *env, jobject thiz, jb JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_createBlockArrayWithCount(JNIEnv *env, jobject thiz, - size_t blockCount) { + jint blockCount) { __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "block array created with count: %zu", blockCount); _blocks = calloc(blockCount, sizeof(*_blocks)); @@ -355,7 +363,7 @@ Java_com_breadwallet_wallet_BRPeerManager_putPeer(JNIEnv *env, jobject thiz, jby JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_createPeerArrayWithCount(JNIEnv *env, jobject thiz, - size_t peerCount) { + jint peerCount) { __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "peer array created with count: %zu", peerCount); _peers = calloc(peerCount, sizeof(BRPeer)); @@ -399,7 +407,7 @@ JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRPeerManager_isCreated(J JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRPeerManager_isConnected(JNIEnv *env, jobject obj) { __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "isConnected"); - return (jboolean) (_peerManager && BRPeerManagerIsConnected(_peerManager)); + return (jboolean) (_peerManager && BRPeerManagerConnectStatus(_peerManager) == BRPeerStatusConnected); } JNIEXPORT jint JNICALL Java_com_breadwallet_wallet_BRPeerManager_getEstimatedBlockHeight( @@ -436,7 +444,7 @@ JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRPeerManager_setFixedPee if (inet_pton(AF_INET, host, &addr) != 1) return JNI_FALSE; address.u16[5] = 0xffff; address.u32[3] = addr.s_addr; - if (port == 0) _port = STANDARD_PORT; + if (port == 0) _port = BRPeerManagerStandardPort(_peerManager); } else { _port = 0; } diff --git a/app/src/main/jni/transition/PeerManager.h b/app/src/main/jni/transition/PeerManager.h index c2f24d91b..0626e2f3d 100644 --- a/app/src/main/jni/transition/PeerManager.h +++ b/app/src/main/jni/transition/PeerManager.h @@ -15,7 +15,8 @@ extern BRPeerManager *_peerManager; JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_create(JNIEnv *env, jobject thiz, int earliestKeyTime, - int blocksCount, int peersCount); + int blocksCount, int peersCount, + double fpRate); JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_connect(JNIEnv *env, jobject thiz); @@ -28,7 +29,7 @@ Java_com_breadwallet_wallet_BRPeerManager_putBlock(JNIEnv *env, jobject thiz, JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_createBlockArrayWithCount(JNIEnv *env, jobject thiz, - size_t blockCount); + jint blockCount); JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_putPeer(JNIEnv *env, jobject thiz, @@ -39,20 +40,20 @@ Java_com_breadwallet_wallet_BRPeerManager_putPeer(JNIEnv *env, jobject thiz, JNIEXPORT void JNICALL Java_com_breadwallet_wallet_BRPeerManager_createPeerArrayWithCount(JNIEnv *env, jobject thiz, - size_t peerCount); + jint peerCount); JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRPeerManager_isCreated(JNIEnv *env, jobject obj); JNIEXPORT jdouble JNICALL -Java_com_breadwallet_wallet_BRPeerManager_syncProgress(JNIEnv *env, jobject thiz, +Java_com_breadwallet_wallet_BRPeerManager_syncProgress(JNIEnv *env, jclass thiz, int startHeight); JNIEXPORT jint JNICALL Java_com_breadwallet_wallet_BRPeerManager_getCurrentBlockHeight(JNIEnv *env, - jobject thiz); + jclass thiz); JNIEXPORT jint JNICALL Java_com_breadwallet_wallet_BRPeerManager_getEstimatedBlockHeight( - JNIEnv *env, jobject thiz); + JNIEnv *env, jclass thiz); JNIEXPORT jlong JNICALL Java_com_breadwallet_wallet_BRPeerManager_getLastBlockTimestamp( JNIEnv *env, jobject thiz); @@ -67,7 +68,7 @@ JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRPeerManager_isConnected jobject obj); JNIEXPORT jint JNICALL Java_com_breadwallet_wallet_BRPeerManager_getRelayCount(JNIEnv *env, - jobject thiz, + jclass thiz, jbyteArray txHash); JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRPeerManager_setFixedPeer( diff --git a/app/src/main/jni/transition/wallet.c b/app/src/main/jni/transition/wallet.c index e28c83480..cd301a7f0 100644 --- a/app/src/main/jni/transition/wallet.c +++ b/app/src/main/jni/transition/wallet.c @@ -113,7 +113,7 @@ static void txAdded(void *info, BRTransaction *tx) { (*env)->SetByteArrayRegion(env, result, 0, (jsize) len, (jbyte *) buf); UInt256 transactionHash = tx->txHash; - const char *strHash = u256_hex_encode(transactionHash); + const char *strHash = u256hex(transactionHash); jstring jstrHash = (*env)->NewStringUTF(env, strHash); (*env)->CallStaticVoidMethod(env, _walletManagerClass, mid, result, (jint) tx->blockHeight, @@ -135,7 +135,7 @@ static void txUpdated(void *info, const UInt256 txHashes[], size_t count, uint32 "(Ljava/lang/String;II)V"); for (size_t i = 0; i < count; i++) { - const char *strHash = u256_hex_encode(txHashes[i]); + const char *strHash = u256hex(txHashes[i]); jstring JstrHash = (*env)->NewStringUTF(env, strHash); (*env)->CallStaticVoidMethod(env, _walletManagerClass, mid, JstrHash, (jint) blockHeight, @@ -152,7 +152,7 @@ static void txDeleted(void *info, UInt256 txHash, int notifyUser, int recommendR if (!env || _walletManagerClass == NULL) return; - const char *strHash = u256_hex_encode(txHash); + const char *strHash = u256hex(txHash); //create class jmethodID mid = (*env)->GetStaticMethodID(env, _walletManagerClass, "onTxDeleted", @@ -296,7 +296,7 @@ Java_com_breadwallet_wallet_BRWalletManager_putTransaction(JNIEnv *env, jobject tmpTx->timestamp = (uint32_t) jTimeStamp; // __android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "tmpTx->timestamp: %u", // tmpTx->timestamp); -// __android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "tmpTx: %s", u256_hex_encode(tmpTx->txHash)); +// __android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "tmpTx: %s", u256hex(tmpTx->txHash)); _transactions[_transactionsCounter++] = tmpTx; } @@ -357,7 +357,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_breadwallet_wallet_BRWalletManager_getTr UInt256 reversedHash = UInt256Reverse((txid)); - jstring txReversed = (*env)->NewStringUTF(env, u256_hex_encode(reversedHash)); + jstring txReversed = (*env)->NewStringUTF(env, u256hex(reversedHash)); jlong Jsent = (jlong) BRWalletAmountSentByTx(_wallet, tempTx); @@ -553,7 +553,7 @@ Java_com_breadwallet_wallet_BRWalletManager_transactionIsVerified(JNIEnv *env, j if (!_wallet) return JNI_FALSE; const char *txHash = (*env)->GetStringUTFChars(env, jtxHash, NULL); - UInt256 txHashResult = u256_hex_decode(txHash); + UInt256 txHashResult = uint256(txHash); BRTransaction *tx = BRWalletTransactionForHash(_wallet, txHashResult); if (!tx) return JNI_FALSE; @@ -842,10 +842,10 @@ Java_com_breadwallet_wallet_BRWalletManager_reverseTxHash(JNIEnv *env, jobject t __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "reverseTxHash"); const char *rawString = (*env)->GetStringUTFChars(env, txHash, 0); - UInt256 theHash = u256_hex_decode(rawString); + UInt256 theHash = uint256(rawString); UInt256 reversedHash = UInt256Reverse(theHash); - return (*env)->NewStringUTF(env, u256_hex_encode(reversedHash)); + return (*env)->NewStringUTF(env, u256hex(reversedHash)); } JNIEXPORT jstring JNICALL @@ -859,10 +859,10 @@ Java_com_breadwallet_wallet_BRWalletManager_txHashToHex(JNIEnv *env, jobject thi UInt256 reversedHash = UInt256Reverse((*(UInt256 *) hash)); // const char *rawString = (*env)->GetStringUTFChars(env, txHash, 0); -// UInt256 theHash = u256_hex_decode(rawString); +// UInt256 theHash = uint256(rawString); // UInt256 reversedHash = UInt256Reverse(theHash); // - return (*env)->NewStringUTF(env, u256_hex_encode(reversedHash)); + return (*env)->NewStringUTF(env, u256hex(reversedHash)); } @@ -872,14 +872,14 @@ Java_com_breadwallet_wallet_BRWalletManager_txHashSha256Hex(JNIEnv *env, jobject __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "reverseTxHash"); const char *rawString = (*env)->GetStringUTFChars(env, txHash, 0); - UInt256 theHash = u256_hex_decode(rawString); + UInt256 theHash = uint256(rawString); // UInt256 reversedHash = UInt256Reverse(theHash); -// __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "reversedHash: %s", u256_hex_encode(reversedHash)); +// __android_log_print(ANDROID_LOG_DEBUG, "Message from C: ", "reversedHash: %s", u256hex(reversedHash)); UInt256 sha256Hash; BRSHA256(&sha256Hash, theHash.u8, sizeof(theHash)); // UInt256 reversedHash = UInt256Reverse(sha256Hash); - char *result = u256_hex_encode(sha256Hash); + char *result = u256hex(sha256Hash); return (*env)->NewStringUTF(env, result); } diff --git a/app/src/main/res/layout/activity_intro.xml b/app/src/main/res/layout/activity_intro.xml index d197c7a0e..5586b649a 100644 --- a/app/src/main/res/layout/activity_intro.xml +++ b/app/src/main/res/layout/activity_intro.xml @@ -3,20 +3,20 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/intro_layout" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@color/litecoin_litewallet_blue" android:orientation="vertical"> diff --git a/app/src/main/res/layout/activity_sync_blockchain.xml b/app/src/main/res/layout/activity_sync_blockchain.xml index 81de87f2b..d1fcb3075 100644 --- a/app/src/main/res/layout/activity_sync_blockchain.xml +++ b/app/src/main/res/layout/activity_sync_blockchain.xml @@ -9,72 +9,55 @@ tools:context="com.breadwallet.presenter.activities.SetPinActivity"> - - + app:layout_constraintLeft_toLeftOf="@+id/textView15" + app:layout_constraintTop_toBottomOf="@+id/textView16" /> + android:textSize="@dimen/header" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/title"/> + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_balance_seed_reminder.xml b/app/src/main/res/layout/fragment_balance_seed_reminder.xml new file mode 100644 index 000000000..c73371243 --- /dev/null +++ b/app/src/main/res/layout/fragment_balance_seed_reminder.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a8ce8c5e5..83cdc17cf 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -763,4 +763,11 @@ Sprachen Bitrefill Geschenkkarten kaufen\n• Prepaid-Telefone aufladen\n• Steam, Amazon, Hotels.com\n• Funktioniert in 170 Ländern + Zeigen + Meine Seed-Phrase anzeigen + Synchronisierungseinstellung: %1$s Fehlalarme + Geringe Privatsphäre (~19 Minuten) + Halbprivat (~42 Minuten) + Anonym (~77 Minuten) + WICHTIG: Warten Sie ca. 1 Stunde auf die Synchronisierung! diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 03b03ea2f..692d1516e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -7,8 +7,8 @@ Hecho por el equipo Litewallet de la Fundación Litecoin\n%1$s Política de privacidad - - + + Términos de uso Acerca de nosotros @@ -763,4 +763,11 @@ Bitrefill Compre tarjetas de regalo\n• Recargue teléfonos prepagos\n• Steam, Amazon, Hotels.com\n• Funciona en 170 países Donar a: Infraestructura Litewallet + Espectáculo + Mostrar mi frase inicial + Preferencia de sincronización: %1$s falsos positivos + Baja privacidad (~19 minutos) + Semiprivado (~42 minutos) + Anónimo (~77 minutos) + IMPORTANTE: ¡Espera ~1 hora para sincronizar! diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 22e2bcddd..ff1d84bf6 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -763,4 +763,11 @@ Bitrefill Achetez des cartes-cadeaux\n• Rechargez des téléphones prépayés\n• Steam, Amazon, Hotels.com\n• Fonctionne dans 170 pays Faire un don à : Litewallet Infrastructure + Montrer + Afficher la phrase de départ + Préférence de synchronisation : %1$s faux positifs + Faible confidentialité (~19 minutes) + Semi-privé (~42 minutes) + Anonyme (~77 minutes) + IMPORTANT : attendez environ 1 heure pour la synchronisation ! diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index a33c2ef4d..9fd7bf180 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -7,7 +7,7 @@ Dibuat oleh Tim Litewallet dari Litecoin Foundation\n%1$s Kebijakan pribadi - + Syarat Penggunaan @@ -765,4 +765,11 @@ Bitrefill Beli kartu hadiah\n• Isi ulang ponsel prabayar\n• Steam, Amazon, Hotels.com\n• Berfungsi di 170 negara Donasi ke: Infrastruktur Litewallet + Menunjukkan + Tunjukkan frase seed saya + Preferensi Sinkronisasi: %1$s positif palsu + Privasi rendah (~19 menit) + Semi-pribadi (~42 menit) + Anonim (~77 menit) + PENTING: Tunggu ~1 jam untuk sinkronisasi! diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 866c74915..737ef58da 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -763,4 +763,11 @@ Bitrefill Acquista buoni regalo\n• Ricarica telefoni prepagati\n• Steam, Amazon, Hotels.com\n• Funziona in 170 paesi Dona a: Litewallet Infrastructure + Spettacolo + Mostra la mia frase seme + Preferenza di sincronizzazione: %1$s falsi positivi + Bassa privacy (~19 minuti) + Semi-privato (~42 minuti) + Anonimo (~77 minuti) + IMPORTANTE: Attendi ~1 ora per la sincronizzazione! diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 72b595fb0..9fee8db5d 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -763,4 +763,11 @@ Bitrefill ギフトカードの購入\n• プリペイド携帯電話の補充\n• Steam、Amazon、Hotels.com\n• 170 か国で利用可能 寄付先: Litewallet インフラストラクチャ + 見せる + 私のシードフレーズを表示 + 同期設定: %1$s 誤検知 + 低プライバシー (~19 分) + セミプライベート(~42分) + 匿名 (~77 分) + 重要: 同期が完了するまで 1 時間ほどお待ちください。 diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 1ac78be69..b372ad4a8 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -763,4 +763,11 @@ Bitrefill 기프트 카드 구매\n• 선불 전화 충전\n• Steam, Amazon, Hotels.com\n• 170개국에서 작동 기부: Litewallet 인프라 + 보여주다 + 내 시드 문구 표시 + 동기화 기본 설정: %1$s 오탐지 + 낮은 프라이버시(~19분) + 세미 프라이빗(~42분) + 익명(~77분) + 중요: 동기화를 위해 1시간 정도 기다리세요! diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 8d1349d13..12885e811 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -763,4 +763,11 @@ Bitrefill Compre vales-presente\n• Recarregue telefones pré-pagos\n• Steam, Amazon, Hotels.com\n• Funciona em 170 países Doe para: Litewallet Infrastructure + Mostrar + Mostrar minha frase de semente + Preferência de sincronização: %1$s falsos positivos + "Baixa privacidade (~19 minutos) " + "Semiprivado (~42 minutos) " + "Anônimo (~ 77 minutos) " + IMPORTANTE: Aguarde cerca de 1 hora para sincronizar! diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9eb4f1a3d..f40cfba34 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -763,4 +763,11 @@ Bitrefill Покупайте подарочные карты\n• Пополняйте предоплаченные телефоны\n• Steam, Amazon, Hotels.com\n• Работает в 170 странах Пожертвовать: Инфраструктура Litewallet + Показывать + " Покажи мою початкову фразу" + Настройка синхронизации: %1$s ложных срабатываний + "Низкая конфиденциальность (~ 19 минут) " + "Полуприватный (~ 42 минуты) " + "Аноним (~77 минут) " + ВАЖНО: Подождите ~1 час для синхронизации! diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 94405d847..c88db042d 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -8,7 +8,7 @@ Gizlilik Politikası - + Kullanım Şartları @@ -802,6 +802,13 @@ Bağış yapmak İptal Bağışta bulunun: Litewallet Altyapısı + Göstermek + " Tohum ifademi göster" + Senkronizasyon Tercihi: %1$s yanlış pozitifler + Düşük gizlilik (~19 dakika) + Yarı özel (~42 dakika) + Anonim (~77 dakika) + ÖNEMLİ: Senkronizasyon için ~1 saat bekleyin! diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 97f395852..eae382f59 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -785,4 +785,11 @@ Пожертвуйте Скасувати Пожертвуйте: Litewallet Infrastructure + Показати + Покажи мою початкову фразу + Налаштування синхронізації: %1$s помилкові спрацьовування + Низька конфіденційність (~19 хвилин) + Напівприватний (~42 хвилини) + Анонімно (~77 хвилин) + ВАЖЛИВО: зачекайте ~1 годину для синхронізації! diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 53b097ff4..4af41a336 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -7,7 +7,7 @@ 由萊特幣基金會的萊特錢包團隊製作\n%1$s 隐私政策 - + 使用条款 @@ -760,7 +760,14 @@ "•购买具有许多法定货币对的LTC\n•以多种方式支付\n•全球支付提供商" 当前的LTC值 %1$s 语言能力 - Bitrefill - 购买礼品卡\n• 为预付费手机充值\n• Steam、亚马逊、Hotels.com\n• 适用于 170 个国家/地区 - 捐赠给:Litewallet 基础设施 + Bitrefill + 购买礼品卡\n• 为预付费手机充值\n• Steam、亚马逊、Hotels.com\n• 适用于 170 个国家/地区 + 捐赠给:Litewallet 基础设施 + 展示 + 显示我的助记词 + 同步偏好:%1$s 误报 + 低隐私(约 19 分钟) + 半私人(约 42 分钟) + 匿名(约 77 分钟) + 重要提示:等待约 1 小时进行同步! diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 5f7d404e1..6dd44f11b 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -760,7 +760,14 @@ "•購買具有許多法定貨幣對的LTC\n•以多種方式支付\n•全球支付提供商" 當前的LTC值 %1$s 語言能力 - Bitrefill - 購買禮品卡\n• 為預付費手機充值\n• Steam、亞馬遜、Hotels.com\n• 適用於 170 個國家/地區 - 捐贈給:Litewallet 基礎設施 + Bitrefill + 購買禮品卡\n• 為預付費手機充值\n• Steam、亞馬遜、Hotels.com\n• 適用於 170 個國家/地區 + 捐贈給:Litewallet 基礎設施 + 展示 + 顯示我的助記詞 + 同步偏好:%1$s 誤報 + 低隱私(約 19 分鐘) + 半私人(約 42 分鐘) + 匿名(約 77 分鐘) + 重要提示:等待約 1 小時進行同步! diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 67799cb90..fce046154 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,7 +9,7 @@ %1$s Privacy Policy - + Instagram Terms of Use @@ -712,7 +712,6 @@ %1$d of %2$d Donate to the Litecoin Foundation (%1$s) - Processing time: These transactions will take %1$s minutes to process. Confirm Donation Amount to Donate: @@ -808,5 +807,14 @@ Cancel Donate to: Litewallet Infrastructure Instagram + 1: %s 2: %s 3: %s 4: %s \\n5: %s 6: %s 7: %s 8: %s%s \\n9: %s 10: %s 11: %s 12: %s %s + Show + Show my seed phrase + Sync Preference: %1$s false positives + Low privacy (~45 minutes) + Semi-private (~60 minutes) + Anonymous (~77 minutes) + IMPORTANT: App will sync to allow 1ltc addresses. Wait ~1 hour for syncing! + diff --git a/build.gradle b/build.gradle index 1b540b693..40315b8d4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,4 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { +buildscript { ext.kotlin_version = '1.6.21' repositories { @@ -9,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.4.0' + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong