<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_DATE_CHANGED"/>
</intent-filter>
</receiver>
Manifests
var intent2 = Intent(requireActivity(), MyReceiver::class.java)
intent2.putExtra("Test", "value")
intent2.setAction(Intent.ACTION_DATE_CHANGED)
override fun onReceive(context: Context, intent: Intent) {
var st = intent.getStringExtra("Test")
if (intent.action.equals(Intent.ACTION_DATE_CHANGED)) {
var st = intent.getStringExtra("Test")
var toast = Toast.makeText(context, st, Toast.LENGTH_LONG) //
toast.show()
}
}
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.DATE_CHANGED from pid=3604, uid=10091
I get an error like this
I searched but couldn't find a solution
Please help...
Try this.
You cannot use ACTION_DATE_CHANGED because it's a private android action, so you need to create your custom action.
<receiver
android:name=".MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="${applicationId}.receiver.RECEIVE_MESSAGE_ACTION" />
</intent-filter>
</receiver>
Then you need to register for your activity before using it. Usually, I put in the onCreate method.
private fun registerReceiver(){
val filter = IntentFilter()
filter.addAction(MyReceiver.RECEIVE_MESSAGE_ACTION)
val customReceiver = MyReceiver()
registerReceiver(customReceiver, filter)
}
And when you called to share your message, use the following code.
companion object {
const val RECEIVE_MESSAGE_ACTION = "${BuildConfig.APPLICATION_ID}.receiver.RECEIVE_MESSAGE_ACTION"
}
private fun callCustomBroadcast(message: String) {
val intent = Intent(RECEIVE_MESSAGE_ACTION)
intent.putExtra("mymessage", message)
sendBroadcast(intent)
}
Related
I have the following code
val pendingIntent = PendingIntent.getActivity(activity, 101,
Intent(activity,classType).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_IMMUTABLE)
val nfcIntentFilter = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED)
val filters = arrayOf(nfcIntentFilter)
val TechLists = arrayOf(arrayOf(Ndef::class.java.name),
arrayOf(NdefFormatable::class.java.name))
nfcAdapter.enableForegroundDispatch(activity, pendingIntent, filters, TechLists)``
and in the activity I am trying to get the tag , action , message
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val type: String? = intent.type
val action: String? = intent.action
}
However, action is already and tag is also null:
val tag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
it.getParcelableExtra(NfcAdapter.EXTRA_TAG,Tag::class.java)
} else {
it.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
}
In the manifest I have the following inside the activity tag:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain"/>
</intent-filter>
I also have the permission enabled:
<uses-permission android:name="android.permission.NFC" />
Tried multiple codes and change the intent filter NDEF_DISCOVERED to TAG_DISCOVERD but everything failed. I have tested it also on three separate phones and also same issue. onNewIntent gets called but the intent does not provide information
I create Custom Intent as below.
Intent().also { intent ->
intent.setAction("STEP_COUNT_NOTIFICATION")
intent.putExtra("stepCount", todayTotalStepCount)
sendBroadcast(intent)
}
And I add this Custom Intent in my Broadcast Receiver tag of AndroidManifest.
<receiver
android:name=".BroadcastReceiver.BroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_DATE_CHANGED" />
<action android:name="com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION" />
</intent-filter>
</receiver>
Since I use two Intent, one is official intent and the other is custom, I need to distinguish received Intent.
onReceive function of BroadcastReceiver
override fun onReceive(context: Context?, intent: Intent?) {
val intentAction = intent!!.action
when (intentAction) {
Intent.ACTION_DATE_CHANGED -> {
// todayTotalStepCount = 0
var todayStepCountSet = hashMapOf<String, Int?>(
"todayStepCount" to 0
)
userDB
.document("$userId")
.set(todayStepCountSet, SetOptions.merge())
}
???? ->
}
}
How can I get STEP_COUNT_NOTIFICATION which is my custom intent?
First, create a public constant for your custom action:
companion object {
const val ACTION_STEP_COUNTER_NOTIFICATION = "com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION"
}
For your Intent, use the same action:
Intent().also { intent ->
intent.setAction(ACTION_STEP_COUNTER_NOTIFICATION)
intent.putExtra("stepCount", todayTotalStepCount)
sendBroadcast(intent)
}
Also, use the same action in your BroadcastReceiver:
override fun onReceive(context: Context?, intent: Intent?) {
val intentAction = intent!!.action
when (intentAction) {
Intent.ACTION_DATE_CHANGED -> {
// todayTotalStepCount = 0
var todayStepCountSet = hashMapOf<String, Int?>(
"todayStepCount" to 0
)
userDB
.document("$userId")
.set(todayStepCountSet, SetOptions.merge())
}
// Your custom action
ACTION_STEP_COUNTER_NOTIFICATION -> { // Add your code here }
}
}
Lastly, for AndroidManifest.xml:
<receiver
android:name=".BroadcastReceiver.BroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_DATE_CHANGED" />
// action should be the same as the value of ACTION_STEP_COUNTER_NOTIFICATION
<action android:name="com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION" />
</intent-filter>
</receiver>
action name should be the same for Intent, AndroidManifest.xml and BroadcastReceiver
Your Intent action needs to match the android:name for the corresponding <intent-filter>. Yours do not.
You have:
intent.setAction("STEP_COUNT_NOTIFICATION")
This has an action string of STEP_COUNT_NOTIFICATION.
You also have:
<action android:name="com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION" />
This has an action string of com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION.
Those two are not the same. They need to be the same. I recommend using com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION in both places.
I'm trying to create an alarm Manager that sends notification every 24 hours at specific time consulted other Stackoverflow code. I tried this code below but onReceive() never gets executed. What i'm doing wrong?
private var HOUR_TO_SHOW_PUSH = 21
private var MINUTE_TO_SHOW_PUSH = 0
private val REQUEST_CODE = 100
private lateinit var alarmManager: AlarmManager
private lateinit var pendingIntent: PendingIntent
class MainActivity : AppCompatActivity() {
...
alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlertReceiver::class.java)
pendingIntent = PendingIntent.getBroadcast(this, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val calendar = GregorianCalendar.getInstance().apply {
if (get(Calendar.HOUR_OF_DAY) >= HOUR_TO_SHOW_PUSH) {
add(Calendar.DAY_OF_MONTH, 1)
}
set(Calendar.HOUR_OF_DAY, HOUR_TO_SHOW_PUSH)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
pendingIntent
)
AlertReceiver
class AlertReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "Alarm", Toast.LENGTH_LONG).show()
println("Alarm")
Log.e("Alarm","Alarm Triggered")
}
Manifest
<receiver
android:name=".AlertReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="MyBroadcastReceiverAction"/>
</intent-filter
</receiver>
Normally you would register your receiver in the AndroidManifest like this:
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
https://developer.android.com/guide/components/broadcasts
it depends on the battery optimization applied to the app by the device, it varies from a device manufacturer to other
Normally you will find it in Settings > Apps > "your app name" > Battery Saver Set it to No Restrictions
ActivityMain is singleTask.
I can use Code A to create a dynamic shortcuts icon in screen, it will show ActivityMain when I click the shortcuts icon.
You know I can also show ActivityMain by clicking the app icon.
How can I know a Activity lanuched from dynamic shortcuts when I use singleTask ?
BTW, Code B doesn't work.
Code A
#TargetApi(25)
private fun createShorcut() {
val sM = getSystemService(ShortcutManager::class.java)
val intent1 = Intent(this, ActivityMain::class.java)
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent1.setAction("My")
val shortcut1 = ShortcutInfo.Builder(this, "shortcut1")
.setIntent(intent1)
.setShortLabel("Shortcut 1")
.setLongLabel("Shortcut 2")
.setShortLabel("This is the shortcut 1")
.setDisabledMessage("Login to open this")
.setIcon(Icon.createWithResource(this, R.drawable.notify_icon))
.build()
sM.dynamicShortcuts = Arrays.asList(shortcut1)
}
#TargetApi(25)
private fun removeShorcuts() {
val shortcutManager = getSystemService(ShortcutManager::class.java)
shortcutManager.disableShortcuts(Arrays.asList("shortcut1"))
shortcutManager.removeAllDynamicShortcuts()
}
if (Build.VERSION.SDK_INT >= 25) {
createShorcut()
}else{
removeShorcuts()
}
<activity android:name=".ui.ActivityMain"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Code B
override fun onResume() {
super.onResume()
if (mActivity.intent.action.equals("My")) {
toast("ActivityMain from dynamic shortcuts")
}
}
Added Content:
To prateek: Thanks!
Do you mean I have to check it both onCreate and onNewIntent event when I use SingleTask?
In SingleTask:
A: When I run the APP (Click either App Icon or Shortcut Icon) for the first time, only onCreate event is fired.
B: If the app is already running, when I fire the App again (Click either App Icon or Shortcut Icon) , only onNewIntent event is fired.
So I have to check it both onCreate and onNewIntent event just like Code C, right?
Code C
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.btnClose).setOnClickListener {
finish()
}
createShorcut()
var which= this.intent.getBooleanExtra("yourkey", false)
displayResult(which)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
var which= intent?.getBooleanExtra("yourkey", false)
displayResult(which?:false)
}
private fun displayResult(which:Boolean){
if (which) {
Toast.makeText(this, "From ShortCut Icon", Toast.LENGTH_LONG).show()
}else{
Toast.makeText(this, "From App Icon", Toast.LENGTH_LONG).show()
}
}
private fun createShorcut() {
val sM = getSystemService(ShortcutManager::class.java)
val intent1 = Intent(this, MainActivity::class.java)
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent1.setAction("My")
intent1.putExtra("yourkey", true)
val shortcut1 = ShortcutInfo.Builder(this, "ShortCut Item")
.setIntent(intent1)
.setShortLabel("Shortcut Item")
.setIcon(Icon.createWithResource(this, R.drawable.ic_launcher_foreground))
.build()
sM.dynamicShortcuts = Arrays.asList(shortcut1)
}
}
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
In my use case, I am adding a flag when creating intent to be launched via shortcut and always able to retrieve it at the other end.
Try something like .putExtra("fromShortcut", true). It should work.
Regarding retrieving action I haven't tried, sorry.
[Update]
This is how I am creating my intent object:
val shortcutIntent = Intent(context, YourActivity::class.java)
.setAction(Intent.ACTION_MAIN)
.putExtra("yourkey", true)
.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
)
and this is how you retrieve it at the receiving end:
mNewIntentReceived.getBooleanExtra("yourkey", false)
Also, I can observe you are not adding 'new task' flag in your intent, add that as well.
I followed everything in the android authentication guide and the quick start guide. I did as the guide told me to generate a SHA1 and adding it to Spotify app dashboard, and I got the app_client and added it to my app as well. Both scenarios still return the same thing. I even tried implementing the Login thru Browser feature, yet it still returns type EMPTY.
Here's my Login class
class SignInActivity : AppCompatActivity(), ConnectionStateCallback, Player.NotificationCallback {
private var mPlayer : SpotifyPlayer? = null
private val CLIENT_ID = //replace this
private val REDIRECT_URI = //replace this
private val REQUEST_CODE = 1337
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
btnSignin.setOnClickListener {
val builder = AuthenticationRequest.Builder(CLIENT_ID, AuthenticationResponse.Type.TOKEN, REDIRECT_URI)
builder.setScopes(arrayOf("user-read-private", "streaming"))
val request = builder.build()
AuthenticationClient.openLoginActivity(this, REQUEST_CODE, request)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
// Check if result comes from the correct activity
if (requestCode == REQUEST_CODE) {
val response = AuthenticationClient.getResponse(resultCode, intent)
Log.i("LoginActivity", Gson().toJson(response))
when (response.type) {
// Response was successful and contains auth token
AuthenticationResponse.Type.TOKEN -> {
Log.i("LoginActivity", "is equals to TOKEN")
val playerConfig = Config(this, response.accessToken, CLIENT_ID)
Spotify.getPlayer(playerConfig, this, object : SpotifyPlayer.InitializationObserver {
override fun onInitialized(spotifyPlayer: SpotifyPlayer) {
mPlayer = spotifyPlayer
mPlayer!!.addConnectionStateCallback(this#SignInActivity)
mPlayer!!.addNotificationCallback(this#SignInActivity)
}
override fun onError(throwable: Throwable) {
Log.e("LoginActivity", "Could not initialize player: " + throwable.message)
}
})
}
// Auth flow returned an error
AuthenticationResponse.Type.ERROR -> {
Log.i("LoginActivity", "ERROR!: $response.error")
}
AuthenticationResponse.Type.EMPTY -> {
Log.i("LoginActivity", "EMPTY!")
}
}
}
}
override fun onLoggedIn() {
Log.d("LoginActivity", "User logged in")
// This is the line that plays a song.
mPlayer!!.playUri(null, "spotify:track:2TpxZ7JUBn3uw46aR7qd6V", 0, 0)
}
}
and here's my AndroidManifest file
`
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".SignInActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<data
android:host="callback"
android:scheme="backdrop.io"/>
</intent-filter>
</activity>
<activity
android:name="com.spotify.sdk.android.authentication.LoginActivity"
android:theme="#android:style/Theme.Translucent.NoTitleBar"/>
</application>
I'm trying to get a Type.TOKEN from this
Had this exact same issue myself, the problem is with this line in onActivityResult():
val response = AuthenticationClient.getResponse(resultCode, intent)
data should be passed as the second argument instead of intent.
The reason this isn't a compiler error is due to Kotlin turning getters and setters into properties, intent is a call to the Activity method getIntent().