{
4 |
5 | /**
6 | * Method will be called when operation has completed successfully
7 | *
8 | * @param result the result received
9 | */
10 | void onResult(T result);
11 |
12 | /**
13 | * Method will be called when operation has completed with error
14 | *
15 | * @param e the exception in case of error
16 | */
17 | void onError(Exception e);
18 | }
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/ServiceProvider.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core;
2 |
3 | public class ServiceProvider {
4 |
5 | /**
6 | * main ethereum network
7 | */
8 | public static final int NETWORK_ID_MAIN = 1;
9 |
10 | /**
11 | * ropsten ethereum TEST network
12 | */
13 | public static final int NETWORK_ID_ROPSTEN = 3;
14 |
15 | /**
16 | * rinkeby ethereum TEST network
17 | */
18 | public static final int NETWORK_ID_RINKEBY = 4;
19 |
20 | /**
21 | * truffle testrpc network
22 | */
23 | public static final int NETWORK_ID_TRUFFLE = 9;
24 |
25 |
26 | private String providerUrl;
27 | private int networkId;
28 |
29 | /**
30 | * A ServiceProvider used to connect to an ethereum node.
31 | *
32 | * For example to connect to an infura test node use
33 | * new ServiceProvider("https://ropsten.infura.io/YOURTOKEN", NETWORK_ID_ROPSTEN);
34 | *
35 | * @param providerUrl the provider to use
36 | * @param networkId for example see {@value #NETWORK_ID_MAIN} {@value NETWORK_ID_ROPSTEN} {@value
37 | * NETWORK_ID_RINKEBY}
38 | */
39 | public ServiceProvider(String providerUrl, int networkId) {
40 | this.providerUrl = providerUrl;
41 | this.networkId = networkId;
42 | }
43 |
44 | public String getProviderUrl() {
45 | return providerUrl;
46 | }
47 |
48 | public int getNetworkId() {
49 | return networkId;
50 | }
51 |
52 | public boolean isMainNet(){
53 | return networkId == NETWORK_ID_MAIN;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/TransactionId.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core;
2 |
3 | /**
4 | * Identifier of the transaction, can be use on etherscan.io
5 | * to find information about the transaction related to this TransactionId.
6 | */
7 | public interface TransactionId {
8 |
9 | /**
10 | * @return the transaction id
11 | */
12 | String id();
13 | }
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/TransactionIdImpl.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core;
2 |
3 | final class TransactionIdImpl implements TransactionId {
4 |
5 | private String id;
6 |
7 | TransactionIdImpl(String id) {
8 | this.id = id;
9 | }
10 |
11 | @Override
12 | public String id() {
13 | return id;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/exception/AccountDeletedException.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.exception;/**/
2 |
3 | public class AccountDeletedException extends OperationFailedException {
4 |
5 | public AccountDeletedException() {
6 | super("Account deleted, Create new account");
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/exception/CreateAccountException.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.exception;
2 |
3 |
4 | public class CreateAccountException extends Exception {
5 |
6 | public CreateAccountException(Throwable cause) {
7 | super(cause);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/exception/DeleteAccountException.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.exception;
2 |
3 |
4 | public class DeleteAccountException extends Exception {
5 |
6 | public DeleteAccountException(Throwable cause) {
7 | super(cause);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/exception/EthereumClientException.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.exception;
2 |
3 | public class EthereumClientException extends Exception {
4 |
5 | public EthereumClientException(String message) {
6 | super(message);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/exception/OperationFailedException.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.exception;
2 |
3 | public class OperationFailedException extends Exception {
4 |
5 | public OperationFailedException(Throwable cause) {
6 | super(cause);
7 | }
8 |
9 | public OperationFailedException(String message) {
10 | super(message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/exception/PassphraseException.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.exception;
2 |
3 | public class PassphraseException extends Exception {
4 |
5 | public PassphraseException() {
6 | super("Wrong passphrase - could not decrypt key with given passphrase");
7 | }
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/util/HexUtils.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.util;
2 |
3 | public class HexUtils {
4 |
5 | public static byte[] hexStringToByteArray(String s) {
6 | int len = s.length();
7 | byte[] data = new byte[len / 2];
8 | for (int i = 0; i < len; i += 2) {
9 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
10 | + Character.digit(s.charAt(i + 1), 16));
11 | }
12 | return data;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/java/kin/sdk/core/util/KinConverter.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.util;
2 |
3 | import java.math.BigDecimal;
4 | import org.ethereum.geth.BigInt;
5 | import org.ethereum.geth.Geth;
6 |
7 | /**
8 | * A Utility class used to convert currency values to/from Kin.
9 | */
10 | public class KinConverter {
11 |
12 | private static final BigDecimal KIN = BigDecimal.TEN.pow(18);
13 |
14 | private static BigInt toBigInt(BigDecimal bigDecimal) {
15 | BigInt bigInt = Geth.newBigInt(0L);
16 | //to get ByteArray representation, convert to Java BigInteger (will discard the fractional part)
17 | //then extract ByteArray from the BigInteger, BigInteger representation is in two's complement,
18 | // but as we're not dealing with negative numbers, it's safe to init the Unsigned BigInt with it
19 | bigInt.setBytes(bigDecimal.toBigInteger().toByteArray());
20 | return bigInt;
21 | }
22 |
23 | public static BigInt fromKin(BigDecimal value) {
24 | BigDecimal bigDecimal = value.multiply(KIN);
25 | return toBigInt(bigDecimal);
26 | }
27 |
28 | public static BigDecimal toKin(BigInt value) {
29 | return toKin(new BigDecimal(value.string()));
30 | }
31 |
32 | public static BigDecimal toKin(BigDecimal value) {
33 | return value.divide(KIN, 18, BigDecimal.ROUND_FLOOR);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/kin-sdk-core/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | kin-sdk-core-sample
3 |
4 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/contracts/BasicToken.sol:
--------------------------------------------------------------------------------
1 | ../kin-token/contracts/BasicToken.sol
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/contracts/BasicTokenMock.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.15;
2 |
3 | import './BasicToken.sol';
4 |
5 | contract BasicTokenMock is BasicToken {
6 | function assign(address _account, uint _balance) {
7 | balances[_account] = _balance;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/contracts/ERC20.sol:
--------------------------------------------------------------------------------
1 | ../kin-token/contracts/ERC20.sol
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/contracts/Migrations.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.15;
2 |
3 | contract Migrations {
4 | address public owner;
5 | uint public last_completed_migration;
6 |
7 | modifier restricted() {
8 | if (msg.sender == owner) _;
9 | }
10 |
11 | function Migrations() public {
12 | owner = msg.sender;
13 | }
14 |
15 | function setCompleted(uint completed) public restricted {
16 | last_completed_migration = completed;
17 | }
18 |
19 | function upgrade(address new_address) public restricted {
20 | Migrations upgraded = Migrations(new_address);
21 | upgraded.setCompleted(last_completed_migration);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/contracts/SafeMath.sol:
--------------------------------------------------------------------------------
1 | ../kin-token/contracts/SafeMath.sol
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | let Migrations = artifacts.require('../contracts/Migrations.sol');
3 | let TestToken = artifacts.require('../contracts/BasicTokenMock.sol');
4 |
5 | module.exports = (deployer, network, accounts) => {
6 | deployer.deploy(Migrations);
7 | deployer.deploy(TestToken).then(async() => {
8 | instance = await TestToken.deployed()
9 | console.log(`TestToken contract deployed at ${instance.address}`);
10 |
11 | // give tokens to the testing account
12 | let numTokens = 1000;
13 | ok = await instance.assign(accounts[0], web3.toWei(numTokens, "ether"));
14 | assert.ok(ok);
15 |
16 | // check resulting balance
17 | let balanceWei = (await instance.balanceOf(accounts[0])).toNumber();
18 | assert.equal(web3.fromWei(balanceWei, "ether"), numTokens);
19 | console.log(`Assigned ${numTokens} tokens to account ${accounts[0]} ...`);
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kin-sdk-core-android",
3 | "version": "0.0.1",
4 | "description": "Kin SDK Core Android",
5 | "repository": "git@github.com:kinfoundation/kin-sdk-core-android.git",
6 | "author": "Kik",
7 | "license": "",
8 | "main": "truffle.js",
9 | "scripts": {
10 | "testrpc": "scripts/testrpc.sh"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/kinfoundation/kin-sdk-core-android/issues"
14 | },
15 | "homepage": "https://github.com/kinfoundation/kin-sdk-core-android",
16 | "dependencies": {
17 | "babel-polyfill": "^6.26.0",
18 | "babel-preset-es2015": "^6.24.1",
19 | "babel-preset-stage-2": "^6.24.1",
20 | "babel-preset-stage-3": "^6.24.1",
21 | "babel-register": "^6.26.0",
22 | "bignumber.js": "^4.0.2",
23 | "kinfoundation-ethereumjs-testrpc": "6.0.4",
24 | "lerna": "^2.0.0",
25 | "lodash": "^4.17.4",
26 | "truffle": "^4.0.1",
27 | "web3": "^1.0.0-beta.18",
28 | "xtend": "^4.0.1",
29 | "yargs": "^8.0.2"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/scripts/prepare-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # export account address environment variables
4 | # see this file for available variables
5 | cd kin-sdk-core/truffle
6 |
7 | source ./scripts/testrpc-accounts.sh
8 |
9 | # create variables
10 | configFile="../src/androidTest/assets/testConfig.json"
11 |
12 | # export token contract address environment variable
13 | export TOKEN_CONTRACT_ADDRESS=$(cat ./token-contract-address)
14 | test -n "${TOKEN_CONTRACT_ADDRESS}"
15 | echo "Set Contract Address ${TOKEN_CONTRACT_ADDRESS}"
16 | echo ""
17 | # write contract address to testConfig.json, will be read by androidTest
18 | printf '"token_contract_address":"%s"\n' "${TOKEN_CONTRACT_ADDRESS}" >> ${configFile}
19 |
20 | # write closing bracket to testConfig.json
21 | printf '}' >> ${configFile}
22 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/scripts/testrpc-accounts.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # create 10 accounts with balance 100 ETH each
4 | balance=100000000000000000000
5 |
6 | export ACCOUNT_0_PRIVATE_KEY=0x11c98b8fa69354b26b5db98148a5bc4ef2ebae8187f651b82409f6cefc9bb0b8
7 | export ACCOUNT_1_PRIVATE_KEY=0xc5db67b3865454f6d129ec83204e845a2822d9fe5338ff46fe4c126859e1357e
8 | export ACCOUNT_2_PRIVATE_KEY=0x6ac1a8c98fa298af3884406fbd9468dca5200898f065e1283fc85dff95646c25
9 | export ACCOUNT_3_PRIVATE_KEY=0xbd9aebf18275f8074c53036818e8583b242f9bdfb7c0e79088007cb39a96e097
10 | export ACCOUNT_4_PRIVATE_KEY=0x8b727508230fda8e0ec96b7c9e51c89ff0e41ba30fad221c2f0fe942158571b1
11 | export ACCOUNT_5_PRIVATE_KEY=0x514111937962a290ba6afa3dd0044e0720148b46cd2dbc8045e811f8157b6b1a
12 | export ACCOUNT_6_PRIVATE_KEY=0x52f21c3eedc184eb13fcd5ec8e45e6741d97bca85a8703d733fab9c19f5e8518
13 | export ACCOUNT_7_PRIVATE_KEY=0xbca3035e18b3f87a38fa34fcc2561a023fe1f9b93354c04c772f37497ef08f3e
14 | export ACCOUNT_8_PRIVATE_KEY=0x2d8676754eb3d184f3e9428c5d52eacdf1d507593ba50c3ef2a59e1a3a46b578
15 | export ACCOUNT_9_PRIVATE_KEY=0xabf8c2dd52f5b14ea437325854048e5daadbca80f99f9d6f8e97ab5e05d4f0ab
16 |
17 | account_array=( \
18 | $ACCOUNT_0_PRIVATE_KEY \
19 | $ACCOUNT_1_PRIVATE_KEY \
20 | $ACCOUNT_2_PRIVATE_KEY \
21 | $ACCOUNT_3_PRIVATE_KEY \
22 | $ACCOUNT_4_PRIVATE_KEY \
23 | $ACCOUNT_5_PRIVATE_KEY \
24 | $ACCOUNT_6_PRIVATE_KEY \
25 | $ACCOUNT_7_PRIVATE_KEY \
26 | $ACCOUNT_8_PRIVATE_KEY \
27 | $ACCOUNT_9_PRIVATE_KEY \
28 | )
29 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/scripts/testrpc-kill.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | cd kin-sdk-core/truffle
4 |
5 | if [ -f './testrpc.pid' ]; then
6 | echo "killing testrpc on port $(cat ./testrpc.pid)"
7 | # Don't fail if the process is already killed
8 | kill -SIGINT $(cat ./testrpc.pid) || true
9 | rm -f ./testrpc.pid
10 | else
11 | echo "./testrpc.pid not found, doing nothing"
12 | fi
13 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/scripts/testrpc-run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | cd kin-sdk-core/truffle
4 | # prepare testrpc accounts parameter string e.g. --account="0x11c..,1000" --account="0xc5d...,1000" ....
5 | source ./scripts/testrpc-accounts.sh
6 |
7 | # create variables
8 | configFile="../src/androidTest/assets/testConfig.json"
9 | accounts=""
10 |
11 | # clear config file
12 | > $configFile
13 |
14 | # copy output to testConfig.json, will be read by androidTest
15 | printf '{ \n "accounts": [' >> ${configFile}
16 | comma=','
17 | for i in ${!account_array[@]}; do
18 | accounts+=$(printf '%saccount=%s,%s' "--" "${account_array[i]}" "${balance}")
19 |
20 | printf '{\n "private_key":"%s"\n }%s\n' "${account_array[i]}" "${comma}" >> ${configFile}
21 |
22 | if [ $i -lt 8 ]; then
23 | comma=','
24 | else
25 | comma=''
26 | fi
27 |
28 | if [ $i -lt 10 ]; then
29 | accounts+=" "
30 | fi
31 | done
32 | # accounts closing bracket, contract address is added in prepare-tests.sh
33 | printf '], \n' >> ${configFile}
34 |
35 | if (nc -z localhost 8545); then
36 | echo "Using existing testrpc instance on port $(ps -fade | grep -e 'node.*testrpc' | head -n 1 | awk '{print $2}')"
37 | else
38 | echo -n "Starting testrpc instance on port ${port} "
39 | ./node_modules/.bin/testrpc ${accounts} -u 0 -u 1 -p "${port}" > testrpc.log 2>&1 & echo $! > testrpc.pid
40 | echo $(cat testrpc.pid)
41 | fi
42 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/scripts/truffle.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | cd kin-sdk-core/truffle
4 |
5 | ./node_modules/.bin/truffle deploy --reset > ./truffle.log 2>&1
6 |
7 | cat ./truffle.log | grep "Token contract deployed at" | tail -n 1 | awk '{print $5}' > ./token-contract-address
8 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/token-contract-address:
--------------------------------------------------------------------------------
1 | 0x8919486b0afaad4656e8f9667ce9adbb62c3f2b1
2 |
--------------------------------------------------------------------------------
/kin-sdk-core/truffle/truffle.js:
--------------------------------------------------------------------------------
1 | require('babel-register');
2 | require('babel-polyfill');
3 |
4 | module.exports = {
5 | networks: {
6 | development: {
7 | host: 'localhost',
8 | port: 8545,
9 | network_id: '*', // Match any network id
10 | gas: 3500000
11 | }
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/kin_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/kin_android.png
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion "26.0.2"
6 | defaultConfig {
7 | applicationId "kin.sdk.core.sample"
8 | minSdkVersion 16
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | compileOptions {
21 | sourceCompatibility JavaVersion.VERSION_1_8
22 | targetCompatibility JavaVersion.VERSION_1_8
23 | }
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(include: ['*.jar'], dir: 'libs')
28 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
29 | exclude group: 'com.android.support', module: 'support-annotations'
30 | })
31 | implementation 'com.android.support:appcompat-v7:26.+'
32 | testImplementation 'junit:junit:4.12'
33 | api project(':kin-sdk-core')
34 | compile 'com.android.volley:volley:1.0.0'
35 | }
36 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
26 |
31 |
35 |
40 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.MenuItem;
8 | import android.view.View;
9 | import android.view.inputmethod.InputMethodManager;
10 | import kin.sdk.core.KinClient;
11 |
12 | public abstract class BaseActivity extends AppCompatActivity {
13 |
14 | // ideally user should be asked for a passphrase when
15 | // creating an account and then the same passphrase
16 | // should be used when sending transactions
17 | // To make the UI simpler for the sample application
18 | // we are using a hardcoded passphrase.
19 | final static String PASSPHRASE1 = "12345";
20 | final static int NO_ACTION_BAR_TITLE = -1;
21 |
22 | abstract Intent getBackIntent();
23 |
24 | abstract int getActionBarTitleRes();
25 |
26 | public boolean isMainNet() {
27 | if (getKinClient() != null && getKinClient().getServiceProvider() != null) {
28 | return getKinClient().getServiceProvider().isMainNet();
29 | }
30 | return false;
31 | }
32 |
33 | protected boolean hasBack() {
34 | return true;
35 | }
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | int theme = isMainNet() ? R.style.AppTheme_Main : R.style.AppTheme_Test;
41 | setTheme(theme);
42 | initActionBar();
43 | }
44 |
45 | private void initActionBar() {
46 | if (getActionBarTitleRes() != NO_ACTION_BAR_TITLE) {
47 | getSupportActionBar().setTitle(getActionBarTitleRes());
48 | }
49 | getSupportActionBar().setDisplayHomeAsUpEnabled(hasBack());
50 | }
51 |
52 | @Override
53 | public void onBackPressed() {
54 | Intent intent = getBackIntent();
55 | if (intent != null) {
56 | startActivity(intent);
57 | overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_left);
58 | }
59 | finish();
60 | }
61 |
62 | public KinClient getKinClient() {
63 | KinClientSampleApplication application = (KinClientSampleApplication) getApplication();
64 | return application.getKinClient();
65 | }
66 |
67 | @Override
68 | public boolean onOptionsItemSelected(MenuItem item) {
69 | onBackPressed();
70 | return true;
71 | }
72 |
73 | @Override
74 | public void startActivity(Intent intent) {
75 | super.startActivity(intent);
76 | overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_right);
77 | finish();
78 | }
79 |
80 | public String getPassphrase() {
81 | return PASSPHRASE1;
82 | }
83 |
84 | protected void hideKeyboard(View view) {
85 | InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
86 | inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/ChooseNetworkActivity.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.Paint;
6 | import android.os.Bundle;
7 | import android.text.Html;
8 | import android.widget.TextView;
9 | import kin.sdk.core.KinClient;
10 |
11 | /**
12 | * User is given a choice to create or use an account on the MAIN or ROPSTEN(test) ethereum networks
13 | */
14 | public class ChooseNetworkActivity extends BaseActivity {
15 |
16 | public static final String TAG = ChooseNetworkActivity.class.getSimpleName();
17 | private static final String KIN_FOUNDATION_URL = "https://github.com/kinfoundation";
18 |
19 | public static Intent getIntent(Context context) {
20 | return new Intent(context, ChooseNetworkActivity.class);
21 | }
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.choose_network_activity);
27 | initWidgets();
28 | }
29 |
30 | @Override
31 | protected boolean hasBack() {
32 | return false;
33 | }
34 |
35 | private void initWidgets() {
36 | TextView urlTextView = (TextView) findViewById(R.id.kin_foundation_url);
37 | urlTextView.setPaintFlags(urlTextView.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
38 | urlTextView.setText(Html.fromHtml(KIN_FOUNDATION_URL));
39 | urlTextView.setOnClickListener(view -> startWebWrapperActivity());
40 | findViewById(R.id.kin_icon).setOnClickListener(view -> startWebWrapperActivity());
41 | findViewById(R.id.btn_main_net).setOnClickListener(
42 | view -> createKinClient(KinClientSampleApplication.NetWorkType.MAIN));
43 |
44 | findViewById(R.id.btn_test_net).setOnClickListener(
45 | view -> createKinClient(KinClientSampleApplication.NetWorkType.ROPSTEN));
46 | }
47 |
48 | private void createKinClient(KinClientSampleApplication.NetWorkType netWorkType) {
49 | KinClientSampleApplication application = (KinClientSampleApplication) getApplication();
50 | KinClient kinClient = application.createKinClient(netWorkType);
51 | if (kinClient.hasAccount()) {
52 | startActivity(WalletActivity.getIntent(this));
53 | } else {
54 | startActivity(CreateWalletActivity.getIntent(this));
55 | }
56 | }
57 |
58 | private void startWebWrapperActivity(){
59 | startActivity(WebWrapperActivity.getIntent(this, KIN_FOUNDATION_URL));
60 | }
61 |
62 | @Override
63 | Intent getBackIntent() {
64 | return null;
65 | }
66 |
67 | @Override
68 | int getActionBarTitleRes() {
69 | return R.string.app_name;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/CreateWalletActivity.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import kin.sdk.core.KinClient;
8 | import kin.sdk.core.exception.CreateAccountException;
9 | import kin.sdk.core.sample.kin.sdk.core.sample.dialog.KinAlertDialog;
10 |
11 | /**
12 | * This activity is displayed only if there is no existing account stored on device for the given network
13 | * The activity will just display a button to create an account
14 | */
15 | public class CreateWalletActivity extends BaseActivity {
16 |
17 | public static final String TAG = CreateWalletActivity.class.getSimpleName();
18 |
19 | public static Intent getIntent(Context context) {
20 | return new Intent(context, CreateWalletActivity.class);
21 | }
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.create_wallet_activity);
27 | initWidgets();
28 | }
29 |
30 | private void initWidgets() {
31 | View createWallet = findViewById(R.id.btn_create_wallet);
32 | if (isMainNet()) {
33 | createWallet.setBackgroundResource(R.drawable.button_main_network_bg);
34 | }
35 | createWallet.setOnClickListener(view -> createAccount());
36 | }
37 |
38 | private void createAccount() {
39 | try {
40 | final KinClient kinClient = getKinClient();
41 | kinClient.createAccount(getPassphrase());
42 | startActivity(WalletActivity.getIntent(this));
43 | } catch (CreateAccountException e) {
44 | KinAlertDialog.createErrorDialog(this, e.getMessage()).show();
45 | }
46 | }
47 |
48 | @Override
49 | Intent getBackIntent() {
50 | return ChooseNetworkActivity.getIntent(this);
51 | }
52 |
53 | @Override
54 | int getActionBarTitleRes() {
55 | return R.string.create_wallet;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/DisplayCallback.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import kin.sdk.core.ResultCallback;
6 | import kin.sdk.core.sample.kin.sdk.core.sample.dialog.KinAlertDialog;
7 |
8 | /**
9 | * Will hide a progressBar and display result on a displayView passed at constructor
10 | * Holds the views as weakReferences and clears the references when canceled
11 | */
12 | public abstract class DisplayCallback implements ResultCallback {
13 |
14 | private View progressBar;
15 | private View displayView;
16 |
17 | public DisplayCallback(View progressBar, View displayView) {
18 | this.progressBar = progressBar;
19 | this.displayView = displayView;
20 | }
21 |
22 | public DisplayCallback(View progressBar) {
23 | this.progressBar = progressBar;
24 | }
25 |
26 | /**
27 | * displayView will be null if DisplayCallback was constructed using the single parameter constructor.
28 | */
29 | abstract public void displayResult(Context context, View displayView, T result);
30 |
31 | @Override
32 | public void onResult(T result) {
33 | progressBar.setVisibility(View.GONE);
34 | displayResult(progressBar.getContext(), displayView, result);
35 | }
36 |
37 | @Override
38 | public void onError(Exception e) {
39 | progressBar.setVisibility(View.GONE);
40 | KinAlertDialog.createErrorDialog(progressBar.getContext(), e.getMessage()).show();
41 | }
42 | }
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/ExportKeystoreActivity.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.text.Editable;
7 | import android.text.TextUtils;
8 | import android.text.TextWatcher;
9 | import android.view.View;
10 | import android.widget.EditText;
11 | import android.widget.TextView;
12 | import kin.sdk.core.KinAccount;
13 | import kin.sdk.core.exception.AccountDeletedException;
14 | import kin.sdk.core.exception.OperationFailedException;
15 | import kin.sdk.core.exception.PassphraseException;
16 | import kin.sdk.core.sample.kin.sdk.core.sample.dialog.KinAlertDialog;
17 | import org.json.JSONException;
18 | import org.json.JSONObject;
19 |
20 | /**
21 | * Enter passphrase to generate Json content that can be used to access the current account
22 | */
23 | public class ExportKeystoreActivity extends BaseActivity {
24 |
25 | public static final String TAG = ExportKeystoreActivity.class.getSimpleName();
26 |
27 | public static Intent getIntent(Context context) {
28 | return new Intent(context, ExportKeystoreActivity.class);
29 | }
30 |
31 | private View exportBtn, copyBtn;
32 | private EditText passphraseInput;
33 | private TextView outputTextView;
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.export_key_store_activity);
39 | initWidgets();
40 | }
41 |
42 | private void initWidgets() {
43 | copyBtn = findViewById(R.id.copy_btn);
44 | exportBtn = findViewById(R.id.generate_btn);
45 | passphraseInput = (EditText) findViewById(R.id.passphrase_input);
46 | outputTextView = (TextView) findViewById(R.id.output);
47 |
48 | findViewById(R.id.copy_btn).setOnClickListener(view -> {
49 | selectAll();
50 | Utils.copyToClipboard(this, outputTextView.getText());
51 | });
52 |
53 | if (isMainNet()) {
54 | exportBtn.setBackgroundResource(R.drawable.button_main_network_bg);
55 | copyBtn.setBackgroundResource(R.drawable.button_main_network_bg);
56 | }
57 | passphraseInput.addTextChangedListener(new TextWatcher() {
58 | @Override
59 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
60 |
61 | }
62 |
63 | @Override
64 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
65 | if (!TextUtils.isEmpty(charSequence)) {
66 | clearOutput();
67 | if (!exportBtn.isEnabled()) {
68 | exportBtn.setEnabled(true);
69 | }
70 | } else if (exportBtn.isEnabled()) {
71 | exportBtn.setEnabled(false);
72 | }
73 | }
74 |
75 | @Override
76 | public void afterTextChanged(Editable editable) {
77 |
78 | }
79 | });
80 |
81 | passphraseInput.setOnFocusChangeListener((view, hasFocus) -> {
82 | if (!hasFocus) {
83 | hideKeyboard(view);
84 | }
85 | });
86 |
87 | exportBtn.setOnClickListener(view -> {
88 | exportBtn.setEnabled(false);
89 | hideKeyboard(exportBtn);
90 | try {
91 | String jsonFormatString = generatePrivateKeyStoreJsonFormat();
92 | updateOutput(jsonFormatString);
93 | copyBtn.setEnabled(true);
94 | } catch (PassphraseException e) {
95 | clearAll();
96 | KinAlertDialog.createErrorDialog(this, e.getMessage()).show();
97 | } catch (JSONException e) {
98 | clearAll();
99 | KinAlertDialog.createErrorDialog(this, e.getMessage()).show();
100 | } catch (OperationFailedException e) {
101 | clearAll();
102 | KinAlertDialog.createErrorDialog(this, e.getMessage()).show();
103 | }
104 | });
105 | }
106 |
107 | private void clearAll() {
108 | clearOutput();
109 | passphraseInput.setText("");
110 | }
111 |
112 | private void selectAll() {
113 | outputTextView.setSelectAllOnFocus(true);
114 | outputTextView.clearFocus();
115 | outputTextView.requestFocus();
116 | outputTextView.setSelectAllOnFocus(false);
117 | }
118 |
119 | private String generatePrivateKeyStoreJsonFormat()
120 | throws PassphraseException, JSONException, OperationFailedException {
121 | KinAccount account = getKinClient().getAccount();
122 | if (account == null) {
123 | throw new AccountDeletedException();
124 | }
125 | String jsonString = account.exportKeyStore(getPassphrase(), passphraseInput.getText().toString());
126 | JSONObject jsonObject = new JSONObject(jsonString);
127 | return jsonObject.toString(1);
128 | }
129 |
130 | private void updateOutput(String outputString) {
131 | if (TextUtils.isEmpty(outputString)) {
132 | outputTextView.setText(outputString);
133 | outputTextView.setTextIsSelectable(false);
134 | } else {
135 | outputTextView.setText(outputString);
136 | outputTextView.setTextIsSelectable(true);
137 | outputTextView.requestFocus();
138 | }
139 | }
140 |
141 | private void clearOutput() {
142 | updateOutput(null);
143 | copyBtn.setEnabled(false);
144 | }
145 |
146 | @Override
147 | Intent getBackIntent() {
148 | return WalletActivity.getIntent(this);
149 | }
150 |
151 | @Override
152 | int getActionBarTitleRes() {
153 | return R.string.export_key_store;
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/KinClientSampleApplication.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.app.Application;
4 | import kin.sdk.core.KinClient;
5 | import kin.sdk.core.ServiceProvider;
6 | import kin.sdk.core.exception.EthereumClientException;
7 |
8 | public class KinClientSampleApplication extends Application {
9 |
10 | //based on parity
11 | private final String ROPSTEN_TEST_NET_URL = "http://parity.rounds.video:8545";
12 | private final String MAIN_NET_URL = "http://mainnet.rounds.video:8545";
13 |
14 |
15 | public enum NetWorkType {
16 | MAIN,
17 | ROPSTEN;
18 | }
19 |
20 | private KinClient kinClient = null;
21 |
22 | public KinClient createKinClient(NetWorkType type) {
23 | String providerUrl;
24 | int netWorkId;
25 | switch (type) {
26 | case MAIN:
27 | providerUrl = MAIN_NET_URL;
28 | netWorkId = ServiceProvider.NETWORK_ID_MAIN;
29 | break;
30 | case ROPSTEN:
31 | providerUrl = ROPSTEN_TEST_NET_URL;
32 | netWorkId = ServiceProvider.NETWORK_ID_ROPSTEN;
33 | break;
34 | default:
35 | providerUrl = ROPSTEN_TEST_NET_URL;
36 | netWorkId = ServiceProvider.NETWORK_ID_ROPSTEN;
37 | }
38 | try {
39 | kinClient = new KinClient(this,
40 | new ServiceProvider(providerUrl, netWorkId));
41 | } catch (EthereumClientException e) {
42 | e.printStackTrace();
43 | }
44 | return kinClient;
45 | }
46 |
47 | public KinClient getKinClient() {
48 | return kinClient;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/TransactionActivity.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.text.Editable;
7 | import android.text.TextUtils;
8 | import android.text.TextWatcher;
9 | import android.view.View;
10 | import android.widget.EditText;
11 | import java.math.BigDecimal;
12 | import kin.sdk.core.KinAccount;
13 | import kin.sdk.core.Request;
14 | import kin.sdk.core.TransactionId;
15 | import kin.sdk.core.exception.AccountDeletedException;
16 | import kin.sdk.core.exception.OperationFailedException;
17 | import kin.sdk.core.sample.kin.sdk.core.sample.dialog.KinAlertDialog;
18 |
19 | /**
20 | * Displays form to enter public address and amount and a button to send a transaction
21 | */
22 | public class TransactionActivity extends BaseActivity {
23 |
24 | public static final String TAG = TransactionActivity.class.getSimpleName();
25 |
26 | public static Intent getIntent(Context context) {
27 | return new Intent(context, TransactionActivity.class);
28 | }
29 |
30 | private View sendTransaction, progressBar;
31 | private EditText toAddressInput, amountInput;
32 | private Request transactionRequest;
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.transaction_activity);
38 | initWidgets();
39 | }
40 |
41 | private void initWidgets() {
42 | sendTransaction = findViewById(R.id.send_transaction_btn);
43 | progressBar = findViewById(R.id.transaction_progress);
44 | toAddressInput = (EditText) findViewById(R.id.to_address_input);
45 | amountInput = (EditText) findViewById(R.id.amount_input);
46 |
47 | if (getKinClient().getServiceProvider().isMainNet()) {
48 | sendTransaction.setBackgroundResource(R.drawable.button_main_network_bg);
49 | }
50 | toAddressInput.addTextChangedListener(new TextWatcher() {
51 | @Override
52 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
53 |
54 | }
55 |
56 | @Override
57 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
58 | if (!TextUtils.isEmpty(charSequence) && !TextUtils.isEmpty(amountInput.getText())) {
59 | if (!sendTransaction.isEnabled()) {
60 | sendTransaction.setEnabled(true);
61 | }
62 | } else if (sendTransaction.isEnabled()) {
63 | sendTransaction.setEnabled(false);
64 | }
65 | }
66 |
67 | @Override
68 | public void afterTextChanged(Editable editable) {
69 |
70 | }
71 | });
72 |
73 | amountInput.addTextChangedListener(new TextWatcher() {
74 | @Override
75 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
76 |
77 | }
78 |
79 | @Override
80 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
81 | if (!TextUtils.isEmpty(charSequence) && !TextUtils.isEmpty(toAddressInput.getText())) {
82 | if (!sendTransaction.isEnabled()) {
83 | sendTransaction.setEnabled(true);
84 | }
85 | } else if (sendTransaction.isEnabled()) {
86 | sendTransaction.setEnabled(false);
87 | }
88 | }
89 |
90 | @Override
91 | public void afterTextChanged(Editable editable) {
92 |
93 | }
94 | });
95 |
96 | toAddressInput.setOnFocusChangeListener((view, hasFocus) -> {
97 | if (!hasFocus && !toAddressInput.hasFocus()) {
98 | hideKeyboard(view);
99 | }
100 | });
101 |
102 | amountInput.setOnFocusChangeListener((view, hasFocus) -> {
103 | if (!hasFocus && !amountInput.hasFocus()) {
104 | hideKeyboard(view);
105 | }
106 | });
107 |
108 | sendTransaction.setOnClickListener(view -> {
109 | BigDecimal amount = new BigDecimal(amountInput.getText().toString());
110 | try {
111 | sendTransaction(toAddressInput.getText().toString(), amount);
112 | } catch (OperationFailedException e) {
113 | KinAlertDialog.createErrorDialog(TransactionActivity.this, e.getMessage()).show();
114 | }
115 | });
116 | }
117 |
118 | @Override
119 | Intent getBackIntent() {
120 | return WalletActivity.getIntent(this);
121 | }
122 |
123 | @Override
124 | int getActionBarTitleRes() {
125 | return R.string.transaction;
126 | }
127 |
128 | private void sendTransaction(String toAddress, BigDecimal amount) throws OperationFailedException {
129 | progressBar.setVisibility(View.VISIBLE);
130 | KinAccount account = getKinClient().getAccount();
131 | if (account != null) {
132 | transactionRequest = account
133 | .sendTransaction(toAddress, getPassphrase(), amount);
134 | transactionRequest.run(new DisplayCallback(progressBar) {
135 | @Override
136 | public void displayResult(Context context, View view, TransactionId transactionId) {
137 | KinAlertDialog.createErrorDialog(context, "Transaction id " + transactionId.id()).show();
138 | }
139 | });
140 | } else {
141 | progressBar.setVisibility(View.GONE);
142 | throw new AccountDeletedException();
143 | }
144 | }
145 |
146 | @Override
147 | protected void onDestroy() {
148 | super.onDestroy();
149 | if (transactionRequest != null) {
150 | transactionRequest.cancel(false);
151 | }
152 | progressBar = null;
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/Utils.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 |
5 | public class Utils {
6 |
7 | public static void copyToClipboard(Context context, CharSequence textToCopy) {
8 | int sdk = android.os.Build.VERSION.SDK_INT;
9 | if (sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
10 | android.text.ClipboardManager clipboard = (android.text.ClipboardManager) context.getSystemService(
11 | Context.CLIPBOARD_SERVICE);
12 | clipboard.setText(textToCopy);
13 | } else {
14 | android.content.ClipboardManager clipboard = (android.content.ClipboardManager) context.getSystemService(
15 | Context.CLIPBOARD_SERVICE);
16 | android.content.ClipData clip = android.content.ClipData
17 | .newPlainText("copied text", textToCopy);
18 | clipboard.setPrimaryClip(clip);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/WalletActivity.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.TextView;
8 | import com.android.volley.Request;
9 | import com.android.volley.RequestQueue;
10 | import com.android.volley.toolbox.StringRequest;
11 | import com.android.volley.toolbox.Volley;
12 | import kin.sdk.core.Balance;
13 | import kin.sdk.core.KinAccount;
14 | import kin.sdk.core.exception.DeleteAccountException;
15 | import kin.sdk.core.sample.kin.sdk.core.sample.dialog.KinAlertDialog;
16 |
17 | /**
18 | * Responsible for presenting details about the account
19 | * Public address, account balance, account pending balance
20 | * and in future we will add here button to backup the account (show usage of exportKeyStore)
21 | * In addition there is "Send Transaction" button here that will navigate to TransactionActivity
22 | */
23 | public class WalletActivity extends BaseActivity {
24 |
25 | public static final String TAG = WalletActivity.class.getSimpleName();
26 | public static final String URL_GET_KIN = "http://kin-faucet.rounds.video/send?public_address=";
27 |
28 | public static Intent getIntent(Context context) {
29 | return new Intent(context, WalletActivity.class);
30 | }
31 |
32 | private TextView balance, pendingBalance, publicKey;
33 | private View getKinBtn;
34 | private View balanceProgress, pendingBalanceProgress;
35 | private kin.sdk.core.Request pendingBalanceRequest;
36 | private kin.sdk.core.Request balanceRequest;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.wallet_activity);
42 | initWidgets();
43 | }
44 |
45 | @Override
46 | protected void onResume() {
47 | super.onResume();
48 | updatePublicKey();
49 | updateBalance();
50 | updatePendingBalance();
51 | }
52 |
53 | private void initWidgets() {
54 | balance = (TextView) findViewById(R.id.balance);
55 | pendingBalance = (TextView) findViewById(R.id.pending_balance);
56 | publicKey = (TextView) findViewById(R.id.public_key);
57 |
58 | balanceProgress = findViewById(R.id.balance_progress);
59 | pendingBalanceProgress = findViewById(R.id.pending_balance_progress);
60 |
61 | final View transaction = findViewById(R.id.send_transaction_btn);
62 | final View refresh = findViewById(R.id.refresh_btn);
63 | getKinBtn = findViewById(R.id.get_kin_btn);
64 | final View exportKeyStore = findViewById(R.id.export_key_store_btn);
65 | final View deleteAccount = findViewById(R.id.delete_account_btn);
66 |
67 | if (isMainNet()) {
68 | transaction.setBackgroundResource(R.drawable.button_main_network_bg);
69 | refresh.setBackgroundResource(R.drawable.button_main_network_bg);
70 | exportKeyStore.setBackgroundResource(R.drawable.button_main_network_bg);
71 | getKinBtn.setVisibility(View.GONE);
72 | } else {
73 | getKinBtn.setVisibility(View.VISIBLE);
74 | getKinBtn.setOnClickListener(view -> {
75 | getKinBtn.setClickable(false);
76 | getKin();
77 | });
78 | }
79 |
80 | deleteAccount.setOnClickListener(view -> showDeleteAlert());
81 |
82 | transaction.setOnClickListener(view -> startActivity(TransactionActivity.getIntent(WalletActivity.this)));
83 | refresh.setOnClickListener(view -> {
84 | updateBalance();
85 | updatePendingBalance();
86 | });
87 |
88 | exportKeyStore.setOnClickListener(view -> startActivity(ExportKeystoreActivity.getIntent(this)));
89 | }
90 |
91 | private void showDeleteAlert() {
92 | KinAlertDialog.createConfirmationDialog(this, getResources().getString(R.string.delete_wallet_warning),
93 | getResources().getString(R.string.delete), this::deleteAccount).show();
94 | }
95 |
96 | private void deleteAccount() {
97 | try {
98 | getKinClient().deleteAccount(getPassphrase());
99 | onBackPressed();
100 | } catch (DeleteAccountException e) {
101 | KinAlertDialog.createErrorDialog(this, e.getMessage()).show();
102 | }
103 | }
104 |
105 | private void getKin() {
106 | final KinAccount account = getKinClient().getAccount();
107 | if (account != null) {
108 | final String publicAddress = account.getPublicAddress();
109 | final String url = URL_GET_KIN + publicAddress;
110 | final RequestQueue queue = Volley.newRequestQueue(this);
111 | final StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
112 | response -> {
113 | updatePendingBalance();
114 | getKinBtn.setClickable(true);
115 | },
116 | e -> {
117 | KinAlertDialog.createErrorDialog(this, e.getMessage()).show();
118 | getKinBtn.setClickable(true);
119 | });
120 | stringRequest.setShouldCache(false);
121 | queue.add(stringRequest);
122 | }
123 | }
124 |
125 | private void updatePublicKey() {
126 | String publicKeyStr = "";
127 | KinAccount account = getKinClient().getAccount();
128 | if (account != null) {
129 | publicKeyStr = account.getPublicAddress();
130 | }
131 | publicKey.setText(publicKeyStr);
132 | }
133 |
134 | private void updateBalance() {
135 | balanceProgress.setVisibility(View.VISIBLE);
136 | KinAccount account = getKinClient().getAccount();
137 | if (account != null) {
138 | balanceRequest = account.getBalance();
139 | balanceRequest.run(new DisplayCallback(balanceProgress, balance) {
140 | @Override
141 | public void displayResult(Context context, View view, Balance result) {
142 | ((TextView) view).setText(result.value(0));
143 | }
144 | });
145 | } else {
146 | balance.setText("");
147 | }
148 | }
149 |
150 | private void updatePendingBalance() {
151 | pendingBalanceProgress.setVisibility(View.VISIBLE);
152 | KinAccount account = getKinClient().getAccount();
153 | if (account != null) {
154 | pendingBalanceRequest = getKinClient().getAccount().getPendingBalance();
155 | pendingBalanceRequest.run(new DisplayCallback(pendingBalanceProgress, pendingBalance) {
156 | @Override
157 | public void displayResult(Context context, View view, Balance result) {
158 | ((TextView) view).setText(result.value(0));
159 | }
160 | });
161 | } else {
162 | pendingBalance.setText("");
163 | }
164 | }
165 |
166 | @Override
167 | Intent getBackIntent() {
168 | return ChooseNetworkActivity.getIntent(this);
169 | }
170 |
171 | @Override
172 | int getActionBarTitleRes() {
173 | return R.string.balance;
174 | }
175 |
176 | @Override
177 | protected void onDestroy() {
178 | super.onDestroy();
179 | if (pendingBalanceRequest != null) {
180 | pendingBalanceRequest.cancel(true);
181 | }
182 | if (balanceRequest != null) {
183 | balanceRequest.cancel(true);
184 | }
185 | pendingBalance = null;
186 | balance = null;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/WebWrapperActivity.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.webkit.WebView;
7 | import android.webkit.WebViewClient;
8 |
9 | /**
10 | */
11 |
12 | public class WebWrapperActivity extends BaseActivity {
13 |
14 | public static final String TAG = WebWrapperActivity.class.getSimpleName();
15 | private static String ARGS_URL = "url";
16 |
17 | public static Intent getIntent(Context context, String url) {
18 | Intent intent = new Intent(context, WebWrapperActivity.class);
19 | intent.putExtra(ARGS_URL, url);
20 | return intent;
21 | }
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.web_holder_activity);
27 | initWidgets();
28 | }
29 |
30 | private void initWidgets() {
31 | WebView webView = (WebView) findViewById(R.id.web);
32 | webView.getSettings().setJavaScriptEnabled(true);
33 | webView.setWebViewClient(new WebViewClient() {
34 | @Override
35 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
36 | view.loadUrl(url);
37 | return true;
38 | }
39 | });
40 | final String url = getIntent().getStringExtra(ARGS_URL);
41 | webView.loadUrl(url);
42 | }
43 |
44 | @Override
45 | Intent getBackIntent() {
46 | return ChooseNetworkActivity.getIntent(this);
47 | }
48 |
49 | @Override
50 | int getActionBarTitleRes() {
51 | return R.string.kin_foundation;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/kin/sdk/core/sample/dialog/KinAlertDialog.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample.kin.sdk.core.sample.dialog;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.text.TextUtils;
7 | import android.view.Gravity;
8 | import android.view.View;
9 | import android.widget.TextView;
10 | import android.widget.Toast;
11 | import kin.sdk.core.sample.R;
12 | import kin.sdk.core.sample.Utils;
13 |
14 | public class KinAlertDialog {
15 |
16 | private Context context;
17 | private android.app.AlertDialog dialog;
18 | private OnConfirmedListener confirmedListener;
19 | private String positiveButtonText;
20 |
21 | public static KinAlertDialog createErrorDialog(Context context, String message) {
22 | KinAlertDialog dialog = new KinAlertDialog(context);
23 | dialog.setMessage(message);
24 | dialog.setConfirmButton();
25 | return dialog;
26 | }
27 |
28 | public static KinAlertDialog createConfirmationDialog(Context context, String message, String confirmationText,
29 | OnConfirmedListener confirmedListener) {
30 | KinAlertDialog dialog = new KinAlertDialog(context);
31 | dialog.setPositiveButtonText(confirmationText);
32 | dialog.setOnConfirmedListener(confirmedListener);
33 | dialog.setMessage(message);
34 | dialog.setConfirmButton();
35 | dialog.setCancelButton();
36 | return dialog;
37 | }
38 |
39 | private KinAlertDialog(Context context) {
40 | this.context = context;
41 | final android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(context);
42 | dialog = builder.create();
43 | dialog.setCancelable(true);
44 | positiveButtonText = context.getResources().getString(R.string.ok);
45 | }
46 |
47 | public void show() {
48 | if (context != null && !((Activity) context).isFinishing()) {
49 | dialog.show();
50 | }
51 | }
52 |
53 | private void setPositiveButtonText(String text){
54 | if(TextUtils.isEmpty(text)) {
55 | positiveButtonText = context.getResources().getString(R.string.ok);
56 | }else {
57 | positiveButtonText = text;
58 | }
59 | }
60 |
61 | protected void setMessage(String message) {
62 | if(TextUtils.isEmpty(message)){
63 | message = context.getResources().getString(R.string.error_no_message);
64 | }
65 | dialog.setView(buildMessageView(message));
66 | }
67 |
68 | protected void setOnConfirmedListener(OnConfirmedListener onConfirmedListener){
69 | this.confirmedListener = onConfirmedListener;
70 | }
71 |
72 | protected void setConfirmButton() {
73 | dialog.setButton(DialogInterface.BUTTON_POSITIVE, positiveButtonText,
74 | (dialogInterface, i) -> {
75 | dialogInterface.dismiss();
76 | onConfirmed();
77 | });
78 | }
79 |
80 | protected void setCancelButton() {
81 | dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getResources().getString(R.string.cancel),
82 | (dialogInterface, i) -> dialogInterface.dismiss());
83 | }
84 |
85 | protected void onConfirmed() {
86 | if (confirmedListener != null) {
87 | confirmedListener.onConfirm();
88 | }
89 | }
90 |
91 | private View buildMessageView(String message) {
92 | TextView textView = new TextView(context);
93 | textView.setTextColor(R.drawable.text_color);
94 | textView.setTextIsSelectable(true);
95 | textView.setTextSize(18f);
96 | textView.setText(message);
97 | textView.setGravity(Gravity.LEFT);
98 | textView.setPadding(35, 35, 35, 0);
99 | textView.setOnLongClickListener(v -> {
100 | Utils.copyToClipboard(v.getContext(), message);
101 | Toast.makeText(v.getContext(), R.string.copied_to_clipboard,
102 | Toast.LENGTH_SHORT)
103 | .show();
104 | return true;
105 | });
106 | return textView;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/sample/src/main/java/kin/sdk/core/sample/kin/sdk/core/sample/dialog/OnConfirmedListener.java:
--------------------------------------------------------------------------------
1 | package kin.sdk.core.sample.kin.sdk.core.sample.dialog;
2 |
3 | /**
4 | * Created by shaybaz on 27/11/2017.
5 | */
6 |
7 | public interface OnConfirmedListener {
8 |
9 | void onConfirm();
10 | }
11 |
--------------------------------------------------------------------------------
/sample/src/main/res/anim/slide_in_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/anim/slide_in_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/anim/slide_out_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/anim/slide_out_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-hdpi/kin_small_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/drawable-hdpi/kin_small_icon.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-mdpi/kin_small_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/drawable-mdpi/kin_small_icon.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/kin_small_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/drawable-xhdpi/kin_small_icon.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xxhdpi/kin_small_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/drawable-xxhdpi/kin_small_icon.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xxxhdpi/kin_small_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/drawable-xxxhdpi/kin_small_icon.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/button_main_network_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/button_red_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/button_test_network_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/output_rectangle_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
10 |
11 |
13 |
14 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/text_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/choose_network_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
18 |
25 |
26 |
33 |
34 |
40 |
41 |
47 |
48 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/create_wallet_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/export_key_store_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
22 |
23 |
24 |
33 |
34 |
35 |
48 |
49 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/transaction_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
19 |
20 |
29 |
30 |
35 |
36 |
44 |
45 |
49 |
50 |
57 |
58 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/wallet_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
19 |
24 |
25 |
33 |
34 |
42 |
43 |
48 |
49 |
54 |
55 |
62 |
63 |
67 |
68 |
72 |
73 |
78 |
79 |
86 |
87 |
88 |
96 |
97 |
98 |
99 |
100 |
104 |
105 |
112 |
113 |
120 |
121 |
122 |
123 |
130 |
131 |
138 |
139 |
145 |
146 |
154 |
155 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/web_holder_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher_rounded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-hdpi/ic_launcher_rounded.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher_rounded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-mdpi/ic_launcher_rounded.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher_rounded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-xhdpi/ic_launcher_rounded.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher_rounded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-xxhdpi/ic_launcher_rounded.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_rounded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kinecosystem/kin-core-android-ethereum/6fc84185244c6bc9d3807197d4bc1baec6f8ad4e/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_rounded.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-hdpi/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 10dp
4 | 0dp
5 | 14sp
6 | 14sp
7 | 10dp
8 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-xhdpi/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 35dp
4 | 10dp
5 | 18sp
6 | 15dp
7 | 18sp
8 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | @color/grey
4 | #303F9F
5 | #FF4081
6 | #FF3636
7 | #B03535
8 | #26BEFF
9 | #1392C9
10 | #FF8A00
11 | #D07100
12 | #696969
13 | #fff
14 | #D1D1D1
15 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16sp
4 | 10dp
5 | 20dp
6 | 10dp
7 | 10dp
8 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Kin Sample App
3 | Kin Foundation
4 | Test Net
5 | Main Net
6 | Reveal
7 | Refresh
8 | Public Address:
9 | Amount:
10 | Copy to clipboard
11 | Copied to clipboard
12 | Export Key Store
13 | Enter Your Passphrase
14 | Balance
15 | Transaction
16 | Send Transaction
17 | Get KIN
18 | Delete Wallet
19 | Are you sure you want to delete your wallet?\n\nDeleting without backed up will cause permanent funds lost!
20 | Delete
21 | Create Wallet
22 | Some error occurred - no message
23 | Ok
24 | Cancel
25 |
26 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
15 |
16 |
21 |
22 |
30 |
31 |
34 |
35 |
38 |
39 |
42 |
43 |
48 |
49 |
52 |
53 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':kin-sdk-core'
2 |
--------------------------------------------------------------------------------
/testfairy-uploader.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This upload script is both for iOS and Android.
4 |
5 | UPLOADER_VERSION=2.12
6 | # Put your TestFairy API_KEY here. Find it here: https://app.testfairy.com/settings/#tab-api-key
7 | TESTFAIRY_API_KEY=$TESTFAIRY_KEY
8 |
9 | # Tester Groups that will be notified when the app is ready. Setup groups in your TestFairy account testers page.
10 | # This parameter is optional, leave empty if not required
11 | TESTER_GROUPS="QA"
12 |
13 | # Should email testers about new version. Set to "off" to disable email notifications.
14 | NOTIFY="on"
15 |
16 | # If AUTO_UPDATE is "on" all users will be prompt to update to this build next time they run the app
17 | AUTO_UPDATE="off"
18 |
19 | # The maximum recording duration for every test.
20 | MAX_DURATION="10m"
21 |
22 | # Is video recording enabled for this build. valid values: "on", "off", "wifi"
23 | VIDEO="off"
24 |
25 | # Comment text will be included in the email sent to testers
26 | COMMENT="$TRAVIS_COMMIT $TRAVIS_COMMIT_MESSAGE"
27 |
28 | # locations of various tools
29 | CURL=curl
30 |
31 | SERVER_ENDPOINT=https://upload.testfairy.com
32 |
33 | usage() {
34 | echo "Usage: testfairy-upload-ios.sh APP_FILENAME"
35 | echo
36 | }
37 |
38 | verify_tools() {
39 |
40 | # Windows users: this script requires curl. If not installed please get from http://cygwin.com/
41 |
42 | # Check 'curl' tool
43 | "${CURL}" --help >/dev/null
44 | if [ $? -ne 0 ]; then
45 | echo "Could not run curl tool, please check settings"
46 | exit 1
47 | fi
48 | }
49 |
50 | verify_settings() {
51 | if [ -z "${TESTFAIRY_API_KEY}" ]; then
52 | usage
53 | echo "Please update API_KEY with your private API key, as noted in the Settings page"
54 | exit 1
55 | fi
56 | }
57 |
58 | if [ $# -ne 1 ]; then
59 | usage
60 | exit 1
61 | fi
62 |
63 | # before even going on, make sure all tools work
64 | verify_tools
65 | verify_settings
66 |
67 | APP_FILENAME=$1
68 | if [ ! -f "${APP_FILENAME}" ]; then
69 | usage
70 | echo "Can't find file: ${APP_FILENAME}"
71 | exit 2
72 | fi
73 |
74 | # temporary file paths
75 | DATE=`date`
76 |
77 | /bin/echo -n "Uploading ${APP_FILENAME} to TestFairy.. "
78 | JSON=$( "${CURL}" -s ${SERVER_ENDPOINT}/api/upload -F api_key=${TESTFAIRY_API_KEY} -F file="@${APP_FILENAME}" -F video="${VIDEO}" -F max-duration="${MAX_DURATION}" -F comment="${COMMENT}" -F testers-groups="${TESTER_GROUPS}" -F auto-update="${AUTO_UPDATE}" -F notify="${NOTIFY}" -F instrumentation="off" -A "TestFairy iOS Command Line Uploader ${UPLOADER_VERSION}" )
79 |
80 | URL=$( echo ${JSON} | sed 's/\\\//\//g' | sed -n 's/.*"build_url"\s*:\s*"\([^"]*\)".*/\1/p' )
81 | if [ -z "$URL" ]; then
82 | echo "FAILED!"
83 | echo
84 | echo "Build uploaded, but no reply from server. Please contact support@testfairy.com"
85 | exit 1
86 | fi
87 |
88 | echo "OK!"
89 | echo
90 | echo "Build was successfully uploaded to TestFairy and is available at:"
91 | echo ${URL}
92 |
--------------------------------------------------------------------------------