I am trying to create payment app which support the tap & pay functionality. I am already done with the Connecting App to NFC terminal with use of SELECT APDU Command.
Now, I want to send the stored card details from app to NFC Terminal, so it can make transaction.
Can you suggest me any kind of documents, which can help me to achieve it, such as how to send the details securely and in what kind of format it should be send?
any help would be appreciated.
here is the code
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nfcemulator">
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce"
android:required="true" />
<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.NFCEmulator">
<activity
android:name=".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=".service.HCEService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="#xml/apduservice" />
</service>
</application>
</manifest>
HCE Service
class HCEService: HostApduService() {
companion object {
val TAG = "Host Card Emulator"
val STATUS_SUCCESS = "9000"
val STATUS_FAILED = "6F00"
val CLA_NOT_SUPPORTED = "6E00"
val INS_NOT_SUPPORTED = "6D00"
val AID = "A0000002471001"
val SELECT_INS = "A4"
val DEFAULT_CLA = "00"
val MIN_APDU_LENGTH = 12
}
override fun onDeactivated(reason: Int) {
Log.d(TAG, "Deactivated: " + reason)
}
override fun processCommandApdu(commandApdu: ByteArray?, extras: Bundle?): ByteArray {
if (commandApdu == null) {
return Utils.hexStringToByteArray(STATUS_FAILED)
}
val hexCommandApdu = Utils.toHex(commandApdu)
if (hexCommandApdu.length < MIN_APDU_LENGTH) {
return Utils.hexStringToByteArray(STATUS_FAILED)
}
if (hexCommandApdu.substring(0, 2) != DEFAULT_CLA) {
return Utils.hexStringToByteArray(CLA_NOT_SUPPORTED)
}
if (hexCommandApdu.substring(2, 4) != SELECT_INS) {
return Utils.hexStringToByteArray(INS_NOT_SUPPORTED)
}
if (hexCommandApdu.substring(10, 24) == AID) {
return Utils.hexStringToByteArray(STATUS_SUCCESS)
} else {
return Utils.hexStringToByteArray(STATUS_FAILED)
}
}
}
apduservices.xml
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="#string/hce_service"
android:requireDeviceUnlock="false">
<aid-group android:description="#string/aid_groups"
android:category="other">
<aid-filter android:name="325041592E5359532E4444463031"/>
</aid-group>
</host-apdu-service>
Related
I'm stuck with the next issue.
I integrated PayPal sdk into my android app.
implementation 'com.paypal.checkout:android-sdk:0.6.1'
My app has an underscore in the package name so I have to use ‘App links’. I tested it in the test-app, all works fine like on the first screenschoot.
But in the main app when I successfully log in to a paypal account and redirect back to the app, the callback does not trigger.
I also figured out if I press on close button, callback yes triggers.
Also when I returns to the app I receive Intent like this:
app.mobile.main.app.name://paypalpay?code=C21AALAqib-oCkJXmgsoDPPbpAiYza7KJgVoA_01gzzYtawIsgofw0PmCpr186xkz1OY6tSQ....
Please write if you have any suggestions.
Thanks and have a nice day.
Here snippets of Manifest file and PayPalFragment.
Android Manifest:
<?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.mobile.main_app.name">
<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"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera" />
<application
android:name=".MyApplication"
android:allowBackup="false"
android:hardwareAccelerated="true"
android:icon="#mipmap/logo"
android:label="#string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="#mipmap/logo"
android:supportsRtl="true"
android:theme="#style/MaterialTheme"
android:usesCleartextTraffic="true"
tools:replace="android:allowBackup">
<activity
android:name=".Ux.Activities.MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:excludeFromRecents="true"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden|adjustResize">
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="paypalpay"
android:scheme="app.mobile.main.app.name" />
</intent-filter>
</activity>
</application>
</manifest>
PayPalFragment.kt
class PayPalFragment : Fragment() {
override fun onAttach(context: Context) {
super.onAttach(context)
PayPalCheckout.registerCallbacks(
onApprove = OnApprove { approval ->
approval.orderActions.capture { captureOrderResult ->
Log.i("tester", "OnApprove called.")
}
},
onCancel = OnCancel {
Log.i("tester", "OnCancel called.")
},
onError = OnError { errorInfo ->
Log.i("tester", "onError called.")
},
onShippingChange = OnShippingChange { shippingChangeData, shippingChangeActions ->
Log.i("tester", "onShippingChange called.")
}
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val fragView = inflater.inflate(R.layout.fragment_pay_pal, container, false)
val payPalButton = fragView.findViewById<Button>(R.id.paypal_button)
payPalButton.setOnClickListener {
PayPalCheckout.startCheckout(
CreateOrder { createOrderActions ->
val order = Order(
intent = OrderIntent.CAPTURE,
appContext = AppContext(
userAction = UserAction.PAY_NOW
),
purchaseUnitList = listOf(
PurchaseUnit(
amount = Amount(
currencyCode = CurrencyCode.USD,
value = "10.00"
)
)
)
)
createOrderActions.create(order)
}
)
}
return fragView
}
}
So solution is to add default PayPal activity to AndroidManifest.xml
You just copy the code below and change YOUR-CUSTOM-SCHEME to what you declared in ReturnUrl in the PayPal developer account.
No need to create this activity, it comes with the PayPal SDK.
It will redirect you back into your app and trigger a PayPal payment sheet.
After the user has completed or canceled the payment, the corresponding callback will be called.
<activity
android:name="com.paypal.openid.RedirectUriReceiverActivity"
android:excludeFromRecents="true"
android:theme="#style/PYPLAppTheme">
<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:host="paypalpay"
android:scheme="YOUR-CUSTOM-SCHEME" />
</intent-filter>
</activity>
I want to show an AlertDialog when the Firebase cloud message received (and either the Android application is foreground or background).
In forground, the app shows the AlertDialog, but in background, the app doesn't show the AlertDialog.
MyFirebaseMessageService.kt
class MyFirebaseMessageService : FirebaseMessagingService() {
private val TAG = "fcm_tag"
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val title = remoteMessage.notification?.title
val body = remoteMessage.notification?.body
Log.d(TAG, "fcm title: $title")
Log.d(TAG, "fcm body: $body")
val alertDialogIntent = Intent(baseContext, AlertDialogActivity::class.java)
alertDialogIntent.putExtra("title", title)
alertDialogIntent.putExtra("body", body)
try {
PendingIntent.getActivity(
baseContext,
0,
alertDialogIntent,
PendingIntent.FLAG_IMMUTABLE
).send()
} catch (e: Exception) {
Log.d(TAG, "fcm error: $e")
}
}
}
AlertDialogActivity.kt
class AlertDialogActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bund = intent.extras
val title = bund?.getString("title")
val body = bund?.getString("body")
AlertDialog.Builder(this).run {
setTitle(title)
setMessage(body)
setPositiveButton("OK") { _, _ ->
finish()
}
setCancelable(false)
show()
}
}
}
AndroidManifest.xml
<?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="com.myproject">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<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.MyProject">
<service
android:name=".MyFirebaseMessageService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<activity
android:name=".AlertDialogActivity"
android:exported="true"
android:theme="#style/Theme.AppCompat.DayNight.Dialog">
</activity>
<activity
android:name=".MainActivity"
android:exported="true"
android:label="#string/app_name"
android:theme="#style/Theme.MyProject">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="fcm_default_channel" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_launcher_foreground" />
</application>
</manifest>
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("Title")
.setMessage("Are you sure?")
.create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alertDialog.show();
And ask for this permission
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
I've been working on the app where I need to implement tap & pay. I am able to connect the HCE service with NFC terminal.
Now my question is what are the next steps, for making actual payment with it?
I've searched everywhere but I could not find a decent document for it. Please help me.
Below is the code I have written to connect HCE service to NFC terminal.
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nfcemulator">
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce"
android:required="true" />
<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.NFCEmulator">
<activity
android:name=".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=".service.HCEService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="#xml/apduservice" />
</service>
</application>
</manifest>
HCE Service
class HCEService: HostApduService() {
companion object {
val TAG = "Host Card Emulator"
val STATUS_SUCCESS = "9000"
val STATUS_FAILED = "6F00"
val CLA_NOT_SUPPORTED = "6E00"
val INS_NOT_SUPPORTED = "6D00"
val AID = "A0000002471001"
val SELECT_INS = "A4"
val DEFAULT_CLA = "00"
val MIN_APDU_LENGTH = 12
}
override fun onDeactivated(reason: Int) {
Log.d(TAG, "Deactivated: " + reason)
}
override fun processCommandApdu(commandApdu: ByteArray?, extras: Bundle?): ByteArray {
if (commandApdu == null) {
return Utils.hexStringToByteArray(STATUS_FAILED)
}
val hexCommandApdu = Utils.toHex(commandApdu)
if (hexCommandApdu.length < MIN_APDU_LENGTH) {
return Utils.hexStringToByteArray(STATUS_FAILED)
}
if (hexCommandApdu.substring(0, 2) != DEFAULT_CLA) {
return Utils.hexStringToByteArray(CLA_NOT_SUPPORTED)
}
if (hexCommandApdu.substring(2, 4) != SELECT_INS) {
return Utils.hexStringToByteArray(INS_NOT_SUPPORTED)
}
if (hexCommandApdu.substring(10, 24) == AID) {
return Utils.hexStringToByteArray(STATUS_SUCCESS)
} else {
return Utils.hexStringToByteArray(STATUS_FAILED)
}
}
}
apduservices.xml
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="#string/hce_service"
android:requireDeviceUnlock="false">
<aid-group android:description="#string/aid_groups"
android:category="other">
<aid-filter android:name="325041592E5359532E4444463031"/>
</aid-group>
</host-apdu-service>
I think you have approached this feature at a low level, which is unnecessary given that this functionality is offered when using Google Pay (it supports NFC payments as well as online purchases).
All you need to know about Google Pay if you’re a developer
The Flutter pay plugin is the quickest method to add payment capabilities for your Android app.
Google Pay introduces a Flutter plugin for payments
Pay plugin 1.0.6
I am trying to start my service when the user wants the service to start on boot. So I have a checkbox preference on my settings fragment to control it. When the box is checked and the user starts the service, the StartOnBootBroadcast BroadcastReceiver will be registered and it will start the service after boot is completed. By default the BroadcastReceiver will not be registered unless the user wants it. But the problem is If I install the app and restarts my device, the broadcast receiver starts the service (BUT I NEVER REGISTERED IT). I've checked the condition with debugger and the conditions never met for starting the receiver.
Broadcast receiver:
class StartOnBootBroadcast : BroadcastReceiver() {
companion object {
private var instance: StartOnBootBroadcast? = null
fun getinstance(): StartOnBootBroadcast {
if (instance == null) {
instance = StartOnBootBroadcast()
}
return instance as StartOnBootBroadcast
}
}
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("BOOTCAST", "onReceive: FIRED")
val serviceIntent = Intent(context, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context!!.startForegroundService(serviceIntent)
} else {
context!!.startService(serviceIntent)
}
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sourav.bettere">
<application
android:name=".App"
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=".activities.MainActivity"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".service.ChargeLoggerService" />
<receiver android:name=".broadcasts.BatteryBroadcast">
<intent-filter>
<action android:name="android.intent.action.BATTERY_CHANGED" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
<receiver android:name=".broadcasts.ChargingBroadcast">
<intent-filter>
<action android:name="android.intent.action.BATTERY_CHANGED" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
<receiver android:name=".broadcasts.StartOnBootBroadcast">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<meta-data
android:name="preloaded_fonts"
android:resource="#array/preloaded_fonts" />
</application>
</manifest>
Methods for registering / unregistering the BroadcastReciever:
prefViewmodel.getBootStatus.observe(viewLifecycleOwner, Observer { value ->
onBoot = value
if (Utilities.getInstance(mContext).isMyServiceRunning(ChargeLoggerService::class.java)){
startOnBoot(onBoot)
}
})
////unrelated codes
switch.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
startService()
Utilities.getInstance(mContext)
.writeToPref(
Constants.PREF_TYPE_BOOL,
Constants.PREF_LOGGER_ACTIVE,
valueBool = true
)
} else {
stopService()
Utilities.getInstance(mContext)
.writeToPref(
Constants.PREF_TYPE_BOOL,
Constants.PREF_LOGGER_ACTIVE,
valueBool = false
)
}
startOnBoot(onBoot)
}
private fun startOnBoot(value: Boolean){
when(value){
true -> Utilities.getInstance(mContext).loadBroadcastReceiver(startOnBoot, IntentFilter(Intent.ACTION_BOOT_COMPLETED))
false -> {
try {
requireContext().unregisterReceiver(startOnBoot)
}catch (e:Exception){
e.printStackTrace()
}}
}
Log.d(TAG, "startOnBoot: $value")
}
Using this manual http://www.techotopia.com/index.php/Kotlin_Android_Broadcast_Intents_and_Broadcast_Receivers#.EF.BB.BFSummary I have implemented BroadcastReceiver in Kotlin so I expect that after rebooting application will start but it does not.
Please, help. Thank you!
BroadcastReceiver
class BroadcastReceiverOnBootComplete : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action.equals(Intent.ACTION_BOOT_COMPLETED, ignoreCase = true)) {
val message = "Broadcast intent detected " + intent.action
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
}
}
}
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="com.simplemobiletools.applauncher"
android:installLocation="internalOnly">
<uses-permission
android:name="android.permission.USE_FINGERPRINT"
tools:node="remove"/>
<permission
android:name="com.simplemobiletools.applauncher.permission.INSTALL_SHORTCUT"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="dangerous"
android:label="#string/permlab_install_shortcut"
android:description="#string/permdesc_install_shortcut" />
<permission
android:name="com.simplemobiletools.applauncher.permission.READ_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"
android:label="#string/permlab_read_settings"
android:description="#string/permdesc_read_settings"/>
<permission
android:name="com.simplemobiletools.applauncher.permission.WRITE_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signatureOrSystem"
android:label="#string/permlab_write_settings"
android:description="#string/permdesc_write_settings"/>
<permission
android:name="com.simplemobiletools.applauncher.permission.RECEIVE_LAUNCH_BROADCASTS"
android:protectionLevel="signature"
/>
<permission
android:name="com.simplemobiletools.applauncher.permission.RECEIVE_FIRST_LOAD_BROADCAST"
android:protectionLevel="signatureOrSystem" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
<uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
<uses-permission android:name="com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS" />
<uses-permission android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST" />
<application
android:name=".App"
android:hardwareAccelerated="true"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_launcher_name"
android:roundIcon="#mipmap/ic_launcher"
android:theme="#style/AppTheme"
android:supportsRtl="true"
android:restoreAnyVersion="true">
<receiver android:name=".activities.BroadcastReceiverOnBootComplete">
<intent-filter>
<action android:name="com.simplemobiletools.applauncher.sendbroadcast" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
<activity
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="nosensor"
android:resumeWhilePausing="true"
android:taskAffinity=""
android:enabled="true"
android:name=".activities.SplashActivity"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
</intent-filter>
</activity>
<activity android:name=".activities.MainActivity"/>
<activity
android:name=".activities.SettingsActivity"
android:label="#string/settings"
android:parentActivityName=".activities.MainActivity"/>
<activity
android:name="com.simplemobiletools.commons.activities.AboutActivity"
android:label="#string/about"
android:parentActivityName=".activities.MainActivity"/>
<activity
android:name="com.simplemobiletools.commons.activities.LicenseActivity"
android:label="#string/third_party_licences"
android:parentActivityName="com.simplemobiletools.commons.activities.AboutActivity"/>
<activity
android:name="com.simplemobiletools.commons.activities.CustomizationActivity"
android:label="#string/customize_colors"
android:parentActivityName=".activities.SettingsActivity"/>
</application>
</manifest>
MainActivity with BroadcastReceiver
class MainActivity : SimpleActivity(), RefreshRecyclerViewListener {
private var launchers = ArrayList<AppLauncher>()
private var mStoredPrimaryColor = 0
private var mStoredTextColor = 0
private var mStoredUseEnglish = false
private var receiver: BroadcastReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
appLaunched()
setupLaunchers()
checkWhatsNewDialog()
storeStateVariables()
configureReceiver()
fab.setOnClickListener {
AddAppLauncherDialog(this, launchers) {
setupLaunchers()
}
}
}
override fun onDestroy() {
// super.onDestroy()
unregisterReceiver(receiver)
}
override fun onResume() {
super.onResume()
if (mStoredUseEnglish != config.useEnglish) {
restartActivity()
return
}
if (mStoredTextColor != config.textColor) {
getGridAdapter()?.updateTextColor(config.textColor)
}
if (mStoredPrimaryColor != config.primaryColor) {
getGridAdapter()?.updatePrimaryColor(config.primaryColor)
}
updateTextColors(coordinator_layout)
}
override fun onPause() {
super.onPause()
storeStateVariables()
}
private fun configureReceiver() {
val filter = IntentFilter()
filter.addAction("com.simplemobiletools.applauncher.sendbroadcast")
filter.addAction("android.intent.action.ACTION_POWER_DISCONNECTED")
filter.addAction("android.intent.action.BOOT_COMPLETED")
receiver = BroadcastReceiverOnBootComplete()
registerReceiver(receiver, filter)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.settings -> launchSettings()
R.id.about -> launchAbout()
else -> return super.onOptionsItemSelected(item)
}
return true
}
private fun launchSettings() {
startActivity(Intent(applicationContext, SettingsActivity::class.java))
}
private fun launchAbout() {
startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_MULTISELECT or LICENSE_STETHO, BuildConfig.VERSION_NAME)
}
private fun getGridAdapter() = launchers_grid.adapter as? LaunchersAdapter
private fun setupLaunchers() {
launchers = dbHelper.getLaunchers()
checkInvalidApps()
val adapter = LaunchersAdapter(this, launchers, this, launchers_grid) {
val launchIntent = packageManager.getLaunchIntentForPackage((it as AppLauncher).packageName)
if (launchIntent != null) {
startActivity(launchIntent)
finish()
} else {
val url = "https://play.google.com/store/apps/details?id=${it.packageName}"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
}
}
adapter.setupDragListener(true)
launchers_grid.adapter = adapter
}
private fun checkInvalidApps() {
val invalidIds = ArrayList<String>()
for ((id, name, packageName) in launchers) {
val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
if (launchIntent == null && !packageName.isAPredefinedApp()) {
invalidIds.add(id.toString())
}
}
dbHelper.deleteLaunchers(invalidIds)
launchers = launchers.filter { !invalidIds.contains(it.id.toString()) } as ArrayList<AppLauncher>
}
private fun storeStateVariables() {
config.apply {
mStoredPrimaryColor = primaryColor
mStoredTextColor = textColor
mStoredUseEnglish = useEnglish
}
}
override fun refreshItems() {
setupLaunchers()
}
private fun checkWhatsNewDialog() {
arrayListOf<Release>().apply {
add(Release(7, R.string.release_7))
checkWhatsNew(this, BuildConfig.VERSION_CODE)
}
}
}
As I could discoverd the prob;em was missing settings here
android:enabled="true"
android:stopWithTask="false"
So it should be like
<receiver android:name=".activities.BroadcastReceiverOnBootComplete" android:enabled="true"
android:stopWithTask="false" >
<intent-filter>
<action android:name="com.simplemobiletools.applauncher.sendbroadcast" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>