Determine when Android has finished updating UI - android

I'm using ActivityInstrumentationTestCase2 to test my UI. My tests will change some value that will appear on the screen. However, after setting the value, I then test the screen by taking a snapshot image, run a checksum on the bitmap and compare the checksum value to the expected value. But after setting the UI value, Android has not completed its updating of the UI. The only solution I've figured out is to use a delay to wait for several seconds although this is not desirable as it has unnecessary waiting time that adds up with enough tests. Is there some way of knowing when Android has actually finished updating my UI?

Doing some more research I came across this. Have yet to try it:
To get notified of system UI visibility changes, register an
View.OnSystemUiVisibilityChangeListener to your view. This is
typically the view you are using to control the navigation visibility.
For example, you could add this code to your activity's onCreate()
method:
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// TODO: The system bars are visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
} else {
// TODO: The system bars are NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
}
}
});
http://developer.android.com/training/system-ui/visibility.html

Related

Android/Xamarin: How to handle events immediately before configuration change for layouts with different elements?

I am unsure if this is a general Andorid or a Xamarin-specific question. I have an Activity with separate layouts for landscape and portrait configuration. The portrait layout has a widget that should be animated after the OK button is pressed, but the landscape view does not have this widget.
In my activity, the event handler for the OK button has the event handler
private void handleOkEvent() {
if (isLandscapeMode()) {
return;
}
Widget.StartAnimation();
...
}
...and I also have the following supporting code:
private bool isLandscapeMode() {
return WindowManager.DefaultDisplay.Rotation == SurfaceOrientation.Rotation90
|| WindowManager.DefaultDisplay.Rotation == SurfaceOrientation.Rotation270;
}
private ImageView Widget
{
get
{
return FindViewById<ImageView>(Resource.Id.widget);
}
}
However, this creates a narrow error situation. If the user is in landscape mode, hits OK and immediately flips to portrait mode, isLandscapeMode returns false but the Widget property returns null since the Widget has not yet been created (we are not fully in portrait mode yet, but isLandscapeMode says we are). Hence Widget.StartAnimation() causes a NullReferenceException.
I can easily check whether the Widget property returns null, but this seems like a hack and would be painful for landscape & portrait layouts that have greater differences than in this example. Am I using the Android Activity correctly here, or is there a more elegant way of doing this?
Or option B, does this appear to be a Xamarin-specific issue that would not be a problem on vanilla Android?
FindViewById will return null, if SetContentView doesn't called.
Activity.OnCreate and Button click events is invoked in UI Thread.
So, handleOkEvent is invoked before Activity.OnCreate and FindViewById can't find your View.

Android view rendering issue - screen painting not happening on time

I'm trying to create a simple loading screen, during which I create new background thread, check some settings, and then start my main activity. I don't need the status bar / activity bar during this time, and I'm executing code to hide it.
During prototyping i'm using system.sleep to simulate waiting. I intent to add a delay of 1 second in my final version to prevent flashing.
However, it seems that system.wait is always happening before the screen is painted (see code below). My understanding was that by the time onResume is called Android will have painted the screen already, but that doesn't seem to be the case. Is there a different way something like this should be implemented?
Code below:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading_screen);
//hide action bar / system bar
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
ActionBar actionBar = getActionBar();
actionBar.hide();
}
public void onResume(){
super.onResume();
//TODO: Start a background thread. Wait during prototyping instead
SystemClock.sleep(3000);
}
You can use Handler for waiting to not hold the UI thread.
check this.

How to tell the activity has been covered by the notification area?

