Force a full screen Activity to remeasure/redraw on resume? - java

Edited to add more details:
(originally asked nearly two months ago...still haven't found a solution)
I have an activity with a somewhat complicated view. Not complicated in a technical sense...there's just a lot going on. All activities in this particular app are set to FullScreen NoTitleBar, and they're all set to Landscape orientation. I noticed early on in development when the app is hidden and then resumes, there was an infrequent tendency for the layout to slide down vertically as if to make room for the titlebar and statusbar.
Later on in development, the app now calls out to various external intents. I notice now that there is more of a tendency to make this same shift when resuming from an externally handled fired intent (such as creating a "chooser" intent or picking an image). I am able to reproduce it inconsistently using the exact same steps...sometimes it happens sometimes it doesn't. It seems as if there's a race condition in between various phases of measuring and laying out. I assume that one of these steps that the system is doing for me is checking for fullscreen and notitlebar, and making the necessary shift. This is probably happening late in some cases.
I put a bunch of logging, and calls to invalidate(), requestLayout(), etc trying to maybe catch the race condition, but the problem seems external to my layouts. The top() and bottom() values of my root layout are always 0 and the height of my screen, respectively, even when I'm logging this while the issue is occurring.
Is there some other method of the Window, WindowManager or any other system view-related object that I can force a full remeasure, redraw, re-check for current theme/style flags?

i had exactly the same problem and also tried several aproches (as the ones mentioned above).
None of them worked. However i found the following workaround:
protected void onResume() {
super.onResume();
handler.postDelayed(new Runnable() {
public void run() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}, 1000);
}
the view will do a short flicker in this procedure, but at least it doensn't stay croped.
A clean solution still needs to be found. However this supports your thesis that there is some kind of timing or race problem.

In my case this behavior was triggered by resume from lock screen. No idea why but after adding empty overloaded function it was fixed (but I tested it only on my HTC Wilfire). It may be a different bug thou.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
/* Workaround a probable Android bug with fullscreen activities:
* on resume status bar hides and black margin stays,
* reproducible half of the time when coming back from lock screen
* (tested on HTC Wildfire)
* No idea why but this empty overload method fixed it.
*/
}

I'm not sure if it'll work, but you might want to try this in that method:
this.getWindow().getDecorView().invalidate();
If that doesn't work on it's own, try adding to the onDraw(Canvas) method the instructions necessary to remove the title bar and do similar adjustments your activity might be doing at startup.
Hope that helps.

Hey Rich,
I had the exact same problem. I fixed it by setting these options in the manifest XML (it seems the API interface is a little buggy). Details here: http://thedevelopersinfo.wordpress.com/2009/10/21/making-an-fullscreen-activity/
opticron

Have you set FullScreen NoTitleBar in your manifest or in code?
If you use code, it may be that it is getting rendered before your code kicks in?
<application android:label="#string/app_name" android:icon="#drawable/icon" android:theme="#android:style/Theme.NoTitleBar.Fullscreen">
I understand that you can set themes on individual activities in an application. Do you? and do they conflict with your application settings?

Have you tried this in onResume()?
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN );

