Standalone transparent activity is showing in recents holding previous intent - android

I have a StandaloneActivity which handles action.SEND which does some work and finishes.
<activity
android:name=".StandaloneActivity"
android:launchMode="singleInstance"
android:theme="#style/Theme.Transparent">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
It has transparent theme:
<style name="Theme.Transparent" parent="Theme.AppCompat">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
StandaloneActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntentExtras(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntentExtras(intent)
}
private fun handleIntentExtras(intent: Intent) {
// do some work and set extras to intent
//Calling setResult() as I start this activity from another activity with startActivityForResult() for another usecase.
setResult(Activity.RESULT_OK, intent)
finish()
}
Expected is, whenever a user shares something with my app from another app, user should not leave current app but StandaloneActivity should be able to do work and finish. StandaloneActivity (my app) should not remain in recents.
The weird this is above setup works as expected in Java version of app but with Kotlin (migrating from Java to Kotlin) StandaloneActivity (my app) is visible in recents and on opening it, it is processing the previous intent and getting finished. StandaloneActivity remains in the recents.

I have tried to recreate the same setup with a simple demo app and after playing around with diffrent launch modes and flags I got the solution.
I have to exclude this activity from the recents, so I added following to the StandaloneActivity in the manifest along with existing setup-
android:excludeFromRecents="true"

Related

Getting Warning Application should not provide its own Splash Screen in Android Studio

I have recently changed my Target SDK Version to 31 (Android 12) and after upgrading I started getting this warning:
The application should not provide its own launch screen.
This is the screenshot:
Is there any better approach to create Splash Screens?
NOTE:
I know it is just a warning and can be ignored but I'm asking for now recommended way to create Splash Screens.
There is better approach now. For Android 12, there is brand new Splash Screen Api which works on previous versions aswell, see more here
It supports theming, custom animations and is super simple to use.
Just change the name, without using "splash" in it.
Starting in Android 12, the SplashScreen API enables a new app launch animation for all apps when running on a device with Android 12 or higher. This includes an into-app motion at launch, a splash screen showing your app icon, and a transition to your app itself.
TLDR; Android provides a new API for integrating SplashScreen.
First, remove the SplashScreen then follow below code block.
Add in build gradle
implementation 'androidx.core:core-splashscreen:1.0.0-rc01'
follow the below steps.
Define:
<style name="Theme.App.Starting" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">#color/ed_colorPrimary</item>
<item name="windowSplashScreenAnimatedIcon">#drawable/ic_logo</item>
<item name="windowSplashScreenAnimationDuration">200</item>
<!-- Set the theme of the Activity that directly follows your splash screen. -->
<!-- Required -->
<item name="postSplashScreenTheme">#style/Theme.MyAppTheme</item>
</style>
Then in Manifest check and verify that you given Theme.App.Starting
<application
...
android:theme="#style/Theme.App.Starting" >
...
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:label="#string/app_name"
android:launchMode="singleTask"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Finally, Don't forget to add.
class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val splashScreen = installSplashScreen()
...
You also can suppress it using this #SuppressLint("CustomSplashScreen"):
#SuppressLint("CustomSplashScreen")
public class SplashActivity extends AppCompatActivity {
...
}

The intent data remains, when I close the app by the back button and restart from the task

I developed a deep link app.
The intent data remains, when I close the app by the back button and restart from the task After launching from deep link.
Manifest:
<application
<activity
android:name=".MainActivity"
android:label="#string/appName"
android:launchMode="singleTask">
<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="news"
android:scheme="example" />
</intent-filter>
</activity>
<activity
android:name=".NextActivity" />
</application>
MainActivity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (intent.action == Intent.ACTION_VIEW && Uri.parse(intent.data.toString()).host == "news") {
// Transition NextActivity
}
}
}
In case of startup after closing with the back button, the code of "Transition Next Activity" is passed many times.
I tried this but did not work.
intent.data = null
setIntent(intent)
I've answered a similar question about "extras" in an Intent in a Notification. The problem is the same. When you launch an app for the first time (in your case via deep link), Android remembers the Intent that was used to launch the app. When your user returns to the app from the "recent tasks" list, Android launches the app using the same (remembered) Intent. To get around this you have 2 options:
Add Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS in your deep-link. This will prevent the task from showing up in the list of recent tasks and therefore precent the deep-link Intent from being remembered.
Detect Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY. When the user launches an app from the list of recent tasks, Android adds this flag to the Intent that is passed to your Activity's onCreate(). You can check for the existence of this flag, and if it is set, you can clear the data from the Intent so that your app does not perform the same actions as when launched by deep-link.
See my answer here for more info: https://stackoverflow.com/a/19820057/769265

How to stop the MainActivity from being called first?