Usually, Android calls onPause on your Activity when it starts being obscured or hidden, followed by onStop when it's no longer shown at all. In my game, I pause the game in onPause, so the user doesn't lose the game while looking elsewhere.
However, when the user drags down the notification bar, it covers my Activity, but neither onPause nor onStop are called. This doesn't seem to be mentioned in the documentation. The game ticks away in the background with nobody looking at it. Is there some other way to tell my Activity has been obscured when this happens, so I can pause the game before the user loses? I can't find anything at all about this on the Android Developers site.
The onWindowFocusChanged(boolean hasFocus) of Activity should serve the required purpose. It is called with false when the notification area is dragged down, and with true once the area is dragged back up. The corresponding Android documentation states that this method "is the best indicator of whether this activity is visible to the user". It also explicitly states that the callback is triggered when the "status bar notification panel" is shown.
It is important to note that this method is also called in other situations. A good example is the display of an AlertDialog. onWindowFocusChanged is even called when the activity itself shows an AlertDialog. This might require consideration, depending on if your game uses AlertDialogs or something else which causes a focus change.
In a scenario similar to the one described in this question, we've used the onWindowFocusChanged method successfully, e.g. on a Nexus 5 with Android 4.4, or a Sony Xperia Tablet with Android 4.1.
Since the StatusBarManager isn't part of the official API, I find it unlikely that there is a way to detect it. Even using reflection, none of the statusbar-classes seem to have a hook for listeners.
If it is feasible, you could deactivate the statusbar. Otherwise, I think you are out of luck :(
Interacting with the status bar has 2 cases:
Case 1: If your activity is already hiding the status bar, and the user pulls down the status bar area without showing the notification: this can be handled by registering OnSystemUiVisibilityChangeListener listener to get notified of system UI visibility changes
boolean mStatusBarShown;
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// TODO: The system bars are visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
mStatusBarShown = true;
} else {
// TODO: The system bars are NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
mStatusBarShown = false;
}
}
});
Case 2: If the status bar is already shown to the user, and the user pulls it down to show the notification area; to detect that, you need to override onWindowFocusChanged(boolean hasFocus) in the
activity, where hasFocus parameter value will be 'false' in case the user pulls the status bar down, and when the user pushes the status bar up again; then the onWindowFocusChanged will be invoked again but this time hasFocus will be true
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// handle when the user pull down the notification bar where
// (hasFocus will ='false') & if the user pushed the
// notification bar back to the top, then (hasFocus will ='true')
if (!hasFocus) {
Log.i("Tag", "Notification bar is pulled down");
} else {
Log.i("Tag", "Notification bar is pushed up");
}
super.onWindowFocusChanged(hasFocus);
}
Check this link for more info.

How to dim the status bar in a fragment

Im trying to dim the status bar at the bottom of the screen in a fragment, then show it again when the fragment goes away. Here's the code:
#Override
public void onPause()
{
super.onPause();
getActivity().getActionBar().show();
getView().setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
}
#Override
public void onStart()
{
super.onStart();
getActivity().getActionBar().hide();
getView().setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
}
If the user launches my fragment, it works. It dims correctly. But if they hit "back", it seems like the status bar gets shown again correctly, but then after a split second, it goes dim again by itself. Has any one else seen this behavior? I think the system is doing something automatically with the status bar, but I cant figure out what it is. If I take out my call to show the status bar, it still shows it by itseft if the user hits back, but then a split second later, it gets dimmed again.
I had the same issue. I think the problem was that I wasn't setting the visibility on the main content view. I ended up copying the code from HoneycombGallery's ContentFragment.java and that finally worked for me.

Making a click-through Activity

I'm trying to adjust the brightness of my phone programmatically. I've got an Activity in my app which is translucent to do this, however users can't click through it to the activity/window beneath it. I kill this activity as soon as the brightness is set, however I want to do more work in this activity (such as gradual brightness adjustment) which requires some time, and I don't want the user tapping at their phone wondering why their actions aren't being registered.
So basically, I need to either create a mock Window which will successfully allow me to adjust screen brightness without being displayed, or work out how to make an Activity click-through. I'm not sure how to do either.
BTW, this is the code making the brightness adjustments in the Activity:
android.provider.Settings.System.putInt(getContentResolver(),
android.provider.Settings.System.SCREEN_BRIGHTNESS, Math.round(SOME_BRIGHTNESS * 255f));
Window window = getWindow();
window.getAttributes().screenBrightness = SOME_BRIGHTNESS;
window.setAttributes(window.getAttributes());
float sysBrightPer = getSystemBrightness(getApplicationContext());
new Thread() {
public void run() {
try {
sleep(BRIGHT_TIMEOUT);
} catch (InterruptedException e) {
e.printStackTrace();
}
finish();
}
}.start();
Any advice?
P.S. I found this app on the market. I wonder if the way this has been achieved would help me? https://market.android.com/details?id=com.haxor
Hah! That app did help me, if only because it led me to this solution!
Brightness Screen Filter
For the click lazy, use this:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
I'm afraid this no longer works in 4.0+, if applied to the window itself (presumably to the prevent use of activity class methods like onkey from a transparent overlay). However one can still use windowmanager.addview or layoutinflater.inflate to add a custom view class which extends viewgroup, and if you use layoutparams.FLAG_NOT_TOUCHABLE in adding or inflating this view, it will be click-through, and remain on top even when the activity that called it goes into onpause.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
If you want to intercept touches on specific views you can use the window manager to add a view with different flags:
e.g.
WindowManager.LayoutParams params = new WindowManager.LayoutParams(...);
getWindowManager().addView(myButton,params);

Categories

Resources