I have found a Solution to this:
#Override
protected void onResume() {
Log.e("", "onResume");
super.onResume();
//this is a simple Splash with "Game paused" Text inside! in my main.xml
final LinearLayout gamePause_text = (LinearLayout) findViewById(R.id.gamePause_text);
OnGlobalLayoutListener asdf = new OnGlobalLayoutListener(){
public void onGlobalLayout() {
Log.e("", "onGlobalLayout");
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
gameSurface.onResume(); //OpenGL Surface onResume();
gamePause_text.getViewTreeObserver().removeGlobalOnLayoutListener(this);
};
gamePause_text.getViewTreeObserver().addOnGlobalLayoutListener(asdf);
}

I Fixed it by setting the theme for application rather than for individual activities.
<application
android:icon="#drawable/icon"
android:installLocation="auto"
android:label="#string/app_name"
android:theme="#android:style/Theme.Black.NoTitleBar.Fullscreen" >
This worked for me. This problem occurs if the next Activity we launch isnt a Full screen Activity and current Activity is a Full screen Activity.

Related

onCreate called again when resize in multiview/split screen

When I change the screen size in the multiview / split screen mode, the onCreate function in MainActivity is called again.
Because in onCreate I have a ProcessLifecycleOwner observer:
ProcessLifecycleOwner.get().GetLifecycle().AddObserver(this);
I don't want it to be restarted ... How do I know that onCreate has been called before?
I know you can add:
android:configChanges="screenSize"
in the manifest, but unfortunately needs to "refresh the layout" when resizing.
Android is going to manage the life cycle, and the programmer needs to deal with all eventualities. On this page, there's an abbreviated diagram:
That would indicate that you would need to manage the observer in the onStop().

hide android title bar without animations

I am trying to show the title bar of my android app on some layouts but not on others. I navigate between layouts without a problem and I call getSupportActionBar().hide(); or getSupportActionBar().show(); without problems, the titlebar does indeed show or hide when I want it to. However, there is an animation which is very ugly and annoying plus it causes some strange graphics problems (black background in my app but it shows a white background in the place of the title bar during its animation)
There is a method for disabling the animation but it does not seem to work at all. How can I have a title bar one one activity but not the other without having an annoying animation to show/hide it? And why cant I just call the method and have it work as it should?
The method I am trying to call is getSupportActionBar().setShowHideAnimationEnabled(false);
it is worth noting that my app is extremely simple and only has two layouts and one java activity. I just inflate two different layouts to show on my one activity.
How it looks like currently: https://i.imgur.com/djTWokI.mp4
<activity android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.Black.NoTitleBar.Fullscreen">
You can try changing AndroidManifest.xml like this
I sort of solved it myself by creating a custom titlebar which I have full control over. What really frustrated me was that setShowHideAnimationEnabled(boolean) doesnt seem to work properly and I couldnt find any official documentation about it.
Googling for it only gave me results from like 2010 about how to enable animations but when animations are enabled by default, I wanted to remove them.
Anyway, turning the actionbar off in the entire application/activity is possible and that is what I did, I then created my own custom actionbar layout and added it to the page(s) that I want to utilize it.
If your context is an activity you can call overridePendingTransition:
Call immediately after one of the flavors of startActivity(Intent) or
finish specifying an explicit transition animation to perform next.
So, programmatically:
startActivity(new Intent(CurrentActivity.this, YourNextActivity.class));
overridePendingTransition(0, 0);

How can I show an overlay on my app when I click the "Recent Apps" button? [duplicate]

The app I'm currently building has the requirement that the app has to prevent the OS to take a screenshot of the app when it's being pushed into the background for security reasons. This way it won't be able to see the last active screen when switching between apps.
I'm planning to put this functionality in the application class's onPause method, but first I need to find out how I can achieve this functionality.
So is there anybody out there, that has a clue how to fix this?
Try FLAG_SECURE:
public class FlagSecureTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.main);
}
}
This definitely secures against manual screenshots and automatic screenshots from the ICS recent-tasks history. It also secures against screen recording (e.g., apps using the media projection APIs).
UPDATE: it also secures against Now On Tap or other assistants on Android 6.0; they will not get access to the details of widgets and containers in your UI if the user brings up the assistant.
UPDATE #2: however, not everything in the activity will be protected. Any pop-up windows — Dialog, Spinner, AutoCompleteTextView, action bar overflow, etc. — will be insecure. You can fix the Dialog problem by calling getWindow() on it and setting FLAG_SECURE. The rest... gets tricky. See this blog post for more.
Be careful about using WindowManager.LayoutParams.FLAG_SECURE, on some devices (verified on Samsung Galaxy ACE, e.g. GT-S5830) this will make the view scrambled. Looks like a Samsung specific bug. I recommend the following:
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
This is what a scrambled screen looks like:
This is working properly on ICS Samsung phones though, so I'm assuming problem is isolated to Gingerbread devices (or older).
The solution provided by CommonsWare continues to be valid also in Lollipop.
Just a note, if you want to continue to not see snapshots in recent list for the entire app, ALL the implemented activities should specify in the onCreate() method the flag getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
before setContentView();
Otherwise a snapshot in the recent list will show the first activity without the flag if the user navigated through it.
In case if someone is looking for a solution in which the app must secure (screen overlay) when the app is background or stick of all running app and the in-app app should allow screenshot.
Try Below:-
#Override
protected void onResume() {
super.onResume();
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
#Override
protected void onPause() {
super.onPause();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
Here is a solution for hiding content of an app by covering it with a splash screen when the app is put into the background. This is not using the FLAG_SECURE technique, I simply override the onPause and onResume methods of the screens and modify the view to show one that covers everything in the back.
https://stackoverflow.com/a/52976001/6686912
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
this worked for me, it prevents from taking screenshot and also any inbuilt or third party recording application from recording screen.
This is work for me after adding these line into the onCreate before setContentView of every activity.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_notification);
As of Android 13, there is a new way to prevent a screenshot being taken for the recent apps list, while still allowing the user to take screenshots while using the app: https://developer.android.com/reference/android/app/Activity#setRecentsScreenshotEnabled(boolean)

Should I be closing my activities as I go through my app or will this cause Memory Leak? OutOfMemory Errors with drawables in layouts

I am currently developing a game with the android development enviornment. And for the past couple of months I've been dealing with a nasty OOM error. My first problem was that I was placing my drawables in the wrong folder (Drawable-xhdpi in drawable folder). But now, the OOM error eventually happens as you go through the game.
It is a rpg, basically compoed of menus in activity layouts with animations and things. and I've tried everything I could to fix it. I've tried the unbindDrawables method:
unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
which does help a lot, but it does not fix the issue. And I cannot use any of the bitmap.factory options or anything, since I load my images through xml in my drawables folder. My images aren't that big by the way, as activities have a background of 720x1280, with some smaller images, and the most total images I'll have on screen at a time is around 8.
So this lead me to think that I may have a memory leak. I did ALOT of research, and I found out that use this(the activity context) will cause a leak, and I should use the application context. However, If I make the switch, there is almost no difference.
So I used MAT to figure out what was going on, and most of my memory is going to byte[], android.graphics.bitmap. And if I drill down to find the cause of this, it seems that java.ref.finalizer is causing all of the retained memory in the VM.
The only reason I could think this is happening, is because whenever I start a new activity I use,
Intent fight = new Intent(this, StartScreen.class);
//add this flag to remove all previous activities
fight.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(fight);
finish();
which opens a new activity, but closes the one we were just in. So, I'm guessing the bitmaps are not being recycled correctly whenever I finish an activity? or is closing and starting activities like this bad for memory?
I've been on Google all day trying to find the solution to this problem and I can't find it. Any soulutions are appreciated, thank you for reading this!
P.S if you would like to see any snippets of my logcat or code or anything, I am more than happy to post it.
P.S P.S My game has about 10-12 different activities I switch between. For example If I have activities A,B,C I open A, Open B close A, Open C close B, open B close C, open A close B.
EDIT: As request about my activities. Usually it is a menu, and when you press a button, that activity finishes, and then moves into another activity. Or buttons will do some math for things like selling, or doing damage to an enemy. One thing about my activity architecture, is that since I am closing every activity as I go to a new one, when I go back to the ones I closed, I am re-creating them. So I don't know if the old activities I finished still have memory in the VM that over time causes the Out Of Memory error, since it all builds up and keeps expanding. I explained My call for a new activity above. And the intent flag closes all past activities (if there are any) in the stack.
EDIT EDIT: As per request my oncreate and onDestroy:
OnCreate:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_screen);
//setting fonts
//a function that binds views by findview by Id and then sets their typeface
setFont();
//set up the music service
//connects the app to the background music service
playMusic();
//aquire wakelock
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
OnDestroy:
#Override
public void onDestroy()
{
super.onDestroy();
//unbinds the service
unbindService(musicConnection);
//unbind drawables (function above)
unbindDrawables((LinearLayout) findViewById(R.id.container));
}
you should destroy the activities that you don't need anymore it takes place in the memory. or if you dont want your user/player to go back to the recent activity you should finish the activity. and if you will notice. if you dont finish the activity and press the back button several times it is layered.
second you mentioned that it is a game. in android programming you need to consider your bitmap resources so to avoid getting an OOM error in your game make use of sprite sheet it will save a lot of memory and usage of bitmaps in your application. i encountered those kind of situation and bitmaps mainly causes the OOM error.
I will say it depends. but with your problem your answer is right here
Quick quote from the site
Note: In most cases, you should not explicitly finish an activity using these methods.
As discussed in the following section about the activity lifecycle,the Android
system manages the life of an activity for you, so you do not need to finish your own
activities. Calling these methods could adversely affect the expected user experience
and should only be used when you absolutely do not want the user to return to this
instance of the activity.
Read for more info
well i get you lucidly now, but im thinking of what you are tryna do here, so y dont you use FragmentActivity for B and C.. So, Activity A opens B..B is opened as fragment but works like activity-(thats fragmentActivity), and opens C which is most likely a Fragment..which i think would be perfect for your situation..
for more info about FragmentActivity click Here
no more activities back and forth.. and its gonna work like an activity..

