6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.core;
10 | import javax.crypto.Mac;
11 | import javax.crypto.spec.SecretKeySpec;
12 |
13 | public class HmacSha1 {
14 |
15 | public static String hmacSha1(String secret, String value) {
16 | return hmacSha(secret, value, "HmacSHA1");
17 | }
18 |
19 | public static String hmacSha256(String secret, String value) {
20 | return hmacSha(secret, value, "HmacSHA256");
21 | }
22 |
23 | private static String hmacSha(String secret, String value, String shaType) {
24 | try {
25 | SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes("UTF-8"), shaType);
26 | Mac mac = Mac.getInstance(shaType);
27 | mac.init(signingKey);
28 | byte[] rawHmac = mac.doFinal(value.getBytes("UTF-8"));
29 | byte[] hexArray = {
30 | (byte)'0', (byte)'1', (byte)'2', (byte)'3',
31 | (byte)'4', (byte)'5', (byte)'6', (byte)'7',
32 | (byte)'8', (byte)'9', (byte)'a', (byte)'b',
33 | (byte)'c', (byte)'d', (byte)'e', (byte)'f'
34 | };
35 | byte[] hexChars = new byte[rawHmac.length * 2];
36 | for ( int j = 0; j < rawHmac.length; j++ ) {
37 | int v = rawHmac[j] & 0xFF;
38 | hexChars[j * 2] = hexArray[v >>> 4];
39 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
40 | }
41 | return new String(hexChars);
42 | }
43 | catch (Exception ex) {
44 | throw new RuntimeException(ex);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/Encoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security;
19 |
20 | /**
21 | * Provides the highest level of abstraction for Encoders.
22 | *
23 | * This is the sister interface of {@link Decoder}. Every implementation of Encoder provides this
24 | * common generic interface which allows a user to pass a generic Object to any Encoder implementation
25 | * in the codec package.
26 | *
27 | * @version $Id$
28 | */
29 | public interface Encoder {
30 |
31 | /**
32 | * Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be
33 | * byte[] or Strings depending on the implementation used.
34 | *
35 | * @param source
36 | * An object to encode
37 | * @return An "encoded" Object
38 | * @throws EncoderException
39 | * An encoder exception is thrown if the encoder experiences a failure condition during the encoding
40 | * process.
41 | */
42 | Object encode(Object source) throws EncoderException;
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
9 |
14 |
15 |
21 |
24 |
27 |
28 |
29 |
30 |
36 |
37 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/Decoder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security;
19 |
20 | /**
21 | * Provides the highest level of abstraction for Decoders.
22 | *
23 | * This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface.
24 | * Allows a user to pass a generic Object to any Decoder implementation in the codec package.
25 | *
26 | * One of the two interfaces at the center of the codec package.
27 | *
28 | * @version $Id$
29 | */
30 | public interface Decoder {
31 |
32 | /**
33 | * Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will
34 | * try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a
35 | * {@link ClassCastException} occurs this decode method will throw a DecoderException.
36 | *
37 | * @param source
38 | * the object to decode
39 | * @return a 'decoded" object
40 | * @throws DecoderException
41 | * a decoder exception can be thrown for any number of reasons. Some good candidates are that the
42 | * parameter passed to this method is null, a param cannot be cast to the appropriate type for a
43 | * specific encoder.
44 | */
45 | Object decode(Object source) throws DecoderException;
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/res/layout/button.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
23 |
24 |
39 |
40 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/kamba-android-sdk/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | apply plugin: 'com.android.library'
10 | apply plugin: 'kotlin-android-extensions'
11 | apply plugin: 'kotlin-android'
12 | apply plugin: 'com.github.dcendents.android-maven'
13 |
14 | group='com.github.usekamba'
15 |
16 | android {
17 | compileSdkVersion 28
18 | defaultConfig {
19 | minSdkVersion 17
20 | targetSdkVersion 28
21 | versionCode 1
22 | versionName "1.0"
23 |
24 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
25 |
26 | }
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 |
35 | }
36 |
37 | ext {
38 | jodaTimeVersion = "2.9.9"
39 | moshiVersion = "1.6.0"
40 | appCompatVersion = "28.0.0"
41 | junitVersion = "4.12"
42 | testRunnerVersion = "1.0.2"
43 | espressoCoreVersion = "3.0.2"
44 | constraintLayoutVersion = "1.1.3"
45 | cardViewVersion = "28.0.0"
46 | okHttpVersion = "3.10.0"
47 | qrGenVersion = "2.5.0"
48 | }
49 |
50 | dependencies {
51 | implementation fileTree(include: ['*.jar'], dir: 'libs')
52 | implementation "com.android.support:appcompat-v7:$appCompatVersion"
53 | implementation "com.android.support.constraint:constraint-layout:$constraintLayoutVersion"
54 | implementation "com.android.support:cardview-v7:$cardViewVersion"
55 | implementation "com.squareup.okhttp3:okhttp:$okHttpVersion"
56 | implementation "com.squareup.moshi:moshi:$moshiVersion"
57 | implementation "com.github.kenglxn.QRGen:android:$qrGenVersion"
58 | implementation "joda-time:joda-time:$jodaTimeVersion"
59 |
60 | testImplementation "junit:junit:$junitVersion"
61 | androidTestImplementation "com.android.support.test:runner:$testRunnerVersion"
62 | androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoCoreVersion"
63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
64 |
65 | }
66 | repositories {
67 | mavenCentral()
68 | }
69 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/DigestUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.core.security;
10 |
11 | import java.security.MessageDigest;
12 |
13 | public class DigestUtils {
14 |
15 | /**
16 | * Used to build output as Hex
17 | */
18 | private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
19 | 'e', 'f' };
20 |
21 | private DigestUtils() {
22 | throw new AssertionError();
23 | }
24 |
25 | /**
26 | * encode By MD5
27 | *
28 | * @param str
29 | * @return String
30 | */
31 | public static String md5(String str) {
32 | if (str == null) {
33 | return null;
34 | }
35 | try {
36 | MessageDigest messageDigest = MessageDigest.getInstance("MD5");
37 | messageDigest.update(str.getBytes());
38 | return new String(encodeHex(messageDigest.digest()));
39 | } catch (Exception e) {
40 | throw new RuntimeException(e);
41 | }
42 | }
43 |
44 | /**
45 | * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
46 | * The returned array will be double the length of the passed array, as it takes two characters to represent any
47 | * given byte.
48 | *
49 | * @param data a byte[] to convert to Hex characters
50 | * @return A char[] containing hexadecimal characters
51 | */
52 | protected static char[] encodeHex(final byte[] data) {
53 | final int l = data.length;
54 | final char[] out = new char[l << 1];
55 | // two characters form the hex value.
56 | for (int i = 0, j = 0; i < l; i++) {
57 | out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
58 | out[j++] = DIGITS_LOWER[0x0F & data[i]];
59 | }
60 | return out;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/usekamba/kamba_payments_sdk/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kamba_payments_sdk;
10 |
11 | import android.content.Context;
12 | import android.content.DialogInterface;
13 | import android.content.Intent;
14 | import android.os.Bundle;
15 | import android.support.v7.app.AppCompatActivity;
16 | import android.view.View;
17 | import android.widget.Button;
18 | import android.widget.Toast;
19 |
20 | import com.usekamba.kambapaysdk.core.client.ClientConfig;
21 | import com.usekamba.kambapaysdk.core.model.CheckoutResponse;
22 | import com.usekamba.kambapaysdk.core.requests.CheckoutRequest;
23 | import com.usekamba.kambapaysdk.core.requests.CheckoutTransaction;
24 | import com.usekamba.kambapaysdk.core.requests.CheckoutTransactionBuilder;
25 | import com.usekamba.kambapaysdk.core.requests.TransactionCallback;
26 |
27 | public class MainActivity extends AppCompatActivity {
28 | private Context context = this;
29 | CheckoutRequest checkoutRequest;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_main);
35 |
36 | checkoutRequest = new CheckoutRequest();
37 | checkoutRequest.setInitialAmount(1.99);
38 | checkoutRequest.setNotes("Serviço de hospedagem - Plano Grande");
39 | findViewById(R.id.start_payment).setOnClickListener(v -> initKambaTransaction());
40 | }
41 |
42 | private void initKambaTransaction() {
43 | CheckoutTransaction checkoutTransaction = new CheckoutTransactionBuilder()
44 | .addClientConfig(ClientConfig.getInstance())
45 | .addCheckoutRequest(checkoutRequest)
46 | .build();
47 | checkoutTransaction.enqueue(new TransactionCallback() {
48 | @Override
49 | public void onSuccess(final CheckoutResponse checkout) {
50 | runOnUiThread(() -> startActivity(new Intent(context, CheckoutActivity.class).putExtra("checkout", checkout)));
51 | }
52 |
53 | @Override
54 | public void onFailure(String message) {
55 | runOnUiThread(() -> Toast.makeText(context, "Error initiating Payment request: " + message, Toast.LENGTH_LONG).show());
56 | }
57 | });
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/client/ClientConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.core.client;
10 |
11 | import android.support.annotation.NonNull;
12 | import android.util.Log;
13 |
14 | /**
15 | * This singleton class is responsible for setting up parameters
16 | * for Payment Requests
17 | */
18 | public class ClientConfig {
19 |
20 | private static volatile ClientConfig instance;
21 | private static final Object LOCK = new Object();
22 | private String merchantId;
23 | private String secretKey;
24 | private Environment environment;
25 |
26 | public enum Environment {SANDBOX, PRODUCTION}
27 |
28 | private ClientConfig() {
29 | }
30 |
31 | public static ClientConfig getInstance() {
32 | if (instance == null) {
33 | synchronized (LOCK) {
34 | if (instance == null) {
35 | instance = new ClientConfig();
36 | }
37 | }
38 | }
39 | return instance;
40 | }
41 |
42 | @SuppressWarnings("ConstantConditions")
43 | public ClientConfig configure(@NonNull String merchantId, @NonNull String secretKey, @NonNull Environment environment) {
44 | if (merchantId == null || merchantId.equals("")) {
45 | throw new IllegalStateException("You must provide a merchant id");
46 | }
47 |
48 | if ((environment == null) || (environment != Environment.PRODUCTION && environment != Environment.SANDBOX)) {
49 | throw new IllegalStateException("You must provide a valid environment");
50 | }
51 |
52 | if (secretKey == null || secretKey.equals("")) {
53 | throw new IllegalStateException("You must provide a secret key");
54 | }
55 |
56 | this.merchantId = merchantId;
57 | this.environment = environment;
58 | this.secretKey = secretKey;
59 | return this;
60 | }
61 |
62 | public String getSecretKey() {
63 | Log.d("MainActivity", secretKey);
64 | return secretKey;
65 | }
66 |
67 | public void setSecretKey(String secretKey) {
68 | this.secretKey = secretKey;
69 | }
70 |
71 | public String getMerchantId() {
72 | return merchantId;
73 | }
74 |
75 | public void setMerchantId(String merchantId) {
76 | this.merchantId = merchantId;
77 | }
78 |
79 | public Environment getEnvironment() {
80 | return environment;
81 | }
82 |
83 | public void setEnvironment(Environment environment) {
84 | this.environment = environment;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/requests/CheckoutTransaction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.core.requests;
10 |
11 | import android.support.annotation.NonNull;
12 | import android.util.Log;
13 |
14 | import com.squareup.moshi.JsonAdapter;
15 | import com.squareup.moshi.Moshi;
16 | import com.usekamba.kambapaysdk.core.Platform;
17 | import com.usekamba.kambapaysdk.core.model.CheckoutResponse;
18 |
19 | import java.io.IOException;
20 |
21 | import okhttp3.Call;
22 | import okhttp3.Callback;
23 | import okhttp3.OkHttpClient;
24 | import okhttp3.Request;
25 | import okhttp3.Response;
26 |
27 | public class CheckoutTransaction {
28 | private OkHttpClient client;
29 | private Request request;
30 | private final Moshi moshi = new Moshi.Builder().build();
31 | private final JsonAdapter checkoutResponseJsonAdapter = moshi.adapter(CheckoutResponse.class);
32 | private TransactionCallback callback;
33 | private String TAG = this.getClass().getSimpleName();
34 |
35 | void setClient(OkHttpClient client) {
36 | this.client = client;
37 | }
38 |
39 |
40 | public void enqueue(final TransactionCallback transactionCallback) {
41 | if (callback == null) {
42 | this.callback = transactionCallback;
43 | }
44 |
45 | client.newCall(request).enqueue(new Callback() {
46 | @Override
47 | public void onFailure(@NonNull Call call, @NonNull IOException e) {
48 | callback.onFailure(e.getMessage());
49 | }
50 |
51 | @Override
52 | public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
53 | if (response.code() == 201) {
54 | callback.onSuccess( checkoutResponseJsonAdapter.fromJson(response.body().string()));
55 | }
56 | if (response.code() == 422) {
57 | callback.onFailure("CheckoutRequest data is not correct");
58 | }
59 |
60 | if (response.code() == 401) {
61 | callback.onFailure("API Key is invalid. Verify that your API KEY is valid otherwise contact suporte@usekamba.com");
62 | }
63 |
64 | if (response.code() == 403) {
65 | Log.d(TAG, "KAMBA ANDROID SDK: " + response.message());
66 | callback.onFailure("Signature is Invalid");
67 | }
68 | }
69 | });
70 |
71 |
72 | }
73 |
74 |
75 | void setRequest(Request request) {
76 | this.request = request;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/usekamba/kamba_payments_sdk/CheckoutActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kamba_payments_sdk;
10 |
11 | import android.content.Context;
12 | import android.content.Intent;
13 | import android.support.annotation.Nullable;
14 | import android.support.v7.app.AppCompatActivity;
15 | import android.os.Bundle;
16 | import android.widget.Toast;
17 |
18 | import com.usekamba.kambapaysdk.core.model.CheckoutResponse;
19 | import com.usekamba.kambapaysdk.ui.CheckoutWidget;
20 | import com.usekamba.kambapaysdk.ui.KambaButton;
21 | import com.usekamba.kambapaysdk.ui.PaymentResultListener;
22 |
23 | public class CheckoutActivity extends AppCompatActivity {
24 | private CheckoutWidget checkoutWidget;
25 | private CheckoutResponse checkoutResponse;
26 | private KambaButton payButton;
27 | private Context context = this;
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_checkout);
32 |
33 | checkoutWidget = findViewById(R.id.checkout);
34 | payButton = findViewById(R.id.pay);
35 | // Para acessar o checkout response da tela anterior usa sempre response "(CheckoutResponse) getIntent().getSerializableExtra("checkout");
36 | checkoutResponse = (CheckoutResponse) getIntent().getSerializableExtra("checkout");
37 | checkoutWidget.setAmount(checkoutResponse.getTotalAmount());
38 | checkoutWidget.setExpirationDate(checkoutResponse.getExpiresAt());
39 | checkoutWidget.setTotalCheckoutAmount(checkoutResponse.getTotalAmount());
40 | checkoutWidget.setItemDescription(checkoutResponse.getNotes());
41 | checkoutWidget.setItemAmount(checkoutResponse.getInitialAmount());
42 | checkoutWidget.setQrCode(checkoutResponse.getQrCode());
43 | payButton.setOnPaymentListener(new PaymentResultListener() {
44 | @Override
45 | public void onSuccessfulPayment() {
46 | Toast.makeText(context, "Purchase Made", Toast.LENGTH_SHORT).show();
47 | }
48 |
49 | @Override
50 | public void onFailure() {
51 | Toast.makeText(context, "Purchase not performed", Toast.LENGTH_SHORT).show();
52 | }
53 | });
54 | payButton.setOnClickListener(v -> payButton.payWithWallet(checkoutResponse, context));
55 |
56 | }
57 |
58 | @Override
59 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
60 | super.onActivityResult(requestCode, resultCode, data);
61 | payButton.onActivityResult(requestCode, resultCode, data);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/helpers/DateHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.helpers;
10 |
11 | import org.joda.time.DateTime;
12 | import org.joda.time.format.DateTimeFormat;
13 | import org.joda.time.format.ISODateTimeFormat;
14 |
15 | import java.util.Locale;
16 |
17 | public class DateHelper {
18 | /***
19 | * Convert a Rails Date Object to day/month/year signature
20 | * @param string - A string version of the date (Usually this will come from a POJO)
21 | * @return a date in string format formatted accordingly
22 | */
23 | public static String convertDate(String string){
24 | String format = "dd/MM/yyyy";
25 | org.joda.time.format.DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();
26 | DateTime date = parser.parseDateTime(string);
27 | org.joda.time.format.DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
28 | return date.toString(fmt);
29 | }
30 |
31 |
32 | public static String getGMTTime(String string){
33 | String format = "EEE, dd MMM yyyy HH:mm:ss 'GMT'";
34 | org.joda.time.format.DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser().withLocale(Locale.US);
35 | DateTime date = parser.parseDateTime(string);
36 | org.joda.time.format.DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
37 | return date.toString(fmt);
38 | }
39 |
40 |
41 | /***
42 | * Convert a Rails Date Object to year signature
43 | * @param string - A string version of the date (Usually this will come from a POJO)
44 | * @return a date in string format formatted accordingly
45 | */
46 | public static String convertDateToYear(String string){
47 | String format = "yyyy";
48 | org.joda.time.format.DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();
49 | DateTime date = parser.parseDateTime(string);
50 | org.joda.time.format.DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
51 | return date.toString(fmt);
52 | }
53 |
54 |
55 | /***
56 | * Convert a Rails Date object to hour:time signature
57 | @param string - A string version of the date (Usually this will come from a POJO)
58 | * @return a date in string format formatted accordingly
59 | */
60 | public static String convertTimeToMin(String string){
61 | String format = "HH:mm";
62 | org.joda.time.format.DateTimeFormatter parser = ISODateTimeFormat.dateTimeParser();
63 | DateTime date = parser.parseDateTime(string);
64 | org.joda.time.format.DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
65 | return date.toString(fmt);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/binary/CharSequenceUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.usekamba.kambapaysdk.core.security.binary;
18 |
19 | /**
20 | *
21 | * Operations on {@link CharSequence} that are null safe.
22 | *
23 | *
24 | * Copied from Apache Commons Lang r1586295 on April 10, 2014 (day of 3.3.2 release).
25 | *
26 | *
27 | * @see CharSequence
28 | * @since 1.10
29 | */
30 | public class CharSequenceUtils {
31 |
32 | /**
33 | * Green implementation of regionMatches.
34 | *
35 | * @param cs
36 | * the CharSequence to be processed
37 | * @param ignoreCase
38 | * whether or not to be case insensitive
39 | * @param thisStart
40 | * the index to start on the cs CharSequence
41 | * @param substring
42 | * the CharSequence to be looked for
43 | * @param start
44 | * the index to start on the substring CharSequence
45 | * @param length
46 | * character length of the region
47 | * @return whether the region matched
48 | */
49 | static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
50 | final CharSequence substring, final int start, final int length) {
51 | if (cs instanceof String && substring instanceof String) {
52 | return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
53 | }
54 | int index1 = thisStart;
55 | int index2 = start;
56 | int tmpLen = length;
57 |
58 | while (tmpLen-- > 0) {
59 | final char c1 = cs.charAt(index1++);
60 | final char c2 = substring.charAt(index2++);
61 |
62 | if (c1 == c2) {
63 | continue;
64 | }
65 |
66 | if (!ignoreCase) {
67 | return false;
68 | }
69 |
70 | // The same check as in String.regionMatches():
71 | if (Character.toUpperCase(c1) != Character.toUpperCase(c2) &&
72 | Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
73 | return false;
74 | }
75 | }
76 |
77 | return true;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/StringEncoderComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security;
19 |
20 | import java.util.Comparator;
21 |
22 | /**
23 | * Compares Strings using a {@link StringEncoder}. This comparator is used to sort Strings by an encoding scheme such as
24 | * Soundex, Metaphone, etc. This class can come in handy if one need to sort Strings by an encoded form of a name such
25 | * as Soundex.
26 | *
27 | * This class is immutable and thread-safe.
28 | *
29 | * @version $Id$
30 | */
31 | @SuppressWarnings("rawtypes")
32 | // TODO ought to implement Comparator but that's not possible whilst maintaining binary compatibility.
33 | public class StringEncoderComparator implements Comparator {
34 |
35 | /**
36 | * Internal encoder instance.
37 | */
38 | private final StringEncoder stringEncoder;
39 |
40 | /**
41 | * Constructs a new instance.
42 | *
43 | * @deprecated Creating an instance without a {@link StringEncoder} leads to a {@link NullPointerException}. Will be
44 | * removed in 2.0.
45 | */
46 | @Deprecated
47 | public StringEncoderComparator() {
48 | this.stringEncoder = null; // Trying to use this will cause things to break
49 | }
50 |
51 | /**
52 | * Constructs a new instance with the given algorithm.
53 | *
54 | * @param stringEncoder
55 | * the StringEncoder used for comparisons.
56 | */
57 | public StringEncoderComparator(final StringEncoder stringEncoder) {
58 | this.stringEncoder = stringEncoder;
59 | }
60 |
61 | /**
62 | * Compares two strings based not on the strings themselves, but on an encoding of the two strings using the
63 | * StringEncoder this Comparator was created with.
64 | *
65 | * If an {@link EncoderException} is encountered, return 0.
66 | *
67 | * @param o1
68 | * the object to compare
69 | * @param o2
70 | * the object to compare to
71 | * @return the Comparable.compareTo() return code or 0 if an encoding error was caught.
72 | * @see Comparable
73 | */
74 | @Override
75 | public int compare(final Object o1, final Object o2) {
76 |
77 | int compareCode = 0;
78 |
79 | try {
80 | @SuppressWarnings("unchecked") // May fail with CCE if encode returns something that is not Comparable
81 | // However this was always the case.
82 | final Comparable> s1 = (Comparable>) this.stringEncoder.encode(o1);
83 | final Comparable> s2 = (Comparable>) this.stringEncoder.encode(o2);
84 | compareCode = s1.compareTo(s2);
85 | } catch (final EncoderException ee) {
86 | compareCode = 0;
87 | }
88 | return compareCode;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/model/CheckoutResponse.java:
--------------------------------------------------------------------------------
1 | package com.usekamba.kambapaysdk.core.model;
2 |
3 | import android.util.Log;
4 |
5 | import com.squareup.moshi.Json;
6 |
7 | import java.io.Serializable;
8 |
9 | public class CheckoutResponse implements Serializable {
10 |
11 | @Json(name = "notes")
12 | private String notes;
13 |
14 | @Json(name = "expires_at")
15 | private String expiresAt;
16 |
17 | @Json(name = "total_amount")
18 | private Double totalAmount;
19 |
20 | @Json(name = "redirect_url_success")
21 | private String redirectUrlSuccess;
22 |
23 | @Json(name = "fee")
24 | private int fee;
25 |
26 | @Json(name = "merchant")
27 | private Merchant merchant;
28 |
29 | @Json(name = "qr_code")
30 | private String qrCode;
31 |
32 | @Json(name = "initial_amount")
33 | private Double initialAmount;
34 |
35 | @Json(name = "id")
36 | private String id;
37 |
38 | @Json(name = "transaction_type")
39 | private String transactionType;
40 |
41 | @Json(name = "status")
42 | private String status;
43 |
44 | public void setNotes(String notes){
45 | this.notes = notes;
46 | }
47 |
48 | public String getNotes(){
49 | return notes;
50 | }
51 |
52 | public void setExpiresAt(String expiresAt){
53 | this.expiresAt = expiresAt;
54 | }
55 |
56 | public String getExpiresAt(){
57 | return expiresAt;
58 | }
59 |
60 | public void setTotalAmount(Double totalAmount){
61 | this.totalAmount = totalAmount;
62 | }
63 |
64 | public Double getTotalAmount(){
65 | return totalAmount;
66 | }
67 |
68 | public void setRedirectUrlSuccess(String redirectUrlSuccess){
69 | this.redirectUrlSuccess = redirectUrlSuccess;
70 | }
71 |
72 | public String getRedirectUrlSuccess(){
73 | return redirectUrlSuccess;
74 | }
75 |
76 | public void setFee(int fee){
77 | this.fee = fee;
78 | }
79 |
80 | public int getFee(){
81 | return fee;
82 | }
83 |
84 | public void setMerchant(Merchant merchant){
85 | this.merchant = merchant;
86 | }
87 |
88 | public Merchant getMerchant(){
89 | return merchant;
90 | }
91 |
92 | public void setQrCode(String qrCode){
93 | this.qrCode = qrCode;
94 | }
95 |
96 | public String getQrCode(){
97 | Log.d("MainActivity", getRedirectUrlSuccess() + "/pay?chID=" + getId());
98 | return getRedirectUrlSuccess() + "/pay?chID=" + getId();
99 | }
100 |
101 | public void setInitialAmount(Double initialAmount){
102 | this.initialAmount = initialAmount;
103 | }
104 |
105 | public Double getInitialAmount(){
106 | return initialAmount;
107 | }
108 |
109 | public void setId(String id){
110 | this.id = id;
111 | }
112 |
113 | public String getId(){
114 | return id;
115 | }
116 |
117 | public void setTransactionType(String transactionType){
118 | this.transactionType = transactionType;
119 | }
120 |
121 | public String getTransactionType(){
122 | return transactionType;
123 | }
124 |
125 | public void setStatus(String status){
126 | this.status = status;
127 | }
128 |
129 | public String getStatus(){
130 | return status;
131 | }
132 |
133 | @Override
134 | public String toString(){
135 | return
136 | "CheckoutResponse{" +
137 | "notes = '" + notes + '\'' +
138 | ",expires_at = '" + expiresAt + '\'' +
139 | ",total_amount = '" + totalAmount + '\'' +
140 | ",redirect_url_success = '" + redirectUrlSuccess + '\'' +
141 | ",fee = '" + fee + '\'' +
142 | ",merchant = '" + merchant + '\'' +
143 | ",qr_code = '" + qrCode + '\'' +
144 | ",initial_amount = '" + initialAmount + '\'' +
145 | ",id = '" + id + '\'' +
146 | ",transaction_type = '" + transactionType + '\'' +
147 | ",status = '" + status + '\'' +
148 | "}";
149 | }
150 | }
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/ui/CheckoutWidget.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.ui;
10 |
11 | import android.content.Context;
12 | import android.content.res.TypedArray;
13 | import android.graphics.Bitmap;
14 | import android.support.constraint.ConstraintLayout;
15 | import android.support.v7.widget.CardView;
16 | import android.util.AttributeSet;
17 | import android.view.View;
18 | import android.widget.ImageView;
19 | import android.widget.TextView;
20 |
21 | import com.usekamba.kambapaysdk.R;
22 | import com.usekamba.kambapaysdk.helpers.DateHelper;
23 |
24 | import net.glxn.qrgen.android.QRCode;
25 |
26 | import java.text.NumberFormat;
27 | import java.util.Locale;
28 |
29 | public class CheckoutWidget extends ConstraintLayout {
30 | private TextView mCheckoutAmount;
31 | private ImageView mCheckoutQrCode;
32 | private TextView mCheckoutExpirationDate;
33 | private TextView mCheckoutItemDescription;
34 | private TextView mCheckoutItemAmount;
35 | private TextView mCheckoutTotalAmount;
36 | private final Locale currentLocale = new Locale("fr", "FR");
37 |
38 | public CheckoutWidget(Context context) {
39 | super(context);
40 | }
41 |
42 | public CheckoutWidget(Context context, AttributeSet attrs) {
43 | super(context, attrs);
44 | init(context, attrs);
45 | }
46 |
47 | public CheckoutWidget(Context context, AttributeSet attrs, int defStyleAttr) {
48 | super(context, attrs, defStyleAttr);
49 | init(context, attrs);
50 | }
51 |
52 | private void init(Context context, AttributeSet attrs) {
53 | View mRoot = inflate(context, R.layout.checkoutwidget, this);
54 | ConstraintLayout mBackground = mRoot.findViewById(R.id.background);
55 | CardView mCardView = mRoot.findViewById(R.id.materialCardView);
56 | mCheckoutAmount = mRoot.findViewById(R.id.checkout_amount);
57 | mCheckoutQrCode = mRoot.findViewById(R.id.checkout_kamba_qr);
58 | mCheckoutExpirationDate = mRoot.findViewById(R.id.checkout_expiration_date);
59 | mCheckoutItemDescription = mRoot.findViewById(R.id.checkout_item_description);
60 | mCheckoutItemAmount = mRoot.findViewById(R.id.checkout_item_amount);
61 | mCheckoutTotalAmount = mRoot.findViewById(R.id.checkout_total_amount);
62 | }
63 |
64 | private String setCurrency(Double amount) {
65 | NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);
66 | return currencyFormatter.format(amount).replace("€", "Kz");
67 | }
68 |
69 | public void setQrCode(String qrCode) {
70 | Bitmap myBitmap = QRCode.from(qrCode).bitmap();
71 | mCheckoutQrCode.setImageBitmap(myBitmap);
72 | }
73 |
74 | public void setAmount(Double amount) {
75 | mCheckoutAmount.setText(setCurrency(amount));
76 | }
77 |
78 | public void setExpirationDate(String expirationDate) {
79 | mCheckoutExpirationDate.setText(String.format("%s às %s", DateHelper.convertDate(expirationDate), DateHelper.convertTimeToMin(expirationDate)));
80 | }
81 |
82 | public void setItemDescription(String itemDescription) {
83 | mCheckoutItemDescription.setText(itemDescription);
84 | }
85 |
86 | public void setItemAmount(Double itemAmount) {
87 | mCheckoutItemAmount.setText(setCurrency(itemAmount));
88 | }
89 |
90 | public void setTotalCheckoutAmount(Double totalCheckoutAmount) {
91 | mCheckoutTotalAmount.setText(setCurrency(totalCheckoutAmount));
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/DecoderException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security;
19 |
20 | /**
21 | * Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder}
22 | * encounters a decoding specific exception such as invalid data, or characters outside of the expected range.
23 | *
24 | * @version $Id$
25 | */
26 | public class DecoderException extends Exception {
27 |
28 | /**
29 | * Declares the Serial Version Uid.
30 | *
31 | * @see Always Declare Serial Version Uid
32 | */
33 | private static final long serialVersionUID = 1L;
34 |
35 | /**
36 | * Constructs a new exception with null as its detail message. The cause is not initialized, and may
37 | * subsequently be initialized by a call to {@link #initCause}.
38 | *
39 | * @since 1.4
40 | */
41 | public DecoderException() {
42 | super();
43 | }
44 |
45 | /**
46 | * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
47 | * be initialized by a call to {@link #initCause}.
48 | *
49 | * @param message
50 | * The detail message which is saved for later retrieval by the {@link #getMessage()} method.
51 | */
52 | public DecoderException(final String message) {
53 | super(message);
54 | }
55 |
56 | /**
57 | * Constructs a new exception with the specified detail message and cause.
58 | *
59 | * Note that the detail message associated with cause is not automatically incorporated into this
60 | * exception's detail message.
61 | *
62 | * @param message
63 | * The detail message which is saved for later retrieval by the {@link #getMessage()} method.
64 | * @param cause
65 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null
66 | * value is permitted, and indicates that the cause is nonexistent or unknown.
67 | * @since 1.4
68 | */
69 | public DecoderException(final String message, final Throwable cause) {
70 | super(message, cause);
71 | }
72 |
73 | /**
74 | * Constructs a new exception with the specified cause and a detail message of (cause==null ?
75 | * null : cause.toString()) (which typically contains the class and detail message of cause).
76 | * This constructor is useful for exceptions that are little more than wrappers for other throwables.
77 | *
78 | * @param cause
79 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null
80 | * value is permitted, and indicates that the cause is nonexistent or unknown.
81 | * @since 1.4
82 | */
83 | public DecoderException(final Throwable cause) {
84 | super(cause);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/EncoderException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security;
19 |
20 | /**
21 | * Thrown when there is a failure condition during the encoding process. This exception is thrown when an
22 | * {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum,
23 | * characters outside of the expected range.
24 | *
25 | * @version $Id$
26 | */
27 | public class EncoderException extends Exception {
28 |
29 | /**
30 | * Declares the Serial Version Uid.
31 | *
32 | * @see Always Declare Serial Version Uid
33 | */
34 | private static final long serialVersionUID = 1L;
35 |
36 | /**
37 | * Constructs a new exception with null as its detail message. The cause is not initialized, and may
38 | * subsequently be initialized by a call to {@link #initCause}.
39 | *
40 | * @since 1.4
41 | */
42 | public EncoderException() {
43 | super();
44 | }
45 |
46 | /**
47 | * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
48 | * be initialized by a call to {@link #initCause}.
49 | *
50 | * @param message
51 | * a useful message relating to the encoder specific error.
52 | */
53 | public EncoderException(final String message) {
54 | super(message);
55 | }
56 |
57 | /**
58 | * Constructs a new exception with the specified detail message and cause.
59 | *
60 | *
61 | * Note that the detail message associated with cause is not automatically incorporated into this
62 | * exception's detail message.
63 | *
64 | *
65 | * @param message
66 | * The detail message which is saved for later retrieval by the {@link #getMessage()} method.
67 | * @param cause
68 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null
69 | * value is permitted, and indicates that the cause is nonexistent or unknown.
70 | * @since 1.4
71 | */
72 | public EncoderException(final String message, final Throwable cause) {
73 | super(message, cause);
74 | }
75 |
76 | /**
77 | * Constructs a new exception with the specified cause and a detail message of (cause==null ?
78 | * null : cause.toString()) (which typically contains the class and detail message of cause).
79 | * This constructor is useful for exceptions that are little more than wrappers for other throwables.
80 | *
81 | * @param cause
82 | * The cause which is saved for later retrieval by the {@link #getCause()} method. A null
83 | * value is permitted, and indicates that the cause is nonexistent or unknown.
84 | * @since 1.4
85 | */
86 | public EncoderException(final Throwable cause) {
87 | super(cause);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/CharEncoding.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security;
19 |
20 | /**
21 | * Character encoding names required of every implementation of the Java platform.
22 | *
23 | * From the Java documentation Standard charsets:
25 | *
26 | * Every implementation of the Java platform is required to support the following character encodings. Consult the
27 | * release documentation for your implementation to see if any other encodings are supported. Consult the release
28 | * documentation for your implementation to see if any other encodings are supported.
29 | *
30 | *
31 | *
32 | * US-ASCII
33 | * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
34 | * ISO-8859-1
35 | * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
36 | * UTF-8
37 | * Eight-bit Unicode Transformation Format.
38 | * UTF-16BE
39 | * Sixteen-bit Unicode Transformation Format, big-endian byte order.
40 | * UTF-16LE
41 | * Sixteen-bit Unicode Transformation Format, little-endian byte order.
42 | * UTF-16
43 | * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order
44 | * accepted on input, big-endian used on output.)
45 | *
46 | *
47 | * This perhaps would best belong in the [lang] project. Even if a similar interface is defined in [lang], it is not
48 | * foreseen that [codec] would be made to depend on [lang].
49 | *
50 | *
51 | * This class is immutable and thread-safe.
52 | *
53 | *
54 | * @see Standard charsets
55 | * @since 1.4
56 | * @version $Id$
57 | */
58 | public class CharEncoding {
59 | /**
60 | * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
61 | *
62 | * Every implementation of the Java platform is required to support this character encoding.
63 | *
64 | * @see Standard charsets
65 | */
66 | public static final String ISO_8859_1 = "ISO-8859-1";
67 |
68 | /**
69 | * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
70 | *
71 | * Every implementation of the Java platform is required to support this character encoding.
72 | *
73 | * @see Standard charsets
74 | */
75 | public static final String US_ASCII = "US-ASCII";
76 |
77 | /**
78 | * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
79 | * (either order accepted on input, big-endian used on output)
80 | *
81 | * Every implementation of the Java platform is required to support this character encoding.
82 | *
83 | * @see Standard charsets
84 | */
85 | public static final String UTF_16 = "UTF-16";
86 |
87 | /**
88 | * Sixteen-bit Unicode Transformation Format, big-endian byte order.
89 | *
90 | * Every implementation of the Java platform is required to support this character encoding.
91 | *
92 | * @see Standard charsets
93 | */
94 | public static final String UTF_16BE = "UTF-16BE";
95 |
96 | /**
97 | * Sixteen-bit Unicode Transformation Format, little-endian byte order.
98 | *
99 | * Every implementation of the Java platform is required to support this character encoding.
100 | *
101 | * @see Standard charsets
102 | */
103 | public static final String UTF_16LE = "UTF-16LE";
104 |
105 | /**
106 | * Eight-bit Unicode Transformation Format.
107 | *
108 | * Every implementation of the Java platform is required to support this character encoding.
109 | *
110 | * @see Standard charsets
111 | */
112 | public static final String UTF_8 = "UTF-8";
113 | }
114 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/requests/CheckoutTransactionBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.core.requests;
10 |
11 | import com.squareup.moshi.JsonAdapter;
12 | import com.squareup.moshi.Moshi;
13 | import com.usekamba.kambapaysdk.core.HmacSha1;
14 | import com.usekamba.kambapaysdk.core.client.ClientConfig;
15 | import com.usekamba.kambapaysdk.core.security.Charsets;
16 | import com.usekamba.kambapaysdk.core.security.binary.Hex;
17 | import org.jetbrains.annotations.NotNull;
18 | import org.joda.time.DateTime;
19 | import org.joda.time.DateTimeZone;
20 | import java.security.MessageDigest;
21 | import java.security.NoSuchAlgorithmException;
22 | import java.util.Base64;
23 | import java.util.HashMap;
24 | import java.util.Locale;
25 | import java.util.Map;
26 | import okhttp3.Headers;
27 | import okhttp3.MediaType;
28 | import okhttp3.OkHttpClient;
29 | import okhttp3.Request;
30 | import okhttp3.RequestBody;
31 |
32 | public class CheckoutTransactionBuilder implements Transaction.TransactionBuilder {
33 | private OkHttpClient client = new OkHttpClient();
34 | private CheckoutRequest checkoutRequest;
35 | private ClientConfig clientConfig;
36 | private final Moshi moshi = new Moshi.Builder().build();
37 | private final MediaType mediaType = MediaType.parse("application/json; charset=utf-8\"");
38 | private final JsonAdapter checkoutRequestJsonAdapter = moshi.adapter(CheckoutRequest.class);
39 | private Request request;
40 | private String URL;
41 | private String timeStamp;
42 |
43 | private void setUpRequestAuthorization(ClientConfig clientConfig) {
44 | if (clientConfig.getEnvironment() == ClientConfig.Environment.SANDBOX) {
45 | String API_SANDBOX_URL = "https://sandbox.usekamba.com/v1/checkouts";
46 | URL = API_SANDBOX_URL.replace("/checkouts", "");
47 | String signature = generateSignature(clientConfig);
48 | buildRequest(clientConfig, API_SANDBOX_URL, signature);
49 | } else {
50 | String API_PRODUCTION_URL = "https://api.usekamba.com/v1/checkouts";
51 | URL = API_PRODUCTION_URL.replace("/checkouts", "");
52 | String signature = generateSignature(clientConfig);
53 | buildRequest(clientConfig,API_PRODUCTION_URL, signature);
54 | }
55 | }
56 |
57 | private void buildRequest(ClientConfig clientConfig, String API_PRODUCTION_URL, String signature) {
58 | RequestBody requestBody = RequestBody.create(mediaType, checkoutRequestJsonAdapter.toJson(checkoutRequest));
59 | Request.Builder builder = new Request.Builder();
60 | Map headers = new HashMap<>();
61 | headers.put("Merchant-ID", clientConfig.getMerchantId());
62 | headers.put("Content-Type", "application/json");
63 | headers.put("Signature", signature);
64 | Headers.of(headers);
65 | builder.url(API_PRODUCTION_URL);
66 | builder.headers(Headers.of(headers));
67 | builder.post(requestBody);
68 | request = builder.build();
69 | }
70 |
71 | @NotNull
72 | private String generateSignature(ClientConfig clientConfig) {
73 | String conanicalString = generateConanicalString(checkoutRequest);
74 | String digest = HmacSha1.hmacSha1(clientConfig.getSecretKey(), conanicalString);
75 | String hex;
76 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
77 | hex = Base64.getEncoder().encodeToString(digest.getBytes());
78 | } else{
79 | hex = android.util.Base64.encodeToString(digest.getBytes(), android.util.Base64.DEFAULT);
80 | }
81 | return timeStamp + "." + hex.replace("\n", "");
82 | }
83 |
84 | private void getTimeStamp() {
85 | this.timeStamp = DateTime.now(DateTimeZone.UTC).toString("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
86 | }
87 |
88 | private String createDigest(String body) {
89 | MessageDigest messageDigest = null;
90 | try {
91 | messageDigest = MessageDigest.getInstance("MD5");
92 | } catch (NoSuchAlgorithmException e) {
93 | e.printStackTrace();
94 | }
95 | messageDigest.reset();
96 | messageDigest.update(body.getBytes(Charsets.UTF_8));
97 | final byte[] resultByte = messageDigest.digest();
98 | final String result = Hex.encodeHexString(resultByte);
99 | return result;
100 | }
101 |
102 | private String generateConanicalString(CheckoutRequest checkoutRequest) {
103 | getTimeStamp();
104 | return "POST,application/json," + createDigest(checkoutRequestJsonAdapter.toJson(checkoutRequest)) + ",/v1/checkouts," + timeStamp;
105 | }
106 |
107 | @Override
108 | public CheckoutTransactionBuilder addCheckoutRequest(CheckoutRequest checkoutRequest) {
109 | this.checkoutRequest = checkoutRequest;
110 | return this;
111 | }
112 |
113 | @Override
114 | public CheckoutTransactionBuilder addClientConfig(ClientConfig clientConfig) {
115 | this.clientConfig = clientConfig;
116 | return this;
117 | }
118 |
119 | @Override
120 | public CheckoutTransaction build() {
121 | setUpRequestAuthorization(clientConfig);
122 | CheckoutTransaction transaction = new CheckoutTransaction();
123 | transaction.setClient(client);
124 | transaction.setRequest(request);
125 | return transaction;
126 | }
127 | }
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
17 |
22 |
27 |
32 |
37 |
42 |
47 |
52 |
57 |
62 |
67 |
72 |
77 |
82 |
87 |
92 |
97 |
102 |
107 |
112 |
117 |
122 |
127 |
132 |
137 |
142 |
147 |
152 |
157 |
162 |
167 |
172 |
173 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/ui/KambaButton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) UseKamba Ltda - All Rights Reserved
3 | * Unauthorized copying of this file, via any medium is strictly prohibited
4 | * Proprietary and confidential and will be punished by law
5 | * Written by Alexandre Antonio Juca
6 | *
7 | */
8 |
9 | package com.usekamba.kambapaysdk.ui;
10 |
11 | import android.app.Activity;
12 | import android.content.ActivityNotFoundException;
13 | import android.content.Context;
14 | import android.content.Intent;
15 | import android.content.pm.PackageManager;
16 | import android.content.pm.ResolveInfo;
17 | import android.content.res.TypedArray;
18 | import android.graphics.Typeface;
19 | import android.net.Uri;
20 | import android.os.Build;
21 | import android.preference.PreferenceManager;
22 | import android.support.annotation.Nullable;
23 | import android.support.annotation.RequiresApi;
24 | import android.support.v4.content.ContextCompat;
25 | import android.support.v4.content.res.ResourcesCompat;
26 | import android.util.AttributeSet;
27 | import android.view.View;
28 | import android.widget.ImageView;
29 | import android.widget.RelativeLayout;
30 | import android.widget.TextView;
31 | import com.usekamba.kambapaysdk.R;
32 | import com.usekamba.kambapaysdk.core.model.CheckoutResponse;
33 | import com.usekamba.kambapaysdk.helpers.FourmeKt;
34 | import java.math.BigDecimal;
35 | import java.util.List;
36 |
37 | public class KambaButton extends RelativeLayout implements PreferenceManager.OnActivityResultListener {
38 | private static final String KAMBA_APP_PACKAGE = "com.usekamba.kamba.kamba";
39 | private static final String PHONE_NUMBER = "phoneNumber";
40 | private static final String TRANSACTION_AMOUNT = "amount";
41 | private static final String DESCRIPTION = "description";
42 | private static final String WEBSITE = "https://www.usekamba.com/";
43 | private static final String MERCHANT_PAYMENT = "localBusinessPayment";
44 | private static final int PURCHASE_COMPLETE = 0;
45 | private static final int PURCHASE_NOT_COMPLETED = -1;
46 | private static final int PURCHASE_ITEM = 0;
47 | private PaymentResultListener listener;
48 |
49 | public KambaButton(Context context) {
50 | super(context);
51 | }
52 |
53 | public KambaButton(Context context, @Nullable AttributeSet attrs) {
54 | super(context, attrs);
55 | init(context, attrs);
56 | }
57 |
58 | public KambaButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
59 | super(context, attrs, defStyleAttr);
60 | init(context, attrs);
61 | }
62 |
63 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
64 | public KambaButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
65 | super(context, attrs, defStyleAttr, defStyleRes);
66 | init(context, attrs);
67 | }
68 |
69 | public void setOnPaymentListener(PaymentResultListener listener) {
70 | this.listener = listener;
71 | }
72 |
73 | private void init(Context context, AttributeSet attrs) {
74 | TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.kamba_res_KambaButton);
75 | View mRoot = inflate(context, R.layout.button, this);
76 | RelativeLayout mBackground = mRoot.findViewById(R.id.kamba_button_bg);
77 | TextView mText = mRoot.findViewById(R.id.kamba_button_text);
78 | ImageView mLogo = mRoot.findViewById(R.id.kamba_logo);
79 | mText.setText(R.string.kamba_res_button_text);
80 | Typeface font = ResourcesCompat.getFont(context, R.font.google_sans_bold);
81 | mText.setTypeface(font, Typeface.BOLD);
82 | if (attributes.getBoolean(R.styleable.kamba_res_KambaButton_lightTheme, true)) {
83 | mBackground.setBackground(ContextCompat.getDrawable(context, R.drawable.kamba_res_button_light_theme));
84 | } else {
85 | mBackground.setBackground(ContextCompat.getDrawable(context, R.drawable.kamba_res_button));
86 | }
87 | attributes.recycle();
88 | }
89 |
90 | public void payWithWallet(CheckoutResponse checkoutResponse, Context context) {
91 | if (checkoutResponse != null) {
92 | PackageManager packageManager = context.getPackageManager();
93 | Intent walletIntent = new Intent(Intent.ACTION_VIEW);
94 | walletIntent.setData(Uri.parse("https://comerciante.usekamba.com/pay?chID=" + checkoutResponse.getId()));
95 | List activities = packageManager.queryIntentActivities(walletIntent, 0);
96 | boolean isIntentSafe = activities.size() > 0;
97 | if (isIntentSafe) {
98 | walletIntent.putExtra(TRANSACTION_AMOUNT, FourmeKt.formatCheckoutAmount(new BigDecimal(checkoutResponse.getTotalAmount())));
99 | walletIntent.putExtra(MERCHANT_PAYMENT, true);
100 | walletIntent.putExtra(DESCRIPTION, checkoutResponse.getNotes());
101 | walletIntent.putExtra(PHONE_NUMBER, checkoutResponse.getMerchant().getPhoneNumber());
102 | ((Activity) context).startActivityForResult(walletIntent, PURCHASE_ITEM);
103 | } else {
104 | try {
105 | walletIntent = new Intent(Intent.ACTION_VIEW);
106 | walletIntent.setData(Uri.parse("market://details?id=" + KAMBA_APP_PACKAGE));
107 | context.startActivity(walletIntent);
108 | } catch (ActivityNotFoundException e) {
109 | walletIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(WEBSITE));
110 | context.startActivity(walletIntent);
111 | }
112 | }
113 | } else {
114 | throw new IllegalStateException("CheckoutResponse must not be null");
115 | }
116 |
117 | }
118 |
119 | /**
120 | * This method triggers the PaymentResultListener based on the request code and result code returned
121 | * from the Wallets PayQRViaActivity.
122 | *
123 | * This code must be called as such:
124 | *
125 | * @Override
126 | * protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
127 | * super.onActivityResult(requestCode, resultCode, data);
128 | * payButton.onActivityResult(requestCode, resultCode, data);
129 | * }
130 | * If not called in your classes onActivityResult method
131 | * then the PaymentResultListener will not be able to dispatch the correct action.
132 | *
133 | * @param requestCode int: The integer request code for initiating a PaymentRequest.
134 | * Should always be PURCHASE_ITEM since the library itself will handle requests
135 | * @param resultCode int: The integer result code received from the Kamba Wallet. Should always be either
136 | * PURCHASE_COMPLETE or PURCHASE_NOT_COMPLETED
137 | * @param data Intent: Data returned from called Activity
138 | */
139 | @Override
140 | public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
141 | if (requestCode == PURCHASE_ITEM) {
142 | if (resultCode == PURCHASE_COMPLETE) {
143 | if (listener != null) {
144 | listener.onSuccessfulPayment();
145 | }
146 | return true;
147 | } if (resultCode == PURCHASE_NOT_COMPLETED) {
148 | if (listener != null) {
149 | listener.onFailure();
150 | }
151 | return false;
152 | }
153 | } else {
154 | listener.onFailure();
155 | return false;
156 | }
157 | return false;
158 | }
159 | }
160 |
161 |
162 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/Charsets.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package com.usekamba.kambapaysdk.core.security;
18 |
19 | import java.nio.charset.Charset;
20 |
21 | /**
22 | * Charsets required of every implementation of the Java platform.
23 | *
24 | * From the Java documentation Standard
25 | * charsets:
26 | *
27 | * Every implementation of the Java platform is required to support the following character encodings. Consult the
28 | * release documentation for your implementation to see if any other encodings are supported. Consult the release
29 | * documentation for your implementation to see if any other encodings are supported.
30 | *
31 | *
32 | *
33 | * US-ASCII
34 | * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
35 | * ISO-8859-1
36 | * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
37 | * UTF-8
38 | * Eight-bit Unicode Transformation Format.
39 | * UTF-16BE
40 | * Sixteen-bit Unicode Transformation Format, big-endian byte order.
41 | * UTF-16LE
42 | * Sixteen-bit Unicode Transformation Format, little-endian byte order.
43 | * UTF-16
44 | * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order
45 | * accepted on input, big-endian used on output.)
46 | *
47 | *
48 | * This perhaps would best belong in the Commons Lang project. Even if a similar class is defined in Commons Lang, it is
49 | * not foreseen that Commons Codec would be made to depend on Commons Lang.
50 | *
51 | *
52 | * This class is immutable and thread-safe.
53 | *
54 | *
55 | * @see Standard charsets
56 | * @since 1.7
57 | * @version $Id: CharEncoding.java 1173287 2011-09-20 18:16:19Z ggregory $
58 | */
59 | public class Charsets {
60 |
61 | //
62 | // This class should only contain Charset instances for required encodings. This guarantees that it will load
63 | // correctly and without delay on all Java platforms.
64 | //
65 |
66 | /**
67 | * Returns the given Charset or the default Charset if the given Charset is null.
68 | *
69 | * @param charset
70 | * A charset or null.
71 | * @return the given Charset or the default Charset if the given Charset is null
72 | */
73 | public static Charset toCharset(final Charset charset) {
74 | return charset == null ? Charset.defaultCharset() : charset;
75 | }
76 |
77 | /**
78 | * Returns a Charset for the named charset. If the name is null, return the default Charset.
79 | *
80 | * @param charset
81 | * The name of the requested charset, may be null.
82 | * @return a Charset for the named charset
83 | * @throws java.nio.charset.UnsupportedCharsetException
84 | * If the named charset is unavailable
85 | */
86 | public static Charset toCharset(final String charset) {
87 | return charset == null ? Charset.defaultCharset() : Charset.forName(charset);
88 | }
89 |
90 | /**
91 | * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
92 | *
93 | * Every implementation of the Java platform is required to support this character encoding.
94 | *
95 | *
96 | * On Java 7 or later, use {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead.
97 | *
98 | *
99 | * @see Standard charsets
100 | */
101 | public static final Charset ISO_8859_1 = Charset.forName(CharEncoding.ISO_8859_1);
102 |
103 | /**
104 | * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
105 | *
106 | * Every implementation of the Java platform is required to support this character encoding.
107 | *
108 | *
109 | * On Java 7 or later, use {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead.
110 | *
111 | *
112 | * @see Standard charsets
113 | */
114 | public static final Charset US_ASCII = Charset.forName(CharEncoding.US_ASCII);
115 |
116 | /**
117 | * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark
118 | * (either order accepted on input, big-endian used on output)
119 | *
120 | * Every implementation of the Java platform is required to support this character encoding.
121 | *
122 | *
123 | * On Java 7 or later, use {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead.
124 | *
125 | *
126 | * @see Standard charsets
127 | */
128 | public static final Charset UTF_16 = Charset.forName(CharEncoding.UTF_16);
129 |
130 | /**
131 | * Sixteen-bit Unicode Transformation Format, big-endian byte order.
132 | *
133 | * Every implementation of the Java platform is required to support this character encoding.
134 | *
135 | *
136 | * On Java 7 or later, use {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead.
137 | *
138 | *
139 | * @see Standard charsets
140 | */
141 | public static final Charset UTF_16BE = Charset.forName(CharEncoding.UTF_16BE);
142 |
143 | /**
144 | * Sixteen-bit Unicode Transformation Format, little-endian byte order.
145 | *
146 | * Every implementation of the Java platform is required to support this character encoding.
147 | *
148 | *
149 | * On Java 7 or later, use {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead.
150 | *
151 | *
152 | * @see Standard charsets
153 | */
154 | public static final Charset UTF_16LE = Charset.forName(CharEncoding.UTF_16LE);
155 |
156 | /**
157 | * Eight-bit Unicode Transformation Format.
158 | *
159 | * Every implementation of the Java platform is required to support this character encoding.
160 | *
161 | *
162 | * On Java 7 or later, use {@link java.nio.charset.StandardCharsets#ISO_8859_1} instead.
163 | *
164 | *
165 | * @see Standard charsets
166 | */
167 | public static final Charset UTF_8 = Charset.forName(CharEncoding.UTF_8);
168 | }
169 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/binary/BinaryCodec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security.binary;
19 |
20 | import com.usekamba.kambapaysdk.core.security.BinaryDecoder;
21 | import com.usekamba.kambapaysdk.core.security.BinaryEncoder;
22 | import com.usekamba.kambapaysdk.core.security.DecoderException;
23 | import com.usekamba.kambapaysdk.core.security.EncoderException;
24 |
25 | /**
26 | * Converts between byte arrays and strings of "0"s and "1"s.
27 | *
28 | * This class is immutable and thread-safe.
29 | *
30 | * TODO: may want to add more bit vector functions like and/or/xor/nand
31 | * TODO: also might be good to generate boolean[] from byte[] et cetera.
32 | *
33 | * @since 1.3
34 | * @version $Id$
35 | */
36 | public class BinaryCodec implements BinaryDecoder, BinaryEncoder {
37 | /*
38 | * tried to avoid using ArrayUtils to minimize dependencies while using these empty arrays - dep is just not worth
39 | * it.
40 | */
41 | /** Empty char array. */
42 | private static final char[] EMPTY_CHAR_ARRAY = new char[0];
43 |
44 | /** Empty byte array. */
45 | private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
46 |
47 | /** Mask for bit 0 of a byte. */
48 | private static final int BIT_0 = 1;
49 |
50 | /** Mask for bit 1 of a byte. */
51 | private static final int BIT_1 = 0x02;
52 |
53 | /** Mask for bit 2 of a byte. */
54 | private static final int BIT_2 = 0x04;
55 |
56 | /** Mask for bit 3 of a byte. */
57 | private static final int BIT_3 = 0x08;
58 |
59 | /** Mask for bit 4 of a byte. */
60 | private static final int BIT_4 = 0x10;
61 |
62 | /** Mask for bit 5 of a byte. */
63 | private static final int BIT_5 = 0x20;
64 |
65 | /** Mask for bit 6 of a byte. */
66 | private static final int BIT_6 = 0x40;
67 |
68 | /** Mask for bit 7 of a byte. */
69 | private static final int BIT_7 = 0x80;
70 |
71 | private static final int[] BITS = {BIT_0, BIT_1, BIT_2, BIT_3, BIT_4, BIT_5, BIT_6, BIT_7};
72 |
73 | /**
74 | * Converts an array of raw binary data into an array of ASCII 0 and 1 characters.
75 | *
76 | * @param raw
77 | * the raw binary data to convert
78 | * @return 0 and 1 ASCII character bytes one for each bit of the argument
79 | * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
80 | */
81 | @Override
82 | public byte[] encode(final byte[] raw) {
83 | return toAsciiBytes(raw);
84 | }
85 |
86 | /**
87 | * Converts an array of raw binary data into an array of ASCII 0 and 1 chars.
88 | *
89 | * @param raw
90 | * the raw binary data to convert
91 | * @return 0 and 1 ASCII character chars one for each bit of the argument
92 | * @throws EncoderException
93 | * if the argument is not a byte[]
94 | * @see org.apache.commons.codec.Encoder#encode(Object)
95 | */
96 | @Override
97 | public Object encode(final Object raw) throws EncoderException {
98 | if (!(raw instanceof byte[])) {
99 | throw new EncoderException("argument not a byte array");
100 | }
101 | return toAsciiChars((byte[]) raw);
102 | }
103 |
104 | /**
105 | * Decodes a byte array where each byte represents an ASCII '0' or '1'.
106 | *
107 | * @param ascii
108 | * each byte represents an ASCII '0' or '1'
109 | * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
110 | * @throws DecoderException
111 | * if argument is not a byte[], char[] or String
112 | * @see org.apache.commons.codec.Decoder#decode(Object)
113 | */
114 | @Override
115 | public Object decode(final Object ascii) throws DecoderException {
116 | if (ascii == null) {
117 | return EMPTY_BYTE_ARRAY;
118 | }
119 | if (ascii instanceof byte[]) {
120 | return fromAscii((byte[]) ascii);
121 | }
122 | if (ascii instanceof char[]) {
123 | return fromAscii((char[]) ascii);
124 | }
125 | if (ascii instanceof String) {
126 | return fromAscii(((String) ascii).toCharArray());
127 | }
128 | throw new DecoderException("argument not a byte array");
129 | }
130 |
131 | /**
132 | * Decodes a byte array where each byte represents an ASCII '0' or '1'.
133 | *
134 | * @param ascii
135 | * each byte represents an ASCII '0' or '1'
136 | * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
137 | * @see org.apache.commons.codec.Decoder#decode(Object)
138 | */
139 | @Override
140 | public byte[] decode(final byte[] ascii) {
141 | return fromAscii(ascii);
142 | }
143 |
144 | /**
145 | * Decodes a String where each char of the String represents an ASCII '0' or '1'.
146 | *
147 | * @param ascii
148 | * String of '0' and '1' characters
149 | * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
150 | * @see org.apache.commons.codec.Decoder#decode(Object)
151 | */
152 | public byte[] toByteArray(final String ascii) {
153 | if (ascii == null) {
154 | return EMPTY_BYTE_ARRAY;
155 | }
156 | return fromAscii(ascii.toCharArray());
157 | }
158 |
159 | // ------------------------------------------------------------------------
160 | //
161 | // static codec operations
162 | //
163 | // ------------------------------------------------------------------------
164 | /**
165 | * Decodes a char array where each char represents an ASCII '0' or '1'.
166 | *
167 | * @param ascii
168 | * each char represents an ASCII '0' or '1'
169 | * @return the raw encoded binary where each bit corresponds to a char in the char array argument
170 | */
171 | public static byte[] fromAscii(final char[] ascii) {
172 | if (ascii == null || ascii.length == 0) {
173 | return EMPTY_BYTE_ARRAY;
174 | }
175 | // get length/8 times bytes with 3 bit shifts to the right of the length
176 | final byte[] l_raw = new byte[ascii.length >> 3];
177 | /*
178 | * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
179 | * loop.
180 | */
181 | for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) {
182 | for (int bits = 0; bits < BITS.length; ++bits) {
183 | if (ascii[jj - bits] == '1') {
184 | l_raw[ii] |= BITS[bits];
185 | }
186 | }
187 | }
188 | return l_raw;
189 | }
190 |
191 | /**
192 | * Decodes a byte array where each byte represents an ASCII '0' or '1'.
193 | *
194 | * @param ascii
195 | * each byte represents an ASCII '0' or '1'
196 | * @return the raw encoded binary where each bit corresponds to a byte in the byte array argument
197 | */
198 | public static byte[] fromAscii(final byte[] ascii) {
199 | if (isEmpty(ascii)) {
200 | return EMPTY_BYTE_ARRAY;
201 | }
202 | // get length/8 times bytes with 3 bit shifts to the right of the length
203 | final byte[] l_raw = new byte[ascii.length >> 3];
204 | /*
205 | * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
206 | * loop.
207 | */
208 | for (int ii = 0, jj = ascii.length - 1; ii < l_raw.length; ii++, jj -= 8) {
209 | for (int bits = 0; bits < BITS.length; ++bits) {
210 | if (ascii[jj - bits] == '1') {
211 | l_raw[ii] |= BITS[bits];
212 | }
213 | }
214 | }
215 | return l_raw;
216 | }
217 |
218 | /**
219 | * Returns true if the given array is null or empty (size 0.)
220 | *
221 | * @param array
222 | * the source array
223 | * @return true if the given array is null or empty (size 0.)
224 | */
225 | private static boolean isEmpty(final byte[] array) {
226 | return array == null || array.length == 0;
227 | }
228 |
229 | /**
230 | * Converts an array of raw binary data into an array of ASCII 0 and 1 character bytes - each byte is a truncated
231 | * char.
232 | *
233 | * @param raw
234 | * the raw binary data to convert
235 | * @return an array of 0 and 1 character bytes for each bit of the argument
236 | * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
237 | */
238 | public static byte[] toAsciiBytes(final byte[] raw) {
239 | if (isEmpty(raw)) {
240 | return EMPTY_BYTE_ARRAY;
241 | }
242 | // get 8 times the bytes with 3 bit shifts to the left of the length
243 | final byte[] l_ascii = new byte[raw.length << 3];
244 | /*
245 | * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
246 | * loop.
247 | */
248 | for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) {
249 | for (int bits = 0; bits < BITS.length; ++bits) {
250 | if ((raw[ii] & BITS[bits]) == 0) {
251 | l_ascii[jj - bits] = '0';
252 | } else {
253 | l_ascii[jj - bits] = '1';
254 | }
255 | }
256 | }
257 | return l_ascii;
258 | }
259 |
260 | /**
261 | * Converts an array of raw binary data into an array of ASCII 0 and 1 characters.
262 | *
263 | * @param raw
264 | * the raw binary data to convert
265 | * @return an array of 0 and 1 characters for each bit of the argument
266 | * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
267 | */
268 | public static char[] toAsciiChars(final byte[] raw) {
269 | if (isEmpty(raw)) {
270 | return EMPTY_CHAR_ARRAY;
271 | }
272 | // get 8 times the bytes with 3 bit shifts to the left of the length
273 | final char[] l_ascii = new char[raw.length << 3];
274 | /*
275 | * We decr index jj by 8 as we go along to not recompute indices using multiplication every time inside the
276 | * loop.
277 | */
278 | for (int ii = 0, jj = l_ascii.length - 1; ii < raw.length; ii++, jj -= 8) {
279 | for (int bits = 0; bits < BITS.length; ++bits) {
280 | if ((raw[ii] & BITS[bits]) == 0) {
281 | l_ascii[jj - bits] = '0';
282 | } else {
283 | l_ascii[jj - bits] = '1';
284 | }
285 | }
286 | }
287 | return l_ascii;
288 | }
289 |
290 | /**
291 | * Converts an array of raw binary data into a String of ASCII 0 and 1 characters.
292 | *
293 | * @param raw
294 | * the raw binary data to convert
295 | * @return a String of 0 and 1 characters representing the binary data
296 | * @see org.apache.commons.codec.BinaryEncoder#encode(byte[])
297 | */
298 | public static String toAsciiString(final byte[] raw) {
299 | return new String(toAsciiChars(raw));
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/res/layout/checkoutwidget.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
22 |
23 |
39 |
40 |
44 |
45 |
62 |
63 |
73 |
74 |
88 |
89 |
99 |
100 |
101 |
102 |
103 |
116 |
117 |
136 |
137 |
150 |
151 |
161 |
162 |
175 |
176 |
182 |
183 |
191 |
192 |
203 |
204 |
205 |
206 |
207 |
208 |
222 |
223 |
234 |
235 |
244 |
245 |
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Guia de Integração da Biblioteca Checkout App2App Android
2 |
3 | [](https://jitpack.io/#usekamba/kamba-android-sdk)
4 |
5 | Ofereça pagamentos de produtos ou serviços em seu aplicativo de forma nativa para Android.
6 |
7 | Com uma única integração, seus clientes poderão realizar pagamentos com a sua carteira via código QR de pagamento ou Botão de pagamento, além de utilizarem seus dados cadastrados para futuras compras em 2 cliques. Notificação para lembretes de finalização de compra, levantamento da quantia para sua conta bancária em até 72 horas e muito mais benefícios técnicos e de negócios à longo termo.
8 |
9 | 
10 |
11 | > A autenticação deve ser feita com as suas credenciais de conta Comerciante. Veja mais sobre os tipos de credenciais em [Autenticação](https://docs.usekamba.com/#autenticacao).
12 |
13 | **Atenção:**
14 | > O Checkout App2App está em fase beta. Para fazer parte desta fase você precisa seguir alguns passos antes:
15 |
16 | - Enviar um e-mail para suporte@usekamba.com informando um telefone de contato e o e-mail para a sua conta Comerciante.
17 | - Assim que possível, nossa equipa entrará em contato com você para obter mais informações e liberar a funcionalidade para a sua conta Comerciante.
18 |
19 | Assim que você implementar o Checkout App2App em sua aplicação, envie o link para seu App Android na Google Play Store e até mesmo feedback para a nossa equipa. Nesta fase de implementação a sua opinião é extremamente importante.
20 |
21 | ## Formas atuais de pagamento
22 | 1. **Pagamento via QR** com um código de pagamento (útil para comerciantes com ponto físico que desejam digitalizar os pagamentos do seu negócio ou para organizadores de eventos para vendas de ingressos, etc, o código pode ser impresso ou enviado para diversos canais sóciais).
23 | 2. **App2App** em que seu aplicativo finaliza os pagamentos abrindo à carteira instalada no dispositivo dos clientes para concluir os pagamentos.
24 |
25 | > **Nota:** Em ambos você acompanha os estados do pagamento, recebe notificações por e-mail, push quando pagamentos são bem sucedidos. E pode ainda controlar todos seus pagamentos com o aplicativo para Comerciantes ou o Painel Web.
26 |
27 | ## Configuração inicial
28 | Crie uma conta Comerciante connosco entrando em contato com nossa equipe de suporte. Você receberá uma `secret_key` e um identificador de comerciante `merchant_id` para testar a biblioteca no modo SANDBOX. Você terá ainda acesso ao App Comerciante e ao Painel Web para adiministração e controle dos seus pagamentos e clientes.
29 |
30 | > Nota: Esta biblioteca está em fase beta e em desenvolvimento contínuo. Se você encontrar algum erro, crie uma issue para que ela seja corrigida o mais rápido possível.
31 |
32 | ## Instalação
33 |
34 | ### Android Studio (ou Gradle)
35 |
36 | Não há necessidade de clonar o repositório ou baixar arquivos para sua máquina - basta adicionar as linhas de código à baixo ao `build.gradle` do seu aplicativo dentro da seção` dependencies`:
37 |
38 | **Passo 1:** Inclua o repositório JitPack em seu arquivo de construção. Adicione-o em sua raiz `build.gradle` no final dos repositórios.
39 | ```
40 | allprojects {
41 | repositories {
42 | ...
43 | maven { url 'https://jitpack.io' }
44 | }
45 | }
46 | ```
47 |
48 | **Passo 2:** Adicione a dependência.
49 |
50 | ```
51 | dependencies
52 | {
53 | implementation 'com.github.usekamba:kamba-android-sdk:v1.0.5'
54 | }
55 | ```
56 |
57 | **Passo 3:** Adicione a permissão para Internet.
58 | ```
59 |
60 | ```
61 | #### Configurar credenciais
62 | É importante configurar suas credenciais para que nossos sistemas possam autenticar suas solicitações de pagamento.
63 | Normalmente, você fará isso na `Activity` que exibirá o método de pagamento para seu aplicativo. Este código será executado após o usuário selecionar a opção de pagamento `Pagar com o Kamba`.
64 |
65 | **NOTA:**
66 | 1) Durante a fase de desenvolvimento deve-se usar o sdk em ambiente SANDBOX.
67 |
68 | 2) Recomendamos que crie uma classe que seja sub-classe da classe Application e chama o ``ClientConfig.getInstance().configure()`` no metódo ``onCreate()``
69 |
70 | ```java
71 |
72 | public class DemoApplication extends Application {
73 | @Override
74 | public void onCreate() {
75 | super.onCreate();
76 | ClientConfig.getInstance().configure("SEU_MERCHAND_ID", "SUA_CHAVE_SECRETA", ClientConfig.Environment.SANDBOX);
77 | }
78 | }
79 | ```
80 | **Configurações do `CLientConfig`:**
81 |
82 | | Atributo | Descrição |
83 | | ------------- |:-------------:|
84 | | `enironment` | O campo `environment` define qual ambiente poderá ser usado. Durante a fase de desenvolvimento deve-se usar o ambiente ```ClientConfig.Environment.SANDBOX``` e quando estiver pronto para produção deve-se usar ```ClientConfig.Environment.PRODUCTION```. |
85 | | `merchantId` | Use o `merchantId` (ID de comerciante) que copiou do seu painel de comerciante para substituir o valor do campo `merchantId`. Recomenda-se usar variáveis de ambiente sempre, e não deve ser compartilhada ou exposta em sua página html. **O ID de comerciante da API para sandbox e production são diferentes. |
86 | | `secretKey` | Campo `secretkey` é a `chave secreta` usado para geração de assinaturas para permitir que seus clientes pagam em ***segurança***|
87 |
88 | **Configurações do `CheckoutRequest`:**
89 |
90 | | Atributo | Descrição |
91 | | ------------- |:-------------:|
92 | |`initialAmount`| Este campo recebe o preço do produto ou serviço a ser comercializado.
eg. ```checkoutRequest.setInitialAmount(28999);```|
93 | |`notes`|Substitua o valor do campo `notes` por uma anotação ou descrição geral a cerca do pagamento.
```checkoutRequest.setNotes("Serviço de hospedagem - Plano Mais");```|
94 |
95 | ## Geração de assinaturas
96 |
97 | Para garantir a segurança do checkout e da transação, uma assinatura é gerada usando a chave secreta atribuída ao comerciante.
98 |
99 | A chave secreta designada deve ser mantida em segurança, pois é usada para autenticar o checkout através da API da Kamba.
100 |
101 | A geração de assinatura é tratada pela própia biblíoteca garantindo assim um checkout com maior segurança para si e os seus clientes.
102 |
103 | ## Implementação
104 | As ferramentas atuais permitem que você use nossos componentes de UI como **Botão de pagamento, tela Checkout, e código QR de pagamento** para exibir as informações para a finalização da compra pelo cliente, seja digitalizando o código QR ou finalizando o pagamento com a sua Carteira.
105 |
106 | ```xml
107 |
111 |
112 | ```
113 |
114 | Também criamos um botão de Pagamento para que seus clientes cliquem para aceitar pagamentos via Carteira. Clicar neste botão abrirá a Carteira do cliente para finalizar o pagamento.
115 |
116 | ```xml
117 |
124 |
125 | ```
126 | Você pode adicionar os dois componentes no mesmo layout para mostrar o **widget Checkout** que contém os detalhes de pagamento na mesma tela em conjunto com a opção **botão de Pagamento**, dando assim aos seus clientes à escolha para melhor opção de pagamento no seu contexto.
127 |
128 | Crie uma instância do objeto `CheckoutRequest` que representa o item que seu cliente selecionou para comprar. Adicione o preço e a descrição conforme necessário. O objeto `CheckoutTransaction` enviará uma solicitação de forma assíncrona para os nossos sistemas que retornará um objeto `CheckoutResponse` que seu `CheckoutWidget` preencherá com as demais informações. No retorno de chamada `onSuccess`, inicie a atividade que mostrará o `CheckoutWidget` e o `KambaButton`.
129 | ```java
130 | public class MerchantActivity extends AppCompatActivity {
131 | ...
132 | checkoutRequest = new CheckoutRequest();
133 | checkoutRequest.setInitialAmount(28999);
134 | checkoutRequest.setNotes("Serviço de hospedagem - Plano Mais");
135 | CheckoutTransaction checkoutTransaction = new CheckoutTransactionBuilder()
136 | .addClientConfig(ClientConfig.getInstance())
137 | .addCheckoutRequest(checkoutRequest)
138 | .build();
139 | checkoutTransaction.enqueue(new TransactionCallback() {
140 | @Override
141 | public void onSuccess(final CheckoutResponse checkout) {
142 | runOnUiThread(() -> startActivity(new Intent(context, CheckoutActivity.class).putExtra("checkout", checkout)));
143 | }
144 |
145 | @Override
146 | public void onFailure(String message) {
147 | runOnUiThread(() -> Toast.makeText(context, "Error initiating Payment request: " + message, Toast.LENGTH_LONG).show() );
148 | }
149 | });
150 |
151 | ...
152 | }
153 |
154 | ```
155 |
156 | Na Activity que mostrará o `CheckoutWidget`, faça o seguinte:
157 |
158 | ```java
159 | public class CheckoutActivity extends AppCompatActivity {
160 | private CheckoutWidget checkoutWidget;
161 | private CheckoutResponse checkoutResponse;
162 | private KambaButton payButton;
163 | private Context context = this;
164 | @Override
165 | protected void onCreate(Bundle savedInstanceState) {
166 | super.onCreate(savedInstanceState);
167 | setContentView(R.layout.activity_checkout);
168 |
169 | checkoutWidget = findViewById(R.id.checkout);
170 | payButton = findViewById(R.id.pay);
171 | // Para acessar o checkout response da tela anterior usa sempre response "(CheckoutResponse) getIntent().getSerializableExtra("checkout");
172 | checkoutResponse = (CheckoutResponse) getIntent().getSerializableExtra("checkout");
173 | checkoutWidget.setAmount(checkoutResponse.getTotalAmount());
174 | checkoutWidget.setExpirationDate(checkoutResponse.getExpiresAt());
175 | checkoutWidget.setTotalCheckoutAmount(checkoutResponse.getTotalAmount());
176 | checkoutWidget.setItemDescription(checkoutResponse.getNotes());
177 | checkoutWidget.setItemAmount(checkoutResponse.getInitialAmount());
178 | checkoutWidget.setQrCode(checkoutResponse.getQrCode());
179 | payButton.setOnPaymentListener(new PaymentResultListener() {
180 | @Override
181 | public void onSuccessfulPayment() {
182 | Toast.makeText(context, "Purchase Made", Toast.LENGTH_SHORT).show();
183 | }
184 |
185 | @Override
186 | public void onFailure() {
187 | Toast.makeText(context, "Purchase not performed", Toast.LENGTH_SHORT).show();
188 | }
189 | });
190 | payButton.setOnClickListener(v -> payButton.payWithWallet(checkoutResponse, context));
191 |
192 | }
193 |
194 | @Override
195 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
196 | super.onActivityResult(requestCode, resultCode, data);
197 | payButton.onActivityResult(requestCode, resultCode, data);
198 | }
199 | }
200 | ```
201 |
202 | **IMPORTANTE:** Se tudo está funcionando bem em modo SANDBOX e o seu aplicativo está pronto para RELEASE (Lançamento) altera o
203 | ambiente para production e certifica que estejas a usar a CHAVE_SECRETA e MERCHANT_ID para PRODUCTION.
204 | ```java
205 | ClientConfig.getInstance().configure("SEU_MERCHAND_ID", "SUA_CHAVE_SECRETA", ClientConfig.Environment.PRODUCTION);
206 | ```
207 |
208 | ## Customizar
209 | Actualmente é possível alterar o estilo do botão conforme a UI do seu app.
210 |
211 | ### Dark Theme
212 | 
213 | Para usar este tema basta definir a propriedade: ```xml app:lightTheme="false" ```
214 |
215 | Exemplo:
216 |
217 | ```xml
218 |
229 |
230 |
231 | ```
232 |
233 | ### Light Theme
234 | 
235 | Para usar este tema basta definir a propriedade: ```xml app:lightTheme="true" ```
236 |
237 | Exemplo:
238 |
239 | ```xml
240 |
251 |
252 |
253 | ```
254 |
255 | ## Histórico de versões
256 | ``` 0.9.3: Melhorias e correção de bugs - 07/07/2018 ```
257 |
258 | ``` 0.9.4: Melhorias e correção de bugs - 20/08/2018 ```
259 |
260 | ``` 1.0.0: Melhoras para reflectir mudanças feitas na API - 03/10/2018 ```
261 |
262 | ``` 1.0.1: Corrigimos o bug que causava uma execção ao gerar o código QR do CheckoutWidget - 04/10/2018 ```
263 |
264 | ``` 1.0.2: Adicionar suporte para temas ao botão Kamba - 09/10/2018 ```
265 |
266 | ``` 1.0.3: Implementamos hmac para asegurar transações e o checkout usando a função de dispersão criptográfica SHA1 - 22/02/2019```
267 |
268 | ``` 1.0.4: Corrigidos conflictos em recursos/assets - 22/02/2019 ```
269 |
270 | ``` 1.0.5: Adicionamos suporte para callbacks para saber se um pagamento foi feito com sucesso ou não. - 24/02/2019 ```
271 |
272 | © 2018 Soluções de Pagamento. Todos os direitos reservados. USEKAMBA, LDA. - Rua Avenida Manuel Vandunem, Ingombotas - Luanda - Angola
273 |
--------------------------------------------------------------------------------
/kamba-android-sdk/src/main/java/com/usekamba/kambapaysdk/core/security/binary/StringUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.usekamba.kambapaysdk.core.security.binary;;
19 |
20 | import com.usekamba.kambapaysdk.core.security.Charsets;
21 |
22 | import java.io.UnsupportedEncodingException;
23 | import java.nio.ByteBuffer;
24 | import java.nio.charset.Charset;
25 |
26 |
27 | /**
28 | * Converts String to and from bytes using the encodings required by the Java specification. These encodings are
29 | * specified in
30 | * Standard charsets.
31 | *
32 | * This class is immutable and thread-safe.
33 | *
34 | * @see CharEncoding
35 | * @see Standard charsets
36 | * @version $Id$
37 | * @since 1.4
38 | */
39 | public class StringUtils {
40 |
41 | /**
42 | *
43 | * Compares two CharSequences, returning true if they represent equal sequences of characters.
44 | *
45 | *
46 | *
47 | * nulls are handled without exceptions. Two null references are considered to be equal.
48 | * The comparison is case sensitive.
49 | *
50 | *
51 | *
52 | * StringUtils.equals(null, null) = true
53 | * StringUtils.equals(null, "abc") = false
54 | * StringUtils.equals("abc", null) = false
55 | * StringUtils.equals("abc", "abc") = true
56 | * StringUtils.equals("abc", "ABC") = false
57 | *
58 | *
59 | *
60 | * Copied from Apache Commons Lang r1583482 on April 10, 2014 (day of 3.3.2 release).
61 | *
62 | *
63 | * @see Object#equals(Object)
64 | * @param cs1
65 | * the first CharSequence, may be null
66 | * @param cs2
67 | * the second CharSequence, may be null
68 | * @return true if the CharSequences are equal (case-sensitive), or both null
69 | * @since 1.10
70 | */
71 | public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
72 | if (cs1 == cs2) {
73 | return true;
74 | }
75 | if (cs1 == null || cs2 == null) {
76 | return false;
77 | }
78 | if (cs1 instanceof String && cs2 instanceof String) {
79 | return cs1.equals(cs2);
80 | }
81 | return cs1.length() == cs2.length() && CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
82 | }
83 |
84 | /**
85 | * Calls {@link String#getBytes(Charset)}
86 | *
87 | * @param string
88 | * The string to encode (if null, return null).
89 | * @param charset
90 | * The {@link Charset} to encode the String
91 | * @return the encoded bytes
92 | */
93 | private static byte[] getBytes(final String string, final Charset charset) {
94 | if (string == null) {
95 | return null;
96 | }
97 | return string.getBytes(charset);
98 | }
99 |
100 | /**
101 | * Calls {@link String#getBytes(Charset)}
102 | *
103 | * @param string
104 | * The string to encode (if null, return null).
105 | * @param charset
106 | * The {@link Charset} to encode the String
107 | * @return the encoded bytes
108 | */
109 | private static ByteBuffer getByteBuffer(final String string, final Charset charset) {
110 | if (string == null) {
111 | return null;
112 | }
113 | return ByteBuffer.wrap(string.getBytes(charset));
114 | }
115 |
116 | /**
117 | * Encodes the given string into a byte buffer using the UTF-8 charset, storing the result into a new byte
118 | * array.
119 | *
120 | * @param string
121 | * the String to encode, may be null
122 | * @return encoded bytes, or null if the input string was null
123 | * @throws NullPointerException
124 | * Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
125 | * required by the Java platform specification.
126 | * @see Standard charsets
127 | * @see #getBytesUnchecked(String, String)
128 | * @since 1.11
129 | */
130 | public static ByteBuffer getByteBufferUtf8(final String string) {
131 | return getByteBuffer(string, Charsets.UTF_8);
132 | }
133 |
134 | /**
135 | * Encodes the given string into a sequence of bytes using the ISO-8859-1 charset, storing the result into a new
136 | * byte array.
137 | *
138 | * @param string
139 | * the String to encode, may be null
140 | * @return encoded bytes, or null if the input string was null
141 | * @throws NullPointerException
142 | * Thrown if {@link Charsets#ISO_8859_1} is not initialized, which should never happen since it is
143 | * required by the Java platform specification.
144 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
145 | * @see Standard charsets
146 | * @see #getBytesUnchecked(String, String)
147 | */
148 | public static byte[] getBytesIso8859_1(final String string) {
149 | return getBytes(string, Charsets.ISO_8859_1);
150 | }
151 |
152 |
153 | /**
154 | * Encodes the given string into a sequence of bytes using the named charset, storing the result into a new byte
155 | * array.
156 | *
157 | * This method catches {@link UnsupportedEncodingException} and rethrows it as {@link IllegalStateException}, which
158 | * should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
159 | *
160 | *
161 | * @param string
162 | * the String to encode, may be null
163 | * @param charsetName
164 | * The name of a required {@link java.nio.charset.Charset}
165 | * @return encoded bytes, or null if the input string was null
166 | * @throws IllegalStateException
167 | * Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
168 | * required charset name.
169 | * @see CharEncoding
170 | * @see String#getBytes(String)
171 | */
172 | public static byte[] getBytesUnchecked(final String string, final String charsetName) {
173 | if (string == null) {
174 | return null;
175 | }
176 | try {
177 | return string.getBytes(charsetName);
178 | } catch (final UnsupportedEncodingException e) {
179 | throw StringUtils.newIllegalStateException(charsetName, e);
180 | }
181 | }
182 |
183 | /**
184 | * Encodes the given string into a sequence of bytes using the US-ASCII charset, storing the result into a new byte
185 | * array.
186 | *
187 | * @param string
188 | * the String to encode, may be null
189 | * @return encoded bytes, or null if the input string was null
190 | * @throws NullPointerException
191 | * Thrown if {@link Charsets#US_ASCII} is not initialized, which should never happen since it is
192 | * required by the Java platform specification.
193 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
194 | * @see Standard charsets
195 | * @see #getBytesUnchecked(String, String)
196 | */
197 | public static byte[] getBytesUsAscii(final String string) {
198 | return getBytes(string, Charsets.US_ASCII);
199 | }
200 |
201 | /**
202 | * Encodes the given string into a sequence of bytes using the UTF-16 charset, storing the result into a new byte
203 | * array.
204 | *
205 | * @param string
206 | * the String to encode, may be null
207 | * @return encoded bytes, or null if the input string was null
208 | * @throws NullPointerException
209 | * Thrown if {@link Charsets#UTF_16} is not initialized, which should never happen since it is
210 | * required by the Java platform specification.
211 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
212 | * @see Standard charsets
213 | * @see #getBytesUnchecked(String, String)
214 | */
215 | public static byte[] getBytesUtf16(final String string) {
216 | return getBytes(string, Charsets.UTF_16);
217 | }
218 |
219 | /**
220 | * Encodes the given string into a sequence of bytes using the UTF-16BE charset, storing the result into a new byte
221 | * array.
222 | *
223 | * @param string
224 | * the String to encode, may be null
225 | * @return encoded bytes, or null if the input string was null
226 | * @throws NullPointerException
227 | * Thrown if {@link Charsets#UTF_16BE} is not initialized, which should never happen since it is
228 | * required by the Java platform specification.
229 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
230 | * @see Standard charsets
231 | * @see #getBytesUnchecked(String, String)
232 | */
233 | public static byte[] getBytesUtf16Be(final String string) {
234 | return getBytes(string, Charsets.UTF_16BE);
235 | }
236 |
237 | /**
238 | * Encodes the given string into a sequence of bytes using the UTF-16LE charset, storing the result into a new byte
239 | * array.
240 | *
241 | * @param string
242 | * the String to encode, may be null
243 | * @return encoded bytes, or null if the input string was null
244 | * @throws NullPointerException
245 | * Thrown if {@link Charsets#UTF_16LE} is not initialized, which should never happen since it is
246 | * required by the Java platform specification.
247 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
248 | * @see Standard charsets
249 | * @see #getBytesUnchecked(String, String)
250 | */
251 | public static byte[] getBytesUtf16Le(final String string) {
252 | return getBytes(string, Charsets.UTF_16LE);
253 | }
254 |
255 | /**
256 | * Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte
257 | * array.
258 | *
259 | * @param string
260 | * the String to encode, may be null
261 | * @return encoded bytes, or null if the input string was null
262 | * @throws NullPointerException
263 | * Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
264 | * required by the Java platform specification.
265 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
266 | * @see Standard charsets
267 | * @see #getBytesUnchecked(String, String)
268 | */
269 | public static byte[] getBytesUtf8(final String string) {
270 | return getBytes(string, Charsets.UTF_8);
271 | }
272 |
273 | private static IllegalStateException newIllegalStateException(final String charsetName,
274 | final UnsupportedEncodingException e) {
275 | return new IllegalStateException(charsetName + ": " + e);
276 | }
277 |
278 | /**
279 | * Constructs a new String by decoding the specified array of bytes using the given charset.
280 | *
281 | * @param bytes
282 | * The bytes to be decoded into characters
283 | * @param charset
284 | * The {@link Charset} to encode the String; not {@code null}
285 | * @return A new String decoded from the specified array of bytes using the given charset,
286 | * or null if the input byte array was null.
287 | * @throws NullPointerException
288 | * Thrown if charset is {@code null}
289 | */
290 | private static String newString(final byte[] bytes, final Charset charset) {
291 | return bytes == null ? null : new String(bytes, charset);
292 | }
293 |
294 | /**
295 | * Constructs a new String by decoding the specified array of bytes using the given charset.
296 | *
297 | * This method catches {@link UnsupportedEncodingException} and re-throws it as {@link IllegalStateException}, which
298 | * should never happen for a required charset name. Use this method when the encoding is required to be in the JRE.
299 | *
300 | *
301 | * @param bytes
302 | * The bytes to be decoded into characters, may be null
303 | * @param charsetName
304 | * The name of a required {@link java.nio.charset.Charset}
305 | * @return A new String decoded from the specified array of bytes using the given charset,
306 | * or null if the input byte array was null.
307 | * @throws IllegalStateException
308 | * Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen for a
309 | * required charset name.
310 | * @see CharEncoding
311 | * @see String#String(byte[], String)
312 | */
313 | public static String newString(final byte[] bytes, final String charsetName) {
314 | if (bytes == null) {
315 | return null;
316 | }
317 | try {
318 | return new String(bytes, charsetName);
319 | } catch (final UnsupportedEncodingException e) {
320 | throw StringUtils.newIllegalStateException(charsetName, e);
321 | }
322 | }
323 |
324 | /**
325 | * Constructs a new String by decoding the specified array of bytes using the ISO-8859-1 charset.
326 | *
327 | * @param bytes
328 | * The bytes to be decoded into characters, may be null
329 | * @return A new String decoded from the specified array of bytes using the ISO-8859-1 charset, or
330 | * null if the input byte array was null.
331 | * @throws NullPointerException
332 | * Thrown if {@link Charsets#ISO_8859_1} is not initialized, which should never happen since it is
333 | * required by the Java platform specification.
334 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
335 | */
336 | public static String newStringIso8859_1(final byte[] bytes) {
337 | return newString(bytes, Charsets.ISO_8859_1);
338 | }
339 |
340 | /**
341 | * Constructs a new String by decoding the specified array of bytes using the US-ASCII charset.
342 | *
343 | * @param bytes
344 | * The bytes to be decoded into characters
345 | * @return A new String decoded from the specified array of bytes using the US-ASCII charset,
346 | * or null if the input byte array was null.
347 | * @throws NullPointerException
348 | * Thrown if {@link Charsets#US_ASCII} is not initialized, which should never happen since it is
349 | * required by the Java platform specification.
350 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
351 | */
352 | public static String newStringUsAscii(final byte[] bytes) {
353 | return newString(bytes, Charsets.US_ASCII);
354 | }
355 |
356 | /**
357 | * Constructs a new String by decoding the specified array of bytes using the UTF-16 charset.
358 | *
359 | * @param bytes
360 | * The bytes to be decoded into characters
361 | * @return A new String decoded from the specified array of bytes using the UTF-16 charset
362 | * or null if the input byte array was null.
363 | * @throws NullPointerException
364 | * Thrown if {@link Charsets#UTF_16} is not initialized, which should never happen since it is
365 | * required by the Java platform specification.
366 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
367 | */
368 | public static String newStringUtf16(final byte[] bytes) {
369 | return newString(bytes, Charsets.UTF_16);
370 | }
371 |
372 | /**
373 | * Constructs a new String by decoding the specified array of bytes using the UTF-16BE charset.
374 | *
375 | * @param bytes
376 | * The bytes to be decoded into characters
377 | * @return A new String decoded from the specified array of bytes using the UTF-16BE charset,
378 | * or null if the input byte array was null.
379 | * @throws NullPointerException
380 | * Thrown if {@link Charsets#UTF_16BE} is not initialized, which should never happen since it is
381 | * required by the Java platform specification.
382 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
383 | */
384 | public static String newStringUtf16Be(final byte[] bytes) {
385 | return newString(bytes, Charsets.UTF_16BE);
386 | }
387 |
388 | /**
389 | * Constructs a new String by decoding the specified array of bytes using the UTF-16LE charset.
390 | *
391 | * @param bytes
392 | * The bytes to be decoded into characters
393 | * @return A new String decoded from the specified array of bytes using the UTF-16LE charset,
394 | * or null if the input byte array was null.
395 | * @throws NullPointerException
396 | * Thrown if {@link Charsets#UTF_16LE} is not initialized, which should never happen since it is
397 | * required by the Java platform specification.
398 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
399 | */
400 | public static String newStringUtf16Le(final byte[] bytes) {
401 | return newString(bytes, Charsets.UTF_16LE);
402 | }
403 |
404 | /**
405 | * Constructs a new String by decoding the specified array of bytes using the UTF-8 charset.
406 | *
407 | * @param bytes
408 | * The bytes to be decoded into characters
409 | * @return A new String decoded from the specified array of bytes using the UTF-8 charset,
410 | * or null if the input byte array was null.
411 | * @throws NullPointerException
412 | * Thrown if {@link Charsets#UTF_8} is not initialized, which should never happen since it is
413 | * required by the Java platform specification.
414 | * @since As of 1.7, throws {@link NullPointerException} instead of UnsupportedEncodingException
415 | */
416 | public static String newStringUtf8(final byte[] bytes) {
417 | return newString(bytes, Charsets.UTF_8);
418 | }
419 |
420 | }
421 |
--------------------------------------------------------------------------------