Kotlin: Start an activity from a thread - kotlin

I try to program an kids-launcher.
I search for my problem three days but I do not find a solution (I am a beginner in android/kotlin)
I want to start an app and after a while (when the time for the kids is elapsed) I want to come back to my launcher
I wrote the function
fun openApp(context: Context, packageName: String?) {
context.startActivity(context.packageManager.getLaunchIntentForPackage(packageName!!))
}
I started an app and after a while (when the time for the kids is elapsed) I want to come back to my launcher
openApp(this, packageName)
timer.schedule(10000) {
openApp(this, "PackageNameMyLauncher")
}
But it does not work.
when I write "openApp(applicationContext, packageName)" instead, than it works a little bit. But when the app is closed and I press the home button than it won´t work.
I think I didn´t understand some fundamental at the moment.
In the thread there is no context
I also tried to run a pendingIntent with an alarmManager
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val mPendingIntent = PendingIntent.getActivity(
this,
123456, //PendingIntentId,
intent,
PendingIntent.FLAG_CANCEL_CURRENT
)
val mgr = this.getSystemService(Context.ALARM_SERVICE) as AlarmManager
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, mPendingIntent)
System.exit(0) //finish()
but that is also not working

I know it is not an answer, but when I was a beginner what I lacked was some kind of upper-level design ideas
I don't think Android provides the ability to schedule app opening without user's intention. And also your timer will be destroyed when you will remove application from processes.
I think your best bet will be to design app that way, that it will be unavailable till some time will elapse. You can save the last timestamp when the app became unavailable on the backend or in shared preferences and later on you can compare it with current timestamp, which you will get each time you open the app. If the
currentTimeStamp - savedTimeStamp >= timeLimit you will make further logic of your app available, otherwise you will display some kind of a message.

Related

[JETPACK COMPOSE]: is there a way to restart whole app programmatically?

I need a way to make my app close and opens again. Or just restart everything inside of it.
Since the issue with my app can be fixed by closing app and opening again (When creating user the loading function to firebase the collection inside user document does not load for some reason)
Below code can do it:
val context = LocalContext.current
val packageManager: PackageManager = context.packageManager
val intent: Intent = packageManager.getLaunchIntentForPackage(context.packageName)!!
val componentName: ComponentName = intent.component!!
val restartIntent: Intent = Intent.makeRestartActivityTask(componentName)
context.startActivity(restartIntent)
Runtime.getRuntime().exit(0)
So... you could write ways to "restart everything", but I am going to strongly suggest not doing that. When building an app, you will run into edge cases. You will hit some failure states that you can't recover from. That happens. But, solving these cases by just "restarting" doesn't actually address the issue and will probably result in wonky and undesirable UX.
I would instead suggest you post here some steps to reproduce and debugging results.
Under what circumstance/flow does this document stop loading?
When it does happen, can you capture the call to Firebase where it is trying to load the document?
If so, what does that call look like?
Is it looking for the document in the correct place?
Can you show an example of the call when it fails and also what the database hierarchy looks like?
Can you show us a snippet of code where this is failing?
Without more information, this sounds more like a race condition - you might be trying to find the document before it is actually created and not handling the error path for when the document is not found. However, we would need to do some debugging to verify.

After getting the permission soft keyboard does not show up for the first time

I read all the similar questions but nothing useful in my case..
I have an activity which shows soft keyboard automatically when it is started.
It's working fluently with no error. But the issue is I need to use permissions for this activity so when the first time activity is executed and permission is asked (then granted), softkeyboard does not show up no matter what (I even need to press edittext 2-3 times for it to load)
I can fix it with recreate() method obviously because it will be necessary only for one time but you know screen refreshing lag makes the application quality lower. Do you have any suggestion please? Thanks
I figured out a way, and though it might not be helpful in your particular scenario, might help someone else. You can set windowSoftInputMode as stateAlwaysVisible for the activity in which you wish to see the keyboard after accpeting/denying permissions, and it will pop up automatically.
I encountered this problem when I was using the Dexter library, and I assume you are using it too.
Solution for those who use the Dexter library: you must call token.continue Permission Request(); in the onPermissionRationaleShouldBeShown event of your PermissionListener.
Dexter.withContext(activity)
.withPermissions(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
.withListener(new MultiplePermissionsListener() {
#SuppressLint("MissingPermission")
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
token.continuePermissionRequest();
}
})
.check();

Push notification click using TaskStackBuilder

I'm setting an activity, Receiver, as the content intent for a notification.
Intent clickIntent = new Intent(context, Receiver.class);
mBuilder.setContentIntent(PendingIntent.getActivity(context, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT));
Inside Receiver Activity, I'm starting activities which are intended to be opened using TaskStackBuilder in the following way.
Intent intent = new Intent(this, Class.forName(className));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
TaskStackBuilder.create(this).addParentStack(Class.forName(className)).addNextIntent(intent).startActivities();
When the app is in the background and a notification click happens, it resumes the ParentActivity. Especially when device goes to idle and comes back. Any help? I'm cracking my head on this.
For an Android app, you should also declare android:launchMode in your androidManifest.xml file.
As discussed in the Android documentation:
An instruction on how the activity should be launched. There are four modes that work in conjunction with activity flags (FLAG_ACTIVITY_* constants) in Intent objects to determine what should happen when the activity is called upon to handle an intent.
They are:
"standard"
"singleTop"
"singleTask"
"singleInstance"
The default mode is "standard".
Solution given in this SO post - resuming an activity from a notification might also help.

