├── .gitignore ├── app ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── cloudipsp │ │ └── android │ │ └── demo │ │ ├── BaseExampleActivity.java │ │ ├── FlexibleExampleActivity.java │ │ ├── GPay.java │ │ ├── MainActivity.java │ │ └── SimpleExampleActivity.java │ └── res │ ├── drawable-hdpi │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ ├── activity_flexible_example.xml │ ├── activity_main.xml │ └── activity_simple_example.xml │ └── values │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── cloudipsp │ │ └── android │ │ ├── BaseConfirmationErrorHandler.java │ │ ├── Card.java │ │ ├── CardCvvEdit.java │ │ ├── CardDisplay.java │ │ ├── CardExpMmEdit.java │ │ ├── CardExpYyEdit.java │ │ ├── CardInputBase.java │ │ ├── CardInputLayout.java │ │ ├── CardInputView.java │ │ ├── CardNumberEdit.java │ │ ├── Cloudipsp.java │ │ ├── CloudipspView.java │ │ ├── CloudipspWebView.java │ │ ├── Currency.java │ │ ├── CvvUtils.java │ │ ├── GooglePayCall.java │ │ ├── Order.java │ │ ├── Receipt.java │ │ ├── ReceiptUtils.java │ │ └── Tls12SocketFactory.java │ └── res │ ├── layout │ └── com_cloudipsp_android_card_input_view.xml │ ├── values-ru │ └── strings.xml │ └── values │ └── strings.xml ├── maven_push.gradle └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # svn 2 | *.svn* 3 | 4 | # built application files 5 | *.apk 6 | *.ap_ 7 | 8 | # files for the dex VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # generated GUI files 15 | */R.java 16 | 17 | # generated folder 18 | bin 19 | gen 20 | 21 | # local 22 | local.properties 23 | 24 | proguard_logs/ 25 | 26 | # log files 27 | log*.txt 28 | 29 | # archives 30 | *.gz 31 | *.tar 32 | *.zip 33 | 34 | # eclipse 35 | *.metadata 36 | *.settings 37 | *.prefs 38 | 39 | #idea 40 | *.idea 41 | *.iml 42 | .idea/ 43 | out/ 44 | 45 | build/ 46 | .gradle/ 47 | .DS_Store 48 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def safeExtGet(prop, fallback) { 4 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 5 | } 6 | 7 | android { 8 | compileSdkVersion safeExtGet('compileSdkVersion', 33) 9 | buildToolsVersion safeExtGet('buildToolsVersion', '33.0.0') 10 | 11 | defaultConfig { 12 | applicationId 'com.cloudipsp.android.demo' 13 | minSdkVersion safeExtGet('minSdkVersion', 14) 14 | targetSdkVersion safeExtGet('targetSdkVersion', 33) 15 | versionCode 1 16 | versionName '1.0' 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation 'com.google.android.gms:play-services-base:18.1.0' 27 | implementation 'com.google.android.gms:play-services-wallet:19.1.0' 28 | implementation project(':library') 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 27 | 28 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/cloudipsp/android/demo/BaseExampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.cloudipsp.android.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.text.TextUtils; 7 | import android.util.Patterns; 8 | import android.view.View; 9 | import android.widget.ArrayAdapter; 10 | import android.widget.EditText; 11 | import android.widget.Spinner; 12 | import android.widget.Toast; 13 | 14 | import com.cloudipsp.android.Card; 15 | import com.cloudipsp.android.Cloudipsp; 16 | import com.cloudipsp.android.CloudipspWebView; 17 | import com.cloudipsp.android.Currency; 18 | import com.cloudipsp.android.GooglePayCall; 19 | import com.cloudipsp.android.Order; 20 | import com.cloudipsp.android.Receipt; 21 | 22 | /** 23 | * Created by vberegovoy on 6/20/17. 24 | */ 25 | 26 | abstract public class BaseExampleActivity extends Activity implements 27 | View.OnClickListener, 28 | Cloudipsp.PayCallback, 29 | Cloudipsp.GooglePayCallback { 30 | private static final int RC_GOOGLE_PAY = 100500; 31 | private static final String K_GOOGLE_PAY_CALL = "google_pay_call"; 32 | 33 | private EditText editAmount; 34 | private Spinner spinnerCcy; 35 | private EditText editEmail; 36 | private EditText editDescription; 37 | private CloudipspWebView webView; 38 | 39 | private Cloudipsp cloudipsp; 40 | private GooglePayCall googlePayCall;// <- this should be serialized on saving instance state 41 | 42 | protected abstract int getLayoutResId(); 43 | 44 | protected abstract Card getCard(); 45 | 46 | @Override 47 | protected void onCreate(Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | setContentView(getLayoutResId()); 50 | 51 | findViewById(R.id.btn_amount).setOnClickListener(this); 52 | editAmount = findViewById(R.id.edit_amount); 53 | spinnerCcy = findViewById(R.id.spinner_ccy); 54 | editEmail = findViewById(R.id.edit_email); 55 | editDescription = findViewById(R.id.edit_description); 56 | findViewById(R.id.btn_pay_card).setOnClickListener(this); 57 | findViewById(R.id.btn_pay_google).setOnClickListener(this); 58 | 59 | webView = findViewById(R.id.web_view); 60 | cloudipsp = new Cloudipsp(1396424, webView); 61 | 62 | spinnerCcy.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, Currency.values())); 63 | 64 | if (savedInstanceState != null) { 65 | googlePayCall = savedInstanceState.getParcelable(K_GOOGLE_PAY_CALL); 66 | } 67 | } 68 | 69 | @Override 70 | protected void onSaveInstanceState(Bundle outState) { 71 | super.onSaveInstanceState(outState); 72 | outState.putParcelable(K_GOOGLE_PAY_CALL, googlePayCall); 73 | } 74 | 75 | @Override 76 | public void onBackPressed() { 77 | if (webView.waitingForConfirm()) { 78 | webView.skipConfirm(); 79 | } else { 80 | super.onBackPressed(); 81 | } 82 | } 83 | 84 | @Override 85 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 86 | super.onActivityResult(requestCode, resultCode, data); 87 | 88 | switch (requestCode) { 89 | case RC_GOOGLE_PAY: 90 | if (!cloudipsp.googlePayComplete(resultCode, data, googlePayCall, this)) { 91 | Toast.makeText(this, R.string.e_google_pay_canceled, Toast.LENGTH_LONG).show(); 92 | } 93 | break; 94 | } 95 | } 96 | 97 | @Override 98 | public void onClick(View v) { 99 | switch (v.getId()) { 100 | case R.id.btn_amount: 101 | fillTest(); 102 | break; 103 | case R.id.btn_pay_card: 104 | processPayCard(); 105 | break; 106 | case R.id.btn_pay_google: 107 | processGooglePay(); 108 | break; 109 | } 110 | } 111 | 112 | private void fillTest() { 113 | editAmount.setText("1"); 114 | editEmail.setText("test@example.com"); 115 | editDescription.setText("test payment"); 116 | } 117 | 118 | private void processPayCard() { 119 | final Order order = createOrder(); 120 | if (order != null) { 121 | final Card card = getCard(); 122 | if (card != null) { 123 | cloudipsp.pay(card, order, this); 124 | } 125 | } 126 | } 127 | 128 | private void processGooglePay() { 129 | if (Cloudipsp.supportsGooglePay(this)) { 130 | final Order googlePayOrder = createOrder(); 131 | if (googlePayOrder != null) { 132 | cloudipsp.googlePayInitialize(googlePayOrder, this, RC_GOOGLE_PAY, this); 133 | } 134 | } else { 135 | Toast.makeText(this, R.string.e_google_pay_unsupported, Toast.LENGTH_LONG).show(); 136 | 137 | } 138 | } 139 | 140 | private Order createOrder() { 141 | editAmount.setError(null); 142 | editEmail.setError(null); 143 | editDescription.setError(null); 144 | 145 | final int amount; 146 | try { 147 | amount = Integer.valueOf(editAmount.getText().toString()); 148 | } catch (Exception e) { 149 | editAmount.setError(getString(R.string.e_invalid_amount)); 150 | return null; 151 | } 152 | 153 | final String email = editEmail.getText().toString(); 154 | final String description = editDescription.getText().toString(); 155 | if (TextUtils.isEmpty(email) || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) { 156 | editEmail.setError(getString(R.string.e_invalid_email)); 157 | return null; 158 | } else if (TextUtils.isEmpty(description)) { 159 | editDescription.setError(getString(R.string.e_invalid_description)); 160 | return null; 161 | } 162 | final Currency currency = (Currency) spinnerCcy.getSelectedItem(); 163 | final Order order = new Order(amount, currency, "vb_" + System.currentTimeMillis(), description, email); 164 | order.setLang(Order.Lang.ru); 165 | return order; 166 | } 167 | 168 | @Override 169 | public void onPaidProcessed(Receipt receipt) { 170 | Toast.makeText(this, "Paid " + receipt.status.name() + "\nPaymentId:" + receipt.paymentId, Toast.LENGTH_LONG).show(); 171 | } 172 | 173 | @Override 174 | public void onPaidFailure(Cloudipsp.Exception e) { 175 | if (e instanceof Cloudipsp.Exception.Failure) { 176 | Cloudipsp.Exception.Failure f = (Cloudipsp.Exception.Failure) e; 177 | 178 | Toast.makeText(this, "Failure\nErrorCode: " + 179 | f.errorCode + "\nMessage: " + f.getMessage() + "\nRequestId: " + f.requestId, Toast.LENGTH_LONG).show(); 180 | } else if (e instanceof Cloudipsp.Exception.NetworkSecurity) { 181 | Toast.makeText(this, "Network security error: " + e.getMessage(), Toast.LENGTH_LONG).show(); 182 | } else if (e instanceof Cloudipsp.Exception.ServerInternalError) { 183 | Toast.makeText(this, "Internal server error: " + e.getMessage(), Toast.LENGTH_LONG).show(); 184 | } else if (e instanceof Cloudipsp.Exception.NetworkAccess) { 185 | Toast.makeText(this, "Network error", Toast.LENGTH_LONG).show(); 186 | } else { 187 | Toast.makeText(this, "Payment Failed", Toast.LENGTH_LONG).show(); 188 | } 189 | e.printStackTrace(); 190 | } 191 | 192 | @Override 193 | public void onGooglePayInitialized(GooglePayCall result) { 194 | this.googlePayCall = result; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /app/src/main/java/com/cloudipsp/android/demo/FlexibleExampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.cloudipsp.android.demo; 2 | 3 | import android.os.Bundle; 4 | import android.util.Log; 5 | import android.widget.EditText; 6 | 7 | import com.cloudipsp.android.Card; 8 | import com.cloudipsp.android.CardInputLayout; 9 | import com.cloudipsp.android.Cloudipsp; 10 | 11 | public class FlexibleExampleActivity extends BaseExampleActivity { 12 | private EditText editCard; 13 | private EditText editExpYy; 14 | private EditText editExpMm; 15 | private EditText editCvv; 16 | private CardInputLayout cardLayout; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | 22 | editCard = findViewById(R.id.edit_card_number); 23 | editExpYy = findViewById(R.id.edit_yy); 24 | editExpMm = findViewById(R.id.edit_mm); 25 | editCvv = findViewById(R.id.edit_cvv); 26 | // ^^^ these fields used only as example for Cloudipsp.setStrictUiBlocking(false); 27 | cardLayout = findViewById(R.id.card_layout); 28 | cardLayout.setCardNumberFormatting(false); 29 | } 30 | 31 | @Override 32 | protected int getLayoutResId() { 33 | return R.layout.activity_flexible_example; 34 | } 35 | 36 | @Override 37 | protected Card getCard() { 38 | // Cloudipsp.setStrictUiBlocking(false); 39 | // Log.i("Cloudipsp", "CardNumber: " + editCard.getText()); 40 | // Log.i("Cloudipsp", "ExpYy: " + editExpYy.getText()); 41 | // Log.i("Cloudipsp", "ExpMm: " + editExpMm.getText()); 42 | // Log.i("Cloudipsp", "Cvv: " + editCvv.getText()); 43 | 44 | return cardLayout.confirm(new CardInputLayout.ConfirmationErrorHandler() { 45 | @Override 46 | public void onCardInputErrorClear(CardInputLayout view, EditText editText) { 47 | 48 | } 49 | 50 | @Override 51 | public void onCardInputErrorCatched(CardInputLayout view, EditText editText, String error) { 52 | 53 | } 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/cloudipsp/android/demo/GPay.java: -------------------------------------------------------------------------------- 1 | package com.example.myapplication; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.Toast; 9 | 10 | import androidx.annotation.Nullable; 11 | import androidx.appcompat.app.AppCompatActivity; 12 | 13 | import com.cloudipsp.android.Cloudipsp; 14 | import com.cloudipsp.android.CloudipspWebView; 15 | import com.cloudipsp.android.GooglePayCall; 16 | import com.cloudipsp.android.Order; 17 | import com.cloudipsp.android.Receipt; 18 | 19 | public class MainActivity extends AppCompatActivity implements 20 | View.OnClickListener, // Implementing OnClickListener for handling button clicks 21 | Cloudipsp.PayCallback, // Implementing Cloudipsp.PayCallback for payment callbacks 22 | Cloudipsp.GooglePayCallback { // Implementing Cloudipsp.GooglePayCallback for Google Pay callbacks 23 | 24 | private static final int RC_GOOGLE_PAY = 100500; 25 | private static final String K_GOOGLE_PAY_CALL = "google_pay_call"; 26 | private Cloudipsp cloudipsp; 27 | private GooglePayCall googlePayCall; // <- this should be serialized on saving instance state 28 | private CloudipspWebView webView; 29 | private Button googlePayButton; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_main); // Set the layout for this activity 35 | 36 | // Initialize UI elements 37 | webView = findViewById(R.id.webView); // Initialize CloudipspWebView from layout 38 | googlePayButton = findViewById(R.id.google_pay_button); // Initialize Button from layout 39 | googlePayButton.setOnClickListener(this); // Set click listener for Google Pay button 40 | 41 | // Check if Google Pay is supported and set button visibility accordingly 42 | if (Cloudipsp.supportsGooglePay(this)) { 43 | googlePayButton.setVisibility(View.VISIBLE); // Show Google Pay button 44 | } else { 45 | googlePayButton.setVisibility(View.GONE); // Hide Google Pay button if unsupported 46 | Toast.makeText(this, R.string.e_google_pay_unsupported, Toast.LENGTH_LONG).show(); // Show unsupported message 47 | } 48 | 49 | if (savedInstanceState != null) { 50 | googlePayCall = savedInstanceState.getParcelable(K_GOOGLE_PAY_CALL); 51 | } 52 | } 53 | 54 | @Override 55 | public void onBackPressed() { 56 | if (webView.waitingForConfirm()) { 57 | webView.skipConfirm(); // Skip confirmation in WebView if waiting 58 | } else { 59 | super.onBackPressed(); // Otherwise, perform default back button behavior 60 | } 61 | } 62 | 63 | 64 | @Override 65 | public void onClick(View v) { 66 | if (v.getId() == R.id.google_pay_button) { 67 | processGooglePay(); // Handle click on Google Pay button 68 | // processGooglePayWithToken(); // Handle click on Google Pay button 69 | } 70 | } 71 | 72 | private void processGooglePay() { 73 | // Initialize Cloudipsp with merchant ID and WebView 74 | cloudipsp = new Cloudipsp(0, webView); // Initialize the payment process with the merchant ID 75 | final Order googlePayOrder = createOrder(); // Create order for Google Pay payment 76 | if (googlePayOrder != null) { 77 | cloudipsp.googlePayInitialize(googlePayOrder, this, RC_GOOGLE_PAY, this); // Initialize Google Pay payment 78 | } 79 | } 80 | 81 | private void processGooglePayWithToken() { 82 | // Initialize Cloudipsp with merchant ID and WebView 83 | cloudipsp = new Cloudipsp(0, webView); // Initialize the payment process with the merchant ID 84 | cloudipsp.googlePayInitialize("321d7ebe83c2b34ce38fee59c4c845e9fef67a0b", this, RC_GOOGLE_PAY, this); // Initialize Google Pay payment 85 | } 86 | 87 | 88 | 89 | private Order createOrder() { 90 | final int amount = 100; 91 | final String email = "test@gmail.com"; 92 | final String description = "test payment"; 93 | final String currency = "GEL"; 94 | return new Order(amount, currency, "vb_" + System.currentTimeMillis(), description, email); // Create and return new payment order 95 | } 96 | 97 | @Override 98 | protected void onSaveInstanceState(Bundle outState) { 99 | super.onSaveInstanceState(outState); 100 | outState.putParcelable(K_GOOGLE_PAY_CALL, googlePayCall); 101 | } 102 | 103 | @Override 104 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 105 | super.onActivityResult(requestCode, resultCode, data); 106 | switch (requestCode) { 107 | case RC_GOOGLE_PAY: 108 | if (!cloudipsp.googlePayComplete(resultCode, data, googlePayCall, this)) { 109 | Toast.makeText(this, R.string.e_google_pay_canceled, Toast.LENGTH_LONG).show(); // Show payment canceled message 110 | } 111 | break; 112 | } 113 | } 114 | 115 | @Override 116 | public void onPaidProcessed(Receipt receipt) { 117 | Toast.makeText(this, "Paid " + receipt.status.name() + "\nPaymentId:" + receipt.paymentId, Toast.LENGTH_LONG).show(); // Show payment success message 118 | Log.d("PaymentStatus", "Paid " + receipt.status.name() + " PaymentId: " + receipt.paymentId); 119 | 120 | } 121 | 122 | @Override 123 | public void onPaidFailure(Cloudipsp.Exception e) { 124 | if (e instanceof Cloudipsp.Exception.Failure) { 125 | Cloudipsp.Exception.Failure f = (Cloudipsp.Exception.Failure) e; 126 | Toast.makeText(this, "Failure\nErrorCode: " + 127 | f.errorCode + "\nMessage: " + f.getMessage() + "\nRequestId: " + f.requestId, Toast.LENGTH_LONG).show(); // Show specific failure details 128 | } else if (e instanceof Cloudipsp.Exception.NetworkSecurity) { 129 | Toast.makeText(this, "Network security error: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Show network security error 130 | } else if (e instanceof Cloudipsp.Exception.ServerInternalError) { 131 | Toast.makeText(this, "Internal server error: " + e.getMessage(), Toast.LENGTH_LONG).show(); // Show internal server error 132 | } else if (e instanceof Cloudipsp.Exception.NetworkAccess) { 133 | Toast.makeText(this, "Network error", Toast.LENGTH_LONG).show(); // Show network access error 134 | } else { 135 | Toast.makeText(this, "Payment Failed", Toast.LENGTH_LONG).show(); // Show generic payment failure 136 | } 137 | e.printStackTrace(); // Print stack trace for debugging 138 | } 139 | 140 | @Override 141 | public void onGooglePayInitialized(GooglePayCall result) { 142 | // Handle Google Pay initialization if needed 143 | Toast.makeText(this, "Google Pay initialized", Toast.LENGTH_LONG).show(); // Show Google Pay initialization message 144 | this.googlePayCall = result; // Store Google Pay call result 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/com/cloudipsp/android/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.cloudipsp.android.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | 8 | /** 9 | * Created by vberegovoy on 6/20/17. 10 | */ 11 | 12 | public class MainActivity extends Activity { 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | } 18 | 19 | public void onSimpleExampleClicked(View view) { 20 | startActivity(new Intent(this, SimpleExampleActivity.class)); 21 | } 22 | 23 | public void onFlexibleExampleClicked(View view) { 24 | startActivity(new Intent(this, FlexibleExampleActivity.class)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/cloudipsp/android/demo/SimpleExampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.cloudipsp.android.demo; 2 | 3 | import android.os.Bundle; 4 | import android.widget.EditText; 5 | 6 | import com.cloudipsp.android.Card; 7 | import com.cloudipsp.android.CardInputView; 8 | 9 | public class SimpleExampleActivity extends BaseExampleActivity { 10 | private CardInputView cardInput; 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | 16 | cardInput = findViewById(R.id.card_input); 17 | if (BuildConfig.DEBUG) { 18 | cardInput.setHelpedNeeded(true); 19 | } 20 | } 21 | 22 | @Override 23 | protected int getLayoutResId() { 24 | return R.layout.activity_simple_example; 25 | } 26 | 27 | @Override 28 | protected Card getCard() { 29 | return cardInput.confirm(new CardInputView.ConfirmationErrorHandler() { 30 | @Override 31 | public void onCardInputErrorClear(CardInputView view, EditText editText) { 32 | 33 | } 34 | 35 | @Override 36 | public void onCardInputErrorCatched(CardInputView view, EditText editText, String error) { 37 | 38 | } 39 | }); 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudipsp/android-sdk/00c21ef23c1f217d900a9a665b60d0e54f5d7c5b/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudipsp/android-sdk/00c21ef23c1f217d900a9a665b60d0e54f5d7c5b/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudipsp/android-sdk/00c21ef23c1f217d900a9a665b60d0e54f5d7c5b/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudipsp/android-sdk/00c21ef23c1f217d900a9a665b60d0e54f5d7c5b/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_flexible_example.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | 10 | 14 | 15 | 20 | 21 | 28 | 29 | 34 | 35 | 40 | 41 | 46 | 47 | 53 | 54 | 59 | 60 | 65 | 66 | 70 | 71 | 75 | 76 | 82 | 83 | 93 | 94 | 99 | 100 | 105 | 106 | 118 | 119 | 131 | 132 | 133 | 138 | 139 | 146 | 147 | 148 | 149 | 155 | 156 | 160 | 161 |