Android: Customizing recent apps thumbnail (screenshot by default)

JavaAndroid

Java Problem Overview


The app I'm working on shows some sensitive information that must not be shown on the "Recent Tasks" screen when stopping the app by pressing the home button.

I'd like to blur the sensitive data in the screenshot or show the app logo instead.

I am aware of the following approaches but they don't fit my requirements:

And then there are some workarounds that I tried out but that didn't work as hoped:

  • Start a new activity that shows the app logo in onPause so that it's screenshot is shown instead of the actual activitie's one. But the new activity takes too long to open and it disrupts the user experience.
  • Set the activitie's content view to an image of the app logo in onPause. That seemed like a great solution to me. Unfortunately, the screenshot for the recent tasks screen is taken at an unspecified time. During testing the app logo quickly appears before the app is closed when pressing 'Home' but the resulting screenshot shows the activity a short time before that.
  • Removing the sensitive data from the widgets (e.g. textView.setText("")) has the same problem of screenshot timing just mentioned.

Any alternative ideas or solutions to the listed workarounds?

Java Solutions


Solution 1 - Java

I looked into this a couple of months ago for the same purpose as you.

Unfortunately, I had to conclude that it is simply not possible. I dug through the android source code and confirmed it.

  • There is no callbacks or methods from android that allows you to customize it (that works anyway). Besides FLAG_SECURE, this part of the code does not accept any input or change.
  • OnPause and similar lifecycle methods are called too late (the screenshot is taken already). All lifecycle methods that would hint that you're about to go into the background runs too late.
  • The image you see in the recent tasks is an actual screenshot - and thus isn't affected by changes you do (too late) to your view. That means you can't modify your view just-in-time (like making it invisible, replacing with something else, adding SECURE_FLAG, or any other obstruction of the view). As an aside, these images can be found on an emulator at /data/system_ce/0/recent_images.
  • The only exception is using FLAG_SECURE, which will prevent the screenshot from being taken of your application. I experimented with setting this FLAG in onPause and removing it in onResume, however as mentioned already these lifecycle methods runs after the screenshot is taken already, and thus had absolutely no effect.

As discussed in https://stackoverflow.com/questions/9130599/how-to-change-the-snapshot-shown-by-recent-apps-list there used to be a callback that you could use to customize the thumbnail: onCreateThumbnail. However, this does not work and it is never called. To be clear, the callback is still there, it is simply never called by the OS. The fact that it stopped working is poorly documented, but apparently was silently deprecated/removed in 4.0.3

As for the thumbnail itself, it is a screenshot taken serverside. It is taken before onPause is called (or in fact before any callbacks indicating that your activity is about to go into the background is called).

When your app does go into the background, your actual view is animated (to get that zoom-out transition). That animation can be affected through changes you do in onPause (if you're fast enough that is) (I experimented with setting opacity to 0 on the window among other things). This will however only affect the animation. When the animation is finished, the view is replaced by the screenshot taken earlier.

Also see these questions that discuss this:

Solution 2 - Java

How about implementing a layout overlay on top of your entire activity?

Make it transparent, it's click-through by default, so no negative impact on UX while in use.

In onPause() set a half-transparent, blurred image as the background of that layout, the data will be scrambled behind it. In onResume() change the background to fully transparent again. Voila.

It might be faster than other types of overlays. The positive side effect is, if you do the unblurring as a short animation effect when the user goes back (with a proper library that uses C++ instead of Java), it might even look cool and the users wouldnt even mind seeing it.

I haven't tried this myself, but it's something you haven't tried yet.

Solution 3 - Java

Currently (28/10/2020) is impossibile customizing app thumbnail in recent apps screen.
As explained by @Dellkan in the previous answer, the onCreateThumbnail method is not called anymore by the OS.

Unfortunately, also the suggestion to create a kind of launcher/splash screen without the FLAG_SECURE flag to let the app take a screenshot of that activity is not working, because the screenshot is taken on the activity you see and not at the launch of the app.

You cannot even customize the color of window background when using FLAG_SECURE as reported here.

Solution 4 - Java

There is a way to customize it. You need your Activities with sensitive data to FLAG_SECURE in onCreate before you setContentView. Then you need an empty Activity, which renders whatever you want to have as the customized thumbnail. This usually is some sort of splash screen. This new Activity needs to be the launcher and is the only Activity not FLAG_SECURE. This Activity is launched and in onResume starts your actual Activity with the sensitive data.

Android OS will take a screenshot of that new Activity at the beginning of your App. Unfortunately the users will also see this Activity for a short moment. Since every other Activity is FLAG_SECURE, Android OS will use the only available screenshot it made at the beginning.

Solution 5 - Java

Was looking for a solution and found some dirty things in case you don't want to use 'FLAG_SECURE'. It doesn't give a nice picture but protects data and doesn't prevent making screenshots for the user while they are in the app.

protected void onPause () {
    this.getWindow().getDecorView().getRootView().setScaleX((float)200);
    this.getWindow().getDecorView().getRootView().setScaleY((float)200);
    super.onPause();
  }

  protected void onResume () {
    this.getWindow().getDecorView().getRootView().setScaleX((float)1);
    this.getWindow().getDecorView().getRootView().setScaleY((float)1);
    super.onResume();
  }

Solution 6 - Java

I think this can only achieve through BroadCastReceiver but there is no receiver present. So therefore you first disable default screenshot functionality in android and then implementing your own functionality to take screenshot and before taking screenshot you should blur your secure information.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTobias UhmannView Question on Stackoverflow
Solution 1 - JavaDellkanView Answer on Stackoverflow
Solution 2 - JavaChapzView Answer on Stackoverflow
Solution 3 - JavaStefano ZanellaView Answer on Stackoverflow
Solution 4 - JavaViktorView Answer on Stackoverflow
Solution 5 - JavaPavel LapinView Answer on Stackoverflow
Solution 6 - JavaArsalan KhanView Answer on Stackoverflow