diff --git a/.idea/misc.xml b/.idea/misc.xml index 6992e56..42d4ab2 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ diff --git a/app/build.gradle b/app/build.gradle index 2ba692a..e219cf5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { defaultConfig { applicationId "com.vernu.sms" - minSdk 21 + minSdk 24 targetSdk 32 versionCode 1 versionName "1.0" @@ -45,4 +45,5 @@ dependencies { implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.journeyapps:zxing-android-embedded:4.1.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8d1fcf8..c9cfaa5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -9,7 +10,8 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.SMSGateway"> + android:theme="@style/Theme.SMSGateway" + android:usesCleartextTraffic="true" > + \ No newline at end of file diff --git a/app/src/main/java/com/vernu/sms/GatewayApiService.java b/app/src/main/java/com/vernu/sms/GatewayApiService.java deleted file mode 100644 index 8d6be14..0000000 --- a/app/src/main/java/com/vernu/sms/GatewayApiService.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.vernu.sms; - -import com.vernu.sms.dtos.UpdateDeviceInputDTO; -import com.vernu.sms.dtos.UpdateDeviceResponseDTO; - -import retrofit2.Call; -import retrofit2.http.Body; -import retrofit2.http.PATCH; -import retrofit2.http.Path; - -public interface GatewayApiService { - @PATCH("gateway/devices/{deviceId}") - Call updateDevice(@Path("deviceId") String deviceId, @Body() UpdateDeviceInputDTO body); -} \ No newline at end of file diff --git a/app/src/main/java/com/vernu/sms/activities/MainActivity.java b/app/src/main/java/com/vernu/sms/activities/MainActivity.java index 4189d57..124638e 100644 --- a/app/src/main/java/com/vernu/sms/activities/MainActivity.java +++ b/app/src/main/java/com/vernu/sms/activities/MainActivity.java @@ -1,12 +1,14 @@ package com.vernu.sms.activities; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; @@ -22,10 +24,12 @@ import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.android.material.snackbar.Snackbar; import com.google.firebase.messaging.FirebaseMessaging; -import com.vernu.sms.GatewayApiService; +import com.google.zxing.integration.android.IntentIntegrator; +import com.google.zxing.integration.android.IntentResult; +import com.vernu.sms.services.GatewayApiService; import com.vernu.sms.R; -import com.vernu.sms.dtos.UpdateDeviceInputDTO; -import com.vernu.sms.dtos.UpdateDeviceResponseDTO; +import com.vernu.sms.dtos.RegisterDeviceInputDTO; +import com.vernu.sms.dtos.RegisterDeviceResponseDTO; import com.vernu.sms.helpers.SharedPreferenceHelper; import retrofit2.Call; @@ -41,28 +45,38 @@ public class MainActivity extends AppCompatActivity { private GatewayApiService gatewayApiService; private Switch gatewaySwitch; - private EditText gatewayKeyEditText, fcmTokenEditText; - private Button updateKeyButton, grantSMSPermissionBtn; + private EditText apiKeyEditText, fcmTokenEditText; + private Button registerDeviceBtn, grantSMSPermissionBtn, scanQRBtn; private static final int SEND_SMS_PERMISSION_REQUEST_CODE = 0; + private static final int SCAN_QR_REQUEST_CODE = 49374; + + private static final String API_BASE_URL = "https://vernu-sms.herokuapp.com/api/v1/"; + + private String deviceId = null; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = getApplicationContext(); + retrofit = new Retrofit.Builder() - .baseUrl("https://vernu-sms.herokuapp.com/api/v1/") + .baseUrl(API_BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); gatewayApiService = retrofit.create(GatewayApiService.class); + deviceId = SharedPreferenceHelper.getSharedPreferenceString(mContext, "DEVICE_ID", ""); + setContentView(R.layout.activity_main); gatewaySwitch = findViewById(R.id.gatewaySwitch); - gatewayKeyEditText = findViewById(R.id.gatewayKeyEditText); + apiKeyEditText = findViewById(R.id.apiKeyEditText); fcmTokenEditText = findViewById(R.id.fcmTokenEditText); - updateKeyButton = findViewById(R.id.updateKeyButton); + registerDeviceBtn = findViewById(R.id.registerDeviceBtn); grantSMSPermissionBtn = findViewById(R.id.grantSMSPermissionBtn); + scanQRBtn = findViewById(R.id.scanQRButton); if (isSMSPermissionGranted(mContext)) { grantSMSPermissionBtn.setEnabled(false); @@ -77,7 +91,7 @@ public class MainActivity extends AppCompatActivity { } - gatewayKeyEditText.setText(SharedPreferenceHelper.getSharedPreferenceString(mContext, "GATEWAY_KEY", "")); + apiKeyEditText.setText(SharedPreferenceHelper.getSharedPreferenceString(mContext, "API_KEY", "")); gatewaySwitch.setChecked(SharedPreferenceHelper.getSharedPreferenceBoolean(mContext, "GATEWAY_ENABLED", false)); gatewaySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @@ -85,16 +99,16 @@ public class MainActivity extends AppCompatActivity { public void onCheckedChanged(CompoundButton compoundButton, boolean isCheked) { View view = compoundButton.getRootView(); compoundButton.setEnabled(false); - String key = gatewayKeyEditText.getText().toString(); + String key = apiKeyEditText.getText().toString(); - UpdateDeviceInputDTO updateDeviceInput = new UpdateDeviceInputDTO(); - updateDeviceInput.setEnabled(isCheked); + RegisterDeviceInputDTO registerDeviceInput = new RegisterDeviceInputDTO(); + registerDeviceInput.setEnabled(isCheked); - Call apiCall = gatewayApiService.updateDevice(key, updateDeviceInput); - apiCall.enqueue(new Callback() { + Call apiCall = gatewayApiService.updateDevice(deviceId, key, registerDeviceInput); + apiCall.enqueue(new Callback() { @Override - public void onResponse(Call call, Response response) { + public void onResponse(Call call, Response response) { if (response.isSuccessful()) { SharedPreferenceHelper.setSharedPreferenceBoolean(mContext, "GATEWAY_ENABLED", isCheked); @@ -108,7 +122,7 @@ public class MainActivity extends AppCompatActivity { } @Override - public void onFailure(Call call, Throwable t) { + public void onFailure(Call call, Throwable t) { Snackbar.make(view, "An error occured :(", Snackbar.LENGTH_LONG).show(); compoundButton.setEnabled(true); @@ -119,65 +133,21 @@ public class MainActivity extends AppCompatActivity { } }); - updateKeyButton.setOnClickListener(new View.OnClickListener() { + registerDeviceBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - String newKey = gatewayKeyEditText.getText().toString(); - updateKeyButton.setEnabled(false); - updateKeyButton.setText("Loading..."); - - FirebaseMessaging.getInstance().getToken() - .addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (!task.isSuccessful()) { - Snackbar.make(view, "Failed to obtain FCM Token :(", Snackbar.LENGTH_LONG).show(); - updateKeyButton.setEnabled(true); - updateKeyButton.setText("Update"); - return; - } - String token = task.getResult(); - fcmTokenEditText.setText(token); - - UpdateDeviceInputDTO updateDeviceInput = new UpdateDeviceInputDTO(); - updateDeviceInput.setEnabled(true); - updateDeviceInput.setFcmToken(token); - updateDeviceInput.setBrand(Build.BRAND); - updateDeviceInput.setManufacturer(Build.MANUFACTURER); - updateDeviceInput.setModel(Build.MODEL); - updateDeviceInput.setBuildId(Build.ID); - updateDeviceInput.setOs(Build.VERSION.BASE_OS); - - - Call apiCall = gatewayApiService.updateDevice(newKey, updateDeviceInput); - apiCall.enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - - if (response.isSuccessful()) { - SharedPreferenceHelper.setSharedPreferenceString(mContext, "GATEWAY_KEY", newKey); - Log.e("API_RESP", response.toString()); - Snackbar.make(view, "DONE :)", Snackbar.LENGTH_LONG).show(); - - } else { - Snackbar.make(view, response.message(), Snackbar.LENGTH_LONG).show(); - } - updateKeyButton.setEnabled(true); - updateKeyButton.setText("Update"); - } - - @Override - public void onFailure(Call call, Throwable t) { - Snackbar.make(view, "An error occured :(", Snackbar.LENGTH_LONG).show(); - updateKeyButton.setEnabled(true); - updateKeyButton.setText("Update"); - - } - }); - } - }); + handleRegisterDevice(); + } + }); + scanQRBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + IntentIntegrator intentIntegrator = new IntentIntegrator(MainActivity.this); + intentIntegrator.setPrompt("Go to vernu-sms.vercel.app/dashboard and click Register Device to generate QR Code"); + intentIntegrator.setRequestCode(SCAN_QR_REQUEST_CODE); + intentIntegrator.initiateScan(); } }); @@ -200,6 +170,66 @@ public class MainActivity extends AppCompatActivity { } + private void handleRegisterDevice() { + + String newKey = apiKeyEditText.getText().toString(); + registerDeviceBtn.setEnabled(false); + registerDeviceBtn.setText("Loading..."); + View view = findViewById(R.id.registerDeviceBtn); + + FirebaseMessaging.getInstance().getToken() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) { + Snackbar.make(view, "Failed to obtain FCM Token :(", Snackbar.LENGTH_LONG).show(); + registerDeviceBtn.setEnabled(true); + registerDeviceBtn.setText("Update"); + return; + } + String token = task.getResult(); + fcmTokenEditText.setText(token); + + RegisterDeviceInputDTO registerDeviceInput = new RegisterDeviceInputDTO(); + registerDeviceInput.setEnabled(true); + registerDeviceInput.setFcmToken(token); + registerDeviceInput.setBrand(Build.BRAND); + registerDeviceInput.setManufacturer(Build.MANUFACTURER); + registerDeviceInput.setModel(Build.MODEL); + registerDeviceInput.setBuildId(Build.ID); + registerDeviceInput.setOs(Build.VERSION.BASE_OS); + + + Call apiCall = gatewayApiService.registerDevice(newKey, registerDeviceInput); + apiCall.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + + if (response.isSuccessful()) { + SharedPreferenceHelper.setSharedPreferenceString(mContext, "API_KEY", newKey); + Log.e("API_RESP", response.toString()); + Snackbar.make(view, "Device Registration Successful :)", Snackbar.LENGTH_LONG).show(); + SharedPreferenceHelper.setSharedPreferenceString(mContext, "DEVICE_ID", response.body().data.get("_id").toString()); + + } else { + Snackbar.make(view, response.message(), Snackbar.LENGTH_LONG).show(); + } + registerDeviceBtn.setEnabled(true); + registerDeviceBtn.setText("Update"); + } + + @Override + public void onFailure(Call call, Throwable t) { + Snackbar.make(view, "An error occured :(", Snackbar.LENGTH_LONG).show(); + registerDeviceBtn.setEnabled(true); + registerDeviceBtn.setText("Update"); + + } + }); + } + }); + } + private void handleSMSRequestPermission(View view) { if (isSMSPermissionGranted(mContext)) { Snackbar.make(view, "Already got permissions", Snackbar.LENGTH_SHORT).show(); @@ -215,6 +245,25 @@ public class MainActivity extends AppCompatActivity { } } + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == SCAN_QR_REQUEST_CODE) { + IntentResult intentResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); + + if (intentResult != null) { + if (intentResult.getContents() == null) { + Toast.makeText(getBaseContext(), "Canceled", Toast.LENGTH_SHORT).show(); + } else { + String scannedQR = intentResult.getContents(); + apiKeyEditText.setText(scannedQR); + handleRegisterDevice(); + } + } + } + } + private boolean isSMSPermissionGranted(Context context) { return ContextCompat.checkSelfPermission(context, Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED; } diff --git a/app/src/main/java/com/vernu/sms/dtos/UpdateDeviceInputDTO.java b/app/src/main/java/com/vernu/sms/dtos/RegisterDeviceInputDTO.java similarity index 94% rename from app/src/main/java/com/vernu/sms/dtos/UpdateDeviceInputDTO.java rename to app/src/main/java/com/vernu/sms/dtos/RegisterDeviceInputDTO.java index dc763fb..f803814 100644 --- a/app/src/main/java/com/vernu/sms/dtos/UpdateDeviceInputDTO.java +++ b/app/src/main/java/com/vernu/sms/dtos/RegisterDeviceInputDTO.java @@ -1,6 +1,6 @@ package com.vernu.sms.dtos; -public class UpdateDeviceInputDTO { +public class RegisterDeviceInputDTO { private String fcmToken; private boolean enabled; private String brand; @@ -13,10 +13,10 @@ public class UpdateDeviceInputDTO { private String appVersionName; private String appVersionCode; - public UpdateDeviceInputDTO() { + public RegisterDeviceInputDTO() { } - public UpdateDeviceInputDTO(String fcmToken) { + public RegisterDeviceInputDTO(String fcmToken) { this.fcmToken = fcmToken; } diff --git a/app/src/main/java/com/vernu/sms/dtos/RegisterDeviceResponseDTO.java b/app/src/main/java/com/vernu/sms/dtos/RegisterDeviceResponseDTO.java new file mode 100644 index 0000000..64ed318 --- /dev/null +++ b/app/src/main/java/com/vernu/sms/dtos/RegisterDeviceResponseDTO.java @@ -0,0 +1,9 @@ +package com.vernu.sms.dtos; + +import java.util.Map; + +public class RegisterDeviceResponseDTO { + public boolean success; + public Map data; + public String error; +} diff --git a/app/src/main/java/com/vernu/sms/dtos/UpdateDeviceResponseDTO.java b/app/src/main/java/com/vernu/sms/dtos/UpdateDeviceResponseDTO.java deleted file mode 100644 index 64ad23a..0000000 --- a/app/src/main/java/com/vernu/sms/dtos/UpdateDeviceResponseDTO.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.vernu.sms.dtos; - -public class UpdateDeviceResponseDTO { - public boolean success; - public Object data; - public String error; -} diff --git a/app/src/main/java/com/vernu/sms/services/GatewayApiService.java b/app/src/main/java/com/vernu/sms/services/GatewayApiService.java new file mode 100644 index 0000000..73e546e --- /dev/null +++ b/app/src/main/java/com/vernu/sms/services/GatewayApiService.java @@ -0,0 +1,19 @@ +package com.vernu.sms.services; + +import com.vernu.sms.dtos.RegisterDeviceInputDTO; +import com.vernu.sms.dtos.RegisterDeviceResponseDTO; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.PATCH; +import retrofit2.http.POST; +import retrofit2.http.Path; +import retrofit2.http.Query; + +public interface GatewayApiService { + @POST("gateway/devices") + Call registerDevice(@Query("apiKey") String apiKey, @Body() RegisterDeviceInputDTO body); + + @PATCH("gateway/devices/{deviceId}") + Call updateDevice(@Path("deviceId") String deviceId, @Query("apiKey") String apiKey, @Body() RegisterDeviceInputDTO body); +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 5f5017a..2b76b7e 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -10,30 +10,32 @@ android:id="@+id/gatewaySwitch" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:minHeight="32dp" android:text="Status" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />