Android: Customizing recent apps thumbnail (screenshot by default) - java

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:
Setting the actvitie's android:excludeFromRecents to true in the manifiest prevents the app from being shown at all in the recent tasks. This would disrupt the user experience.
Using FLAG_SECURE results in a blank card on the recents tasks screen. (How do I prevent Android taking a screenshot when my app goes to the background?) I don't like the blank screen. However, I'll stick to this solution if there is no workaround.
Overriding onCreateThumbnail seems like the ideal solution but, unfortunately, doesn't work as it's currently not invoked by the OS :( (https://code.google.com/p/android/issues/detail?id=29370)
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?

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 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:
When does Android take its recent apps switcher screenshot?
Show custom application image in task manager on ICS or JB
Android never call method onCreateThumbnail

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.

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.

Since onPause is called to late, I use WindowFocusChangeListener to observe when the Fragment loses focus. At this moment we can hide all view which show sensitive data:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// hide sensitive data when window moves to background (before system screenshot is captured)
myViewWithSensitiveData.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
}
});

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.

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();
}

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.

Related

How to close an application without animation

I need to have an invisible button that close my application but without the animation displaying that an application was closed.
The transition must be seemless because the app will be displaying a screenshot of phone's home page and it must look likes there were no application opened when the user touch the button.
I tried removing activity animations in theme and in code but there is still an animation when the app close.
Is it possible ? How ?
This isn't possible, as that is something that is dealt with on an OS level. You could intentionally crash the app by throwing an uncaught exception or something like that, but then you will get a dialog showing that it indeed crashed.
I think you need to go back to the drawing board with coming up with a good prank. :)
Maybe be you can try this:
finish();
overridePendingTransition(0,0);
You need invoke overridePendingTransition(0,0) after finish that will disable transition animation

Refresh of screens on backgrounding and foregrounding an application

I am working on an Android app with multiple activities. When moving from one activity to another in certain cases I want to refresh the display but not in others.
One case is where I background the application and foreground it again. When I foreground it, I want to refresh everything on the screen depending on which activity
I backgrounded to begin with. How can I do this? I am unfortunately a bit new to Android so some appropriate basics where applicable would also be helpful.
http://developer.android.com/guide/components/activities.html#SavingActivityState
You can use onSaveInstanceState() to save information before onPause() is called. In onResume() you can use the saved info as a case in a switch statement or some conditional to refresh what you want.

Android screensaver in app if it's not used

I created an android app. The screen never turns off:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Now I want to show a picture if the screen is not pressed for 5 minutes or something else. The app should not be closed, when pressing on the image the app should be open.
How can I realize that?
I would discourage you from taking this approach. Users expect to have a consistent user experience between various apps on their devices, and likely have a preference to how their device sleeps, either by having specified a sleep timeout or displaying a daydream as introduced in Android 4.2.
If you'd like to provide users with the option to display a screensaver associated with your app, I suggest including a Daydream in your app and otherwise acknowledging the user's preferences.
That being said, if you cannot use Daydream, you could observe if the app is being used or not. Two things come to mind:
Have the root view of your activity intercept touch events to observe if any of its children have been touched.
Observe the activity's onPause() and onResume() to acknowledge that the activity is still being displayed.
You could then invoke a Runnable by posting it to a view using postDelayed(Runnable action, long delayMillis), being wary to remove it when the activity is paused or the timer should be reset using removeCallbacks(Runnable).
I solved the problem!!!
I used that event:
public boolean dispatchTouchEvent(MotionEvent ev)
{
super.dispatchTouchEvent(ev);
// cancel my Timer
return true;
}
Thanks!!

How to change app theme from ordinary "Blank Activity" to "Master/Detail Flow"