In my AndroidManifest.xml file, I have two activities:
<activity android:name=".activities.LoginActivity"/>
<activity android:name=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
According to the logic of my app, if I'm logged in, I'm redirected directly to the MainActivity, otherwise to the LoginActivity. First time I'm opening the app, LoginActivity is opened but in the background MainActivity is also called. How stop this from happening? But without making LoginActivity as the main activity?
The solution I always adopt is to create a third Activity SplashScreenActivity
<activity
android:name=".activities.SplashScreenActivity"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
This is nothing more than a Loading Activity where you can instantiate all the stuff you need across application and where you can make this logic.
You can, for example, call this in your SplashActivity's OnCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(/*logics to see if user is logged*/) {
startActivity(SplashScreenActivity.this, MainActivity.class);
}
else {
startActivity(SplashScreenActivity.this, LoginActivity.class);
}
finish(); //finish the splash activity.
}
Another little trick :)
Link from PPartisan in comment: How to implement SplashScreen
I always make this activity Layout-less so that you don't have that annoying "black screen flash" when you first launch your application. In order to do that, as you can see, I specified a theme in that activity's manifest where I simply set this:
<style name="SplashTheme" parent="AppTheme">
<item name="android:windowBackground">#drawable/background_splash</item>
</style>
where that resource is nothing more than a drawable with a background (white background and logo in center, for example).
That way you won't have that black flash when you run your application.
Good luck!
You should move the following code to your login activity but LoginActivity will be the main activity:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
You can also use one activity with fragments inside and choose which fragment to display to the user according to the login status. See https://developer.android.com/guide/components/fragments
Finally, as mentioned in comments, you can create a splash screen that check if the user is already logged in. But here again, the splash screen will be your main activity. See https://android.jlelse.eu/right-way-to-create-splash-screen-on-android-e7f1709ba154
Best

Open invisible activity on share action (ACTION_SEND)

There are a lot of similar questions on StackOverfow but they don't solve my problem.
The task is to process in Service intents sent with default share mechanism (ACTION_SEND) from different applications.
But as far as ACTION_SEND is an activity action we have to pick up intent in activity and broadcast it to service. And it will be perfect if this activity will be invisible to the user.
I've researched a lot and have tried many solutions already.
First step of making activity invisible belongs to activity style.
I've tried this values.
android:theme="#android:style/Theme.Translucent.NoTitleBar"
android:theme="#android:style/Theme.Translucent"
android:theme="#android:style/Theme.Translucent.NoTitleBar.Fullscreen"
Also i"ve tried to create a custom theme.
<style name="Theme.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
How the activity in AndroidManifest.xml looks like.
<activity
android:name="xxx.xxx.activities.HandleShareIntentActivity"
android:theme="#style/Theme.Transparent"
android:noHistory="true"
android:excludeFromRecents="true"
android:label="#string/title_activity_handle_share_intent">
<intent-filter>
<action android:name="com.google.android.gm.action.AUTO_SEND"/>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.google.android.voicesearch.SELF_NOTE"/>
<data android:mimeType="*/*"/>
</intent-filter>
</activity>
Activity code. No setContentView(). finish() in onCreate().
public class HandleShareIntentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startService(new Intent(this, xxxService.class).putExtra(
Constants.ACTION_SHARE_KEY, getIntent()));
finish();
}
}
On Nexus 5, android 4.4.4 I do have black screen blink while handling any share event.
Any solutions?
I've tried this values.
Use Theme.NoDisplay.
I Just did this, and it helped in my case:
<activity
android:name=".SensorBoardActivity"
android:theme="#android:style/Theme.NoDisplay"
android:excludeFromRecents="true"
android:noHistory="true">
I see you already have finish(); but just for others it is important to execute it just before leaving the onCreate().

Android Service application

I'm writing a software suite for Android devices that will keep track of call times and various other call info. I'd like one of the applications to run as a Service without being started from an Activity, and I'd like it to initialize immediately when the phone boots, and stay running constantly, listening for phone calls, logging information to a database as necessary. The Service will need to present a dialog to the user at the end of each call.
2 questions:
How do I get the program (Service) to initialize at boot automatically with no user setting or interaction required?
I was under the impression that you cannot instantiate and display dialogs without using an Activity. I would like the dialogs to appear laid over whatever the user currently has on the screen, and display a dialog. Is there a way to make an Activity completely transparent over the current Activity or is there a way to display dialogs from a Service?
thanks in advance.
How do I get the program (Service) to initialize at boot automatically with no user setting or interaction required?
Add this permission to your manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Then add a receiver to your manifest:
<receiver android:name="your.package.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
Create a receiver in Java code:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// start the service from here
}
}
I was under the impression that you cannot instantiate and display dialogs without using an Activity. I would like the dialogs to appear laid over whatever the user currently has on the screen, and display a dialog. Is there a way to make an Activity completely transparent over the current Activity or is there a way to display dialogs from a Service?
Yes, that's true. You have to have an activity that pops up the dialog. To create a transparent activity add the following style in your res/values/styles.xml file (if you don’t have one, create it.) Here’s a complete file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">#00000000</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
</resources>
Then apply the style to your activity, for example:
<activity android:name=".TransparentActivity" android:theme="#style/Theme.Transparent">
...
</activity>

Categories

Resources