Browse Source

some

gradlePlay
Gutyn 9 years ago
parent
commit
2e1e618b77
  1. 2
      .gitignore
  2. 9
      .idea/dictionaries/Mihail.xml
  3. 18
      .idea/gradle.xml
  4. 2
      .idea/misc.xml
  5. 2
      app/build.gradle
  6. 2
      app/src/main/AndroidManifest.xml
  7. 28
      app/src/main/java/com/breadwallet/presenter/activities/IntroActivity.java
  8. 2
      app/src/main/java/com/breadwallet/presenter/activities/IntroShowPhraseActivity.java
  9. 134
      app/src/main/java/com/breadwallet/presenter/activities/MainActivity.java
  10. 2
      app/src/main/java/com/breadwallet/presenter/entities/PaymentRequestEntity.java
  11. 64
      app/src/main/java/com/breadwallet/presenter/fragments/CloudDialogFragment.java
  12. 23
      app/src/main/java/com/breadwallet/presenter/fragments/FragmentRecoveryPhrase.java
  13. 4
      app/src/main/java/com/breadwallet/presenter/fragments/FragmentSettingsAll.java
  14. 8
      app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionExpanded.java
  15. 16
      app/src/main/java/com/breadwallet/presenter/fragments/FragmentWipeWallet.java
  16. 15
      app/src/main/java/com/breadwallet/presenter/fragments/IntroNewRecoverFragment.java
  17. 18
      app/src/main/java/com/breadwallet/presenter/fragments/IntroNewWalletFragment.java
  18. 27
      app/src/main/java/com/breadwallet/presenter/fragments/IntroRecoverWalletFragment.java
  19. 7
      app/src/main/java/com/breadwallet/presenter/fragments/PasswordDialogFragment.java
  20. 7
      app/src/main/java/com/breadwallet/tools/CurrencyManager.java
  21. 52
      app/src/main/java/com/breadwallet/tools/TypesConverter.java
  22. 14
      app/src/main/java/com/breadwallet/tools/animation/BackgroundMovingAnimator.java
  23. 106
      app/src/main/java/com/breadwallet/tools/security/KeyStoreManager.java
  24. 4
      app/src/main/java/com/breadwallet/tools/security/PassCodeManager.java
  25. 12
      app/src/main/java/com/breadwallet/tools/security/RequestHandler.java
  26. 4
      app/src/main/java/com/breadwallet/tools/threads/PassCodeTask.java
  27. 30
      app/src/main/java/com/breadwallet/wallet/BRPeerManager.java
  28. 28
      app/src/main/java/com/breadwallet/wallet/BRWalletManager.java
  29. 5
      app/src/main/jni/Android.mk
  30. 2
      app/src/main/jni/breadwallet-core
  31. 27
      app/src/main/jni/transition/PeerManager.c
  32. 2
      app/src/main/jni/transition/PeerManager.h
  33. 42
      app/src/main/jni/transition/core.c
  34. 7
      app/src/main/jni/transition/core.h
  35. 37
      app/src/main/jni/transition/testingStuff.c
  36. 2
      app/src/main/jni/transition/wallet.c
  37. 27
      app/src/main/jni/transition/wallet.h
  38. 1
      app/src/main/res/layout-sw600dp/fragment_settings.xml
  39. 1
      app/src/main/res/layout/activity_main.xml
  40. 77
      app/src/main/res/layout/fingerprint_dialog_backup.xml
  41. 65
      app/src/main/res/layout/fingerprint_dialog_container.xml
  42. 58
      app/src/main/res/layout/fingerprint_dialog_content.xml
  43. 4
      app/src/main/res/layout/fragment_about.xml
  44. 2
      app/src/main/res/layout/fragment_main.xml
  45. 2
      app/src/main/res/layout/fragment_password_dialog.xml
  46. 1
      app/src/main/res/layout/fragment_qr_main.xml
  47. 6
      app/src/main/res/layout/fragment_settings_all.xml
  48. 5
      app/src/main/res/layout/fragment_wipe_wallet.xml
  49. 2
      app/src/main/res/layout/intro_fragment_new_recover.xml
  50. 2
      app/src/main/res/layout/intro_fragment_new_wallet.xml
  51. 4
      app/src/main/res/layout/transaction_list_item.xml
  52. 9
      app/src/main/res/values/strings.xml
  53. 4
      gradle/wrapper/gradle-wrapper.properties

2
.gitignore

@ -46,6 +46,8 @@ gradle.properties
/.idea/workspace.xml
/.idea/libraries
/.idea/vcs.xml
/.idea/gradle.xml
/.idea/encodings.xml
#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
.navigation/

9
.idea/dictionaries/Mihail.xml

@ -1,9 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="Mihail">
<words>
<w>bitcoin</w>
<w>bitcoins</w>
<w>breadwallet</w>
</words>
</dictionary>
</component>

18
.idea/gradle.xml

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.7" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

2
.idea/misc.xml

@ -37,7 +37,7 @@
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

2
app/build.gradle

@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
buildToolsVersion '23.0.3'
lintOptions {
// set to true to turn off analysis progress reporting by lint

2
app/src/main/AndroidManifest.xml

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
@ -14,7 +15,6 @@
<application
android:name=".presenter.BreadWalletApp"
android:allowBackup="true"
android:debuggable="true"
android:icon="@mipmap/icon80"
android:label="@string/app_name"
android:largeHeap="true"

28
app/src/main/java/com/breadwallet/presenter/activities/IntroActivity.java

@ -26,6 +26,7 @@ import com.breadwallet.presenter.fragments.IntroRecoverWalletFragment;
import com.breadwallet.presenter.fragments.IntroWarningFragment;
import com.breadwallet.presenter.fragments.IntroWelcomeFragment;
import com.breadwallet.tools.animation.BackgroundMovingAnimator;
import com.breadwallet.wallet.BRPeerManager;
import com.breadwallet.wallet.BRWalletManager;
import java.util.List;
@ -77,13 +78,8 @@ public class IntroActivity extends FragmentActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intro);
app = this;
//TODO put that back
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
// WindowManager.LayoutParams.FLAG_SECURE);
leftButton = (Button) findViewById(R.id.intro_left_button);
leftButton.setVisibility(View.GONE);
leftButton.setClickable(false);
@ -97,8 +93,7 @@ public class IntroActivity extends FragmentActivity {
getFragmentManager().beginTransaction().add(R.id.intro_layout, new IntroWelcomeFragment(),
IntroWelcomeFragment.class.getName()).commit();
startTheWalletIfExists();
if (isUsingCustomInputMethod())
((BreadWalletApp) getApplication()).showCustomToast(this, "CUSTOM INPUT TYPE!", 300, Toast.LENGTH_LONG, 0);
}
@Override
@ -224,23 +219,6 @@ public class IntroActivity extends FragmentActivity {
}
}
public boolean isUsingCustomInputMethod() {
InputMethodManager imm = (InputMethodManager) getSystemService(
Context.INPUT_METHOD_SERVICE);
List<InputMethodInfo> mInputMethodProperties = imm.getEnabledInputMethodList();
final int N = mInputMethodProperties.size();
for (int i = 0; i < N; i++) {
InputMethodInfo imi = mInputMethodProperties.get(i);
if (imi.getId().equals(
Settings.Secure.getString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD))) {
if ((imi.getServiceInfo().applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) == 0) {
return true;
}
}
}
return false;
}
}

2
app/src/main/java/com/breadwallet/presenter/activities/IntroShowPhraseActivity.java

