Custom ActionMode in AlertDialog - java

I spent a few hours to get the same look of ActionMode during selecting text inside Dialog as in eg Fragment. If I select text in Fragment, ActionMode, it looks like it is from from Lollipop if in Dialog like on 4.3.
What is most annoying is that sometimes it is showing normal icons (grey) but sometimes they are white so you don't know what you can click. I don't have more ideas, I tried everything I found:
Custom style of: actionModeStyle
Specified in main style: actionModeBackground (doesn't work any of other options too)
Custom ActionMode.Callback (this one works but is showing under default ActionMode)
Changed theme of context passed to AlertDialog.Builder working but its not same as in eg fragment.
App compiled with API21, target 21, tested on SGS3. Compiling with API20 doesn't change anything, so I don't know how it is possible that ActionMode changed look to new design. S3 works on stock system 4.3.
Screenshots
In fragment
Dialog - with white icons, sometimes they are grey
Dialog - with themedContext passed to Builder
Is it possible to get the same look inside Dialog as is normal in Fragment? Or everywhere as in Dialog? Before one of the last updates I always had ActionMode as on 2nd image, but showing correctly.

Related

Android: Customizing recent apps thumbnail (screenshot by default)

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.

Changing background colors affects unrelated views in another activity

I'm currently having a really weird issue in an Android app I'm developing.
The short story is that background colors I set programmatically in one Activity are appearing on completely unrelated views in another activity.
Basically, in one Activity I have a ListView in which the user can select or unselect any item by tapping it. When selected, an item is highlighted with an orange background. This background color is set programmatically via a ListAdapter.
The user may then navigate to a second Activity with a completely different layout in which every view is supposed to have a white background (this is set in the appropriate style/layout xml files). However, sometimes, the entire background of this second Activity turns the same orange color as the highlighted ListView items in the first Activity. Nowhere in the second Activity are background colors set programmatically, so I have no idea how they're changing color at all, let alone why they're turning orange.
If that's not weird enough, it only consistently happens on one device (a Droid Razr Maxx with Android 4.1.2) out of the 10-15 devices of varying manufacturers and Android versions I've tested the app on so far. Other than on that Razr, I've only seen it happen once on one other device. And even on that one, after selecting/unselecting different ListView items and going back and forth between the Activities a couple times, the issue disappeared and I couldn't reproduce it again.
Anybody have an idea what might be going on?

Android Pre-Load Splash Screen

Hopefully this isn't a dumb question, but when I initially click on my app, a kind of splash screen first appears for a few seconds with just a title bar indicating the name of the app and nothing else - then the app loads as expected. Is there any way to remove this screen?
The system looks into your AndroidManifest.xml to find out what is the theme of the main Activity. If you don't specify it manually, it assumes the application theme, if you don't specify application theme then the default theme is used. The system then creates the "splash screen" solely acoording to the theme.
So if you want to remove it, create a theme that has a transparent background and no ActionBar. And in onCreate() you probably want to change the theme again (or just change the background and show the ActionBar).
But it's better to have some visible "splash screen". Otherwise if you click on the icon, you won't see nothing for 1 - 2 seconds, which is quite weird, almost no app does this.
Initializing more resources on
onCreate()
may take some time. Try not to overload onCreate() method of Activity.
Try not to deep down more than 30 levels inside the xml layout file. which can also take up some time to initialize .
setContentView(R.layout.main)

Android - how to kill all activities when HOME is pressed?

I have an application containing multiple activities.
At the moment the whole application contains about 8 activities. First I show a splash screen for a few seconds where all the preferences are loaded and set up (from sharedPreferences) - these are saved in a "Setting" class I made for this - this class basicly just have a bunch of static variables, so all activities in the app can read these and modify them as they need to.
EDIT: More data is getting stored in this class as the app runs, some of this is from a webservice - the data is parsed into obejcts and references to these obejcts are saved in the Settings class too (or a list of the objects).
My problem is then, that when users press the HOME key, the current activity is put in the background. If the activity is in the background for a long time (a lot of users "close" apps by pressing home instead of back), and then reopened it shows the activity that was running before HOME was pressed.
As an example - lets say the user starts the app, sees the Splash screen for a few seconds. The splash screen then starts a new activity and calls finish on itself.
This means that now the Activity stack is just the MainActivity (main menu). In the MainActivity I supply all the buttons with listeners in the onCreate method, and most buttons require some info from the Settings class mentioned above.
When I then press HOME and reopens the app a few hours later, none of the buttons works anymore - seems the graphic is reacting etc, but something still goes wrong. One of the buttons that should work even with all settings wiped will just open a dialog with some text in it.
The listener:
Button b = (Button)v.findViewById(R.id.id_b1);
b.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Dialog dialog = createDialog(MainActivity.this, DIALOG_CONST1);
dialog.show();
}
});
I have some constantst for dialog types, as I'm using some custom designs for the dialogs I have created a class to created the dialogs for me.
From the activity containing the button (simplified a bit):
public static Dialog createDialog(final Context c, int dialogId) {
Dialog dialog = null;
CustomDialog.Builder customBuilder;
switch (dialogId) {
...
case d1:
customBuilder = new CustomDialog.Builder(c, DIALOG_CONST1);
//Sets up the parapters to create the dialog afterwards
customBuilder.setTitle("Header").setMessage("Content")
.setPositiveButton("", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog = customBuilder.create(); //Creates the dialog from the above settings
dialog.setCanceledOnTouchOutside(true);
break;
...
}
... //Set the width of the dialog
return dialog;
}
The CustomDialog class extends the Dialog class and then depending on the const it
s supplied with it inflates one of several dialog layouts and adds content etc. Works great normally, but after the app have been paused by HOME for a while, and things go wrong no dialog is shown when I press the button. I do se a flash of a loading dialog on the other buttons, but nothing happens afterwards - no dialog is shown. Strange thing is that if I press on the button again in the middle of the screen, I can't press it (grahics dont react), but when pressing once in the side of the screen and then in the middle the graphics do react, the dialogs does get cancelled when pressing outside, so I'm wondering if there is some very slim "transparent" dialog in the middle or something - I just have no clue why this would happen.
EDIT: Actually looking through the variables I save in Settings class I see that I do save the width and height in pixels of the screen. Width used to set the width of the custom dialogs to a certain % of the screen width. IF the Settings gets wiped, that might explain why I don't see any dialogs as width is set to 0... I really can't seem to figure what is happening if it's not all my variables in the Settings class that gets wiped - everything really do point to that.
dialog.getWindow().setLayout(Settings._widthpx - (Settings._widthpx/5), dialog.getWindow().getAttributes().height); //Width = 80%
Actually I have to admit that I don't really know what is causing this, as I'm rather new to Android. I suspect that the GC does delete all my variables after a while when the Settings class haven't been used - causing all settings to be wiped when the user returns a few hours later. This however does not explain why the buttons doesn't work (one of them require no setting).
This main activity can start other activities, and these can again launch new activities.
I think all my problems can be solved if I can just force the whole app to close when HOME is pressed, and thereby force it to be started from scratch whenever the icon is pressed - forcing the listeners on the buttons and the settings to be loaded.
I read on here about "android:clearTaskOnLaunch", " android:launchMode" and "android:finishOnTaskLaunch" but I'm not quite sure how to use these correct.
Anyone who could either explain to me why the buttons does not work, or what might happen to the variables in my Settings class when the app has been in the background for a while, or maybe give me a few good hints on how to use the "activity" settigns properly.
EDIT: The app will be running Android 1.6+, so I can't use any newer functions or anything...
Thank you very much
DO NOT override home key functionality. Maybe you'll find something, somewhere, that would allow you to do this. A god-fearing, standards-embracing application would not in any way override the home key.
Just put android:clearTaskOnLaunch=true in your manifest. This will ensure that your main activity will be launched everytime you press the launcher icon.
I suspect that the GC does delete all my variables after a while when
the Settings class haven't been used - causing all settings to be
wiped when the user returns a few hours later
Android is not that evil to do this to your app. It may kill your application, services, and whatever is running on the background after some time of inactivity and/or need for more memory, but will never leave your application hanging in there without your variables.
I had actually customized this for android 2.0 development 2.0.May be better options are available now.What I did was to declare all activities global and when you click home button from anywhere we check whether each of them is not null.If not null close them and set references to null.The activities are only declared globally.They are defined only when they are to be used.
If you are using Android 4.0 or higher, you can enable "Don't keep activities" in Developer options?. If you don't have a 4.0 device, then use the emulator.
you have to kill all the activities that are on the top of current activity on Home button and
for do that you have to override Home key functionality in which you have to write
Intent intent = new Intent(context,login.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
this will clear all the activities on the top of that activity where you press home key and switch it to login activity and
if you don't want to override Home key functionallity then you have to write only one in Androidmanifest.xml that is android:clearTaskOnLaunch=true from this when ever you click on app icon it will starts your 1st activity
I Suggest the second approach is best suted for you.
For posterity, in my app I just added finish(); in the onStop() method after everything i do there and it worked as a charm.

Android ListView - onListItemClick does not work properly

I created a ListView in Android, and a corresponding ListActivity. Each individual item in the ListView has just one TextView (I plan to add an image and a CheckBox later).The ListActivity overrides the onListItemClick to perform certain tasks on click of any item on the list.
Heres whats happening -
When I first tried clicking on any item, nothing happened.
I then tried setting the properties "Focusable" and "Focusable in Touch Mode" to false for the TextView, as mentioned here, here and here. The List items started recognizing clicks, but only when I clicked somewhere away from the TextView. Whenever I tried clicking on the TextView or anywhere near it, it did not work.
I also tried changing various attributes like Clickable, but nothing has worked so far.
Any idea what I could be doing wrong ?
Thanks
After playing around with virtually every attribute in my TextView, I finally found the reason why it was not working. It was because of the attribute android:inputType="text" in my TextView. I'm not sure why I added that piece of code (I probably copied the TextView from one of my other applications), but removing it solves my problem.
Class which will listen clicks on ListView should implement interface AdapterView.OnItemClickListener

Categories