I have an application that works on the basic theme "Blank Activity" and what i would like to do is to change it to a "Master/Detail Flow" theme. I do know that this will make my application work on android SDK 11 + (android 3.0 Honeycomb +), that is OK with me. The issue is i don't know where to start from, what are the basic steps to make this BIG conversion? I couldn't find any example to help me out with this issue. What should i be looking for. i am sure this has been done, can you at least please give me some pointer on how to do this?
my Application is not that complicated it uses activities, async tasks, DB, custom lists,... it is very basic. I use the custom list to display data and when i click on it it displays much more details, so I thought what better way to do this in a more professorial matter than the "Master/Detail Flow". If you have any tutorial regarding the "Master/Detail Flow" that you can hook me up with that might help.
I have an application that works on the basic theme "Blank Activity"
and what i would like to do is to change it to a Master/Detail Flow"
theme.
I think a change of the application flow would be more appropriate then a change of theme. Two obvious questions that would appear are why do you suddenly want to make this change and are sure your app makes sense in a master/detail flow? The answer would most likely be positive but you should answer them nonetheless.
I do know that this will make my application work on android SDK 11 +
(android 3.0 Honeycomb +), that is OK with me
I don't see why you're app couldn't run on versions below with the new master/detail stuff.
The issue is i don't know where to start from, what are the basic
steps to make this BIG conversion? I couldn't find any example to help
me out with this issue. What should i be looking for. i am sure this
has been done, can you at least please give me some pointer on how to
do this?
You haven't provided details about how is your app implemented. The change would revolve around fragments so a BIG question would be if the current single pane version is built using the fragments framework.
If your app is built using fragments then making the change shouldn't be too hard. You'd need to:
establish which parts(fragments) should be combined in an activity(from your old ones) to make the master/detail(when the space would allow it)
change the multi pane activity to accommodate the new fragment(s). This should be easy to do but it would depend on the size of the features exposed by each of those fragments.
modify the rest of the activities(for when the app will not run in the multi pane mode), this would be small changes as the activities would mainly remain as the current version
If your app isn't built using fragments, then what I said above still applies but you'd need to also actually make the required fragments wrapping whatever functionality your app has. This would most likely result in a big code refactoring.
Here is a tutorial about the Master/Detail template in Android - An Android Master/Detail Flow Tutorial.
As far as I understand your application is up and running - so I'm not sure whether it is worth it to try rewriting it, unless you are experiencing some problems of course. :)
In general the master/details flow requires the following steps:
Implement a ListFragment showing basic information of your items
Implement a Fragment showing detailed information about a particular item
Make an xml layout file for large devices (located in layout-sw600dp folder for example). In this layout you have to put both your fragments.
Write a general version of this layout file (i.e. file with the same name but located in the layout folder), which contains only the ListFragment.
Let your activity handle onItemClick event from the ListFragment. Each time an item is clicked, you have to check if the activity is showing both fragments or only the ListFragment. If both are visible, you have to notify the details fragment that new item is selected so it can show its data. Otherwise you have to create new details fragment (you reuse it of course), pass it some information about the selected item (so it can show the item's data) and replace the ListFragment with the new one.
That a basic overview, but it should be enough to give you some idea about this flow. If you need any more details - just let me know. :)
Master/detail flow and blank activity is not same as you want to change by only changing app theme or app base theme. It will be better, if you first design master/detail flow template using UI fragments, then according integrate you blank activity with the master template making necessary changes. And for master/detail flow tutorial just google it, you will find lots of example there.
Here are some links from developer.android.com fragment-ui and adaptui
These are some guidelines about fragments but they are told using a master/Detail app.
Also dont forget to checkout the news reader app provided as sample in the second link.
If you have a recent version of the Android SDK, you should be able to create a new Android application and during that process you can elect to have the wizard create a Master/Detail Flow app for you. It will create a basic working app so that you can look through the code and understand the necessary parts.
Then, depending on how simple your app is, you may want to move all your present code to the new application or vise versa.
Macro changes that will happen:
Change all your current Activities to extend Fragment instead.
You will have to create a FragmentActivity to call your Fragments. This will basically be the boilerplate code, with just the names of your Fragments added to it.
Don't forget to double check your Manifest!
In your converted Fragments that previously extended Activity:
Everywhere you needed a Context, switch that with getActivty() (or create a global variable so that it is only called once)
Change onCreate() to
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_signals, container, false);
setHasOptionsMenu(true); // Add if you want to display a Menu
// Your initiation code here
return mView;
}
If you have a menu, change it to
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.activity_main, menu);
super.onCreateOptionsMenu(menu, inflater);
}
And that's it for basic applications. When you first change Activities to Fragments, there will be many errors. But, they are all easy to fix.

How to re-enable screen dimming?

I needed to keep screen on while displaying my application so I disabled Dimming using this code :
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
the problem is that when I close the application, dimming is still disabled
and I want to re-enable screen dimming for power saving is there a code to reverse it ?
note my application has services working in background all the time,I think it's irrelevant as I put the code in an activity class;
You should use the View function setKeepScreenOn(). It's more friendly.

Categories