android finish current activity causes app close

I am executing maswebview class and I would like to finish only this activity. I tried maswebview.this.finish() but when executed, app is been closed. Then if I set a new view for the tab content, it is loaded properly and webviewmas dissapears but just for a while, then appears again fitting fullscreen. How to finish maswebview completely? ThanK you
public void onClick(View arg0)
{
/*
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
startActivityForResult(intent, 1);
Intent intentmas = new Intent (maswebview.this, mas.class);
intentmas.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intentmas.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentmas.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intentmas.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
View vista = getLocalActivityManager().startActivity("maswb", intentmas).getDecorView();
setContentView(vista); */
maswebview.this.finish();
Do you have any other activities of your app in the stack by the time you call finish()? If you don't, you'll want to start the desired activity instead of finishing the current one.
But actually it seems to me that you're trying to accomplish something that can be done simpler. Can you provide more info on the task at hand and your app structure you're trying to go about it with?
From what you said, it seems like you have tabbed UI and you're trying to show a webview in one of the tabs, then hide it.
First, I don't see why you want the webview in a separate activity. Seems to me you could just have it in layout of one of the tabs and just call setVisibility(GONE) to hide it.
Second - and this is important - looks like you're trying to implement tabs the old way - TabWidget, TabHost, etc. Since Honeycomb has been released, there's much more convenient way to implement tabbed UI - Action Bar Tabs and Fragments - that approach is much more convenient and will render your webview problems obsolete: there's a thing called WebViewFragment which is basically a WebView but smarter - it will handle its own lifecycle with minimum effort required from you (i.e. pause when removed, resume when added). It will take some effort to study up on Fragments, but it's well worth it. You can get Fragments API for pre-Honeycomb android sdks as a static library - it's called android-support-v4 and you can download it in Android SDK Manager.
Are you calling "maswebview.this.finish();" before the new Activity is started?
Also if you want to just start this new activity without having the old activity in existence then you can add android:nohistory="true" to your manifest.xml. This will cause the current activity to be the only activity in the queue.
See HERE
You need to provide a little more information for us to better understand what exactly is going on.
I hope this helps.
Try following code
#Override
public void onBackPressed() {
if(childView != null && parentLayout.getChildCount()==2){
childView.stopLoading();
parentLayout.removeViewAt(parentLayout.getChildCount()-1);
if(webView.getVisibility() == View.GONE)
webView.setVisibility(View.VISIBLE);
}else{
super.onBackPressed();
}
Do you have a parent activity which is launching this one? If yes make sure you don't call finish() after launching maswebview, that way the parent activity will remain in the stack. Once maswebview would exit, onResume would be called for your parent activity.

Categories

Resources