@ -48,7 +48,7 @@ public class IntroShowPhraseActivity extends Activity {
Log.e(TAG, "IntroShowPhraseActivity onCreate()");
writeDownLayout.setVisibility(View.GONE);
String phrase = KeyStoreManager.getKeyStoreString(this);
String phrase = KeyStoreManager.getKeyStorePhrase(this);
if (phrase != null && phrase.length() > 1) {
thePhrase.setText(phrase);
} else {

134
app/src/main/java/com/breadwallet/presenter/activities/MainActivity.java

@ -9,6 +9,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.hardware.fingerprint.FingerprintManager;
@ -16,6 +17,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
@ -24,6 +26,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.ImageView;
@ -144,6 +147,7 @@ public class MainActivity extends FragmentActivity implements Observer {
private BubbleTextVew middleBubbleBlocks;
public BubbleTextVew qrBubble1;
public BubbleTextVew qrBubble2;
private ToastUpdater toastUpdater;
public static boolean appInBackground = false;
@ -175,6 +179,23 @@ public class MainActivity extends FragmentActivity implements Observer {
setUpApi23();
new Thread(new Runnable() {
@Override
public void run() {
if (isUsingCustomInputMethod())
runOnUiThread(new Runnable() {
@Override
public void run() {
((BreadWalletApp) getApplication()).showCustomToast(app, "CUSTOM INPUT TYPE!", 300, Toast.LENGTH_LONG, 0);
}
});
}
}).start();
//TOOD take off
// String phrase = new String(KeyStoreManager.getKeyStorePhrase(this));
// Log.e(TAG, "phrase fresh: " + phrase);
if (((BreadWalletApp) getApplication()).isEmulatorOrDebug()) {
MODE = DEBUG;
Log.e(TAG, "DEBUG MODE!!!!!!");
@ -209,27 +230,14 @@ public class MainActivity extends FragmentActivity implements Observer {
// ToastBlockShowTask.getInstance(app).startOneToast();
middleBubbleBlocks.setVisibility(View.VISIBLE);
SpringAnimator.showBubbleAnimation(middleBubbleBlocks);
new Thread(new Runnable() {
@Override
public void run() {
while (middleBubbleBlocks.getVisibility() == View.VISIBLE) {
runOnUiThread(new Runnable() {
@Override
public void run() {
String currBlock = String.valueOf(BRPeerManager.getCurrentBlockHeight());
String latestBlockKnown = String.valueOf(BRPeerManager.getEstimatedBlockHeight());
String formattedBlockInfo = String.format("block #%s of %s", currBlock, latestBlockKnown);
middleBubbleBlocks.setText(formattedBlockInfo);
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
if (toastUpdater != null) {
toastUpdater.interrupt();
toastUpdater = null;
}
toastUpdater = new ToastUpdater();
toastUpdater.start();
return;
}
if (FragmentAnimator.level == 0 && BreadWalletApp.unlocked) {
@ -578,6 +586,7 @@ public class MainActivity extends FragmentActivity implements Observer {
if (cm.isNetworkAvailable(this)) {
BRWalletManager m = BRWalletManager.getInstance(this);
boolean txPossible = m.tryTransaction(addressHolder, cm.getSatoshisFromBits(Math.round(amountAsDouble)));
double feeForTx = cm.getBitsFromSatoshi(m.feeForTransaction(addressHolder, cm.getSatoshisFromBits(Math.round(amountAsDouble))));
if (!txPossible && amountAsDouble <= cm.getBitsFromSatoshi(cm.getBALANCE()) && amountAsDouble > 0) {
final double maxAmountDouble = cm.getBitsFromSatoshi(m.getMaxOutputAmount());
Log.e(TAG, "maxAmountDouble: " + maxAmountDouble);
@ -602,7 +611,7 @@ public class MainActivity extends FragmentActivity implements Observer {
alert.show();
return;
}
long feeForTx = cm.getBitsFromSatoshi(m.feeForTransaction(addressHolder, cm.getSatoshisFromBits(Math.round(amountAsDouble))));
Log.e(TAG, "pay >>>> feeForTx: " + feeForTx + ", amountAsDouble: " + amountAsDouble +
", CurrencyManager.getInstance(this).getBALANCE(): " + cm.getBitsFromSatoshi(cm.getBALANCE()));
if (feeForTx != 0 && amountAsDouble + feeForTx < cm.getBitsFromSatoshi(cm.getBALANCE())) {
@ -640,7 +649,12 @@ public class MainActivity extends FragmentActivity implements Observer {
Intent intent;
String tempAmount = FragmentScanResult.currentCurrencyPosition == FragmentScanResult.BITCOIN_RIGHT ?
AmountAdapter.getRightValue() : AmountAdapter.getLeftValue();
BRWalletManager m = BRWalletManager.getInstance(this);
double minAmount = CurrencyManager.getInstance(this).getBitsFromSatoshi(m.getMinOutputAmount());
if (Double.valueOf(tempAmount) < minAmount) {
((BreadWalletApp) getApplication()).showCustomDialog(getString(R.string.warning), "The amount cannot be less than ƀ" + minAmount, getString(R.string.ok));
return;
}
String strAmount = String.valueOf(new BigDecimal(tempAmount).divide(new BigDecimal("1000000")));
SharedPreferences prefs = getSharedPreferences(MainFragmentQR.RECEIVE_ADDRESS_PREFS, Context.MODE_PRIVATE);
String testTemp = prefs.getString(MainFragmentQR.RECEIVE_ADDRESS, "");
@ -745,16 +759,21 @@ public class MainActivity extends FragmentActivity implements Observer {
String iso = settings.getString(FragmentCurrency.CURRENT_CURRENCY, "USD");
float rate = settings.getFloat(FragmentCurrency.RATE, 1.0f);
String amount = String.valueOf(request.amount);
CurrencyManager m = CurrencyManager.getInstance(this);
final String message = certification + allAddresses.toString() + "\n\n" + "amount: " + m.getFormattedCurrencyString("BTC", String.valueOf(request.amount))
+ " (" + m.getExchangeForAmount(rate, iso, amount) + ")";
CurrencyManager cm = CurrencyManager.getInstance(this);
BRWalletManager m = BRWalletManager.getInstance(this);
final double feeForTx = cm.getBitsFromSatoshi(m.feeForTransaction(request.addresses[0], cm.getSatoshisFromBits(request.amount)));
final double total = Long.valueOf(amount) + feeForTx;
final String message = certification + allAddresses.toString() + "\n\n" + "amount: " + cm.getFormattedCurrencyString("BTC", String.valueOf(request.amount))
+ " (" + cm.getExchangeForAmount(rate, iso, amount) + ")" + "\nnetwork fee: +" + cm.getFormattedCurrencyString("BTC", String.valueOf(feeForTx))
+ " (" + cm.getExchangeForAmount(rate, iso, String.valueOf(feeForTx)) + ")" + "\ntotal: +" + cm.getFormattedCurrencyString("BTC", String.valueOf(total))
+ " (" + cm.getExchangeForAmount(rate, iso, String.valueOf(total)) + ")";
// ((BreadWalletApp) getApplication()).showCustomDialog("payment info", certification + allAddresses.toString() +
// "\n\n" + "amount " + CurrencyManager.getInstance(this).getFormattedCurrencyString("BTC", String.valueOf(request.amount / 100))
// + " (" + CurrencyManager.getInstance(this).getFormattedCurrencyString(iso, amount) + ")", "send");
long minOutput = BRWalletManager.getInstance(this).getMinOutputAmount() / 100;
double minOutput = BRWalletManager.getInstance(this).getMinOutputAmount() / 100d;
if (request.amount < minOutput) {
final String bitcoinMinMessage = String.format("bitcoin payments can't be less than ƀ%d", minOutput);
final String bitcoinMinMessage = String.format("bitcoin payments can't be less than ƀ%.2f", minOutput);
runOnUiThread(new Runnable() {
@Override
public void run() {
@ -843,7 +862,6 @@ public class MainActivity extends FragmentActivity implements Observer {
BRWalletManager m = BRWalletManager.getInstance(this);
final BRPeerManager pm = BRPeerManager.getInstance(this);
// String phrase = KeyStoreManager.getKeyStoreString(this);
// if (phrase == null) return;
// String normalizedPhrase = Normalizer.normalize(phrase, Normalizer.Form.NFKD);
@ -855,7 +873,7 @@ public class MainActivity extends FragmentActivity implements Observer {
List<BRMerkleBlockEntity> blocks = sqLiteManager.getBlocks();
List<BRPeerEntity> peers = sqLiteManager.getPeers();
final int transactionsCount = transactions.size();
int transactionsCount = transactions.size();
final int blocksCount = blocks.size();
final int peersCount = peers.size();
@ -873,8 +891,8 @@ public class MainActivity extends FragmentActivity implements Observer {
}
}
String pubkeyEncoded = KeyStoreManager.getMasterPublicKey(this);
int r = pubkeyEncoded.length() == 0 ? 0 : 1;
byte[] pubkeyEncoded = KeyStoreManager.getMasterPublicKey(this);
int r = pubkeyEncoded == null || pubkeyEncoded.length == 0 ? 0 : 1;
m.createWallet(transactionsCount, pubkeyEncoded, r);
}
@ -897,9 +915,10 @@ public class MainActivity extends FragmentActivity implements Observer {
Log.e(TAG, "blocksCount before connecting: " + blocksCount);
Log.e(TAG, "peersCount before connecting: " + peersCount);
// earliestKeyTime = 1456796244;
String walletTimeString = KeyStoreManager.getWalletCreationTime(this);
final long earliestKeyTime = !walletTimeString.isEmpty() ? Long.valueOf(walletTimeString) : 0;
int walletTimeString = KeyStoreManager.getWalletCreationTime(this);
final int earliestKeyTime = walletTimeString != 0 ? walletTimeString : 0;
//TODO take offs
// final long tempTime = 1454736431;
Log.e(TAG, "earliestKeyTime before connecting: " + earliestKeyTime);
new Thread(new Runnable() {
@Override
@ -909,7 +928,6 @@ public class MainActivity extends FragmentActivity implements Observer {
}).start();
}
}
private void registerScreenLockReceiver() {
@ -949,8 +967,8 @@ public class MainActivity extends FragmentActivity implements Observer {
}
private void askForPasscode() {
final String pass = KeyStoreManager.getPassCode(app);
if (pass == null || pass.isEmpty()) {
final int pass = KeyStoreManager.getPassCode(app);
if (pass == 0) {
new Handler().post(new Runnable() {
@Override
public void run() {
@ -1055,4 +1073,44 @@ public class MainActivity extends FragmentActivity implements Observer {
Log.e(specsTag, "");
}
public class ToastUpdater extends Thread {
public void run() {
while (middleBubbleBlocks.getVisibility() == View.VISIBLE) {
runOnUiThread(new Runnable() {
@Override
public void run() {
String currBlock = String.valueOf(BRPeerManager.getCurrentBlockHeight());
String latestBlockKnown = String.valueOf(BRPeerManager.getEstimatedBlockHeight());
String formattedBlockInfo = String.format("block #%s of %s", currBlock, latestBlockKnown);
middleBubbleBlocks.setText(formattedBlockInfo);
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public boolean isUsingCustomInputMethod() {
InputMethodManager imm = (InputMethodManager) getSystemService(
Context.INPUT_METHOD_SERVICE);
List<InputMethodInfo> mInputMethodProperties = imm.getEnabledInputMethodList();
final int N = mInputMethodProperties.size();
for (int i = 0; i < N; i++) {
InputMethodInfo imi = mInputMethodProperties.get(i);
if (imi.getId().equals(
Settings.Secure.getString(getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD))) {
if ((imi.getServiceInfo().applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) == 0) {
return true;
}
}
}
return false;
}
}

2
app/src/main/java/com/breadwallet/presenter/entities/PaymentRequestEntity.java

@ -29,13 +29,11 @@ public class PaymentRequestEntity {
public final String[] addresses;
public final long amount;
private final double fee;
public final String cn;
public PaymentRequestEntity(String theAddress[], long theAmount, String theCn) {
addresses = theAddress;
amount = theAmount;
fee = (double) 13;
cn = theCn;
}

64
app/src/main/java/com/breadwallet/presenter/fragments/CloudDialogFragment.java

@ -1,64 +0,0 @@
package com.breadwallet.presenter.fragments;
/**
* BreadWallet
* <p/>
* Created by Mihail on 7/24/15.
* Copyright (c) 2015 Mihail Gutan <mihail@breadwallet.com>
* <p/>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* <p/>
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* <p/>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import android.annotation.TargetApi;
import android.app.DialogFragment;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.breadwallet.R;
public class CloudDialogFragment extends DialogFragment {
private static final String TAG = CloudDialogFragment.class.getName();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_TITLE, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.cloud_dialog, container);
getDialog().getWindow().setBackgroundDrawableResource(R.drawable.cloud_round_dialog);
return view;
}
//0 is Up , 1 is Down.
public void setCarrotIndicator(int upDown, int position){
}
}

23
app/src/main/java/com/breadwallet/presenter/fragments/FragmentRecoveryPhrase.java

@ -6,17 +6,19 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import com.breadwallet.R;
import com.breadwallet.presenter.BreadWalletApp;
import com.breadwallet.tools.BRClipboardManager;
import com.breadwallet.tools.TypesConverter;
import com.breadwallet.tools.adapter.MiddleViewAdapter;
import com.breadwallet.tools.security.KeyStoreManager;
import com.breadwallet.wallet.BRWalletManager;
import java.nio.CharBuffer;
/**
* BreadWallet
* <p/>
@ -54,19 +56,18 @@ public class FragmentRecoveryPhrase extends Fragment {
thePhrase = (TextView) rootView.findViewById(R.id.the_phrase);
// //TODO delete this code below which is for testing reasons only
// thePhrase.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// BRClipboardManager.copyToClipboard(getActivity(),thePhrase.getText().toString());
// ((BreadWalletApp)getActivity().getApplication()).showCustomToast(getActivity(),
// getString(R.string.copied), 300, Toast.LENGTH_SHORT,0);
// }
// });
thePhrase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
BRClipboardManager.copyToClipboard(getActivity(),thePhrase.getText().toString());
((BreadWalletApp)getActivity().getApplication()).showCustomToast(getActivity(),
getString(R.string.copied), 300, Toast.LENGTH_SHORT,0);
}
});
// final long startTime = System.currentTimeMillis();
//return the new method if the API is 23+
thePhrase.setText(KeyStoreManager.getKeyStoreString(getActivity()));
thePhrase.setText(KeyStoreManager.getKeyStorePhrase(getActivity()));
return rootView;
}

4
app/src/main/java/com/breadwallet/presenter/fragments/FragmentSettingsAll.java

@ -296,11 +296,11 @@ public class FragmentSettingsAll extends Fragment {
Log.e(TAG, "item.getTimeStamp(): " + itemTimeStamp);
dateTextView.setText(itemTimeStamp != 0 ? getFormattedDateFromLong(itemTimeStamp * 1000) : getFormattedDateFromLong(System.currentTimeMillis()));
long bitsAmount = m.getBitsFromSatoshi(received ? item.getReceived() : (item.getSent() - item.getReceived()) * -1);
double bitsAmount = m.getBitsFromSatoshi(received ? item.getReceived() : (item.getSent() - item.getReceived()) * -1);
bitsTextView.setText(m.getFormattedCurrencyString("BTC", String.valueOf(bitsAmount)));
dollarsTextView.setText(String.format("(%s)", m.getExchangeForAmount(m.getRateFromPrefs(), m.getISOFromPrefs(), String.valueOf(bitsAmount))));
long bitsAfterTx = m.getBitsFromSatoshi(item.getBalanceAfterTx());
double bitsAfterTx = m.getBitsFromSatoshi(item.getBalanceAfterTx());
bitsTotalTextView.setText(m.getFormattedCurrencyString("BTC", String.valueOf(bitsAfterTx)));
dollarsTotalTextView.setText(String.format("(%s)", m.getExchangeForAmount(m.getRateFromPrefs(), m.getISOFromPrefs(), String.valueOf(bitsAfterTx))));

8
app/src/main/java/com/breadwallet/presenter/fragments/FragmentTransactionExpanded.java

@ -106,11 +106,11 @@ public class FragmentTransactionExpanded extends Fragment {
TextView toFeeAmountText = (TextView) rootView.findViewById(R.id.tx_to_fee_amount_text);
TextView toFeeExchangeText = (TextView) rootView.findViewById(R.id.tx_to_fee_exchange_text);
long tempReceived = m.getBitsFromSatoshi(item.getReceived());
long tempSent = m.getBitsFromSatoshi(item.getSent());
long tempFee = m.getBitsFromSatoshi(item.getFee());
double tempReceived = m.getBitsFromSatoshi(item.getReceived());
double tempSent = m.getBitsFromSatoshi(item.getSent());
double tempFee = m.getBitsFromSatoshi(item.getFee());
long amount = tempSent - tempReceived;
double amount = tempSent - tempReceived;
Log.e(TAG, "Tx Detail sent!!!! amount: " + amount + " tempFee: " + tempFee + " tempSent: "
+ tempSent + " item.getBlockHeight(): " + item.getBlockHeight());

16
app/src/main/java/com/breadwallet/presenter/fragments/FragmentWipeWallet.java

@ -19,11 +19,13 @@ import android.widget.TextView;
import com.breadwallet.R;
import com.breadwallet.presenter.BreadWalletApp;
import com.breadwallet.presenter.activities.IntroActivity;
import com.breadwallet.presenter.activities.MainActivity;
import com.breadwallet.tools.TypesConverter;
import com.breadwallet.tools.security.KeyStoreManager;
import com.breadwallet.tools.sqlite.SQLiteManager;
import com.breadwallet.wallet.BRWalletManager;
import java.nio.CharBuffer;
/**
* BreadWallet
* <p/>
@ -115,15 +117,15 @@ public class FragmentWipeWallet extends Fragment {
}
private boolean phraseIsValid(String insertedPhrase) {
String thePhrase = KeyStoreManager.getKeyStoreString(getActivity());
String thePhrase = KeyStoreManager.getKeyStorePhrase(getActivity());
if (thePhrase == null) throw new NullPointerException("Phrase is null! weird behaviour");
Log.e(TAG,"thePhrase: " + thePhrase);
Log.e(TAG,"insertedPhrase: " + insertedPhrase);
Log.e(TAG, "thePhrase: " + thePhrase);
Log.e(TAG, "insertedPhrase: " + insertedPhrase);
String trimmedPhrase = thePhrase.trim();
String trimmedInsertedPhrase = insertedPhrase.trim();
Log.e(TAG,"trimmedPhrase: " + trimmedPhrase);
Log.e(TAG,"trimmedInsertedPhrase: " + trimmedInsertedPhrase);
Log.e(TAG, "trimmedPhrase: " + trimmedPhrase);
Log.e(TAG, "trimmedInsertedPhrase: " + trimmedInsertedPhrase);
// Log.e(TAG,"Inserted:" + insertedPhrase);
// Log.e(TAG,"Actual:" + thePhrase);
return trimmedInsertedPhrase.equalsIgnoreCase(trimmedPhrase);
@ -132,7 +134,7 @@ public class FragmentWipeWallet extends Fragment {
@Override
public void onPause() {
super.onPause();
((BreadWalletApp)getActivity().getApplication()).hideKeyboard(getActivity());
((BreadWalletApp) getActivity().getApplication()).hideKeyboard(getActivity());
}
private void startIntroActivity() {

15
app/src/main/java/com/breadwallet/presenter/fragments/IntroNewRecoverFragment.java

@ -1,14 +1,18 @@
package com.breadwallet.presenter.fragments;
import android.app.Fragment;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import com.breadwallet.R;
import com.breadwallet.presenter.activities.IntroActivity;
import com.breadwallet.tools.animation.BackgroundMovingAnimator;
/**
* BreadWallet
@ -59,7 +63,18 @@ public class IntroNewRecoverFragment extends Fragment {
((IntroActivity) getActivity()).showRecoverWalletFragment();
}
});
SharedPreferences prefs = getActivity().getSharedPreferences(MainFragmentQR.RECEIVE_ADDRESS_PREFS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(MainFragmentQR.RECEIVE_ADDRESS, null);
editor.apply();
return rootView;
}
@Override
public void onResume() {
super.onResume();
ImageView background = (ImageView) getActivity().findViewById(R.id.intro_bread_wallet_image);
background.setScaleType(ImageView.ScaleType.MATRIX);
BackgroundMovingAnimator.animateBackgroundMoving(background);
}
}

18
app/src/main/java/com/breadwallet/presenter/fragments/IntroNewWalletFragment.java

@ -3,6 +3,7 @@ package com.breadwallet.presenter.fragments;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -62,15 +63,13 @@ public class IntroNewWalletFragment extends Fragment {
public void run() {
String phrase = m.generateRandomSeed();
if (phrase == null) throw new NullPointerException("Cannot be null!");
KeyStoreManager.putWalletCreationTime(String.valueOf((System.currentTimeMillis() / 1000)), getActivity());
KeyStoreManager.putWalletCreationTime((int) (System.currentTimeMillis() / 1000), getActivity());
String normalizedPhrase = Normalizer.normalize(phrase, Normalizer.Form.NFKD);
String pubKey = m.getMasterPubKey(normalizedPhrase);
byte[] pubKey = m.getMasterPubKey(normalizedPhrase);
KeyStoreManager.putMasterPublicKey(pubKey, getActivity());
// Log.w(TAG, "The phrase from keystore is: " + KeyStoreManager.getKeyStoreString(getActivity()));
((IntroActivity) getActivity()).showWarningFragment();
ImageView background = (ImageView) getActivity().findViewById(R.id.intro_bread_wallet_image);
background.setScaleType(ImageView.ScaleType.MATRIX);
BackgroundMovingAnimator.animateBackgroundMoving(background);
}
});
@ -79,4 +78,11 @@ public class IntroNewWalletFragment extends Fragment {
return rootView;
}
}
@Override
public void onResume() {
super.onResume();
ImageView background = (ImageView) getActivity().findViewById(R.id.intro_bread_wallet_image);
background.setScaleType(ImageView.ScaleType.MATRIX);
BackgroundMovingAnimator.animateBackgroundMoving(background);
}
}

27
app/src/main/java/com/breadwallet/presenter/fragments/IntroRecoverWalletFragment.java

@ -4,7 +4,6 @@ import android.app.AlertDialog;
import android.app.Fragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@ -15,12 +14,15 @@ import android.widget.EditText;
import android.widget.TextView;
import com.breadwallet.R;
import com.breadwallet.presenter.BreadWalletApp;
import com.breadwallet.presenter.activities.IntroActivity;
import com.breadwallet.tools.TypesConverter;
import com.breadwallet.tools.WordsReader;
import com.breadwallet.tools.security.KeyStoreManager;
import com.breadwallet.wallet.BRWalletManager;
import java.io.IOException;
import java.nio.CharBuffer;
import java.text.Normalizer;
import java.util.List;
@ -88,27 +90,34 @@ public class IntroRecoverWalletFragment extends Fragment {
} catch (IOException e) {
e.printStackTrace();
}
// int length = editText.length();
// char[] result= new char[length + 1];
// editText.getText().getChars(0, length, result, 0);
// result[length] = '\0';
// char[] phraseToCheck = TypesConverter.lowerCaseCharArray(result);
String phraseToCheck = editText.getText().toString().trim();
Log.e(TAG, "phraseToCheck: |" + phraseToCheck + "|");
if (words.length != 2048)
throw new IllegalArgumentException("words.length is not 2048");
if (validateRecoveryPhrase(words, phraseToCheck.toLowerCase())) {
if (validateRecoveryPhrase(words, phraseToCheck)) {
String normalizedPhrase = Normalizer.normalize(phraseToCheck, Normalizer.Form.NFKD);
boolean success = KeyStoreManager.setKeyStoreString(normalizedPhrase, getActivity());
boolean success = KeyStoreManager.putKeyStorePhrase(normalizedPhrase, getActivity());
// CharSequence sequence = CharBuffer.wrap(phraseToCheck);
// char[] normalizedPhrase = Normalizer.normalize(sequence, Normalizer.Form.NFKD).toCharArray();
if (!success)
throw new NullPointerException("Something went wrong when set the phrase into the KeyStore");
BRWalletManager m;
m = BRWalletManager.getInstance(getActivity());
// KeyStoreManager.putWalletCreationTime((int) (System.currentTimeMillis() / 1000), getActivity());
String pubKey = m.getMasterPubKey(normalizedPhrase.toLowerCase());
byte[] pubKey = m.getMasterPubKey(normalizedPhrase.toLowerCase());
KeyStoreManager.putMasterPublicKey(pubKey, getActivity());
// Log.w(TAG, "The phrase from keystore is: " + KeyStoreManager.getKeyStoreString(getActivity()));
((IntroActivity) getActivity()).startMainActivity();
getActivity().overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
} else {
alertDialog.setTitle(getResources().getString(R.string.alert));
alertDialog.setMessage("\"" + phraseToCheck + "\" - " +
//don't use
alertDialog.setMessage("\"" + new String(phraseToCheck) + "\" - " +
getResources().getString(R.string.dialog_recovery_phrase_invalid));
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, getResources().getString(R.string.ok),
new DialogInterface.OnClickListener() {
@ -129,4 +138,10 @@ public class IntroRecoverWalletFragment extends Fragment {
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
((BreadWalletApp) getActivity().getApplication()).hideKeyboard(getActivity());
}
}

7
app/src/main/java/com/breadwallet/presenter/fragments/PasswordDialogFragment.java

@ -48,6 +48,7 @@ import com.breadwallet.presenter.activities.MainActivity;
import com.breadwallet.presenter.entities.PaymentRequestEntity;
import com.breadwallet.tools.BRConstants;
import com.breadwallet.tools.CurrencyManager;
import com.breadwallet.tools.TypesConverter;
import com.breadwallet.tools.adapter.CustomPagerAdapter;
import com.breadwallet.tools.adapter.MiddleViewAdapter;
import com.breadwallet.tools.animation.FragmentAnimator;
@ -120,7 +121,7 @@ public class PasswordDialogFragment extends DialogFragment {
}
});
title.setText(getResources().getString(R.string.insert_old_passcode));
title.setText(getResources().getString(R.string.enter_old_passcode));
getDialog().getWindow().setBackgroundDrawableResource(R.drawable.rounded_dialog);
if (firstTime) {
@ -247,7 +248,7 @@ public class PasswordDialogFragment extends DialogFragment {
} else if (mode == BRConstants.AUTH_FOR_PAY && request != null) {
BRWalletManager walletManager = BRWalletManager.getInstance(getActivity());
String seed = KeyStoreManager.getSeed();
String seed = KeyStoreManager.getKeyStorePhrase(getActivity());
if (seed != null && !seed.isEmpty()) {
boolean success = walletManager.pay(request.addresses[0], request.amount * 100, seed);
if (!success) {
@ -255,6 +256,8 @@ public class PasswordDialogFragment extends DialogFragment {
"Failed to send", MainActivity.screenParametersPoint.y / 2, Toast.LENGTH_LONG, 0);
return false;
}
} else {
throw new Error("seed is gone!");
}
seed = null;
System.gc();

7
app/src/main/java/com/breadwallet/tools/CurrencyManager.java

@ -86,6 +86,7 @@ public class CurrencyManager extends Observable {
}
public boolean isNetworkAvailable(Context context) {
if(context == null) return false;
ConnectivityManager connectivityManager
= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
@ -239,7 +240,7 @@ public class CurrencyManager extends Observable {
return getFormattedCurrencyString(iso, String.valueOf(decimalFormat.format(exchange)));
}
public long getBitsFromSatoshi(long target) {
public double getBitsFromSatoshi(double target) {
return target / 100;
}
@ -250,11 +251,11 @@ public class CurrencyManager extends Observable {
public String getCurrentBalanceText() {
String iso = getISOFromPrefs();
double rate = getRateFromPrefs();
long balance = getBitsFromSatoshi(getBALANCE());
double balance = getBitsFromSatoshi(getBALANCE());
double exchange = (balance * rate / 1000000);
// CustomLogger.LogThis("rate", String.valueOf(rate), "exchange", String.valueOf(exchange));
// Log.e(TAG, "getCurrentBalanceText: " + result);
return getFormattedCurrencyString("BTC", String.valueOf(balance)) + "(" +
return getFormattedCurrencyString("BTC", String.valueOf(balance)) + " (" +
getFormattedCurrencyString(iso, String.valueOf(exchange)) + ")";
}

52
app/src/main/java/com/breadwallet/tools/TypesConverter.java

@ -0,0 +1,52 @@
package com.breadwallet.tools;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* Created by Mihail on 4/7/16.
*/
public class TypesConverter {
private TypesConverter(){};
public static byte[] intToBytes(int x) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(x);
return buffer.array();
}
public static int bytesToInt(byte[] bytes) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.put(bytes);
buffer.flip();
return buffer.getInt();
}
public static byte[] toBytes(char[] chars) {
CharBuffer charBuffer = CharBuffer.wrap(chars);
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
byteBuffer.position(), byteBuffer.limit());
// Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
// Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
return bytes;
}
public static char[] lowerCaseCharArray(char[] arr){
char[] lowerPhrase = new char[arr.length];
for(int i = 0; i < arr.length; i++){
lowerPhrase[i] = Character.toLowerCase(arr[i]);
}
return lowerPhrase;
}
public static char[] toChars(byte[] arr) {
char[] charArray = new char[arr.length];
for(int i = 0; i < arr.length; i++)
charArray[i] = (char) arr[i];
return charArray;
}
}

14
app/src/main/java/com/breadwallet/tools/animation/BackgroundMovingAnimator.java

@ -71,12 +71,12 @@ public class BackgroundMovingAnimator {
mCurrentAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// if (mDirection == RightToLeft)
mDirection = LeftToRight;
// else
// mDirection = RightToLeft;
// animate();
if (mDirection == RightToLeft)
mDirection = LeftToRight;
else
mDirection = RightToLeft;
//
animate();
}
});
mCurrentAnimator.start();
@ -90,8 +90,6 @@ public class BackgroundMovingAnimator {
public static void animateBackgroundMoving(ImageView theBackground) {
background = theBackground;
background.clearAnimation();
mMatrix = new Matrix();
background.post(new Runnable() {
@Override
public void run() {

106
app/src/main/java/com/breadwallet/tools/security/KeyStoreManager.java

@ -11,6 +11,7 @@ import android.util.Log;
import com.breadwallet.presenter.activities.IntroActivity;
import com.breadwallet.presenter.activities.MainActivity;
import com.breadwallet.tools.TypesConverter;
import org.apache.commons.io.IOUtils;
@ -20,6 +21,8 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
@ -28,6 +31,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.Enumeration;
import javax.crypto.Cipher;
@ -88,7 +92,7 @@ public class KeyStoreManager {
public static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1;
public static boolean setKeyStoreString(String strToStore, Context context) {
public static boolean putKeyStorePhrase(String strToStore, Context context) {
//TODO CHECK FOR FINGERPRINT SET!!! CANNOT WORK WITHOUT IT
//TODO refactor the String to byte[] or char[]
if (strToStore == null) return false;
@ -152,7 +156,7 @@ public class KeyStoreManager {
}
public static String getKeyStoreString(final Context context) {
public static String getKeyStorePhrase(final Context context) {
KeyguardManager myKM = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (myKM.inKeyguardRestrictedInputMode()) {
@ -170,18 +174,17 @@ public class KeyStoreManager {
keyStore.load(null);
SecretKey secretKey = (SecretKey)
keyStore.getKey(PHRASE_ALIAS, null);
if (secretKey == null) throw new RuntimeException("secretKey is null");
if (secretKey == null) throw new NullPointerException("secretKey is null");
// SecretKeyFactory factory = SecretKeyFactory.getInstance(secretKey.getAlgorithm(), ANDROID_KEY_STORE);
// KeyInfo keyInfo;
// try {
// keyInfo = (KeyInfo) factory.getKeySpec(secretKey, KeyInfo.class);
//// Log.e(TAG, "keyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware(): " + keyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware());
//// Log.e(TAG, "keyInfo.isInsideSecureHardware(): " + keyInfo.isInsideSecureHardware());
//// Log.e(TAG, "keyInfo.isUserAuthenticationRequired(): " + keyInfo.isUserAuthenticationRequired());
// Log.e(TAG, "keyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware(): " + keyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware());
// Log.e(TAG, "keyInfo.isInsideSecureHardware(): " + keyInfo.isInsideSecureHardware());
// Log.e(TAG, "keyInfo.isUserAuthenticationRequired(): " + keyInfo.isUserAuthenticationRequired());
// } catch (InvalidKeySpecException e) {
// Log.e(TAG, "keyInfo is not created, invalid SecretKey");
// }
String path = filesDirectory + File.separator + PHRASE_IV;
byte[] iv = readBytesFromFile(path);
Cipher outCipher;
@ -202,14 +205,14 @@ public class KeyStoreManager {
e.printStackTrace();
}
// Log.e(TAG, "recovered phrase: " + recoveredSecret);
return recoveredSecret;
}
public static boolean putMasterPublicKey(String masterPubKey, Context context) {
public static boolean putMasterPublicKey(byte[] masterPubKey, Context context) {
if (masterPubKey == null) return false;
if (masterPubKey.length() == 0) return false;
if (masterPubKey.length == 0) return false;
try {
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
keyStore.load(null);
@ -243,8 +246,7 @@ public class KeyStoreManager {
if (!success) throw new NullPointerException("FAILED TO WRITE BYTES TO FILE");
CipherOutputStream cipherOutputStream = new CipherOutputStream(
new FileOutputStream(encryptedDataFilePath), inCipher);
byte[] strBytes = masterPubKey.getBytes("UTF-8");
cipherOutputStream.write(strBytes);
cipherOutputStream.write(masterPubKey);
try {
cipherOutputStream.close();
} catch (Exception ex) {
@ -258,9 +260,9 @@ public class KeyStoreManager {
return false;
}
public static String getMasterPublicKey(final Context context) {
public static byte[] getMasterPublicKey(final Context context) {
KeyStore keyStore;
String recoveredSecret = "";
byte[] recoveredSecret = null;
String filesDirectory = context.getFilesDir().getAbsolutePath();
String encryptedDataFilePath = filesDirectory + File.separator + PUB_KEY_FILENAME;
try {
@ -286,18 +288,18 @@ public class KeyStoreManager {
roundTrippedBytes[index] = (byte) nextByte;
index++;
}
recoveredSecret = new String(roundTrippedBytes, 0, index, "UTF-8");
ByteBuffer bf = ByteBuffer.wrap(roundTrippedBytes, 0, index);
recoveredSecret = trimBytes(bf.array());
//TODO test the result recoveredSecret
} catch (Exception e) {
e.printStackTrace();
}
// Log.e(TAG, "recovered pubKey: " + recoveredSecret);
Log.e(TAG, "recovered pubKey: " + recoveredSecret);
return recoveredSecret;
}
public static boolean putWalletCreationTime(String creationTime, Context context) {
if (creationTime == null) return false;
if (creationTime.length() == 0) return false;
public static boolean putWalletCreationTime(int creationTime, Context context) {
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
@ -335,7 +337,7 @@ public class KeyStoreManager {
if (!success) throw new NullPointerException("FAILED TO WRITE BYTES TO FILE");
CipherOutputStream cipherOutputStream = new CipherOutputStream(
new FileOutputStream(encryptedDataFilePath), inCipher);
byte[] bytesToStore = creationTime.getBytes("UTF-8");
byte[] bytesToStore = TypesConverter.intToBytes(creationTime);
cipherOutputStream.write(bytesToStore);
cipherOutputStream.close();
return true;
@ -352,11 +354,11 @@ public class KeyStoreManager {
}
public static String getWalletCreationTime(final Context context) {
public static int getWalletCreationTime(final Context context) {
// if (!((BreadWalletApp) context.getApplicationContext()).allowKeyStoreAccess) {
// return null;
// }
String recoveredSecret = "";
int recoveredSecret = 0;
KeyStore keyStore;
String filesDirectory = context.getFilesDir().getAbsolutePath();
String encryptedDataFilePath = filesDirectory + File.separator + WALLET_CREATION_TIME_FILENAME;
@ -374,15 +376,16 @@ public class KeyStoreManager {
CipherInputStream cipherInputStream = new CipherInputStream(
new FileInputStream(encryptedDataFilePath), outCipher);
byte[] roundTrippedBytes = new byte[16];
byte[] roundTrippedBytes = new byte[4];
int index = 0;
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
roundTrippedBytes[index] = (byte) nextByte;
index++;
}
recoveredSecret = new String(roundTrippedBytes, 0, index, "UTF-8");
// Log.e(TAG, "recovered walletCreationTime: " + recoveredSecret);
ByteBuffer bf = ByteBuffer.wrap(roundTrippedBytes, 0, index);
recoveredSecret = TypesConverter.bytesToInt(trimBytes(bf.array()));
Log.e(TAG, "recovered walletCreationTime: " + recoveredSecret);
} catch (Exception e) {
e.printStackTrace();
}
@ -390,10 +393,8 @@ public class KeyStoreManager {
}
public static boolean putPassCode(String passcode, Context context) {
public static boolean putPassCode(int passcode, Context context) {
if (passcode == null) return false;
if (passcode.length() == 0) return false;
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
@ -431,7 +432,7 @@ public class KeyStoreManager {
if (!success) throw new NullPointerException("FAILED TO WRITE BYTES TO FILE");
CipherOutputStream cipherOutputStream = new CipherOutputStream(
new FileOutputStream(encryptedDataFilePath), inCipher);
byte[] bytesToStore = passcode.getBytes("UTF-8");
byte[] bytesToStore = TypesConverter.intToBytes(passcode);
cipherOutputStream.write(bytesToStore);
cipherOutputStream.close();
return true;
@ -447,7 +448,7 @@ public class KeyStoreManager {
return false;
}
public static String getPassCode(final Context context) {
public static int getPassCode(final Context context) {
// KeyguardManager myKM = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
// if (myKM.inKeyguardRestrictedInputMode()) {
// Log.e(TAG, "THE SCREEN IS LOCKED!");
@ -456,7 +457,7 @@ public class KeyStoreManager {
// Log.e(TAG, "THE SCREEN IS UNLOCKED!");
// }
KeyStore keyStore;
String recoveredSecret = "";
int recoveredSecret = 0;
String filesDirectory = context.getFilesDir().getAbsolutePath();
String encryptedDataFilePath = filesDirectory + File.separator + PASS_CODE_FILENAME;
try {
@ -480,7 +481,9 @@ public class KeyStoreManager {
roundTrippedBytes[index] = (byte) nextByte;
index++;
}
recoveredSecret = new String(roundTrippedBytes, 0, index, "UTF-8");
ByteBuffer bf = ByteBuffer.wrap(roundTrippedBytes, 0, index);
recoveredSecret = TypesConverter.bytesToInt(trimBytes(bf.array()));
Log.e(TAG, "recovered passcode: " + recoveredSecret);
} catch (Exception e) {
e.printStackTrace();
}
@ -592,29 +595,28 @@ public class KeyStoreManager {
return false;
}
public static String getSeed() {
Log.e(TAG, "in getSeed in KeyStoreManager");
String denied = "none";
Context app = MainActivity.app;
if (app == null)
app = IntroActivity.app;
if (app == null) return denied;
String result = getKeyStoreString(app);
static byte[] trimBytes(byte[] bytes)
{
int i = bytes.length - 1;
while (i >= 0 && bytes[i] == 0)
{
--i;
}
return result == null ? denied : result;
return Arrays.copyOf(bytes, i + 1);
}
private static byte[] intToBytes(int x) {
ByteBuffer buffer = ByteBuffer.allocate(Integer.SIZE);
buffer.putInt(x);
return buffer.array();
}
// public static String getSeed() {
// Log.e(TAG, "in getSeed in KeyStoreManager");
// String denied = "none";
// Context app = MainActivity.app;
// if (app == null)
// app = IntroActivity.app;
// if (app == null) return denied;
// String result = getKeyStoreString(app);
//
// return result == null ? denied : result;
// }
private static int bytesToInt(byte[] bytes) {
ByteBuffer buffer = ByteBuffer.allocate(Integer.SIZE);
buffer.put(bytes);
buffer.flip();
return buffer.getInt();
}
}

4
app/src/main/java/com/breadwallet/tools/security/PassCodeManager.java

@ -41,10 +41,10 @@ public class PassCodeManager {
public boolean checkAuth(CharSequence passcode, Context context) {
return passcode.equals(KeyStoreManager.getPassCode(context));
return passcode.equals(String.valueOf(KeyStoreManager.getPassCode(context)));
}
public void setPassCode(String pass, Context context) {
KeyStoreManager.putPassCode(pass, context);
KeyStoreManager.putPassCode(Integer.valueOf(pass), context);
}
}

12
app/src/main/java/com/breadwallet/tools/security/RequestHandler.java

@ -149,13 +149,13 @@ public class RequestHandler {
Double doubleAmount = Double.parseDouble(requestObject.amount ) * 1000000;
long amount = doubleAmount.longValue();
PaymentRequestEntity requestEntity = new PaymentRequestEntity(addresses,
amount, "");
Log.e(TAG, "requestEntity.amount: " + requestEntity.amount);
Log.e(TAG, "requestEntity.addresses[0]: " + requestEntity.addresses[0]);
String strAmount = String.valueOf(requestEntity.amount );
// PaymentRequestEntity requestEntity = new PaymentRequestEntity(addresses,
// amount, null);
Log.e(TAG, "requestEntity.amount: " + amount);
Log.e(TAG, "requestEntity.addresses[0]: " + addresses[0]);
String strAmount = String.valueOf(amount);
if (app != null) {
app.pay(requestEntity.addresses[0], strAmount);
app.pay(addresses[0], strAmount);
}
} else {
MainActivity.app.runOnUiThread(new Runnable() {

4
app/src/main/java/com/breadwallet/tools/threads/PassCodeTask.java

@ -34,7 +34,7 @@ import com.breadwallet.tools.security.KeyStoreManager;
public class PassCodeTask extends Thread {
public static final String TAG = PassCodeTask.class.getName();
static PasswordDialogFragment passwordDialogFragment;
String pass = "";
int pass = 0;
private Activity activity;
public PassCodeTask(Activity activity) {
@ -47,7 +47,7 @@ public class PassCodeTask extends Thread {
if (activity == null) return;
final FragmentManager fm = activity.getFragmentManager();
while (pass != null && pass.isEmpty() && activity != null) {
while (pass == 0 && activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {

30
app/src/main/java/com/breadwallet/wallet/BRPeerManager.java

@ -88,27 +88,23 @@ public class BRPeerManager {
* int (*networkIsReachable)(void *info))
*/
public static synchronized void syncStarted() {
public static void syncStarted() {
Log.e(TAG, "syncStarted");
startSyncingProgressThread();
}
public static synchronized void syncSucceeded() {
public static void syncSucceeded() {
Log.e(TAG, "syncSucceeded");
if (ctx == null) ctx = MainActivity.app;
if (ctx != null)
// if (KeyStoreManager.getWalletCreationTime(ctx) == 0) {
// Log.e(TAG, "getWalletCreationTime() is 0 ! setting the new walletCreationTime in the keystore!");
// KeyStoreManager.putWalletCreationTime((int) (System.currentTimeMillis() / 1000), ctx);
// }
stopSyncingProgressThread();
}
public static synchronized void syncFailed() {
public static void syncFailed() {
stopSyncingProgressThread();
}
public static synchronized void txStatusUpdate() {
public static void txStatusUpdate() {
Log.e(TAG, "txStatusUpdate");
if (ctx == null) ctx = MainActivity.app;
if (ctx != null)
@ -120,11 +116,11 @@ public class BRPeerManager {
}
public static synchronized void txRejected(int rescanRecommended) {
public static void txRejected(int rescanRecommended) {
Log.e(TAG, "txStatusUpdate");
}
public static synchronized void saveBlocks(final BlockEntity[] blockEntities) {
public static void saveBlocks(final BlockEntity[] blockEntities) {
Log.e(TAG, "saveBlocks: " + blockEntities.length);
if (ctx == null) ctx = MainActivity.app;
@ -132,8 +128,8 @@ public class BRPeerManager {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < blockEntities.length; i++) {
SQLiteManager.getInstance(ctx).insertMerkleBlock(blockEntities[i].getBlockBytes(), blockEntities[i].getBlockHeight());
for (BlockEntity blockEntity : blockEntities) {
SQLiteManager.getInstance(ctx).insertMerkleBlock(blockEntity.getBlockBytes(), blockEntity.getBlockHeight());
}
}
}).start();
@ -141,7 +137,7 @@ public class BRPeerManager {
}
public static synchronized void savePeers(final PeerEntity[] peerEntities) {
public static void savePeers(final PeerEntity[] peerEntities) {
Log.e(TAG, "savePeers");
if (ctx == null) ctx = MainActivity.app;
if (ctx != null) {
@ -157,12 +153,12 @@ public class BRPeerManager {
}
public static synchronized boolean networkIsReachable() {
public static boolean networkIsReachable() {
Log.e(TAG, "networkIsReachable");
return ctx != null && CurrencyManager.getInstance(ctx).isNetworkAvailable(ctx);
}
public static synchronized void deleteBlocks() {
public static void deleteBlocks() {
Log.e(TAG, "deleteBlocks");
if (ctx == null) ctx = MainActivity.app;
if (ctx != null) {
@ -176,7 +172,7 @@ public class BRPeerManager {
}
}
public static synchronized void deletePeers() {
public static void deletePeers() {
Log.e(TAG, "deletePeers");
if (ctx == null) ctx = MainActivity.app;
if (ctx != null) {
@ -242,7 +238,6 @@ public class BRPeerManager {
}
});
}
try {
if (syncTask != null) {
syncTask.interrupt();
@ -320,6 +315,7 @@ public class BRPeerManager {
} catch (InterruptedException e) {
e.printStackTrace();
}
// Log.e(TAG,"sync task run ...");
// if (progressStatus >= 1) running = false;
}

28
app/src/main/java/com/breadwallet/wallet/BRWalletManager.java

@ -19,6 +19,7 @@ import com.breadwallet.presenter.entities.TransactionListItem;
import com.breadwallet.presenter.fragments.FragmentSettingsAll;
import com.breadwallet.presenter.fragments.MainFragmentQR;
import com.breadwallet.tools.CurrencyManager;
import com.breadwallet.tools.TypesConverter;
import com.breadwallet.tools.WordsReader;
import com.breadwallet.tools.adapter.CustomPagerAdapter;
import com.breadwallet.tools.adapter.MiddleViewAdapter;
@ -117,7 +118,7 @@ public class BRWalletManager {
byte[] phrase = encodeSeed(keyBytes, words);
String strPhrase = new String(phrase);
// String phrase = "short apple trunk riot coyote innocent zebra venture ill lava shop test";
boolean success = KeyStoreManager.setKeyStoreString(strPhrase, ctx);
boolean success = KeyStoreManager.putKeyStorePhrase(strPhrase, ctx);
Log.e(TAG, "setKeyStoreString was successful: " + success);
return success ? strPhrase : null;
}
@ -132,6 +133,7 @@ public class BRWalletManager {
* a signed transaction that will sweep the balance into wallet (doesn't publish the tx)
*/
public boolean sweepPrivateKey() {
freeEverything();
return KeyStoreManager.deleteKeyStoreEntry();
}
@ -139,14 +141,13 @@ public class BRWalletManager {
* true if keychain is available and we know that no wallet exists on it
*/
public boolean noWallet(Context ctx) {
String pubkey = KeyStoreManager.getMasterPublicKey(ctx);
Log.e(TAG, "in the noWallet, pubkey.length(): " + pubkey.length());
byte[] pubkey = KeyStoreManager.getMasterPublicKey(ctx);
// Log.e(TAG, "in the noWallet, pubkey.length(): " + pubkey.length);
// Log.e(TAG, "in the noWallet, pubkey: " + pubkey);
return pubkey.length() == 0;
return pubkey == null || pubkey.length == 0;
}
/**
* true if device passcode is enabled
*/
@ -231,9 +232,9 @@ public class BRWalletManager {
}
public static void onTxAdded(byte[] tx, int blockHeight, long timestamp, final long amount, String hash) {
Log.e(TAG, "in the BRWalletManager - onTxAdded: " + tx.length + " " + blockHeight + " " + timestamp);
Log.e(TAG, "in the BRWalletManager - onTxAdded: " + tx.length + " " + blockHeight + " " + timestamp + " " + amount);
final RequestQRActivity requestApp = RequestQRActivity.requestApp;
if(requestApp != null && !requestApp.activityIsInBackground){
if (requestApp != null && !requestApp.activityIsInBackground) {
requestApp.runOnUiThread(new Runnable() {
@Override
public void run() {
@ -241,11 +242,6 @@ public class BRWalletManager {
}
});
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (ctx == null) ctx = MainActivity.app;
if (ctx != null && !MiddleViewAdapter.getSyncing()) {
((Activity) ctx).runOnUiThread(new Runnable() {
@ -290,7 +286,7 @@ public class BRWalletManager {
private native byte[] encodeSeed(byte[] seed, String[] wordList);
// public native void createWallet(ByteBuffer transactions[], int transactionCount);
public native void createWallet(int transactionCount, String pubkey, int r);
public native void createWallet(int transactionCount, byte[] pubkey, int r);
public native void putTransaction(byte[] transaction, long blockHeight, long timeStamp);
@ -300,7 +296,7 @@ public class BRWalletManager {
public native void setPeerManagerCallbacks(byte[] peerManager);
public native String getMasterPubKey(String normalizedString);
public native byte[] getMasterPubKey(String normalizedString);
public native void testWalletCallbacks();
@ -322,7 +318,7 @@ public class BRWalletManager {
public native int feeForTransaction(String addressHolder, long amountHolder);
public native long getMinOutputAmount();
public native double getMinOutputAmount();
public native long getMaxOutputAmount();
@ -336,4 +332,6 @@ public class BRWalletManager {
public native long bitcoinAmount(long localAmount, double price);
public native void freeEverything();
}

5
app/src/main/jni/Android.mk

@ -4,7 +4,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := core
LOCAL_CFLAGS := -std=c99 -DBITCOIN_TESTNET=1
LOCAL_CFLAGS := -std=c99 -DBITCOIN_TESTNET=1 -Wno-trigraphs -Wmissing-field-initializers -Wno-missing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code-aggressive -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wunused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas -pedantic -Wshadow -Wfour-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wassign-enum -Wshorten-64-to-32 -Wpointer-sign -Wnewline-eof -Wdeprecated-declarations -Wno-sign-conversion
LOCAL_LDLIBS := -llog -lm
@ -25,8 +25,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := bread
LOCAL_CFLAGS := -std=c99 -DBITCOIN_TESTNET=1
LOCAL_CFLAGS := -std=c99 -DBITCOIN_TESTNET=1 -Wno-trigraphs -Wmissing-field-initializers -Wno-missing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code-aggressive -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wunused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas -pedantic -Wshadow -Wfour-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wassign-enum -Wshorten-64-to-32 -Wpointer-sign -Wnewline-eof -Wdeprecated-declarations -Wno-sign-conversion
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/breadwallet-core/secp256k1\
$(LOCAL_PATH)/breadwallet-core

2
app/src/main/jni/breadwallet-core

@ -1 +1 @@
Subproject commit d74485f7467ff9051075e1b5e8955c927d138e70
Subproject commit 701ef671c633f8602da628d797be390e91f4ec0a

27
app/src/main/jni/transition/PeerManager.c

@ -151,7 +151,7 @@ static void savePeers(void *info, const BRPeer peers[], size_t count) {
jmethodID mid = (*env)->GetStaticMethodID(env, _peerManagerClass, "savePeers", "([Lcom/breadwallet/presenter/entities/PeerEntity;)V");
//call java methods
if(count != 1){
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "deleting %d peers", count);
// __android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "deleting %d peers", count);
jmethodID delete_mid = (*env)->GetStaticMethodID(env, _peerManagerClass, "deletePeers", "()V");
(*env)->CallStaticVoidMethod(env, _peerManagerClass, delete_mid);
}
@ -203,9 +203,12 @@ static int networkIsReachable(void *info) {
}
JNIEXPORT void Java_com_breadwallet_wallet_BRPeerManager_createAndConnect(JNIEnv *env, jobject thiz,
jint earliestKeyTime,
jint blocksCount,
jint peersCount) {
int earliestKeyTime,
int blocksCount,
int peersCount) {
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "blocksCount: %d", blocksCount);
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "peersCount: %d", peersCount);
jint rs = (*env)->GetJavaVM(env, &_jvm);
jclass walletManagerCLass = (*env)->FindClass(env, "com/breadwallet/wallet/BRPeerManager");
@ -226,8 +229,6 @@ JNIEXPORT void Java_com_breadwallet_wallet_BRPeerManager_createAndConnect(JNIEnv
return;
}
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "blocksCount: %d", blocksCount);
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "peersCount: %d", peersCount);
if (!_peerManager) {
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "BRPeerManagerNew called: %d", ++_managerNewCounter);
@ -275,6 +276,7 @@ JNIEXPORT void Java_com_breadwallet_wallet_BRPeerManager_putBlock(JNIEnv *env,
JNIEXPORT void Java_com_breadwallet_wallet_BRPeerManager_createBlockArrayWithCount(JNIEnv *env,
jobject thiz,
size_t bkCount) {
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "block array created with count: %d", bkCount);
_blocks = calloc(bkCount, sizeof(BRMerkleBlock));
// need to call free();
}
@ -315,6 +317,7 @@ JNIEXPORT void Java_com_breadwallet_wallet_BRPeerManager_putPeer(JNIEnv *env,
JNIEXPORT void Java_com_breadwallet_wallet_BRPeerManager_createPeerArrayWithCount(JNIEnv *env,
jobject thiz,
size_t prCount) {
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "peer array created with count: %d",prCount);
_peers = calloc(prCount, sizeof(BRPeer));
// need to call free();
}
@ -343,18 +346,6 @@ JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRPeerManager_isCreated
JNIEXPORT jint Java_com_breadwallet_wallet_BRPeerManager_getEstimatedBlockHeight(JNIEnv *env,
jobject thiz) {
// int estimatedBlockHeight = BRPeerManagerEstimatedBlockHeight(_peerManager);
// int lastBlockHeight = BRPeerManagerLastBlockHeight(_peerManager);
// __android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "estimatedBlockHeight: %d, "
// "lastBlockHeight: %d", estimatedBlockHeight, lastBlockHeight);
// int result = 0;
// if(estimatedBlockHeight >= INT32_MAX){
// result = lastBlockHeight;
// } else {
// result = estimatedBlockHeight;
// }
//
// return (jint) result;
return (jint) BRPeerManagerEstimatedBlockHeight(_peerManager);
}

2
app/src/main/jni/transition/PeerManager.h

@ -11,7 +11,7 @@
extern BRPeerManager *_peerManager;
JNIEXPORT void Java_com_breadwallet_wallet_BRPeerManager_createAndConnect(JNIEnv *env, jobject thiz,
jint earliestKeyTime,
int earliestKeyTime,
int blocksCount,
int peersCount);

42
app/src/main/jni/transition/core.c

@ -4,10 +4,11 @@
#include "core.h"
#include "wallet.h"
#include <stdio.h>
#include "breadwallet-core/BRPaymentProtocol.h"
#include "breadwallet-core/BRTransaction.h"
#include "breadwallet-core/BRAddress.h"
#include "breadwallet-core/BRWallet.h"
#include "BRPaymentProtocol.h"
#include "BRTransaction.h"
#include "BRAddress.h"
#include "BRWallet.h"
#include "BRBIP39Mnemonic.h"
#include <android/log.h>
//TODO make sure to free() everything
@ -152,10 +153,8 @@ JNIEXPORT jobject Java_com_breadwallet_tools_security_RequestHandler_parsePaymen
//read amount and addresses from outputs
uint64_t outputsLength = nativeRequest->details->outputsCount;
uint64_t total_amount = 0;
int singleAddressLength = sizeof(nativeRequest->details->outputs[0].address);
// char addresses[(singleAddressLength + 2) * outputsLength];
jobjectArray stringArray = (jobjectArray) (*env)->NewObjectArray(env, outputsLength,
jobjectArray stringArray = (jobjectArray) (*env)->NewObjectArray(env, (jsize) outputsLength,
(*env)->FindClass(env, "java/lang/String"),
(*env)->NewStringUTF(env, ""));
if (outputsLength > 0) {
@ -257,9 +256,9 @@ JNIEXPORT jbyteArray Java_com_breadwallet_tools_security_RequestHandler_getCerti
// __android_log_write(ANDROID_LOG_DEBUG, ">>>>>>MESSAGE FROM C: ", (char *) length);
//convert it to jbyteArray
jbyte *certJbyte = (const jbyte *) buf;
jbyteArray result = (*env)->NewByteArray(env, length);
(*env)->SetByteArrayRegion(env, result, 0, length, (const jbyte *)certJbyte);
jbyte *certJbyte = (jbyte *) buf;
jbyteArray result = (*env)->NewByteArray(env, (jsize) length);
(*env)->SetByteArrayRegion(env, result, 0, (jsize) length, (const jbyte *)certJbyte);
//release everything
(*env)->ReleaseByteArrayElements(env, result, certJbyte, JNI_COMMIT);
(*env)->ReleaseByteArrayElements(env, payment, bytePayment, JNI_COMMIT);
@ -270,26 +269,31 @@ JNIEXPORT jbyteArray Java_com_breadwallet_tools_security_RequestHandler_getCerti
JNIEXPORT jboolean JNICALL Java_com_breadwallet_presenter_fragments_IntroRecoverWalletFragment_validateRecoveryPhrase
(JNIEnv *env, jobject obj, jobjectArray stringArray, jstring jPhrase) {
(JNIEnv *env, jobject obj, jobjectArray stringArray, jcharArray jPhrase) {
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "validateRecoveryPhrase: %s" , (char *) jPhrase);
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "validateRecoveryPhrase");
int wordsCount = (*env)->GetArrayLength(env, stringArray);
const char *wordList[wordsCount];
for (int i = 0; i < wordsCount; i++) {
jstring string = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
char *rawString = (*env)->GetStringUTFChars(env, string, 0);
const char *rawString = (*env)->GetStringUTFChars(env, string, 0);
wordList[i] = rawString;
(*env)->DeleteLocalRef(env, string);
// Don't forget to call `ReleaseStringUTFChars` when you're done.
}
const char *str;
str = (char *) (*env)->GetStringUTFChars(env, jPhrase, NULL);
jchar *phraseCharPointer = (*env)->GetCharArrayElements(env, jPhrase, 0);
jint phraseSize = (*env)->GetArrayLength(env, jPhrase);
char rawPhrase[phraseSize];
for(int i = 0; i < phraseSize; i++)
rawPhrase[i] = (char)phraseCharPointer[i];
__android_log_print(ANDROID_LOG_ERROR, "Message from C: ", "theSeed: address %s", rawPhrase);
jboolean b;
// int BRBIP39PhraseIsValid(const char *wordList[], const char *phrase);
int result = BRBIP39PhraseIsValid(wordList, str);
int result = BRBIP39PhraseIsValid(wordList, rawPhrase);
// __android_log_print(ANDROID_LOG_ERROR, "LOG_TAG", "This is the result : %d", result);
return result ? JNI_TRUE : JNI_FALSE;
@ -302,7 +306,7 @@ JNIEXPORT void JNICALL Java_com_breadwallet_presenter_activities_MainActivity_cl
}
JNIEXPORT void JNICALL Java_com_breadwallet_presenter_activities_MainActivity_cTests(JNIEnv *env, jobject obj){
int result = BRRunTests();
__android_log_print(ANDROID_LOG_ERROR, "Core Tests: ", "%d", result);
// int result = BRRunTests();
// __android_log_print(ANDROID_LOG_ERROR, "Core Tests: ", "%d", result);
}

7
app/src/main/jni/transition/core.h

@ -9,12 +9,15 @@
//JNIEXPORT jbyteArray Java_com_breadwallet_wallet_BRWalletManager_encodePhrase
// (JNIEnv *env, jobject obj, jbyteArray seed, jbyteArray wordList);
JNIEXPORT jboolean JNICALL Java_com_breadwallet_tools_security_RequestHandler_validateAddress
(JNIEnv *env, jobject obj, jstring address);
//JNIEXPORT jboolean JNICALL Java_com_breadwallet_tools_security_RequestHandler_validateAddress
// (JNIEnv *env, jobject obj, jstring address);
jbyteArray Java_com_breadwallet_tools_security_RequestHandler_parsePaymentRequest
(JNIEnv *env, jobject obj, jbyteArray payment);
JNIEXPORT jboolean JNICALL Java_com_breadwallet_presenter_fragments_IntroRecoverWalletFragment_validateRecoveryPhrase
(JNIEnv *env, jobject obj, jobjectArray stringArray, jcharArray jPhrase);
jbyteArray Java_com_breadwallet_tools_security_RequestHandler_getCertificatesFromPaymentRequest
(JNIEnv *env, jobject obj, jbyteArray payment, jint index);

37
app/src/main/jni/transition/testingStuff.c

@ -1,37 +0,0 @@
#include <jni.h>
#include "stdio.h"
#include "string.h"
//#define DEBUG_TAG "NDK_AndroidNDK1SampleActivity"
JNIEXPORT jstring Java_com_breadwallet_presenter_activities_MainActivity_messageFromNativeCode
(JNIEnv *env, jobject this, jstring logThis) {
const char *nativeString = (*env)->GetStringUTFChars(env, logThis, 0);
return (*env)->NewStringUTF(env, nativeString);
}
JNIEXPORT jbyteArray Java_com_breadwallet_wallet_BRWalletManager_wallet
(JNIEnv *env, jobject obj) {
//test
struct wallet {
int account_number;
char *first_name;
char *last_name;
float balance;
};
struct wallet wallet1;
wallet1.account_number = 123;
wallet1.balance = 52415.21;
wallet1.first_name = "Mihail";
wallet1.last_name = "Gutan";
size_t wallet_size = sizeof(wallet1);
char raw_wallet[wallet_size];
memcpy(raw_wallet, &wallet1, wallet_size);
jbyteArray arr = (*env)->NewByteArray(env, wallet_size);
(*env)->SetByteArrayRegion(env, arr, 0, wallet_size, raw_wallet);
return arr;
}

2
app/src/main/jni/transition/wallet.c

File diff suppressed because one or more lines are too long

27
app/src/main/jni/transition/wallet.h

@ -11,6 +11,7 @@
extern BRWallet *_wallet;
extern jclass _walletManagerClass;
JNIEXPORT jbyteArray Java_com_breadwallet_wallet_BRWalletManager_encodeSeed(JNIEnv *env,
jobject thiz,
@ -24,16 +25,15 @@ JNIEXPORT void Java_com_breadwallet_wallet_BRWalletManager_createWallet(JNIEnv *
int r);
JNIEXPORT jbyteArray Java_com_breadwallet_wallet_BRWalletManager_getMasterPubKey(JNIEnv *env,
jobject thiz,
jstring phrase);
jobject thiz,
jstring phrase);
JNIEXPORT jbyteArray Java_com_breadwallet_wallet_BRWalletManager_putTransaction(JNIEnv *env,
JNIEXPORT void Java_com_breadwallet_wallet_BRWalletManager_putTransaction(JNIEnv *env,
jobject thiz,
jbyteArray transaction,
jlong blockHeight,
jlong timeStamp);
JNIEXPORT void Java_com_breadwallet_wallet_BRWalletManager_createTxArrayWithCount(JNIEnv *env,
jobject thiz,
int txCount);
@ -43,8 +43,8 @@ JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRWalletManager_validateA
JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRWalletManager_addressContainedInWallet
(JNIEnv *env, jobject obj, jstring address);
JNIEXPORT jlong JNICALL Java_com_breadwallet_wallet_BRWalletManager_getMinOutputAmount
(JNIEnv *env, jobject obj);
JNIEXPORT jdouble JNICALL Java_com_breadwallet_wallet_BRWalletManager_getMinOutputAmount
(JNIEnv *env, jobject obj) ;
JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRWalletManager_addressIsUsed
(JNIEnv *env, jobject obj, jstring address);
@ -65,7 +65,8 @@ JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRWalletManager_tryTransa
(JNIEnv *env, jobject obj, jstring address, jlong amount);
JNIEXPORT jboolean Java_com_breadwallet_wallet_BRWalletManager_pay(JNIEnv *env, jobject thiz,
jstring address, jlong amount,
jstring address,
jlong amount,
jstring strSeed);
JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRWalletManager_transactionIsVerified
@ -74,7 +75,17 @@ JNIEXPORT jboolean JNICALL Java_com_breadwallet_wallet_BRWalletManager_transacti
JNIEXPORT jlong JNICALL Java_com_breadwallet_wallet_BRWalletManager_getMaxOutputAmount
(JNIEnv *env, jobject obj);
const void *theSeed(void *info, const char *authPrompt, uint64_t amount, size_t *seedLen);
JNIEXPORT jlong Java_com_breadwallet_wallet_BRWalletManager_localAmount(JNIEnv *env, jobject thiz,
jlong amount,
double price);
JNIEXPORT jlong Java_com_breadwallet_wallet_BRWalletManager_bitcoinAmount(JNIEnv *env, jobject thiz,
jlong localAmount,
double price);
JNIEXPORT void Java_com_breadwallet_wallet_BRWalletManager_freeEverything(JNIEnv *env, jobject thiz);
//const void *theSeed(void *info, const char *authPrompt, uint64_t amount, size_t *seedLen);
#endif //BREADWALLET_WALLET_H

1
app/src/main/res/layout-sw600dp/fragment_settings.xml

@ -20,7 +20,6 @@
android:id="@+id/settings_line_1"
android:layout_width="match_parent"
android:layout_height="@dimen/separator_height"
android:layout_marginTop="30dp"
android:background="@color/grey" />
<RelativeLayout

1
app/src/main/res/layout/activity_main.xml

@ -42,6 +42,7 @@
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="2dp"
android:visibility="gone"
android:layout_below="@+id/main_button_burger"
android:progressDrawable="@drawable/progress_blue"
/>

77
app/src/main/res/layout/fingerprint_dialog_backup.xml

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/backup_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="8dp"
android:paddingTop="16dp">
<FrameLayout
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp">
<TextView
android:id="@+id/password_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/password_description"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorSecondary" />
<TextView
android:id="@+id/new_fingerprint_enrolled_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/new_fingerprint_enrolled_description"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorSecondary"
android:visibility="gone" />
</FrameLayout>
<EditText
android:id="@+id/password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/description"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="16dp"
android:ems="10"
android:hint="@string/password"
android:imeOptions="actionGo"
android:inputType="textPassword" />
<CheckBox
android:id="@+id/use_fingerprint_in_future_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/password"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="16dp"
android:checked="true"
android:text="@string/use_fingerprint_in_future"
android:visibility="gone" />
</RelativeLayout>

65
app/src/main/res/layout/fingerprint_dialog_container.xml

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<include layout="@layout/fingerprint_dialog_content" />
<include
layout="@layout/fingerprint_dialog_backup"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:gravity="bottom"
style="?android:attr/buttonBarStyle">
<Space
android:id="@+id/spacer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<Button
android:id="@+id/cancel_button"
style="?android:attr/buttonBarNegativeButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/second_dialog_button"
style="?android:attr/buttonBarPositiveButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>

58
app/src/main/res/layout/fingerprint_dialog_content.xml

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2015 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fingerprint_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="8dp"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:paddingTop="16dp">
<TextView
android:id="@+id/fingerprint_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text="@string/fingerprint_description"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorSecondary"/>
<ImageView
android:id="@+id/fingerprint_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/fingerprint_description"
android:layout_marginTop="20dp"
android:src="@drawable/ic_fp_40px" />
<TextView
android:id="@+id/fingerprint_status"
style="@android:style/TextAppearance.Material.Body1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/fingerprint_icon"
android:layout_alignTop="@+id/fingerprint_icon"
android:layout_marginStart="16dp"
android:layout_toEndOf="@+id/fingerprint_icon"
android:gravity="center_vertical"
android:text="@string/fingerprint_hint"
android:textColor="@color/hint_color" />
</RelativeLayout>

4
app/src/main/res/layout/fragment_about.xml

@ -33,7 +33,7 @@
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="40dp"
android:text="breadwallet v 1.0"
android:text="breadwallet v0.6"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@color/dark_grey"
android:textSize="@dimen/text_size" />
@ -44,7 +44,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/about1"
android:layout_centerHorizontal="true"
android:text="copyright \u00A9 2015 breadwallet llc"
android:text="copyright \u00A9 2016 breadwallet llc"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@color/dark_grey"
android:textSize="@dimen/text_size" />

2
app/src/main/res/layout/fragment_main.xml

@ -38,6 +38,7 @@
android:src="@drawable/cameraguide_blue_small"
android:text="@string/scan_qr_code"
android:textAllCaps="false"
android:stateListAnimator="@null"
android:textColor="@color/dark_blue"
android:textSize="16sp" />
@ -46,6 +47,7 @@
android:layout_width="240dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:stateListAnimator="@null"
android:layout_marginTop="50dp"
android:background="@drawable/button_regular_blue"
android:shadowColor="@android:color/transparent"

2
app/src/main/res/layout/fragment_password_dialog.xml

@ -1,5 +1,5 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_width="260dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">

1
app/src/main/res/layout/fragment_qr_main.xml

@ -46,6 +46,7 @@
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textColor="@color/dark_blue"
android:padding="15dp"
android:textSize="14sp" />
</RelativeLayout>

6
app/src/main/res/layout/fragment_settings_all.xml

@ -3,6 +3,10 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="90dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/separator_height"
android:background="@color/grey" />
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@ -40,7 +44,7 @@
android:layout_height="wrap_content"
android:padding="20dp"
android:layout_gravity="center"
android:text="no Transactions"
android:text="@string/no_transactions"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@color/light_grey"
android:textSize="@dimen/text_size" />

5
app/src/main/res/layout/fragment_wipe_wallet.xml

@ -47,7 +47,6 @@
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="18sp" />
<EditText
android:id="@+id/editText_phrase"
android:layout_width="fill_parent"
@ -57,13 +56,11 @@
android:layout_marginLeft="20dp"
android:inputType="textMultiLine"
android:maxLines="5"
android:stretchColumns="4"
android:shrinkColumns="4"
android:scrollHorizontally="false"
android:singleLine="false"
android:layout_marginRight="20dp"
android:layout_marginTop="30dp"
android:gravity="top|center"
android:gravity="top"
android:imeOptions="actionDone" />
</RelativeLayout>

2
app/src/main/res/layout/intro_fragment_new_recover.xml

@ -16,12 +16,14 @@
android:layout_height="wrap_content"
android:background="@drawable/button_white"
android:textAllCaps="false"
android:stateListAnimator="@null"
android:text="@string/new_wallet"
android:textColor="@color/white"
android:textSize="20sp" />
<Button
android:id="@+id/intro_recover_wallet"
android:stateListAnimator="@null"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:layout_below="@+id/intro_new_wallet"

2
app/src/main/res/layout/intro_fragment_new_wallet.xml

@ -32,6 +32,7 @@
android:gravity="center"
android:text="@string/generate_phrase_text2"
android:textAlignment="center"
android:stateListAnimator="@null"
android:textColor="@color/white"
android:textSize="20sp" />
@ -41,6 +42,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/intro_new_wallet_text2"
android:stateListAnimator="@null"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:background="@drawable/button_white"

4
app/src/main/res/layout/transaction_list_item.xml

@ -54,7 +54,7 @@
android:clickable="false"
android:text="some dollars"
android:textColor="@color/grey"
android:textSize="13sp" />
android:textSize="14sp" />
<com.breadwallet.tools.AutoResizeTextView
@ -83,7 +83,7 @@
android:clickable="false"
android:text="some bits"
android:textColor="@color/dark_grey"
android:textSize="13sp"
android:textSize="14sp"
android:textStyle="bold" />
<com.breadwallet.tools.AutoResizeTextView

9
app/src/main/res/values/strings.xml

@ -20,7 +20,7 @@
<string name="ok_button">OK</string>
<string name="cancel_button">Cancel</string>
//End QR
<string name="app_name">BreadWallet</string>
<string name="app_name">breadwallet</string>
<string name="the_address">address</string>
<string name="action_settings">Settings</string>
<string name="title_activity_main">MainActivity</string>
@ -47,7 +47,7 @@
<string name="cancel">cancel</string>
<string name="alert">Alert</string>
<string name="mainfragment_clipboard_invalid_data">"clipboard doesn't contain a valid bitcoin address\n"</string>
<string name="ok">OK</string>
<string name="ok">ok</string>
<string name="sharing_message">Hi, here is my bitcoin address: </string>
<string name="dialog_receive_bitcoins">Receive bitcoins</string>
<string name="toast_address_copied">Address copied to clipboard</string>
@ -59,7 +59,7 @@
<string name="middle_view_tip_second">&#384; is for \'bits\'. &#384;1,000,000 = 1 bitcoin.</string>
<string name="done">done</string>
<string name="remind_me_later">remind me later</string>
<string name="insert_old_passcode">Insert old passcode</string>
<string name="enter_old_passcode">Enter old passcode</string>
<string name="chose_a_new_passcode">chose a new passcode</string>
<string name="verify_passcode">verify passcode</string>
<string name="insert_password">Insert password</string>
@ -151,8 +151,9 @@
<string name="generate_recovery_phrase">generate recovery phrase</string>
<string name="request">request</string>
<string name="pay">pay</string>
<string name="at_this_address">at this address:</string>
<string name="at_this_address">Receive bitcoins at this address:</string>
<string name="generate_phrase_text1">start a new wallet by generating a wallet recovery phrase</string>
<string name="generate_phrase_text2">if you ever lose your phone, you will need this phrase to recover your wallet</string>
<string name="i_wrote_it_down">I wrote it down:</string>
<string name="no_transactions">no transactions</string>
</resources>

4
gradle/wrapper/gradle-wrapper.properties

@ -1,6 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
#Thu Apr 07 15:22:46 PDT 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip

Loading…
Cancel
Save