I have a layout called a controller in it i have a couple buttons and such
the problem is in my onTouch function i want to show it on one click and hide it on another. Now this works after 2 touches. The first touch is supposed to show the controller while the next is supposed to make it disappear. The first and second touches do nothing but on the third touch it works. Here are the related functions for this
public boolean onTouchEvent(MotionEvent event)
{
int eventx = event.getAction();
switch(eventx)
{
case MotionEvent.ACTION_DOWN:
if(isLifted)
{
if(!isVisible)
{
Log.i("onTouch", "called showPuse menu");
isVisible = true;
isPaused = true;
showPauseMenu();
}
else if(isVisible)
{
hidePauseMenu();
isVisible= false;
}
isLifted = false;
}
break;
case MotionEvent.ACTION_UP:
if(!isLifted)
{
isLifted = true;
//Log.i("onTouchEvent", "Lifted");
}
}
return false;
}
/***************************************************
* Shows All Views needed to be shown
* Also pauses video and audio
*
* *************************************************/
private void showPauseMenu()
{
Log.i("showPauseMenu", "called");
playButton.setVisibility(View.VISIBLE);
Log.i("showPauseMenu", "plaButton visible");
bottomButtons.setVisibility(View.VISIBLE);
Log.i("showPauseMenu", "bottom Menu showed");
playButton.invalidate();
bottomButtons.invalidate();
pauseMedia();
}
/************************************************
* Hides Views that are part of Pause Menu
* Also starts video and audio back again
*/
private void hidePauseMenu() {
playButton.setVisibility(View.GONE);
bottomButtons.setVisibility(View.GONE);
playMedia();
}
Can anyone say what the problem might be? I've been looking at this code for a couple of days now and cant see what it might be.
A few pointers about this code:
The isLifted variable presumably starts out false, and on the first touch event it causes nothing to happen on the down event. When the user lifts his/her finger the variable is set to true so the second event can actually be processed. This means the first touch will never have any visible effect.
You're using an isVisible boolean instead of just checking the visibility of the components themselves. This makes it very easy to get them out of sync.
Without the full class it's hard to tell, but I'd investigate both these points.
While designing the xml make the widget android:visibility="gone". During the program check the state if its hidden onclick set View.VISIBLE and if visible on second touchView.GONE.
I think this will work. Try it once.
Related
I am trying to write a launcher-like app which can add Widgets to its screen.
I am using Leonardo Fischer's tutorial (http://leonardofischer.com/hosting-android-widgets-my-appwidgethost-tutorial/) which is great.
In order to remove a widget, the user is supposed to longpress the Widget and that's where I am running into some trouble; some Widgets (WhatsApp Messagelist, Evernote List, for instance) allow you to scroll them. For some reason, if you scroll, Android fires a LongClick event which wrongfully removes the widget...
My code:
(creates the widget and set LongClickListener)
public void createWidget(Intent data) {
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
hostView.setAppWidget(appWidgetId, appWidgetInfo);
// relative layout
//RelativeLayout.LayoutParams lp = new RelativeLayout()
//mainlayout.addView(hostView, lp);
mainlayout.addView(hostView);
// [COMMENTED OUT] hostView.setOnLongClickListener(new AppWidgetLongClickListener(hostView));
}
UPDATE
Countless hours later, I think I partially understood what's happening, but I still can't get the correct behaviour.
According to http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/ , you need to implement an onInterceptTouchEvent in the parent container (mainlayout in my case) to intercept and treat events before they reach the children (widgets in my case).
So I googled up the following code and tried to adapt to my needs:
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Consume any touch events for ourselves after longpress is triggered
//Log.i(TAG,"OnIntercept: "+ev.toString());
if (mHasPerformedLongPress) {
Log.i(TAG,"Longpress OK!: "+ev.toString());
mHasPerformedLongPress = false;
return true;
}
// Watch for longpress events at this level to make sure
// users can always pick up this widget
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
postCheckForLongClick();
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
}
break;
}
// Otherwise continue letting touch events fall through to children
return false;
}
class CheckForLongPress implements Runnable {
private int mOriginalWindowAttachCount;
public void run() {
Log.i(TAG,"Inside RUN");
if (getParent()!= null) {
Log.i(TAG,"getParent:"+getParent().toString());
}
if ((getParent() != null) && hasWindowFocus()
&& (mOriginalWindowAttachCount == getWindowAttachCount())
&& !mHasPerformedLongPress) {
if (performLongClick()) { // <-- DOESN'T WORK :(
mHasPerformedLongPress = true;
}
}
}
public void rememberWindowAttachCount() {
mOriginalWindowAttachCount = getWindowAttachCount();
}
}
private void postCheckForLongClick() {
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());
}
#Override
public void cancelLongPress() {
super.cancelLongPress();
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
}
}
The above code does intercept touch events when I click a widget, but its logic seems aimed at intercepting (and direct for further treatment) longclicks to widgets. What I actually need is to intercept a longclick inside the parent view.
The trick seems to lie at if (performLongClick()), which, as far as I could get, fires a LongClick event to the widget...
... so I guess my question now is how to track a longclick inside the parent view.
Sorry for the long (and seemingly basic) question on handling Android UI events, but from what I googled this seems a very convoluted topic..
So it's done...! I am not sure whether this is an elegant solution, but it works.
onInterceptTouchEvent allows a parent view to act on events before they are sent to the final sender. Please note the it won't fire if you touch the actual view. So if you have a Layout with some "blank space" and some elements, onInterceptTouchEvent won't fire if you touch the layout's "blank space" (you will need the layout's onTouchEvent in this case).
Because we can essentially only track ACTION_UP, ACTION_MOVE and ACTION_DOWN events, we need to time the duration of a ACTION_DOWN / ACTION_UPpair of events to decide whether this is a longclick or not, so what I did follows:
public class time_counter {
private long begin_time;
private long end_time;
public time_counter(long i, long f) {
this.begin_time = i;
this.end_time = f;
}
public long getDuration() {
return (this.end_time - this.begin_time);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Consume any touch events for ourselves after longpress is triggered
// Watch for longpress events at this level to make sure
// users can always pick up this widget
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
cnt = new time_counter(ev.getEventTime(), (long)0);
break;
}
case MotionEvent.ACTION_MOVE: {
if (cnt != null) {
cnt.end_time = ev.getEventTime();
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (cnt != null) {
cnt.end_time = ev.getEventTime();
}
Log.i(TAG, "DURATION: " + cnt.getDuration());
if (cnt.getDuration() > ViewConfiguration.getLongPressTimeout()) {
Log.i(TAG, "it's a longpress: " + this.toString());
if (processClick) {
processClick = false;
this.doRemoveWidget();
}
cancelLongPress();
return true;
}
break;
}
// Otherwise continue letting touch events fall through to children
return false;
}
Whenever Android sends an ACTION_DOWN event, the code start to track its duration using a simple "time counter" object. The counter's end timestamp is continually updated throughout ACTION_MOVE events and when Android sends an ACTION_UP or ACTION_CANCEL, the code checks for the final duration. If it's over ViewConfiguration.getLongPressTimeout() (default = 500ms), it triggers the action.
Notice that in my case I needed a boolean variable to prevent multiple event firing, since I wanted to use a LongClick to remove a widget. A second accidental firing, which would almost always happen, would trigger a null pointer exception since the widget had already been removed.
I tested it with several widgets (big, small, configurable, with and without scrolling views, etc, etc, etc.) and I haven't found a glitch.
Again, not sure if this an elegant or "android-wise" solution, but it solved my problem.
Hope this helps!
REFERENCE:
If you need an excellent article on touch events, please check http://balpha.de/2013/07/android-development-what-i-wish-i-had-known-earlier/. It gave me the correct "frame of mind" to address my problem.
If you really are seeing an event for starting a scroll being followed by an event for a long click, you could deal with that by setting a flag in your event handling class that tracks when scroll begins and ends, and choose to ignore the long click if a scroll is in progress.
I want to use TalkBack within my app, but still want some activities to behave differently. For example, when entering a specific activity I want to select a button (trigger a button click) when lifting finger up from that button. TalkBack enables only double-click to select a button.
How can I "override" TalkBack gestures?
Thanks!
You can perform a click action on HOVER_EXIT, but you'll need to do some work to prevent TalkBack from expecting the normal double-click action. The phone dialer's DialPadImageButton provides a good example of this behavior. Here are some relevant portions of code from that class:
#Override
public boolean onHoverEvent(MotionEvent event) {
// When touch exploration is turned on, lifting a finger while inside
// the button's hover target bounds should perform a click action.
if (mAccessibilityManager.isEnabled()
&& mAccessibilityManager.isTouchExplorationEnabled()) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_ENTER:
// Lift-to-type temporarily disables double-tap activation.
setClickable(false);
break;
case MotionEvent.ACTION_HOVER_EXIT:
if (mHoverBounds.contains((int) event.getX(), (int) event.getY())) {
simulateClickForAccessibility();
}
setClickable(true);
break;
}
}
return super.onHoverEvent(event);
}
/**
* When accessibility is on, simulate press and release to preserve the
* semantic meaning of performClick(). Required for Braille support.
*/
private void simulateClickForAccessibility() {
// Checking the press state prevents double activation.
if (isPressed()) {
return;
}
setPressed(true);
// Stay consistent with performClick() by sending the event after
// setting the pressed state but before performing the action.
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
setPressed(false);
}
I have a top level ViewGroup, which I call SliderView, in which I want to detect swiping. This is mostly working, but one weird failure persists.
The essence of SliderView is to override onInterceptTouchEvent and, once the user is actually swiping, return "true" to prevent other views from seing the MotionEvent. Here is a snip of code:
public class SliderView extends ViewGroup
{
enum MoveState { MS_NONE, MS_HSCROLL, MS_VSCROLL };
private MoveState moveState = MoveState.MS_NONE;
... other code ...
public boolean onInterceptTouchEvent(MotionEvent e)
{
final int action = e.getAction();
switch (action & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
moveState = MoveState.MS_NONE;
break;
case MotionEvent.ACTION_MOVE:
if (moveState == MoveState.MS_NONE)
{
if (motion is horizontal)
{
moveState = MoveState.MS_VSCROLL;
return true;
}
else
moveState = MoveState.MS_VSCROLL; // let child window handl MotionEvent
}
else if (moveState == MoveState.MS_HSCROLL)
return true; // don't let children see motion event.
}
return super.onInterceptTouchEvent (e);
}
... other code ...
}
It is my understanding that my SliderView (which is the outermost view) should always recevie onInterceptTouchEvent. In one of my tests, where the top level child is a However, in the following case, this appears not to be.
When the top level child is a ScrollView, onInterceptTouchEvent gets ACTION_MOVE and my code does what I want. In another case, where the top level child is a LinearLayout, it fails sometimes: it always gets ACTION_DOWN but gets ACTION_MOVE only if the user touches a widget inside the LinearLayout; if touching blank area, only ACTION_DOWN comes through.
I'll note that it behaves as if the fail-case touches are happening outside the SliderView. However, if that were the case, why would I get the ACTION_DOWN events?
Second note: looking at the source code for ScrollView, I see it checking for "inChild"; I have not figured out what that's for and how it might be relevant.
Due to the answer of user123321 here
onInterceptTouchEvent only get called if the parent has a child view which returns "true" from onTouchEvent. Once the child returns true, the parent now has a chance to intercept that event
All you need is to call
requestDisallowInterceptTouchEvent(true);
on the parent view, like this -
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
view.getParent().requestDisallowInterceptTouchEvent(true);
switch(motionEvent.getActio){
}
return false;
}
From Android developer's reference (http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)):
"2.
.... Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal."
Maybe because your onTouchEvent always returns true..?
When intercepting onTouchEvent, there are two things to do to properly intercept the touches (all else being default).
Return false in onInterceptTouchEvent()
#Override
public boolean onInterceptTouchEvent(MotionEvent me) {
return false;
}
Return true in onTouchEvent()
#Override
public boolean onTouchEvent(MotionEvent me) {
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
log("MotionEvent.ACTION_DONE");
break;
case MotionEvent.ACTION_MOVE:
log("MotionEvent.ACTION_MOVE");
break;
case MotionEvent.ACTION_CANCEL:
log("MotionEvent.ACTION_CANCEL");
userActionDown = false;
break;
case MotionEvent.ACTION_UP:
log("MotionEvent.ACTION_UP");
break;
}
return true;
}
Then, for your case (and others). Do all your calculations in the onTouchEvent() as shown above. The onInterceptTouchEvent() will only be called once for the ACTION_DOWN. But, the onTouchEvent will also get the ACTION_DOWN event, and you'll need to return true there, rather than the super.
For more information regarding onInterceptTouchEvent(): http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
ps - When you ask questions here, you should also write the description of what you are trying to do. You might quite possibly find much better ways of doing things. For your case of navigation, the real answer you are looking for is ViewPager. It works great and is very easy to implement. You should also check out some other easy navigation patters that Android has to offer developers: link.
I'm using an opensource numberpicker I found somewhere (credit to Jeffrey F. Cole) but I just found a bug.
The numberpicker has a handler to increase the number faster when you touch the button
long`private Handler repeatUpdateHandler = new Handler();
`
class RepetetiveUpdater implements Runnable {
public void run() {
if (autoIncrement) {
increment();
repeatUpdateHandler.postDelayed(new RepetetiveUpdater(),
REPEAT_DELAY);
} else if (autoDecrement) {
decrement();
repeatUpdateHandler.postDelayed(new RepetetiveUpdater(),
REPEAT_DELAY);
}
}
}
.....
public class NumberPicker extends LinearLayout {
.....
// Auto increment for a long click
increment.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View arg0) {
autoIncrement = true;
repeatUpdateHandler.post(new RepetetiveUpdater());
return false;
}
});
// When the button is released, if we're auto incrementing, stop
increment.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP && autoIncrement) {
autoIncrement = false;
}
return false;
}
});
The problem is when you longclick the button the counter starts to increase, but when you hold your finger down and drag your finger across the screen the counter keeps adding up, even when you lift your finger.
So how can I detect that the finger gets out of my numberpicker layout and stop the counter?
Thx :)
I'm not so sure that's a bug and I'm not even sure it's coming from changes that this number picker made on top of the numberpicker from the API itself. I'm assumings that the buttons that handles incrementing and decrementing the pickers are set up to keep going until an ACTION_UP MotionEvent is received, but this might be over-simplifying it.
EDIT:
I've tested this on stock Android 2.3.3 and this is precisely the result.
EDIT:
Based on your clarification in the comments, this does sound like a pretty bad bug. Looks like what you need to do is have the Handler removes the callbacks to that runnable in ACTION_UP. Can you link me to the project so I can try to submit a patch?
EDIT
The NumberPicker you provided wasn't using Handlers correctly, IMO. Instead of keeping a reference to the same Handler so that callbacks could later be removed, it was created a new one everytime it posted. I've made some changes and fixed the issues here: https://gist.github.com/3657989
I call
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
when my app starts to make my app able to display the full screen.
I want my app's UI to pop up when screen is touched, but Activity.onTouchEvent() is not triggered until the screen is touched a second time. At first touch, only the Virtual Keys are shown.
So, I have to trigger my app's UI to pop up on
public void onSystemUiVisibilityChange(int visibility) {
if (visibility == View.SYSTEM_UI_FLAG_VISIBLE) {
// show my APP UI
}
}
but onSystemUiVisibilityChange with View.SYSTEM_UI_FLAG_VISIBLE will be invoked NOT once per touch (3 times on my Galaxy Nexus) by system, especially if the user touches the screen very fast/often.
project lib 4.0 or 4.03.
Samsung galaxy(9250) with 4.03.
Android 4.4 (API Level 19) introduces a new SYSTEM_UI_FLAG_IMMERSIVE flag for setSystemUiVisibility() that lets your app go truly "full screen." This flag, when combined with the SYSTEM_UI_FLAG_HIDE_NAVIGATION and SYSTEM_UI_FLAG_FULLSCREEN flags, hides the navigation and status bars and lets your app capture all touch events on the screen.
This did work for me:
setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
// show my app UI
}
}
});
What I've done is first imported android.view.GestureDetector so I can use it to detect gestures. Android has a number of default gestures that are automatically detected in the GestureDector class. Most of this info is found here, but below is code in a form that I've used in an actual project that works.
First I've made an anonymous class in my Activity (this can be nested wherever, but I tend to make my anonymous classes at the bottom, right before the closing bracket). NOTE: You can also implement OnGestureListener as part of your class, also.
The code below is for using gesture detection to give a simple hide/show.
I've declared and defined my action bar (my UI, which is initially hidden) as an instance variable, so I can access it here, and wherever else, but you can substitute it for a getActionBar().show() and getActionBar().hide() in the case you don't want to declare it as an instance variable. Substitute your UI in the place of the actionBar here:
public class Example extends ActionBarActivity {
// declared in onCreate() method
private android.support.v7.app.ActionBar actionBar;
private GestureDetectorCompat mDetector;
private YourView view1;
private YourView view2;
private YourView view3;
private YourView view4;
// some other code
class GestureListener extends GestureDetector.SimpleOnGestureListener {
private static final String DEBUG_TAG = "Gestures in Example Class";
#Override
public boolean onDoubleTap(MotionEvent event) {
Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString());
// if there is a double tap, show the action bar
actionBar.show();
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString());
// if the tap is below the action bar, hide the action bar
if (event.getRawY() > getResources().getDimension(R.dimen.abc_action_bar_default_height)) {
actionBar.hide();
return true;
}
return false;
}
#Override
public boolean onDown(MotionEvent event) {
return true;
}
} // end-of-Example Class
Then in my onCreate() I've declared my GestureDetector and also (optionally) set my GestureListeners:
private GestureDetectorCompat mDetector;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// some code here
mDetector = new GestureDetectorCompat(this, new GestureListener());
// this code is for more advanced view logic not needed for a basic set-up
//setGestureListeners();
} // end-of-method onCreate()
Then in order to actually send gestures to be processed we provide the instructions for doing that, there are two ways I know about, first the simplest:
/**
* This method recognizes a touchEvent and passes it to your custom GestureListener
* class.
*/
#Override
public boolean onTouchEvent(MotionEvent event){
this.mDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
The second way is more complex, but if you want to only recognize touch events on certain Views in your layout as in the case where you have overlapping views and can only access the top View, you can create a custom class to pass the event around or up:
class MyOnTouchListener implements View.OnTouchListener {
public boolean onTouch(View v, MotionEvent event) {
if (v.equals(view4)) {
return mDetector.onTouchEvent(event);
} else return false;
}
} // end-of-class MyOnTouchListener
and then use it here:
public void setGestureListeners() {
/* when we return false for any of these onTouch methods
* it means that the the touchEvent is passed onto the next View.
* The order in which touchEvents are sent to are in the order they
* are declared.
*/
view1.setOnTouchListener(new MyOnTouchListener());
view2.setOnTouchListener(new MyOnTouchListener());
view3.setOnTouchListener(new MyOnTouchListener());
view4.setOnTouchListener(new MyOnTouchListener());
} // end-of-method setGestureListeners()
In my setGestureListeners method, I gave them all the same set of commands, that essentially only recognizes touchEvents on view4. Otherwise, it just passes the touchEvent to the next view.
This is code using AppCompat, but if you are not building for older versions, you can use the regular GestureDetector and ActionBar.
Have you tried adding code to only show your UI when the state has changed? You have to maintain the last known visibility and only show your UI when you first come into being visible:
int mLastSystemUiVis;
#Override
public void onSystemUiVisibilityChange(int visibility) {
int diff = mLastSystemUiVis ^ visibility;
mLastSystemUiVis = visibility;
if ((diff&SYSTEM_UI_FLAG_VISIBLE) != 0
&& (visibility&SYSTEM_UI_FLAG_VISIBLE) == 0) {
// DISPLAY YOUR UI
}
}
Code sample adopted from the Android docs
The method Activity.onTouchEvent() gets called at the end of the responder chain (meaning after all other views have had a chance to consume the event). If you tap on a view that is interested in touch (i.e. a Button or EditText) there's a good chance your Activity will never see that event.
If you want to have access to touches before they every get dispatched to your view(s), override Activity.dispatchTouchEvent() instead, which is the method called at the beginning of the event chain:
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
//Check the event and do magic here, such as...
if (event.getAction() == MotionEvent.ACTION_DOWN) {
}
//Be careful not to override the return unless necessary
return super.dispatchTouchEvent(event);
}
Beware not to override the return value of this method unless you purposefully want to steal touches from the rest of the views, an unnecessary return true; in this spot will break other touch handling.
I got this problem too, and I found this http://developer.android.com/reference/android/view/View.html#SYSTEM_UI_FLAG_HIDE_NAVIGATION
So, no way to help. Even the android system packaged Gallery app used SYSTEM_UI_FLAG_LOW_PROFILE instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION in photo page view. This is at least what we can do.
I had a very similar issue with trying to update the UI from an onTouchEvent() requiring two touches to work, and I tried a bunch of elaborate stuff before finally getting it to work on the first click.
In my case, I was showing a previously hidden item, then getting its height, then moving a button down by that height. The problem I ran into is that the height was showing as 0 until after the first touch event finished. I was able to solve this by calling show() during ACTION_UP for the onTouchEvent() instead of its ACTION_DOWN. Maybe it'd work if you did something similar?
Try to use:
getWindow().getDecorView().setSystemUiVisibility(View.GONE);
instead:
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
After that you can use normal activity in fullscreen and if you want nav keys you need to swipe from bottom to up. Working for me at Galaxy Tab 2 with android 4.1.2