MediaPlayer issues - audio file only plays back once

I'm trying to implement a basic MediaPlayer in an app, and have the button change states depending on whether the clip is playing, playback is completed, or playback is manually interrupted (by pressing the same button).
With the code below, I get the following results:
On first load, the audio plays back fine.
If I press the ImageButton a second time during playback, the playback stops. When I press it again, the playback resumes from the timestamp in which it was stopped (I thought this was strange behaviour more typical of a "pause()".
Once the playback is completed, the button change works perfectly, however I can not replay the audio file a second time. When I press start, it starts playing back, then immediately transitions to playbackcompleted, without actually playing the audio.
I've been scouring through other posts / google / android documentation, but haven't found a solution as yet.
I have also tried so far:
setLooping(true); - this had no effect at all, other than the setOnCompletionListener never being reached. The audio did not replay at all.
In the onCompletion method, setting the seekTo() to several different values (0, 100), and using log messages including the "getCurrentPosition()" to confirm it was actually doing it, but even when this confirms that it's starting from position 0, or 100, the result is still the same (no audio is heard and completion occurs immediately).
In the onCompletion method, several combinations of calling "stop()", "prepareAsync()" or even prepare(). The results were the same, however on subsequent attempts (i.e. attempt 2, 3, etc) to playback, when the onCompletion method was called, I started getting various errors for calling stop() / prepare() methods in the incorrect state.
final ImageButton pauseButton = (ImageButton) rootView.findViewById(R.id.playButton1);
final MediaPlayer mediaPlayer = MediaPlayer.create(getActivity().getApplicationContext(), R.raw.ch01_01);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
pauseButton.setImageResource(R.drawable.play_button);
}
});
pauseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.prepareAsync();
pauseButton.setImageResource(R.drawable.play_button);
} else {
mediaPlayer.start();
pauseButton.setImageResource(R.drawable.stop_button);
}
}
});
Any help would be appreciated!
P.S. I'm using all of this code in the onCreateView method for a Fragment in my application. Just in case anyone thinks that might be relevant.
Apparently this issue is simply my Samsung Galaxy S2, as the same code works perfectly as expected on my Nexus 7 (2013) running Lollipop 5.0.1.
The issue on the Galaxy S2 includes the following:
Once an MediaPlayer is in the PlaybackCompleted state, it will not play the same file a second time when play is pressed
Attempting to run Methods in the PlaybackCompleted state (which should be valid according to Android documentation) seem to do something (i.e. seekTo(0); will actually seek to 0, but the audio file will never play a second time.

Check if display is at sleep or receive sleep notifications

I have an application utility which becomes useless when there's no user. So, in order to save resources, I'd like it to know when/whether display is at sleep.
There's a dedicated article about wake/sleep notifications by apple, but it deals only with computer sleep and not display sleep.
Is there a way for application to 'hibernate' when display is at sleep?
Thank you
The DisplayWrangler service sends notifications for when the display will power off:
// Doesn't include error checking - just a quick example
io_service_t displayWrangler;
IONotificationPortRef notificationPort;
io_object_t notification;
displayWrangler = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceNameMatching("IODisplayWrangler");
notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
IOServiceAddInterestNotification(notificationPort, displayWrangler, kIOGeneralInterest, displayPowerNotificationsCallback, NULL, &notification);
CFRunLoopAddSource (CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notificationPort), kCFRunLoopDefaultMode);
IOObjectRelease (displayWrangler);
Then the callback looks something like this:
void displayPowerNotificationsCallback(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
{
switch (messageType) {
case kIOMessageDeviceWillPowerOff :
// This is called twice - once for display dim event, then once
// for display power off
break;
case kIOMessageDeviceHasPoweredOn :
// Display powering back on
break;
}
}
This is response to a question asked a while ago - but I thought it would be useful to add my answer.
NSWorkspace has a couple of notifications for when displays wake and sleep: NSWorkspaceScreensDidSleepNotification and NSWorkspaceScreensDidWakeNotification
Since I couldn´t find any call issued by the display falling to sleep (maybe the screensaver does that? It´s very likely to kick in before the system falls to sleep), I´d suggest detecting the idle time manually and then comparing it to the display sleep settings.
This article covers how to get the idle time from IOKit and you should be able to easily get the current sleep settings, e.g. with "pmset -g | grep sleep".
Two minutes after posting the above, I discovered an open source command line tool that will probably help you a lot getting there: SleepWatcher seems to be able to do just what you asked for.