I’m having some trouble getting Google Assistant to play media for my media app.
I have verified using the Media Controller Tester app that the play actions are working. I am able to use Open Feature Actions with Assistant.
But every time I try to use phrases like Play AppName or Play Station on AppName, Assistant tries to launch TuneIn.
If I try Play music on AppName Assistant launches YouTube Music .
I have tried everything in the docs here and have used UAMP as a base (of which I am also seeing similar behaviour)
Here is a cut down version of my audio service:
class AudioService : MediaBrowserServiceCompat() {
#Inject
lateinit var audioServiceBrowserManager: AudioServiceBrowserManager
#Inject
lateinit var schedulerProvider: RxSchedulerProvider
#Inject
lateinit var playbackPreparer: AppPlaybackPreparer
#Inject
lateinit var playbackControlDispatcher: AppControlDispatcher
#Inject
lateinit var audioProvider: AudioProvider
#Inject
lateinit var playbackManager: PlaybackManager
#Inject
lateinit var mediaSessionChangedCallback: MediaSessionChangedCallback
private lateinit var mediaSession: MediaSessionCompat
private lateinit var mediaSessionConnector: MediaSessionConnector
private lateinit var mediaController: MediaControllerCompat
private lateinit var audioNotificationManager: AudioNotificationManager
private lateinit var packageValidator: PackageValidator
private val disposables = CompositeDisposable()
companion object {
private const val SEEK_BACKWARD_INCREMENT = 15000
private const val SEEK_FORWARD_INCREMENT = 30000
private const val MEDIA_SESSION_TAG: String = "AudioService"
internal const val METADATA_MEDIA_TYPE = "au.net.app.player.service.metadata.mediaType"
internal const val METADATA_MEDIA_TYPE_ONDEMAND_VIDEO = 0L
internal const val METADATA_MEDIA_TYPE_ONDEMAND_AUDIO = 2L
internal const val METADATA_MEDIA_TYPE_LIVE = 1L
val DEFAULT_PLAYBACK_STATE: PlaybackStateCompat = PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_NONE, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 1.0f)
.build()
}
override fun onCreate() {
AndroidInjection.inject(this)
super.onCreate()
mediaSession = MediaSessionCompat(this, MEDIA_SESSION_TAG).apply {
setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
isActive = true
}
sessionToken = mediaSession.sessionToken
mediaSessionConnector = MediaSessionConnector(mediaSession).apply {
setRewindIncrementMs(SEEK_BACKWARD_INCREMENT)
setFastForwardIncrementMs(SEEK_FORWARD_INCREMENT)
setPlaybackPreparer(playbackPreparer)
setQueueNavigator(AppQueueNavigator(mediaSession, audioProvider, this#AudioService, this))
setControlDispatcher(playbackControlDispatcher)
setPlayer(playbackManager.currentPlayback.playerImpl)
registerCustomCommandReceiver(playbackManager.mediaSessionCommandReceiver)
}
disposables.add(
playbackManager.currentPlaybackObservable.subscribe { currentPlayback ->
mediaSessionConnector.setPlayer(currentPlayback.playerImpl)
}
)
mediaController = MediaControllerCompat(this, mediaSession)
mediaController.registerCallback(mediaSessionChangedCallback)
try {
audioNotificationManager = AudioNotificationManager(this, mediaController)
} catch (e: RemoteException) {
throw IllegalStateException("Could not create a MediaNotificationManager", e)
}
packageValidator = PackageValidator(this, R.xml.allowed_media_browser_callers)
}
private var currentLoadChildrenDisposable: Disposable? = null
override fun onLoadChildren(parentId: String, result: Result<MutableList<MediaBrowserCompat.MediaItem>>) {
Timber.d("""
onLoadChildren(
parentId = $parentId,
result = $result
)
""".trimIndent())
}
override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot? {
Timber.d("""
onGetRoot(
clientPackageName = $clientPackageName,
clientUid = $clientUid,
rootHints = $rootHints
)
""".trimIndent())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
return START_STICKY
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
playbackManager.handleStop()
stopSelf()
}
override fun onDestroy() {
super.onDestroy()
playbackManager.handleStop()
disposables.dispose()
mediaSession.isActive = false
mediaSession.release()
}
}
The module manifest (note - the service is not in my main app module)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="au.net.app.player.service">
<uses-permission android:name="android.permission.INTERNET" />
<application>
<service
android:name="au.net.app.player.service.AudioService"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="#xml/automotive_app_desc" />
</application>
</manifest>
In the main app manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="au.net.app"
android:installLocation="auto">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:name=".AppApplication"
android:allowBackup="true"
android:label="#string/app_name"
android:icon="#mipmap/ic_launcher"
android:networkSecurityConfig="#xml/network_security_config"
android:supportsRtl="true"
android:hardwareAccelerated="true"
android:theme="#style/AppTheme">
<activity
android:name=".mainscreen.MainActivity"
android:launchMode="singleTask"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Intent filters to open Feature screens -->
<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="feature"
android:pathPattern="/.*"
android:scheme="${APP_SCHEME}" />
</intent-filter>
<!-- Declares that the app handles SEARCH intent for media playback -->
<!-- This is mandatory for Android Auto support: -->
<!-- https://stackoverflow.com/questions/31953155/android-auto-voice-cannot-perform-play-x-on-y/31976075#31976075 -->
<intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Required for Google Assistant integration -->
<meta-data android:name="com.google.android.actions" android:resource="#xml/actions" />
</application>
</manifest>
I have also tried setting up my playback state with:
val DEFAULT_PLAYBACK_STATE: PlaybackStateCompat = PlaybackStateCompat.Builder()
.setActions(getSupportedActions())
.setState(PlaybackStateCompat.STATE_NONE, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 1.0f)
.build()
private fun getSupportedActions(): Long {
return PlaybackStateCompat.ACTION_PLAY or
PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH or
PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
PlaybackStateCompat.ACTION_PLAY_PAUSE
}
But my understanding is I shouldn't need to as MediaSessionConnector should take care of that (since I am using ExoPlayer). Adding this does not help.
Related
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 have 2 app and i want app A share data with B by content provider, i can access content provider in app A but not in app B.I feel like my permission mess up but idk how to fixe it.
Heres my file...
App A's manifest file:
<permission android:name="myper.READ" android:protectionLevel="normal" />
<permission android:name="myper.WRITE" android:protectionLevel="normal" />
<application
android:name=".ui.MyApplication"
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.Ex">
<activity android:name="com.abcd.aaaaa.ui.MainActivity"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:authorities="com.advance.usercontentprovider"
android:name=".contentprovider.UserContentProvider"
android:enabled="true"
android:exported="true"
android:multiprocess="true"
android:readPermission="myper.READ"
android:writePermission="myper.WRITE"
/>
</application>
and B's manifest file:
<uses-permission android:name="myper.READ" />
<uses-permission android:name="myper.WRITE" />
<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.aaaa">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Custom Content Provider:
val PROVIDER_NAME = "com.advance.usercontentprovider"
val URL = "content://$PROVIDER_NAME/users"
val CONTENT_URI = Uri.parse(URL)
override fun onCreate(): Boolean {
return true
}
val URI_ALL_ITEMS_CODE = 1
val URI_ONE_ITEM_CODE = 2
var uriMatcher: UriMatcher? = null
init
{
uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
uriMatcher!!.addURI(PROVIDER_NAME, "users", URI_ALL_ITEMS_CODE)
uriMatcher!!.addURI(PROVIDER_NAME, "users" + "/#", URI_ONE_ITEM_CODE)
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? {
/// do smt
}
override fun getType(uri: Uri): String? {
// do smt
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
// do smt
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
// do smt
}
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<out String>?
): Int {
// do smt
}
and every time i call this in app B
val cursor = contentResolver?.query(
Uri.parse("content://com.advance.usercontentprovider/users")
, null, null, null, null)
cursor always null.
Ive tried all the solutions that i found but nothing work.Help :"<
I realize that im using android 11 and they limit the package visibility so just need to add
<queries>
<provider
android:authorities="com.advance.usercontentprovider" />
</queries>
in app B's manifest (not in application tag) file so B can see your custom content provider of A
I use Google OAuth to let users sign in to the android app via Google account. When the user taps the Google login button it immediately crashes with information that
A required meta-data tag in your app's AndroidManifest.xml does not exist. You must have the following declaration within the <application> element: <meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
doesn't exists in AndroidManifest when it does. google_play_services_versions value is 12451000, hardcoding it doesn't changes anything
Stacktrace
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mateuszsiedlecki.whatsthere, PID: 578
java.lang.IllegalStateException: A required meta-data tag in your app's AndroidManifest.xml does not exist. You must have the following declaration within the <application> element: <meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
at com.google.android.gms.common.GooglePlayServicesUtilLight.isGooglePlayServicesAvailable(com.google.android.gms:play-services-basement##17.1.1:17)
at com.google.android.gms.common.GoogleApiAvailabilityLight.isGooglePlayServicesAvailable(com.google.android.gms:play-services-basement##17.1.1:5)
at com.google.android.gms.common.GoogleApiAvailability.isGooglePlayServicesAvailable(com.google.android.gms:play-services-base##17.1.0:96)
at com.google.android.gms.auth.api.signin.GoogleSignInClient.zzg(com.google.android.gms:play-services-auth##18.0.0:9)
at com.google.android.gms.auth.api.signin.GoogleSignInClient.getSignInIntent(com.google.android.gms:play-services-auth##18.0.0:18)
at com.mateuszsiedlecki.whatsthere.login.SocialLoginFragment.googleSignIn(SocialLoginFragment.kt:101)
at com.mateuszsiedlecki.whatsthere.login.SocialLoginFragment.access$googleSignIn(SocialLoginFragment.kt:24)
at com.mateuszsiedlecki.whatsthere.login.SocialLoginFragment$onViewCreated$2.onClick(SocialLoginFragment.kt:70)
at android.view.View.performClick(View.java:7161)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:967)
at android.view.View.performClickInternal(View.java:7133)
at android.view.View.access$3500(View.java:804)
at android.view.View$PerformClick.run(View.java:27416)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:241)
at android.app.ActivityThread.main(ActivityThread.java:7604)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
Code
class SocialLoginFragment : Fragment() {
val gso: GoogleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestProfile()
.requestId()
.build()
private val facebookRequestedData = "id,first_name,last_name,email,picture,name"
private var fbCallbackManager: CallbackManager = CallbackManager.Factory.create()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_social_login, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
FacebookSdk.sdkInitialize(this.context)
LoginManager.getInstance().registerCallback(
fbCallbackManager,
object : FacebookCallback<LoginResult?> {
override fun onSuccess(loginResult: LoginResult?) {
Log.d("login", "Facebook Login")
val fbUser = getFbUserData(loginResult!!.accessToken)
UserDataManager.user = fbUser
loginFinished()
}
override fun onCancel() {
Log.d("login", "Facebook Login Cancel")
}
override fun onError(exception: FacebookException) {
Log.d("login", "Facebook Login error")
}
}
)
val googleLoginButton = getView()?.findViewById<Button>(R.id.googleLogin)
googleLoginButton?.setOnClickListener {
googleSignIn()
}
val facebookLoginButton = getView()?.findViewById<Button>(R.id.facebookLogin)
facebookLoginButton?.setOnClickListener {
LoginManager.getInstance().logInWithReadPermissions(
this,
listOf("public_profile", "email")
)
}
val emailLoginButton = getView()?.findViewById<Button>(R.id.emailLogin)
emailLoginButton?.setOnClickListener {
val intent = Intent(this.context, EmailLoginActivity::class.java)
startActivity(intent)
}
val noLogin: Button = getView()?.findViewById<Button>(R.id.noLogin) as Button
noLogin.setOnClickListener {
(activity as LoginActivity?)?.openEmailFragment()
}
}
private fun googleSignIn() {
val mGoogleSignInClient: GoogleSignInClient = GoogleSignIn.getClient(
this.context!!,
gso
)
val signInIntent: Intent = mGoogleSignInClient.signInIntent // crashing here
startActivityForResult(signInIntent, 1)
}
...
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mateuszsiedlecki.whatsthere">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity android:name=".EmailLoginActivity" />
<activity
android:name=".osmMapsActivity"
android:label="#string/title_activity_maps" />
<activity android:name=".login.LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="#string/facebook_app_id" />
<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>
</manifest>
I have an app that, when is first installed a splash screen appears and then a intro with 3 fragments appears and explains how the app works. However once the user walked through that "intro" only the splash screen appears. How should I do that? I belive this has to do my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.pfinal">
<!-- Permissoes para o acesso a camera -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Permissoes para o acesso ao GPS -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_fire_round"
android:label="AppFogos"
android:roundIcon="#mipmap/ic_fire_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".Intro">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- The below is for the splash screen and we need no action bar and the default theme -->
<activity
android:name=".SplashScreen"
android:theme="#style/AppTheme.NoActionBar">
<!-- <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>-->
</activity>
<activity android:name=".AppFogos" />
<activity android:name=".HomePage">
<!-- <intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>-->
</activity>
</application>
Intro is the activity with the walktrough and SplashScreen is the activity with the splash screen.
Right now, only the Intro appears.
Here is the code for the "Intro":
val fragment1 = SliderFragment()
val fragment2 = SliderFragment()
val fragment3 = SliderFragment()
lateinit var adapter : myPagerAdapter
lateinit var activity: Activity
lateinit var preference : SharedPreferences
val pref_show_intro = "Intro"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_intro)
activity = this
preference = getSharedPreferences("~PFinal", Context.MODE_PRIVATE)
if(!preference.getBoolean(pref_show_intro,true)){
startActivity(Intent(activity,SplashScreen::class.java))
finish()
}
fragment1.setTitle("welcome")
fragment2.setTitle("fogos")
fragment3.setTitle("o que utilizamos")
adapter = myPagerAdapter(supportFragmentManager)
adapter.list.add(fragment1)
adapter.list.add(fragment2)
adapter.list.add(fragment3)
view_pager.adapter = adapter
next.setOnClickListener {
view_pager.currentItem++
}
skip.setOnClickListener { goToHomePage() }
view_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
}
override fun onPageSelected(position: Int) {
if(position == adapter.list.size-1)
{
//lastpage
next.text="DONE"
next.setOnClickListener {
goToHomePage()
}
}else{
next.text="NEXT"
next.setOnClickListener {
view_pager.currentItem++
}
}
when(view_pager.currentItem)
{
0->{
indicator1.setTextColor(Color.BLACK)
indicator2.setTextColor(Color.GRAY)
indicator3.setTextColor(Color.GRAY)
}
1->{
indicator1.setTextColor(Color.GRAY)
indicator2.setTextColor(Color.BLACK)
indicator3.setTextColor(Color.GRAY)
}
2->{
indicator1.setTextColor(Color.GRAY)
indicator2.setTextColor(Color.GRAY)
indicator3.setTextColor(Color.BLACK)
}
}
}
})
}
fun goToHomePage(){
startActivity(Intent(activity,HomePage::class.java))
finish()
val editor = preference.edit()
editor.putBoolean(pref_show_intro,false)
editor.apply()
}
class myPagerAdapter(manager : FragmentManager): FragmentPagerAdapter(manager){
val list : MutableList<Fragment> = ArrayList()
override fun getItem(position: Int): Fragment {
return list[position]
}
override fun getCount(): Int {
return list.size
}
}
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>