├── .gitignore ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── msg91 │ │ └── sendotp │ │ └── sample │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── msg91 │ │ └── sendotp │ │ └── sample │ │ ├── ApplicationClass.java │ │ ├── CountrySpinner.java │ │ ├── DataManager.java │ │ ├── MainActivity.java │ │ ├── OtpEditText.java │ │ └── VerificationActivity.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── bg_spinner.xml │ ├── button_blue_generic.xml │ ├── checkmark.png │ ├── gradient_bg.xml │ ├── gradient_bg_white.xml │ ├── ic_checkmark.xml │ ├── ic_down.png │ ├── ic_launcher_background.xml │ ├── ic_magic.xml │ ├── ic_sendotp.xml │ ├── ic_sort_down.xml │ ├── ic_verify.xml │ ├── input_background.xml │ ├── inputbox.xml │ ├── inputbox_new.xml │ ├── msg91_logo.png │ ├── progress.xml │ └── rounded_corner.xml │ ├── layout │ ├── activity_main_new.xml │ ├── activity_verification.xml │ ├── custom_progress_bar.xml │ └── simple_spinner_item.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-v21 │ └── style.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── style.xml ├── build.gradle └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /app/app-release.apk 3 | /local.properties 4 | /app/build/* 5 | /gradle 6 | /app/app.iml 7 | /gradle.properties 8 | /gradlew.bat 9 | /sample.iml 10 | /sample/build/* 11 | /.gradle 12 | /.idea 13 | **/.DS_Store 14 | .okbuck/keystore 15 | /library/build/tmp 16 | /library/build/intermediates 17 | /library/build/outputs 18 | /library/build/generated 19 | /library/build/docs 20 | /library/library.iml 21 | /library/gradle.properties 22 | /build 23 | **/*.iml 24 | library/build/ 25 | /gradlew 26 | projectFilesBackup/.idea/ 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SendOTP Android Sdk! 7 | =================== 8 | ## For Androidx and Above use this library and [for older sdk 28 and blow see here](https://github.com/MSG91/sendotp-android/tree/version_1.2) 9 | **This Library Supports Androidx and older versions up to (SDK-16):** 10 | 11 | The **SendOtp** Verification SDK makes verifying phone numbers easy. SDK supports the verification of phone numbers via **SMS & Calls**. 12 | 13 | ---------- 14 | 15 | Getting started 16 | =============== 17 | 18 | Gradle 19 | ------ 20 | 21 | Just add below dependency in project's app level build.gradle file 22 | 23 | dependencies { 24 | ... 25 | implementation 'com.msg91.sendotpandroid.library:library:1.7' 26 | ... 27 | } 28 | 29 | 30 | Also, add below url in project's project level build.gradle file 31 | 32 | maven{ 33 | url "https://dl.bintray.com/walkover/Android-Libs" 34 | } 35 | 36 | 37 | 38 | Maven 39 | ------ 40 | grab via Maven: 41 | 42 | 43 | com.msg91.sendotpandroid.library 44 | library 45 | 1.7 46 | pom 47 | 48 | Ivy 49 | ------ 50 | grab via Ivy: 51 | 52 | 53 | 54 | 55 | 56 | > -Login or create account at [MSG91]([https://control.msg91.com/signup/sendotp](https://control.msg91.com/signup/sendotp)) to use sendOTP services. 57 | 58 | #### Get your authKey 59 | 60 | After login at [MSG91](https://control.msg91.com/) follow below steps to get your **authkey** 61 | 62 | 63 | 64 | 65 | > - Select **API** option available on panel. 66 | > - If you are first time user then generate new authkey. 67 | > - copy authKey & keep it enable 68 | > - DLT_TE_ID to get from Network provider 69 | 70 | #### Usage 71 | 72 | > initialize'**SendOTP**' in your Application class. 73 | 74 | public class ApplicationClass extends Application { 75 | @Override 76 | public void onCreate() { 77 | super.onCreate(); 78 | SendOTP.initializeApp(this,"authKey", "your DLT_TE_ID here"); //initialization 79 | } 80 | } 81 | 82 | > implement '**VerificationListener**' in your class & override below result callback. 83 | 84 | @Override 85 | public void onSendOtpResponse(final SendOTPResponseCode responseCode, final String message) { 86 | runOnUiThread(new Runnable() { 87 | @Override 88 | public void run() { 89 | Log.e(TAG, "onSendOtpResponse: " + responseCode.getCode() + "=======" + message); 90 | if (responseCode == SendOTPResponseCode.DIRECT_VERIFICATION_SUCCESSFUL_FOR_NUMBER || responseCode == SendOTPResponseCode.OTP_VERIFIED) { 91 | //otp verified OR direct verified by send otp 2.O 92 | } else if (responseCode == SendOTPResponseCode.READ_OTP_SUCCESS) { 93 | //Auto read otp from sms successfully 94 | // you can get otp form message filled 95 | } else if (responseCode == SendOTPResponseCode.SMS_SUCCESSFUL_SEND_TO_NUMBER || responseCode == SendOTPResponseCode.DIRECT_VERIFICATION_FAILED_SMS_SUCCESSFUL_SEND_TO_NUMBER) 96 | { 97 | // Otp send to number successfully 98 | } else { 99 | //exception found 100 | } 101 | } 102 | }); 103 | } 104 | 105 | Build Your requirements by initialize builder with pass country code and mobile number. 106 | Optional Parameters are gose in blow method. 107 | 108 | new SendOTPConfigBuilder() 109 | .setCountryCode(countryCode) 110 | .setMobileNumber(phoneNumber) 111 | .setVerifyWithoutOtp(true)//direct verification while connect with mobile network 112 | .setAutoVerification(VerificationActivity.this)//Auto read otp from Sms And Verify 113 | .setSenderId("ABCDEF") 114 | .setMessage("##OTP## is Your verification digits.") 115 | .setOtpLength(OTP_LNGTH) 116 | .setVerificationCallBack(this).build(); 117 | 118 | 119 | **Sending OTP / StartVerification** to Number by using above configuration. 120 | 121 | SendOTP.getInstance().getTrigger().initiate(); 122 | 123 | manually **verifying OTP** 124 | 125 | SendOTP.getInstance().getTrigger().verify(otp); 126 | **resend OTP** by voice or text . 127 | 128 | SendOTP.getInstance().getTrigger().resend(RetryType.VOICE); 129 | **OR** 130 | 131 | 132 | SendOTP.getInstance().getTrigger().resend(RetryType.TEXT); 133 | 134 | **onDestroy** 135 | 136 | @Override 137 | protected void onDestroy() { 138 | super.onDestroy(); 139 | SendOTP.getInstance().getTrigger().stop(); 140 | } 141 | 142 | 143 | 144 | **customize message text** : 145 | 146 | ##OTP## is use for default OTP genrated from sdk 147 | 148 | .message("##OTP## is Your verification digits.") 149 | **OR** 150 | genrate your otp and set in parameter 151 | 152 | String OTP = "1234"; 153 | 154 | and use blow method 155 | 156 | .otp(OTP ) 157 | .message(OTP +" is Your verification digits.") 158 | 159 | **Unicode** : To show unicode sms set true in unicode parameter. 160 | 161 | .unicode(true) 162 | 163 | **Quick integration video [here it is](https://www.youtube.com/watch?v=LSHhzTuj2gM)** 164 | 165 | Optional Parameters 166 | ------ 167 | > - **setMessage**("##OTP## with your Custom OTP message.") [for custom OTP message] 168 | >- **setOtpExpireInMinute**(5) [long param ,default value is one day] 169 | >- **setSenderId**("SENDOTP") 170 | >- **setOtp**("1234") [use your OTP code] 171 | >- **setOtpLength**("4") [custom OTP length] 172 | >- **setUnicodeEnable**(false) [use unicode (or other languages)] 173 | >- **setVerifyWithoutOtp** (true) [direct verification while connect with mobile network] 174 | >- **setOtpHits** (5) [number of otp request per number] 175 | >- **setOtpHitsTimeOut** (0L) [number of otp request time out reset in milliseconds default is 24 hours] 176 | >- **setAutoVerification** (ActivityContext_here) [number of otp request per number] 177 | > 178 | 179 | 180 | License 181 | ======= 182 | 183 | Copyright 2020 MSG91 184 | 185 | Licensed under the Apache License, Version 2.0 (the "License"); 186 | you may not use this file except in compliance with the License. 187 | You may obtain a copy of the License at 188 | 189 | http://www.apache.org/licenses/LICENSE-2.0 190 | 191 | Unless required by applicable law or agreed to in writing, software 192 | distributed under the License is distributed on an "AS IS" BASIS, 193 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 194 | See the License for the specific language governing permissions and 195 | limitations under the License. 196 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 30 5 | buildToolsVersion "29.0.3" 6 | defaultConfig { 7 | multiDexEnabled true 8 | applicationId "com.msg91.sendotp.sample" 9 | minSdkVersion 16 10 | targetSdkVersion 30 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled true 18 | shrinkResources true 19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation fileTree(dir: 'libs', include: ['*.jar']) 26 | implementation 'androidx.appcompat:appcompat:1.1.0' 27 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 28 | implementation 'com.google.android.material:material:1.1.0' 29 | testImplementation 'junit:junit:4.12' 30 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 31 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 32 | implementation 'com.msg91.sendotpandroid.library:library:1.7' 33 | implementation 'com.android.support:multidex:1.0.3' 34 | } 35 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/rakshitsoni/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/msg91/sendotp/sample/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.msg91.sendotp.sample; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/msg91/sendotp/sample/ApplicationClass.java: -------------------------------------------------------------------------------- 1 | package com.msg91.sendotp.sample; 2 | 3 | import android.app.Application; 4 | 5 | import com.msg91.sendotpandroid.library.internal.SendOTP; 6 | 7 | public class ApplicationClass extends Application { 8 | @Override 9 | public void onCreate() { 10 | super.onCreate(); 11 | SendOTP.initializeApp(this,"authKey", "DLT_TE_ID"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/msg91/sendotp/sample/CountrySpinner.java: -------------------------------------------------------------------------------- 1 | package com.msg91.sendotp.sample; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | import android.widget.AdapterView; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.TextView; 9 | 10 | import androidx.appcompat.widget.AppCompatSpinner; 11 | import androidx.core.content.ContextCompat; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Locale; 16 | import java.util.Map; 17 | import java.util.TreeMap; 18 | 19 | public class CountrySpinner extends AppCompatSpinner { 20 | private Map mCountries = new TreeMap<>(); 21 | private List mListeners = new ArrayList<>(); 22 | 23 | public CountrySpinner(Context context) { 24 | super(context); 25 | } 26 | 27 | public CountrySpinner(Context context, AttributeSet attrs) { 28 | super(context, attrs); 29 | } 30 | 31 | public void init(String defaultCountry) { 32 | initCountries(); 33 | 34 | List countryList = new ArrayList<>(mCountries.keySet()); 35 | countryList.remove(defaultCountry); 36 | countryList.add(0, defaultCountry); 37 | 38 | ArrayAdapter adapter = new ArrayAdapter<>(getContext(), R.layout.simple_spinner_item, countryList); 39 | 40 | setAdapter(adapter); 41 | 42 | setOnItemSelectedListener(new OnItemSelectedListener() { 43 | @Override 44 | public void onItemSelected(AdapterView adapterView, View view, int position, long id) { 45 | final String selectedCountry = (String) adapterView.getItemAtPosition(position); 46 | TextView textView = (TextView) view; 47 | textView.setTextColor(ContextCompat.getColor(getContext(), R.color.white)); 48 | notifyListeners(selectedCountry); 49 | } 50 | 51 | @Override 52 | public void onNothingSelected(AdapterView adapterView) { 53 | } 54 | }); 55 | } 56 | 57 | public void addCountryIsoSelectedListener(CountryIsoSelectedListener listener) { 58 | mListeners.add(listener); 59 | } 60 | 61 | private void initCountries() { 62 | String[] isoCountryCodes = Locale.getISOCountries(); 63 | for (String iso : isoCountryCodes) { 64 | String country = new Locale("", iso).getDisplayCountry(); 65 | mCountries.put(country, iso); 66 | } 67 | } 68 | 69 | private void notifyListeners(String selectedCountry) { 70 | final String selectedIso = mCountries.get(selectedCountry); 71 | for (CountryIsoSelectedListener listener : mListeners) { 72 | listener.onCountryIsoSelected(selectedIso); 73 | } 74 | } 75 | 76 | public interface CountryIsoSelectedListener { 77 | void onCountryIsoSelected(String iso); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/msg91/sendotp/sample/DataManager.java: -------------------------------------------------------------------------------- 1 | package com.msg91.sendotp.sample; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.text.Html; 7 | import android.view.View; 8 | import android.view.WindowManager; 9 | import android.widget.TextView; 10 | 11 | public class DataManager { 12 | private static final DataManager ourInstance = new DataManager(); 13 | private boolean isProgressDialogRunning; 14 | private Dialog mDialog; 15 | 16 | private DataManager() { 17 | } 18 | 19 | public static DataManager getInstance() { 20 | return ourInstance; 21 | } 22 | 23 | public void hideProgressMessage() { 24 | isProgressDialogRunning = true; 25 | try { 26 | if (mDialog != null) 27 | mDialog.dismiss(); 28 | } catch (Exception ex) { 29 | ex.printStackTrace(); 30 | } 31 | } 32 | 33 | public void showProgressMessage(Context dialogActivity, String msg) { 34 | try { 35 | if (isProgressDialogRunning) { 36 | hideProgressMessage(); 37 | } 38 | isProgressDialogRunning = true; 39 | mDialog = new Dialog(dialogActivity, R.style.MyMaterialTheme); 40 | mDialog.setContentView(R.layout.custom_progress_bar); 41 | // mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(dialogActivity,R.color.white_trance))); 42 | mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT)); 43 | TextView textView = mDialog.findViewById(R.id.loadingText); 44 | textView.setVisibility(View.VISIBLE); 45 | if (msg != null) 46 | textView.setText(Html.fromHtml(msg)); 47 | else textView.setVisibility(View.GONE); 48 | WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); 49 | lp.dimAmount = 0.8f; 50 | mDialog.getWindow().setAttributes(lp); 51 | mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); 52 | mDialog.setCancelable(false); 53 | mDialog.setCanceledOnTouchOutside(false); 54 | mDialog.show(); 55 | } catch (Exception ex) { 56 | ex.printStackTrace(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/msg91/sendotp/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.msg91.sendotp.sample; 2 | 3 | import android.Manifest; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.graphics.Color; 8 | import android.os.Bundle; 9 | import android.telephony.TelephonyManager; 10 | import android.text.Editable; 11 | import android.text.TextWatcher; 12 | import android.view.View; 13 | import android.widget.EditText; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import androidx.appcompat.app.AppCompatActivity; 18 | import androidx.core.app.ActivityCompat; 19 | 20 | import com.msg91.sendotpandroid.library.internal.Iso2Phone; 21 | import com.msg91.sendotpandroid.library.utils.PhoneNumberFormattingTextWatcher; 22 | import com.msg91.sendotpandroid.library.utils.PhoneNumberUtils; 23 | 24 | import java.util.Locale; 25 | 26 | public class MainActivity extends AppCompatActivity { 27 | 28 | public static final String INTENT_PHONENUMBER = "phonenumber"; 29 | public static final String INTENT_COUNTRY_CODE = "code"; 30 | 31 | private EditText mPhoneNumber; 32 | private TextView mSmsButton; 33 | private String mCountryIso; 34 | private TextWatcher mNumberTextWatcher; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | 40 | setContentView(R.layout.activity_main_new); 41 | mPhoneNumber = findViewById(R.id.phoneNumber); 42 | mSmsButton = findViewById(R.id.smsVerificationButton); 43 | 44 | mCountryIso = PhoneNumberUtils.getDefaultCountryIso(this); 45 | final String defaultCountryName = new Locale("", mCountryIso).getDisplayName(); 46 | final CountrySpinner spinner = (CountrySpinner) findViewById(R.id.spinner); 47 | spinner.init(defaultCountryName); 48 | spinner.addCountryIsoSelectedListener(new CountrySpinner.CountryIsoSelectedListener() { 49 | @Override 50 | public void onCountryIsoSelected(String selectedIso) { 51 | if (selectedIso != null) { 52 | mCountryIso = selectedIso; 53 | resetNumberTextWatcher(mCountryIso); 54 | // force update: 55 | mNumberTextWatcher.afterTextChanged(mPhoneNumber.getText()); 56 | } 57 | } 58 | }); 59 | resetNumberTextWatcher(mCountryIso); 60 | 61 | tryAndPrefillPhoneNumber(); 62 | } 63 | 64 | private void tryAndPrefillPhoneNumber() { 65 | if (checkCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { 66 | TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 67 | mPhoneNumber.setText(manager.getLine1Number()); 68 | } else { 69 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 0); 70 | } 71 | } 72 | 73 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 74 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 75 | tryAndPrefillPhoneNumber(); 76 | } else { 77 | if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) { 78 | Toast.makeText(this, "This application needs permission to read your phone number to automatically " 79 | + "pre-fill it", Toast.LENGTH_LONG).show(); 80 | } 81 | } 82 | } 83 | 84 | private void openActivity(String phoneNumber) { 85 | Intent verification = new Intent(this, VerificationActivity.class); 86 | verification.putExtra(INTENT_PHONENUMBER, phoneNumber); 87 | verification.putExtra(INTENT_COUNTRY_CODE, Iso2Phone.getPhone(mCountryIso)); 88 | startActivity(verification); 89 | } 90 | 91 | private void setButtonsEnabled(boolean enabled) { 92 | mSmsButton.setEnabled(enabled); 93 | } 94 | 95 | public void onButtonClicked(View view) { 96 | openActivity(getE164Number()); 97 | } 98 | 99 | private void resetNumberTextWatcher(String countryIso) { 100 | 101 | if (mNumberTextWatcher != null) { 102 | mPhoneNumber.removeTextChangedListener(mNumberTextWatcher); 103 | } 104 | 105 | mNumberTextWatcher = new PhoneNumberFormattingTextWatcher(countryIso) { 106 | @Override 107 | public void onTextChanged(CharSequence s, int start, int before, int count) { 108 | super.onTextChanged(s, start, before, count); 109 | } 110 | 111 | @Override 112 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 113 | super.beforeTextChanged(s, start, count, after); 114 | } 115 | 116 | @Override 117 | public synchronized void afterTextChanged(Editable s) { 118 | super.afterTextChanged(s); 119 | if (isPossiblePhoneNumber()) { 120 | setButtonsEnabled(true); 121 | mPhoneNumber.setTextColor(Color.WHITE); 122 | } else { 123 | setButtonsEnabled(false); 124 | mPhoneNumber.setTextColor(Color.RED); 125 | } 126 | } 127 | }; 128 | 129 | mPhoneNumber.addTextChangedListener(mNumberTextWatcher); 130 | } 131 | 132 | private boolean isPossiblePhoneNumber() { 133 | return PhoneNumberUtils.isPossibleNumber(mPhoneNumber.getText().toString(), mCountryIso); 134 | } 135 | 136 | private String getE164Number() { 137 | return mPhoneNumber.getText().toString().replaceAll("\\D", "").trim(); 138 | // return PhoneNumberUtils.formatNumberToE164(mPhoneNumber.getText().toString(), mCountryIso); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/msg91/sendotp/sample/OtpEditText.java: -------------------------------------------------------------------------------- 1 | package com.msg91.sendotp.sample; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.text.Editable; 8 | import android.util.AttributeSet; 9 | import android.view.ActionMode; 10 | import android.view.View; 11 | 12 | import androidx.appcompat.widget.AppCompatEditText; 13 | 14 | public class OtpEditText extends AppCompatEditText { 15 | private float mSpace = 10; //24 dp by default, space between the lines 16 | private float mNumChars = 4; 17 | private float mLineSpacing = 4; //8dp by default, height of the text from our lines 18 | 19 | public int getMaxLength() { 20 | return mMaxLength; 21 | } 22 | 23 | public void setMaxLength(int maxLength) { 24 | mNumChars = mMaxLength = maxLength; 25 | if(canvas!=null) 26 | drawMethod(canvas); 27 | } 28 | 29 | public int mMaxLength = 4; 30 | private float mLineStroke = 2; 31 | private Paint mLinesPaint; 32 | private OnClickListener mClickListener; 33 | private Canvas canvas; 34 | 35 | public OtpEditText(Context context) { 36 | super(context); 37 | } 38 | 39 | public OtpEditText(Context context, AttributeSet attrs) { 40 | super(context, attrs); 41 | init(context, attrs); 42 | } 43 | 44 | public OtpEditText(Context context, AttributeSet attrs, int defStyleAttr) { 45 | super(context, attrs, defStyleAttr); 46 | init(context, attrs); 47 | } 48 | 49 | private void init(Context context, AttributeSet attrs) { 50 | float multi = context.getResources().getDisplayMetrics().density; 51 | mLineStroke = multi * mLineStroke; 52 | mLinesPaint = new Paint(getPaint()); 53 | mLinesPaint.setStrokeWidth(mLineStroke); 54 | mLinesPaint.setColor(getResources().getColor(R.color.white)); 55 | setBackgroundResource(0); 56 | mSpace = multi * mSpace; //convert to pixels for our density 57 | mLineSpacing = multi * mLineSpacing; //convert to pixels for our density 58 | mNumChars = mMaxLength; 59 | 60 | super.setOnClickListener(new OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | // When tapped, move cursor to end of text. 64 | setSelection(getText().length()); 65 | if (mClickListener != null) { 66 | mClickListener.onClick(v); 67 | } 68 | } 69 | }); 70 | } 71 | 72 | @Override 73 | public void setOnClickListener(OnClickListener l) { 74 | mClickListener = l; 75 | } 76 | 77 | @Override 78 | public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) { 79 | throw new RuntimeException("setCustomSelectionActionModeCallback() not supported."); 80 | } 81 | 82 | @Override 83 | protected void onDraw(Canvas canvas) { 84 | this.canvas = canvas; 85 | drawMethod(canvas); 86 | } 87 | 88 | private void drawMethod(Canvas canvas) { 89 | int availableWidth = getWidth() - getPaddingRight() - getPaddingLeft(); 90 | float mCharSize; 91 | if (mSpace < 0) { 92 | mCharSize = (availableWidth / (mNumChars * 2 - 1)); 93 | } else { 94 | mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars; 95 | } 96 | 97 | int startX = getPaddingLeft(); 98 | int bottom = getHeight() - getPaddingBottom(); 99 | 100 | //Text Width 101 | Editable text = getText(); 102 | int textLength = text.length(); 103 | float[] textWidths = new float[textLength]; 104 | getPaint().getTextWidths(getText(), 0, textLength, textWidths); 105 | getPaint().setColor(Color.parseColor("#FFFFFF")); // Here we are set text color. 106 | for (int i = 0; i < mNumChars; i++) { 107 | canvas.drawLine(startX, bottom, startX + mCharSize, bottom, mLinesPaint); 108 | if (getText().length() > i) { 109 | float middle = startX + mCharSize / 2; 110 | canvas.drawText(text, i, i + 1, middle - textWidths[0] / 2, bottom - mLineSpacing, getPaint()); 111 | } 112 | if (mSpace < 0) { 113 | startX += mCharSize * 2; 114 | } else { 115 | startX += mCharSize + mSpace; 116 | } 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /app/src/main/java/com/msg91/sendotp/sample/VerificationActivity.java: -------------------------------------------------------------------------------- 1 | package com.msg91.sendotp.sample; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.os.CountDownTimer; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.view.inputmethod.InputMethodManager; 10 | import android.widget.ImageView; 11 | import android.widget.ProgressBar; 12 | import android.widget.RelativeLayout; 13 | import android.widget.TextView; 14 | 15 | import androidx.appcompat.app.AppCompatActivity; 16 | import androidx.core.app.ActivityCompat; 17 | import androidx.core.content.ContextCompat; 18 | 19 | import com.msg91.sendotpandroid.library.internal.SendOTP; 20 | import com.msg91.sendotpandroid.library.listners.VerificationListener; 21 | import com.msg91.sendotpandroid.library.roots.RetryType; 22 | import com.msg91.sendotpandroid.library.roots.SendOTPConfigBuilder; 23 | import com.msg91.sendotpandroid.library.roots.SendOTPResponseCode; 24 | 25 | 26 | public class VerificationActivity extends AppCompatActivity implements 27 | ActivityCompat.OnRequestPermissionsResultCallback, VerificationListener { 28 | private static final String TAG = "VerificationActivity"; 29 | private static final int OTP_LNGTH = 4; 30 | TextView resend_timer; 31 | private OtpEditText mOtpEditText; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | 36 | 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_verification); 39 | resend_timer = (TextView) findViewById(R.id.resend_timer); 40 | resend_timer.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | ResendCode(); 44 | } 45 | }); 46 | startTimer(); 47 | mOtpEditText = findViewById(R.id.inputCode); 48 | mOtpEditText.setMaxLength(OTP_LNGTH); 49 | enableInputField(true); 50 | initiateVerification(); 51 | } 52 | 53 | void createVerification(String phoneNumber, int countryCode) { 54 | new SendOTPConfigBuilder() 55 | .setCountryCode(countryCode) 56 | .setMobileNumber(phoneNumber) 57 | //////////////////direct verification while connect with mobile network///////////////////////// 58 | .setVerifyWithoutOtp(true) 59 | //////////////////Auto read otp from Sms And Verify/////////////////////////// 60 | .setAutoVerification(VerificationActivity.this) 61 | .setOtpExpireInMinute(5)//default value is one day 62 | .setOtpHits(3) //number of otp request per number 63 | .setOtpHitsTimeOut(0L)//number of otp request time out reset in milliseconds default is 24 hours 64 | .setSenderId("ABCDEF") 65 | .setMessage("##OTP## is Your verification digits.") 66 | .setOtpLength(OTP_LNGTH) 67 | .setVerificationCallBack(this).build(); 68 | 69 | SendOTP.getInstance().getTrigger().initiate(); 70 | 71 | 72 | } 73 | 74 | 75 | void initiateVerification() { 76 | Intent intent = getIntent(); 77 | if (intent != null) { 78 | DataManager.getInstance().showProgressMessage(this, ""); 79 | String phoneNumber = intent.getStringExtra(MainActivity.INTENT_PHONENUMBER); 80 | int countryCode = intent.getIntExtra(MainActivity.INTENT_COUNTRY_CODE, 0); 81 | TextView phoneText = (TextView) findViewById(R.id.numberText); 82 | phoneText.setText("+" + countryCode + phoneNumber); 83 | createVerification(phoneNumber, countryCode); 84 | } 85 | } 86 | 87 | public void ResendCode() { 88 | startTimer(); 89 | SendOTP.getInstance().getTrigger().resend(RetryType.VOICE); 90 | } 91 | 92 | public void onSubmitClicked(View view) { 93 | String code = mOtpEditText.getText().toString(); 94 | if (!code.isEmpty()) { 95 | hideKeypad(); 96 | verifyOtp(code); 97 | DataManager.getInstance().showProgressMessage(this, ""); 98 | TextView messageText = (TextView) findViewById(R.id.textView); 99 | messageText.setText("Verification in progress"); 100 | enableInputField(false); 101 | 102 | } 103 | 104 | } 105 | 106 | 107 | void enableInputField(final boolean enable) { 108 | runOnUiThread(new Runnable() { 109 | @Override 110 | public void run() { 111 | View container = findViewById(R.id.inputContainer); 112 | if (enable) { 113 | container.setVisibility(View.VISIBLE); 114 | mOtpEditText.requestFocus(); 115 | } else { 116 | container.setVisibility(View.GONE); 117 | } 118 | TextView resend_timer = (TextView) findViewById(R.id.resend_timer); 119 | resend_timer.setClickable(false); 120 | } 121 | }); 122 | 123 | } 124 | 125 | void hideProgressBarAndShowMessage(int message) { 126 | hideProgressBar(); 127 | TextView messageText = (TextView) findViewById(R.id.textView); 128 | messageText.setText(message); 129 | } 130 | 131 | void hideProgressBar() { 132 | ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressIndicator); 133 | progressBar.setVisibility(View.INVISIBLE); 134 | TextView progressText = (TextView) findViewById(R.id.progressText); 135 | progressText.setVisibility(View.INVISIBLE); 136 | } 137 | 138 | void showProgress() { 139 | ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressIndicator); 140 | progressBar.setVisibility(View.VISIBLE); 141 | } 142 | 143 | void showCompleted(boolean isDirect) { 144 | ImageView checkMark = (ImageView) findViewById(R.id.checkmarkImage); 145 | if (isDirect) { 146 | checkMark.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_magic)); 147 | } else { 148 | checkMark.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_checkmark)); 149 | } 150 | checkMark.setVisibility(View.VISIBLE); 151 | } 152 | 153 | public void verifyOtp(String otp) { 154 | SendOTP.getInstance().getTrigger().verify(otp); 155 | } 156 | 157 | 158 | @Override 159 | public void onSendOtpResponse(final SendOTPResponseCode responseCode, final String message) { 160 | runOnUiThread(new Runnable() { 161 | @Override 162 | public void run() { 163 | Log.e(TAG, "onSendOtpResponse: " + responseCode.getCode() + "=======" + message); 164 | if (responseCode == SendOTPResponseCode.DIRECT_VERIFICATION_SUCCESSFUL_FOR_NUMBER || responseCode == SendOTPResponseCode.OTP_VERIFIED) { 165 | DataManager.getInstance().hideProgressMessage(); 166 | enableInputField(false); 167 | hideKeypad(); 168 | TextView textView2 = (TextView) findViewById(R.id.textView2); 169 | TextView textView1 = (TextView) findViewById(R.id.textView1); 170 | TextView messageText = (TextView) findViewById(R.id.textView); 171 | ImageView topImg = (ImageView) findViewById(R.id.topImg); 172 | TextView phoneText = (TextView) findViewById(R.id.numberText); 173 | RelativeLayout topLayout = findViewById(R.id.topLayout); 174 | if (android.os.Build.VERSION.SDK_INT > 16) 175 | topLayout.setBackgroundDrawable(ContextCompat.getDrawable(VerificationActivity.this, R.drawable.gradient_bg_white)); 176 | else 177 | topLayout.setBackgroundResource(R.drawable.gradient_bg_white); 178 | messageText.setVisibility(View.GONE); 179 | phoneText.setVisibility(View.GONE); 180 | topImg.setVisibility(View.INVISIBLE); 181 | textView1.setVisibility(View.VISIBLE); 182 | textView2.setVisibility(View.VISIBLE); 183 | if (responseCode == SendOTPResponseCode.DIRECT_VERIFICATION_SUCCESSFUL_FOR_NUMBER) 184 | textView2.setText("Mobile verified using Invisible OTP."); 185 | else textView2.setText("Your Mobile number has been successfully verified."); 186 | 187 | hideProgressBarAndShowMessage(R.string.verified); 188 | showCompleted(responseCode == SendOTPResponseCode.DIRECT_VERIFICATION_SUCCESSFUL_FOR_NUMBER); 189 | } else if (responseCode == SendOTPResponseCode.READ_OTP_SUCCESS) { 190 | DataManager.getInstance().hideProgressMessage(); 191 | mOtpEditText.setText(message); 192 | 193 | } else if (responseCode == SendOTPResponseCode.SMS_SUCCESSFUL_SEND_TO_NUMBER || responseCode == SendOTPResponseCode.DIRECT_VERIFICATION_FAILED_SMS_SUCCESSFUL_SEND_TO_NUMBER) { 194 | DataManager.getInstance().hideProgressMessage(); 195 | } else if (responseCode == SendOTPResponseCode.NO_INTERNET_CONNECTED) { 196 | DataManager.getInstance().hideProgressMessage(); 197 | } else { 198 | DataManager.getInstance().hideProgressMessage(); 199 | hideKeypad(); 200 | hideProgressBarAndShowMessage(R.string.failed); 201 | enableInputField(true); 202 | } 203 | } 204 | }); 205 | } 206 | 207 | private void startTimer() { 208 | resend_timer.setClickable(false); 209 | resend_timer.setTextColor(ContextCompat.getColor(VerificationActivity.this, R.color.white)); 210 | new CountDownTimer(30000, 1000) { 211 | int secondsLeft = 0; 212 | 213 | public void onTick(long ms) { 214 | if (Math.round((float) ms / 1000.0f) != secondsLeft) { 215 | secondsLeft = Math.round((float) ms / 1000.0f); 216 | resend_timer.setText("Resend via call ( " + secondsLeft + " )"); 217 | } 218 | } 219 | 220 | public void onFinish() { 221 | resend_timer.setClickable(true); 222 | resend_timer.setText("Resend via call"); 223 | resend_timer.setTextColor(ContextCompat.getColor(VerificationActivity.this, R.color.white)); 224 | } 225 | }.start(); 226 | } 227 | 228 | private void hideKeypad() { 229 | View view = getCurrentFocus(); 230 | if (view != null) { 231 | InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 232 | imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 233 | } 234 | } 235 | 236 | @Override 237 | protected void onDestroy() { 238 | super.onDestroy(); 239 | SendOTP.getInstance().getTrigger().stop(); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 9 | 16 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 43 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_spinner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_blue_generic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSG91/sendotp-android/4640e54dafabe3e768457a0624fc24b9ed5a514b/app/src/main/res/drawable/checkmark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gradient_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gradient_bg_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_checkmark.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSG91/sendotp-android/4640e54dafabe3e768457a0624fc24b9ed5a514b/app/src/main/res/drawable/ic_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_magic.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 57 | 60 | 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sendotp.xml: -------------------------------------------------------------------------------- 1 | 7 | 14 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 34 | 41 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_verify.xml: -------------------------------------------------------------------------------- 1 | 7 | 14 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 37 | 42 | 47 | 52 | 55 | 58 | 61 | 64 | 69 | 76 | 77 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/input_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/inputbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/inputbox_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/msg91_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MSG91/sendotp-android/4640e54dafabe3e768457a0624fc24b9ed5a514b/app/src/main/res/drawable/msg91_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded_corner.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_new.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | 21 | 26 | 27 | 34 | 35 | 36 | 43 | 44 | 51 | 52 | 53 | 66 | 67 | 68 | 69 | 70 | 78 | 79 | 93 | 94 | 95 | 96 | 105 | 106 |