I have an NFC TAG scanner application which works fine and scans the tag and i can also read and write into tags without any issues , the only issue is that when i change the app package name and start the code , the nfc no longer works and scans tags , but when i revert to the other package name it works fine , any reason why and what could be wrong , Thank you in advance
class ActivateActivity : AppCompatActivity() {
private lateinit var binding : ActivityActivateScreenBinding
lateinit var writeTagFilters: Array<IntentFilter>
var nfcAdapter: NfcAdapter? = null
var pendingIntent: PendingIntent? = null
var writeMode = false
var myTag: Tag? = null
var actualMsg = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityActivateScreenBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnActivate.setOnClickListener {
val organizationId = binding.organizationIdEdit.text.toString()
val nfcMsg = binding.txtNFCMessage.text.toString()
actualMsg = DOMAIN + organizationId + ucync + nfcMsg
try {
if(myTag == null){
Toast.makeText(this, ERROR_DETECTED,Toast.LENGTH_LONG).show()
} else {
write(actualMsg,myTag)
Toast.makeText(this, WRITE_SUCCESS,Toast.LENGTH_LONG).show()
}
}
catch (e : IOException){
Toast.makeText(this, WRITE_ERROR, Toast.LENGTH_LONG).show()
e.printStackTrace()
}
catch (e: FormatException){
Toast.makeText(this, WRITE_ERROR, Toast.LENGTH_LONG).show()
e.printStackTrace()
}
}
nfcAdapter = NfcAdapter.getDefaultAdapter(this)
if (nfcAdapter == null) {
// Stop here, we definitely need NFC
Toast.makeText(this, "This device doesn't support NFC.", Toast.LENGTH_LONG).show()
finish()
}
//For when the activity is launched by the intent-filter for android.nfc.action.NDEF_DISCOVERE
readFromIntent(intent)
pendingIntent = PendingIntent.getActivity(this, 0, Intent(this, javaClass)
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
PendingIntent.FLAG_IMMUTABLE)
val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
tagDetected.addCategory(Intent.CATEGORY_DEFAULT)
writeTagFilters = arrayOf(tagDetected)
}
/******************************************************************************
* Read From NFC Tag
****************************************************************************/
private fun readFromIntent(intent: Intent) {
val action = intent.action
if (NfcAdapter.ACTION_TAG_DISCOVERED == action || NfcAdapter.ACTION_TECH_DISCOVERED == action || NfcAdapter.ACTION_NDEF_DISCOVERED == action) {
myTag = intent.getParcelableExtra<Parcelable>(NfcAdapter.EXTRA_TAG) as Tag?
val rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
val msgs = mutableListOf<NdefMessage>()
if (rawMsgs != null) {
for (i in rawMsgs.indices) {
msgs.add(i, rawMsgs[i] as NdefMessage)
}
buildTagViews(msgs.toTypedArray())
}
}
}
private fun buildTagViews(msgs: Array<NdefMessage>) {
if (msgs.isEmpty()) return
val text: String
val payload = msgs[0].records[0].payload
val textEncoding: Charset = if ((payload[0] and 128.toByte()).toInt() == 0) Charsets.UTF_8 else Charsets.UTF_16 // Get the Text Encoding
val languageCodeLength: Int = (payload[0] and 51).toInt() // Get the Language Code, e.g. "en"
try {
// Get the Text
text = String(payload, languageCodeLength + 1, payload.size - languageCodeLength - 1, textEncoding)
Log.d("VALUE","VALUE IS " + text)
} catch (e: UnsupportedEncodingException) {
Log.e("UnsupportedEncoding", e.toString())
}
}
/******************************************************************************
* Write to NFC Tag
****************************************************************************/
private fun write(msg : String , tag : Tag?){
val records = arrayOf(createRecord(msg))
val message = NdefMessage(records)
// Get an instance of Ndef for the tag.
val ndef = Ndef.get(tag)
// Enable I/O
ndef.connect()
// Write the message
ndef.writeNdefMessage(message)
// Close the connection
ndef.close()
}
#Throws(UnsupportedEncodingException::class)
private fun createRecord(text: String): NdefRecord {
val lang = "en"
val textBytes = text.toByteArray()
val langBytes = lang.toByteArray(charset("US-ASCII"))
val langLength = langBytes.size
val textLength = textBytes.size
val payload = ByteArray(1 + langLength + textLength)
// set status byte (see NDEF spec for actual bits)
payload[0] = langLength.toByte()
// copy langbytes and textbytes into payload
System.arraycopy(langBytes, 0, payload, 1, langLength)
System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength)
return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), payload)
}
/**
* For reading the NFC when the app is already launched
*/
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
readFromIntent(intent)
if (NfcAdapter.ACTION_TAG_DISCOVERED == intent.action) {
myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
}
}
public override fun onPause() {
super.onPause()
writeModeOff()
}
public override fun onResume() {
super.onResume()
writeModeOn()
}
/******************************************************************************
* Enable Write and foreground dispatch to prevent intent-filter to launch the app again
****************************************************************************/
private fun writeModeOn() {
writeMode = true
nfcAdapter!!.enableForegroundDispatch(this, pendingIntent, writeTagFilters, null)
}
/******************************************************************************
* Disable Write and foreground dispatch to allow intent-filter to launch the app
****************************************************************************/
private fun writeModeOff() {
writeMode = false
nfcAdapter!!.disableForegroundDispatch(this)
}
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.NFC"/>
<uses-feature android:name="android.hardware.nfc"
android:required="true"/>
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:dataExtractionRules="#xml/data_extraction_rules"
android:fullBackupContent="#xml/backup_rules"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.UcyncBusiness"
tools:targetApi="31">
<activity
android:name=".ui.ActivateActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".ui.HomeActivity"
android:exported="false">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="#xml/nfc_tech_filter" />
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".ui.SplashActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity android:name=".MainActivity" />
</application>
Related
I want to implement Call Recording for one of my client application but above Android 10 I am unable to do is successfully. here is my code classes. Your suggestions will be highly appreciated.
I know due to security reasons Google stopped working around Call Recording above Android 10(Q), But I needs this feature for CRM application.
This is my Receiver Class
public abstract class PhonecallReceiver extends BroadcastReceiver {
// The receiver will be recreated whenever android feels like it.
// We need a static variable to remember data between instantiations
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static boolean isIncoming;
private static String savedNumber; // because the passed incoming is only valid in ringing
#Override
public void onReceive(final Context context, Intent intent) {
// We listen to two intents. The new outgoing call only tells us of an outgoing call.
// We use it to get the number.
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
} else {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
state = TelephonyManager.CALL_STATE_IDLE;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
state = TelephonyManager.CALL_STATE_OFFHOOK;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
state = TelephonyManager.CALL_STATE_RINGING;
}
onCustomCallStateChanged(context, state, number);
} else {
// Android 9+
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String number) {
onCustomCallStateChanged(context, state, number);
}
}, PhoneStateListener.LISTEN_CALL_STATE);
}
}
}
// Derived classes should override these to respond to specific events of interest
protected abstract void onIncomingCallStarted(Context ctx, String number, Date start);
protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start);
protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end);
protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end);
protected abstract void onMissedCall(Context ctx, String number, Date missed);
// Deals with actual events
// Incoming call - goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
// Outgoing call - goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
public void onCustomCallStateChanged(Context context, int state, String number) {
if (lastState == state) {
// No change, debounce extras
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();
savedNumber = number;
onIncomingCallStarted(context, number, callStartTime);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
if (lastState != TelephonyManager.CALL_STATE_RINGING) {
isIncoming = false;
callStartTime = new Date();
onOutgoingCallStarted(context, savedNumber, callStartTime);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
// Went to idle - this is the end of a call. What type depends on previous state(s)
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
// Ring but no pickup - a miss
onMissedCall(context, savedNumber, callStartTime);
} else if (isIncoming) {
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
} else{
onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
}
break;
}
lastState = state;
}
}
This is my service that will work in background to record Audio Calls.
class CallRecorderNew : Service(), onCallingListner {
private lateinit var recorder: MediaRecorder
private var recordStarted = false
private var savedNumber: String? = null
private var lastState = TelephonyManager.CALL_STATE_IDLE
private var isIncoming = false
var fileName //Obtained by intent
: String? = null
var audiouri: Uri? = null
var file: ParcelFileDescriptor? = null
private val CHANNEL_ID = "NOTIFICATION_CHANNEL"
private lateinit var callReceiver: CallReceiver
private var viewmodal: ViewModal? = null
override fun onBind(arg0: Intent): IBinder? {
// TODO Auto-generated method stub
return null
}
override fun onDestroy() {
this.unregisterReceiver(callReceiver)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val intentFilter = IntentFilter()
intentFilter.addAction(ACTION_IN)
intentFilter.addAction(ACTION_OUT)
callReceiver = CallReceiver(this)
this.registerReceiver(callReceiver, intentFilter)
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
0, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(R.string.app_name.toString() + " is running")
.setContentText("Please don not use battery optimizations")
.setSmallIcon(R.drawable.meeting_ic)
.setContentIntent(pendingIntent)
.setColor(resources.getColor(R.color.colorPrimary))
.build()
startForeground(1, notification)
// return super.onStartCommand(intent, flags, startId);
return START_STICKY
}
private fun stopRecording() {
if (recordStarted) {
try {
recorder.stop()
} catch (e: Exception) {
e.printStackTrace()
}
recordStarted = false
}
}
override fun onCreate() {
super.onCreate()
createNotificationChannel()
isServiceRunning = true
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val appName = getString(R.string.app_name)
val serviceChannel = NotificationChannel(
CHANNEL_ID,
appName,
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(
NotificationManager::class.java
)
manager.createNotificationChannel(serviceChannel)
}
}
private fun saveAudioToExternalStorage(displayName: String): Boolean {
val recordingCollection = sdk29AndUp {
MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} ?: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val contentValue = ContentValues().apply {
put(MediaStore.Audio.Media.DISPLAY_NAME, displayName)
put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg")
put(MediaStore.Audio.Media.TITLE, displayName)
put(MediaStore.Audio.Media.DATE_ADDED, (System.currentTimeMillis() / 1000).toInt())
}
return try {
contentResolver.insert(recordingCollection, contentValue)?.also { uri ->
contentResolver.openOutputStream(uri).use { outputStream ->
file = contentResolver.openFileDescriptor(uri, "w")
if (file != null) {
recorder = MediaRecorder()
recorder.setAudioSource(MediaRecorder.AudioSource.MIC)
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
recorder.setOutputFile(file!!.fileDescriptor)
recorder.prepare()
recorder.start()
MainActivity.history[MainActivity.history.size - 1].recordingUrl =
uri.toString()
}
}
} ?: throw IOException("Couldn't create Media Store Entry")
true
} catch (e: Exception) {
e.printStackTrace()
false
}
}
companion object {
const val ACTION_IN = "android.intent.action.PHONE_STATE"
const val ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL"
const val EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"
var isServiceRunning = false
}
override fun onIncomingCallStarted(ctx: Context?, number: String?, date: String) {
isIncoming = true
savedNumber = number
saveAudioToExternalStorage("Incoming $savedNumber $date")
recordStarted = true
}
override fun onIncomingCallEnded(ctx: Context?, number: String?, date: String) {
stopRecording()
}
override fun onOutgoingCallStarted(ctx: Context?, number: String?, date: String) {
isIncoming = true
savedNumber = number
saveAudioToExternalStorage("Outgoing $savedNumber $date")
recordStarted = true
}
override fun onOutgoingCallEnded(ctx: Context?, number: String?, date: String) {
stopRecording()
}
override fun onMissedCall(ctx: Context?, number: String?, date: String) {
stopRecording()
}
internal class CallReceiver(private val callingListner: onCallingListner) :
PhonecallReceiver() {
override fun onOutgoingCallStarted(ctx: Context, number: String, start: Date) {
val msg = "start outgoing call: $number at $start"
Log.d("CallReceiverChecker", msg)
Toast.makeText(ctx.applicationContext, msg, Toast.LENGTH_SHORT).show()
callingListner.onOutgoingCallStarted(ctx, number, setDateTime())
}
override fun onOutgoingCallEnded(ctx: Context, number: String, start: Date?, end: Date) {
val msg = "end outgoing call: $number at $end"
Log.d("CallReceiverChecker", msg)
Toast.makeText(ctx.applicationContext, msg, Toast.LENGTH_SHORT).show()
callingListner.onOutgoingCallEnded(ctx, number, setDateTime())
}
override fun onIncomingCallStarted(ctx: Context, number: String, start: Date) {
val msg = "start incoming call: $number at $start"
Log.d("CallReceiverChecker", msg)
Toast.makeText(ctx.applicationContext, msg, Toast.LENGTH_SHORT).show()
callingListner.onIncomingCallStarted(ctx, number, setDateTime())
}
override fun onIncomingCallEnded(ctx: Context, number: String, start: Date?, end: Date) {
val msg = "end incoming call: $number at $end"
Log.d("CallReceiverChecker", msg)
Toast.makeText(ctx.applicationContext, msg, Toast.LENGTH_SHORT).show()
callingListner.onIncomingCallEnded(ctx, number, setDateTime())
}
override fun onMissedCall(ctx: Context, number: String, missed: Date) {
// callingListner.onMissedCall(ctx, number, setDateTime())
val msg = "missed call: $number at $missed"
Log.d("CallReceiverChecker", msg)
Toast.makeText(ctx.applicationContext, msg, Toast.LENGTH_SHORT).show()
callingListner.onMissedCall(ctx, number, setDateTime())
}
}
}
This is manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="app.sten.wit">
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.PROCESS_INCOMING_CALLS" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="com.android.vending.BILLING"/>
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
<application
android:allowBackup="true"
android:fullBackupContent="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning">
<!-- <activity-->
<!-- android:name=".Views.MainActivity"-->
<!-- android:exported="true">-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.MAIN" />-->
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
<!-- </intent-filter>-->
<!-- </activity>-->
<service android:name=".CallRecorderNew" />
<activity
android:name=".Views.HistoryActivity"
android:exported="true" />
<activity
android:name=".Views.AddMeetingsActivity"
android:exported="true" />
<activity
android:name=".Views.AddClientActivity"
android:exported="false" />
<activity
android:name=".Views.ScheduleMeetingsActivity"
android:exported="false" /> <!-- <activity -->
<!-- android:name=".Views.MeetingsActivity" -->
<!-- android:exported="false" /> -->
<activity
android:name=".Views.DetailsActivity"
android:exported="false" />
<activity
android:name=".Views.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- <receiver-->
<!-- android:name=".BootCompleteReceiver"-->
<!-- android:exported="true">-->
<!-- <intent-filter android:priority="999">-->
<!-- <action android:name="android.intent.action.BOOT_COMPLETED" />-->
<!-- <action android:name="android.intent.action.QUICKBOOT_POWERON" />-->
<!-- <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />-->
<!-- </intent-filter>-->
<!-- </receiver>-->
<service android:name=".CallRecorderNew" />
</application>
</manifest>
I have also added permission for MediaProjectionManager but I don't think this is working.
Google is actively disallowing call recording by 3rd-party apps. Here's a good write-up for it, but the short answer is that you simply can't record calls any longer
#My app is working till I try to save the Message on the Database, see the image here:
#[App_Working][1]
#[1]: https://i.stack.imgur.com/G26MS.jpg
#I tried to find the content://com.courses.applicationcontentprovider.provider/notes file but i'm new on Developing world and didn't find
#Can someone show me how to fix that?
#I also checked some similar question's but this isn't work.
#Here is my AndroidManiFest.xml
<?xml version="1.0" encoding="utf-8"?>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.ApplicationContentProvider.">
<provider
android:name=".database.NotesProvider"
android:authorities="com.example.applicationcontentprovider.provider"
android:enabled="true"
android:exported="true" />
<activity
android:name=".database.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
#And the logcat in pointing to the NotesDetailFragments.kt
Process: com.example.contentprovider, PID: 787
java.lang.IllegalArgumentException: Unknown URL content://com.courses.applicationcontentprovider.provider/notes
at android.content.ContentResolver.insert(ContentResolver.java:2145)
at android.content.ContentResolver.insert(ContentResolver.java:2111)
at com.example.contentprovider.database.NotesDetailFragments.onClick(NotesDetailFragments.kt:78)
at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:174)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
#tHANKS
class NotesDetailFragments: DialogFragment(), DialogInterface.OnClickListener {
private lateinit var noteEdiTitle: EditText
private lateinit var noteEditDescription: EditText
private var id: Long = 0
companion object {
private const val EXTRA_ID = "id"
fun newInstance(id: Long): NotesDetailFragments {
val bundle = Bundle()
bundle.putLong(EXTRA_ID, id)
val notesFragment = NotesDetailFragments()
notesFragment.arguments = bundle
return notesFragment
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view: View? = activity?.layoutInflater?.inflate(R.layout.note_detail, null)
noteEdiTitle = view?.findViewById(R.id.note_edt_title) as EditText
noteEditDescription = view.findViewById(R.id.note_edt_description) as EditText
var newNote = true
if (arguments != null && arguments?.getLong(EXTRA_ID) != 0L){
id = arguments?.getLong(EXTRA_ID) as Long
val uri = Uri.withAppendedPath(URI_NOTES, id.toString())
val cursor =
activity?.contentResolver?.query(uri, null, null, null, null)
if (cursor?.moveToNext() as Boolean ) {
newNote = false
noteEdiTitle.setText(cursor.getString(cursor.getColumnIndex(TITTLE_NOTES)))
noteEditDescription.setText(cursor.getString(cursor.getColumnIndex(DESCRIPTION_NOTES)))
}
cursor.close()
}
return AlertDialog.Builder(activity as Activity)
.setTitle(if (newNote) "Nova mensagem" else "Editar Mensagem")
.setView(view)
.setPositiveButton("Salvar", this)
.setNegativeButton("Cancelar", this)
.create()
}
override fun onClick(dialog: DialogInterface?, which: Int) {
val values = ContentValues()
values.put(TITTLE_NOTES, noteEdiTitle.text.toString())
values.put(DESCRIPTION_NOTES, noteEditDescription.text.toString())
if(id != 0L){
val uri = Uri.withAppendedPath(URI_NOTES, id.toString())
context?.contentResolver?.update(uri, values, null, null)
}else {
context?.contentResolver?.insert(URI_NOTES, values)
}
}
My application is a Phone Dialer User-interface. I want to mute the mic. So I need to do something like InCallService.setMuted(true), but I'm having trouble access this android "system" service? The problem is that I cannot access the Android System Servies.
This is the code:
Manifest file:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.DIAL"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="tel"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".CallActivity"
android:theme="#style/AppTheme.CallScreen"/>
<service
android:name=".CallService"
android:permission="android.permission.BIND_INCALL_SERVICE">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true"/>
<intent-filter>
<action android:name="android.telecom.InCallService"/>
</intent-filter>
</service>
</application>
</manifest>
</code>
<code>
class CallActivity : AppCompatActivity() {
companion object {
private const val LOG_TAG = "CallActivity"
}
private var updatesDisposable = Disposables.empty()
private var timerDisposable = Disposables.empty()
private var inCallService: InCallService? = null
/* A VER2
// Variable to hold service class name
val serviceClass = CallService::class.java
// Initialize a new Intent instance
val intentService = Intent(applicationContext, serviceClass)
*/
private val myConnection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as CallService.CallBinder
inCallService = binder.getService()
Log.i("SERV_BOUND", "Service in Call Bound!")
}
override fun onServiceDisconnected(name: ComponentName) {
Log.i("SERV_UNBOUND", "Service in Call Unbound!")
}
}
// val inCallService: InCallService = getSystemService(Context.TELECOM_SERVICE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
setContentView(R.layout.activity_call)
val intent = Intent(this, CallService::class.java)
hideBottomNavigationBar()
buttonHangup.setOnClickListener { CallManager.cancelCall() }
buttonAnswer.setOnClickListener { CallManager.acceptCall() }
buttonMute.setOnClickListener { muteCall() }
}
override fun onResume() {
super.onResume()
updatesDisposable = CallManager.updates()
.doOnEach { Log.i(LOG_TAG, "updated call: $it") }
.doOnError { throwable -> Log.e(LOG_TAG, "Error processing
call", throwable) }
.subscribe { updateView(it) }
}
private fun updateView(gsmCall: GsmCall) {
textStatus.visibility = when (gsmCall.status) {
GsmCall.Status.ACTIVE -> View.GONE
else -> View.VISIBLE
}
textStatus.text = when (gsmCall.status) {
GsmCall.Status.CONNECTING -> "Connecting…"
GsmCall.Status.DIALING -> "Calling…"
GsmCall.Status.RINGING -> "Incoming call"
GsmCall.Status.ACTIVE -> ""
GsmCall.Status.DISCONNECTED -> "Finished call"
GsmCall.Status.UNKNOWN -> ""
}
textDuration.visibility = when (gsmCall.status) {
GsmCall.Status.ACTIVE -> View.VISIBLE
else -> View.GONE
}
buttonHangup.visibility = when (gsmCall.status) {
GsmCall.Status.DISCONNECTED -> View.GONE
else -> View.VISIBLE
}
if (gsmCall.status == GsmCall.Status.DISCONNECTED) {
buttonHangup.postDelayed({ finish() }, 3000)
}
when (gsmCall.status) {
GsmCall.Status.ACTIVE -> startTimer()
GsmCall.Status.DISCONNECTED -> stopTimer()
else -> Unit
}
textDisplayName.text = gsmCall.displayName ?: "Unknown"
buttonAnswer.visibility = when (gsmCall.status) {
GsmCall.Status.RINGING -> View.VISIBLE
else -> View.GONE
}
}
override fun onPause() {
super.onPause()
updatesDisposable.dispose()
}
private fun hideBottomNavigationBar() {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
}
private fun startTimer() {
timerDisposable = Observable.interval(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { textDuration.text = it.toDurationString() }
}
private fun stopTimer() {
timerDisposable.dispose()
}
private fun Long.toDurationString() = String.format("%02d:%02d:%02d", this /
3600, (this % 3600) / 60, (this % 60))
fun muteCall() {
Log.i(CallManager.LOG_TAG, "muteCall")
inCallService!!.setMuted(!inCallService!!.callAudioState.isMuted)
}
class CallService : InCallService() {
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example.
// private val myBinder = CallBinder()
//
// override fun onBind(intent: Intent): IBinder? {
// return this.mBinder
// }
/**
* Class for clients to access. Because we know this service always
* runs in the same process as its clients, we don't need to deal with
* IPC.
*/
inner class CallBinder : Binder() {
fun getService(): CallService {
return this#CallService
}
}
override fun onCallAdded(call: Call) { //app receives a new incoming call via onCallAdded
super.onCallAdded(call)
Log.i(LOG_TAG, "onCallAdded: $call")
call.registerCallback(callCallback)
val i = Intent(this, CallActivity::class.java)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(i)
CallManager.updateCall(call)
}
override fun onCallRemoved(call: Call) {
super.onCallRemoved(call)
Log.i(LOG_TAG, "onCallRemoved: $call")
call.unregisterCallback(callCallback)
CallManager.updateCall(null)
}
private val callCallback = object : Call.Callback() {
override fun onStateChanged(call: Call, state: Int) {
Log.i(LOG_TAG, "Call.Callback onStateChanged: $call, state: $state")
CallManager.updateCall(call)
}
}
}
In CallActivity I need to obtain an instance of the "running" InCallService, to mute it. How can I do it?
The error is onBind in line: val binder = service as CallService.CallBinder
Process: com.mbarrben.dialer, PID: 6923
java.lang.ClassCastException: android.telecom.InCallService$InCallServiceBinder cannot be cast to com.delphi.dialer.CallService$CallBinder
at com.delphi.dialer.CallActivity$myConnection$1.onServiceConnected(CallActivity.kt:46)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1730)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1762)
at android.os.Handler.handleCallback(Handler.java:873)
I attach an image with a watch of the objects on the moments of crash.
Class Cast Error Onbind Service 1
this thing is behaving very strange with us. Some devices hit onmsgrcv, while others dont when the app is closed. How come apps like Whatsapp receives notification when they are closed? Why dont I receive when my app is closed? Need help...
alert.php
$divisions = $_GET['divisions'];
$tokens = array();
$tokens[0] = "e3-nlNImIR8:APA91bGQ3WJW_jWfelz5mEp6L6--wNgdZtb93Bx7kZBSsXUaGYOvdg0_RaP7KlnlfGBD4Xqs3Kyr-IKc0s3072DPGCvToeFeO0w9EHazGOqZt30KbNE7zQr4gbklJ9nZlypyU8IyYzIl";
$tokens[1] = "fWFN3lpvIjI:APA91bF1Kkh-EBEEi8-qkrBgtwxzFAK4WfupWvgjA1PlWjquKTg8yUzMALO9UeTBJHw8UMbE_SLM2cObpf_PolQNkg4AW10Dsg7rtwvI41tIL83Kpm8BZ8cs4GEGXOYrbF0KaB_GG3jo";
$tokens[2] = "eimGs3j1bsA:APA91bFhJHRtxTKldSsrIVr8d12fVLId1DYkUIKgiczTrXGgKLQnoud9ZMIvi1wKHHQWkGcV2ptmLqLfHywgIwWzRxpfaJuICNvgqF2OUnfKist3_t-2XuASukuc4_6Ua9sER29c-oi9";
$data = array(
"divisions" => $divisions
);
$fields = array(
'to' => "/topics/ALERT",
'data' => $data
);
$headers = array(
'Authorization:key = AAAAjCAUSaQ:APA91bGa0FsAjY-5tjEBIiavo960rU39UmendbRC-akMdKxJIdSsqwwlNl4YMl1iAIYd2evyp_5kWe6l_RmpzLGXHiY91NY8LRKa75XNruD9Jvnyu8xNA2IIinLlkJLi8TL5Ud4M9hjY',
'Content-Type: application/json'
);
$ch = curl_init();
$url = "https://fcm.googleapis.com/fcm/send";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch, CURLOPT_POSTFIELDS,json_encode($fields));
$result = curl_exec($ch);
echo $result;
curl_close($ch);
?>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:hardwareAccelerated="false"
android:largeHeap="true"
android:label="#string/app_name"
android:roundIcon="#drawable/ic_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:name="android.support.multidex.MultiDexApplication"
>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_launcher" />
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
<activity
android:name="com.kayhanswarup.avtro.prokriti.ui.HomeActivity"
android:configChanges="locale|orientation"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
</activity>
<!-- <service android:name=".services.MyService" android:process=":my_service" /> -->
<service android:name="com.kayhanswarup.avtro.prokriti.services.CloudMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name="com.kayhanswarup.avtro.prokriti.services.InstanceTokenService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<provider android:authorities="com.facebook.app.FacebookContentProvider1697853730520523"
android:name="com.facebook.FacebookContentProvider"
android:exported="true"/>
<meta-data android:name="com.facebook.sdk.ApplicationId"
android:value="#string/facebook_app_id"/>
<activity android:name="com.kayhanswarup.avtro.prokriti.ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="#string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="#string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
</application>
CloudMessagingService.java
public class CloudMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if (remoteMessage.getData().size() > 0) {
ML.d("Message data exists. Should go background: " + remoteMessage.getData());
goBackend(remoteMessage.getData().get("divisions"));
}
else if (remoteMessage.getNotification() != null) {
ML.d("Message Notification Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getBody());
}
}
public int currentDivisionIndex = -1;
public String currentDivision="";
private void goBackend(final String messageBody){
ML.setTagServer(true);
ML.i("Reached with data: "+messageBody);
final Intent intent1 = new Intent(this,HomeActivity.class);
final String[] divisions = ApiEndPoints.DIVISIONS;
try {
provider = LocationManager.NETWORK_PROVIDER;
locationManager=(LocationManager)getBaseContext().getSystemService(Context.LOCATION_SERVICE);
final Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(location!=null){
ML.d("location(lng,lat) value in background app: "+location.getLongitude()+","+location.getLatitude());
ApiClient.getInstance(getBaseContext())
.getWeather(location.getLatitude()+"", location.getLongitude()+"", new OnResponse<Weather, ANError>() {
#Override
public void onResponse(Weather response) {
try{
currentDivision= response.getQuery().getResults().getChannel().getLocation()
.getRegion();
}catch (Exception e){
ML.e("Exception during api client weather: "+e.getMessage());
return;
}
ML.d("Current DIVISION: "+currentDivision);
if(currentDivision!=null&¤tDivision.length()>=3){
ML.d("current Division is: "+currentDivision);
for(int i=0;i<divisions.length;i++){
ML.i("No#"+i+" division: "+divisions[i]);
if((currentDivision.toLowerCase().contains(divisions[i].toLowerCase()))||divisions[i].toLowerCase().contains(currentDivision.toLowerCase())){
ML.d("We got a match: "+i);
currentDivisionIndex = i;
}else{
ML.d("Current division: "+currentDivision.toLowerCase());
ML.d("INDEX DIVISION: "+divisions[i].toLowerCase());
}
}
ML.d("Current: "+currentDivisionIndex);
if(currentDivisionIndex<0||(currentDivisionIndex>=0&&messageBody.substring(currentDivisionIndex,currentDivisionIndex+1).equals("0"))){
ML.d("Returning from background" +
"DONE");
ML.d("Reached background but location mismatched");
if(currentDivisionIndex>=0){
ML.d("What is this: "+messageBody.substring(currentDivisionIndex,currentDivisionIndex+1));
}
return;
}else{
ML.d("Atleast found sth...");
}
ML.d("VALUE ACCORDING TO : "+messageBody.substring(currentDivisionIndex,currentDivisionIndex+1));
int val=0;
try {
val= Integer.parseInt(messageBody.substring(currentDivisionIndex,currentDivisionIndex+1));
} catch (Exception e) {
ML.e("Integer parsing error: "+e.getMessage());
}
if(currentDivisionIndex>=0&&val!=0){
String lang = "en";
try {
lang = isLangBangla()?"bn":"en";
} catch (Exception e) {
ML.e("GOT EXCEPTION");
lang="bn";
}
FirebaseDatabase.getInstance().getReference("versions")
.child("001")
.child("locales")
.child(lang)
.child("alert")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
ML.d("Will show an alert... IF LUCKY...");
final Alert alert = dataSnapshot.getValue(Alert.class);
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("versions").child("001")
.child("LOG");
String key = ref.push().getKey();
ref.child(key).setValue(ML.getLog() + "", new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if(databaseError==null)
Log.d("Prokriti","sent");
ML.setTagServer(false);
Notify.getInstance().setHasNotification(true);
String title = getString(R.string.alert_title);
String body = getString(R.string.alert_body);
try {
if(alert!=null){
ML.d("Alert: "+alert.toString());
title = alert.getTitle();
body = alert.getBody();
}else ML.e("Alert is null");
} catch (Exception e) {
ML.e("no alert found"+e.getMessage());
}
try {
Notify.getInstance().setTitle(title);
Notify.getInstance().setDescription(body);
} catch (Exception e) {
ML.e("Notify error: "+e.getMessage());
Notify.getInstance().setTitle("Title");
Notify.getInstance().setDescription("Danger");
}
PendingIntent pendingIntent = PendingIntent.getActivity(CloudMessagingService.this, 0 /* Request code */, intent1,
PendingIntent.FLAG_UPDATE_CURRENT);
ML.d("Pack res path: "+getPackageResourcePath());
ML.d("Pack res: "+getPackageName());
Uri defaultSoundUri= Uri.parse("android.resource://"+getPackageName()+"/"+ R.raw.alert);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(CloudMessagingService.this)
.setSmallIcon(R.drawable.ic_cloud)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
});
// intent.putExtra("locale","notify");
}
#Override
public void onCancelled(DatabaseError databaseError) {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("versions").child("001")
.child("LOG");
String key = ref.push().getKey();
ref.child(key).setValue(ML.getLog() + "", new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if(databaseError==null)
Log.d("Prokriti","sent");
ML.setTagServer(false);
}
});
}
});
}
}
}
#Override
public void onError(ANError error) {
ML.e("Error: "+error.getMessage());
}
});
}
} catch (Exception e) {
ML.e("Still shows fucking ERROR: "+e.getMessage());
}
}
public static boolean isLangBangla(){
return LocaleManager.getInstance().getLocale().getDisplayLanguage().toLowerCase().contains("bengali");
}
LocationManager locationManager=null;
String provider;
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// provider = LocationManager.NETWORK_PROVIDER;
// locationManager=(LocationManager)getBaseContext().getSystemService(Context.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(provider);
if(location!=null){
ML.d("location(lng,lat): "+location.getLongitude()+","+location.getLatitude());
}else ML.d("location is null...");
intent.putExtra("locale","notify");
Notify.getInstance().setHasNotification(true);
Notify.getInstance().setTitle("Title");
Notify.getInstance().setDescription("ED");
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
ML.d("Pack res path: "+getPackageResourcePath());
ML.d("Pack res: "+getPackageName());
Uri defaultSoundUri= Uri.parse("android.resource://"+getPackageName()+"/"+ R.raw.alert);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_cloud)
.setContentTitle(getString(R.string.alert_title))
.setContentText(getString(R.string.alert_body))
.setAutoCancel(false)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
LocationListener locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
};
}
I'm trying to read USSD response to get Sim balance amount etc, and I'm having issues, I have been reading many questions related to that on Stackoverflow, nothing has worked so far. Except for this that came close: Prevent USSD dialog and read USSD response?. by #HenBoy331
But i'm still having issues with it. My broadcast receiver doesn't get called too. I'm using 4.4.2
But it shows nothing. I can't seem to parse the message and get the balance.
I have a MainActivity to make the phone call, ReceiverActivity to implement broadcast receiver, USSDService class to get the USSD response.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, USSDService.class));
dailNumber("100");
}
private void dailNumber(String code) {
String ussdCode = "*" + code + Uri.encode("#");
startActivity(new Intent("android.intent.action.CALL", Uri.parse("tel:" + ussdCode)));
}
}
RecieverActivity.java
public class RecieverActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter("com.times.ussd.action.REFRESH");
this.registerReceiver(new Receiver(), filter);
}
public class Receiver extends BroadcastReceiver {
private String TAG = "XXXX";
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
Log.i(TAG, "Got message: " + message);
}
}
}
USSDService.java
public class USSDService extends AccessibilityService {
public String TAG = "XXXX";
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, "onAccessibilityEvent");
AccessibilityNodeInfo source = event.getSource();
/* if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !event.getClassName().equals("android.app.AlertDialog")) { // android.app.AlertDialog is the standard but not for all phones */
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !String.valueOf(event.getClassName()).contains("AlertDialog")) {
return;
}
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && (source == null || !source.getClassName().equals("android.widget.TextView"))) {
return;
}
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && TextUtils.isEmpty(source.getText())) {
return;
}
List<CharSequence> eventText;
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
eventText = event.getText();
} else {
eventText = Collections.singletonList(source.getText());
}
String text = processUSSDText(eventText);
if( TextUtils.isEmpty(text) ) return;
// Close dialog
performGlobalAction(GLOBAL_ACTION_BACK); // This works on 4.1+ only
Log.d(TAG, text);
// Handle USSD response here
Intent intent = new Intent("com.times.ussd.action.REFRESH");
intent.putExtra("message", text);
sendBroadcast(intent);
}
private String processUSSDText(List<CharSequence> eventText) {
for (CharSequence s : eventText) {
String text = String.valueOf(s);
// Return text if text is the expected ussd response
if( true ) {
return text;
}
}
return null;
}
#Override
public void onInterrupt() {
}
#Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.d(TAG, "onServiceConnected");
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.flags = AccessibilityServiceInfo.DEFAULT;
info.packageNames = new String[]{"com.android.phone"};
info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
setServiceInfo(info);
}
}
AndroidManifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dialussd">
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".services.USSDService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="#xml/config_service" />
</service>
<receiver android:name=".RecieverActivity$Receiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
Please, is there any way i'm implementing this wrongly, Or perhaps there is a new way to get USSD responses which works?
After the launch, change the settings manually
Setting->Accessibility Setting -> You can see a option 'your app name'. Turn it on. (This has to be done from as a part of application flow(not manual))
instead of using broadcast receiver use these two lines of code in
add this code in MainActivity
public static void setTextViewToModify(String Text) {
textView.setText(Text);}
and add this in service class with in onAccessibityEvent
MainActivity.setTextViewToModify(text);