onBackPressed function not working under IMMERSIVE STICKY mode - android

I'm using Immersive Mode for an activity with videoView inside.
My goal is when touch on screen, the media controller and the system control bar show or disappear together. Everything works fine now.
The problem is I can't leave activity properly. When I press the back button once, the system bar just hide again and nothing happens. I have to press twice to exit the activity. I don't know why.
Here's my code.
I use an FullScreenActivity() activity to define IMMERSIVE MODE:
#TargetApi(Build.VERSION_CODES.KITKAT)
private void FullScreenActivity() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav // bar
| View.SYSTEM_UI_FLAG_FULLSCREEN// hide status bar;
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
in OnCreate():
#Override
protected void onCreate(Bundle savedInstanceState) {
//getActionBar().setDisplayShowTitleEnabled(false);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
FullScreenActivity();
And in the media controller, I define the IMMERSIVE MODE again, because if I don't after the controller shows, the actionbar and system bar will be back again.
private class MyController extends MediaController {
public MyController(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public boolean onTouchEvent(MotionEvent event) {
//........
}
#Override
public void show() {
super.show();
FullScreenActivity();
}
#Override
public void hide() {
super.hide();
FullScreenActivity();
}
}
and at last, in the onBackPressed(), I implemented my function:
#Override
public void onBackPressed() {
Toast.makeText(getApplicationContext(), "onbackpressed", Toast.LENGTH_SHORT).show();
super.onBackPressed();
if (tgtIDArr != null && tgtIDArr.size() > 0) {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Exit Player!")
.setMessage("Are you sure you want to leave Player?")
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
.......
finish();
}
}).setNegativeButton("No", null).show();
}else{
........
finish();
}
}
I don't know why, but only when I press back button twice would trigger this onBackPressed() function.
Anyone knows why? thanks!!

If you want to exit the activity when the back button is pressed and the media controller is visible then you can intercept the back button with the following code snippet.
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.KEYCODE_BACK) {
finish();
return true;
}
return super.dispatchKeyEvent(event);
}
Which is the same solution to a similar problem here Back button not working in Media player

Related

Make screen not clickable until a button is clicked

I'm working on a kotlin app, My activity is in fullscreen and I want to make a button in which the screen can't be exit or back or anything unless the button is clicked. Like the one in the video player lock type.
My first idea was to make boolean isLocked and after clicking button change this value to the opposite and override all functions/events etc which You would like to lock and if isLocked is true just don't execute them.
Here is a simple code where I locked back button (in java but it can be easily changed to Kotlin)
public class MainActivity extends AppCompatActivity
{
boolean isLocked = false;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
isLocked ^= true;
System.out.println(isLocked);
}
});
}
#Override
public void onBackPressed()
{
if (!isLocked)
{
super.onBackPressed();
}
}
}
I think that in a similar way You can lock every event.
You can also make something like this:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (!isLocked)
{
return super.onKeyDown(keyCode, event);
}
else
{
return true;
}
}
This will cancel every event like clicking back button or changing volume

Starting activity from onPostExecute(String result) doesn't set ui flags

My overall goal here is to hide the navigation bars when I start an activity in my Android app.
I have two activities, the first one is a login screen and has an async task running and depending on the out come of the result I start my new activity
OnPostExecute in first activity
.....
#Override
protected void onPostExecute(String result)
{
try
{
if (result.equals("true"))
{
Intent intent = new Intent(mContext, MainRota.class);
startActivity(intent);
finish();
}
else
{
CharSequence text = "One or more fields are incorrect!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(mContext, text, duration);
toast.show();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
The second activity immediately sets the ui flags to hide the nav bars
OnCreate of second activity
.....
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
View decorView = getWindow().getDecorView();
// Hide both the navigation bar and the status bar.
// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
// a general rule, you should design your app to hide the status bar whenever you
// hide the navigation bar.
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
decorView.setSystemUiVisibility(uiOptions);
}
when the second activity is started it is almost as if the flags are ignored and the bars are not hidden.
If i start the second activity straight from the onCreate of the first activity it works fine, but obviously i am by passing my login doing this.
Does anyone know why this happens and how to fix as I was under the impression onPostExecute runs on the main thread so there shouldn't be a problem starting an activity here.
Update!!
I have found what is causing the issue but i am still not sure why.
From the login activity i had added a listener so that when you typed the password in and pressed "done" it logged straight in rather than having to hit the login button. If i remove this listener and go back to using the login button it works fine. here is my listener code.
((EditText)findViewById(R.id.password)).setOnEditorActionListener(
new EditText.OnEditorActionListener()
{
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
actionId == EditorInfo.IME_ACTION_DONE ||
event.getAction() == KeyEvent.ACTION_DOWN &&
event.getKeyCode() == KeyEvent.KEYCODE_ENTER)
{
new GetJSONResult().execute("");
return true;
}
return false;
}
});
and here is my login button
LoginButton = (Button) findViewById(R.id.loginButton2);
LoginButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
new GetJSONResult().execute("");
}
});
So the question now is, why would calling the asyncTask from the listener on the EditText cause the systemUI flags to be ignored on the new activity I start from the OnPostExecute
Simply return false from OnEditorActionListener method.
Just a little bit change in your code:
((EditText)findViewById(R.id.password)).setOnEditorActionListener(
new EditText.OnEditorActionListener()
{
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
actionId == EditorInfo.IME_ACTION_DONE ||
event.getAction() == KeyEvent.ACTION_DOWN &&
event.getKeyCode() == KeyEvent.KEYCODE_ENTER)
{
new GetJSONResult().execute("");
}
return false;
}
});
I have checked it and it's working fine for me.
Hope this will help you ツ
Try to start your AsyncTask in the UI thread like :
runOnUiThread(new Runnable(){
#Override public void run(){
new GetJSONResult().execute("");
}
});

Avoid Alert Dialog getting closed when back button pressed?

First thing I want to say, this was done by seeing a tutorial. Here is the Custom Alert Dialog activity part I am calling from a broadcast receiver. The only problem is the back button click. Once the Alert dialog activity got started, when I press the back button it is getting closed.
public class AlertDialogActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
setContentView(R.layout.activity_inmsgdialog);
}
#Override
public void onBackPressed()
{
super.onBackPressed();
Toast.makeText(getApplicationContext(), "Back Pressed", Toast.LENGTH_SHORT).show();
}
}
I have tried onBackPressed and I'm able to see the toast message but the activity is getting closed.
See here:
#Override
public void onBackPressed()
{
super.onBackPressed(); //Remove this line
Toast.makeText(getApplicationContext(), "Back Pressed", Toast.LENGTH_SHORT).show();
}
Do not call super.onBackPressed(); code if you want to disable back button for activity. So remove this line. Hope it helps.
You can use the below option to handle back button press
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//your code
return true;
} else {
}
}
Don't propagate the event and you should be good.
#Override
public void onBackPressed()
{
//don't call super
}

How to set window focus

In an android game app I have the splash screen layout with start, resume and exit buttons. From the start button I go to a surfaceview and start a worker thread from there.
I want to implement the device back button properly. When the user touches the back button, I come back to the splash screen menu. The problem is this: when I return to the splash screen, the start, resume and exit buttons don't react from user interactions anymore. It seems like they loosed focus.
How can I set the Splash Screen to have focus again?
public class SplashScreen extends Activity {
...
...
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen_layout);
this.mRoadView = (RoadView) findViewById(R.id.road_view);
this.mStartButton = (Button) findViewById(R.id.start_button);
this.mResumeButton = (Button) findViewById(R.id.resume_button);
this.mExitButton = (Button) findViewById(R.id.exit_button);
prepareButtonListeners();
}
#Override
public void onBackPressed() {
if (mDoubleBackPressed) {
super.onBackPressed();
} else {
setContentView(R.layout.splash_screen_layout);
mDoubleBackPressed = true;
}
}
private void prepareButtonListeners() {
this.mStartButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mDoubleBackPressed = false;
setContentView(R.layout.road_view_layout);
}
});
...
...
...
Thank you very much,
Daniel.
KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
view.dispatchTouchEvent(downEvent);
view.dispatchTouchEvent(upEvent);

Back pressed events with system alert window

I need to dismiss system alert window on back pressed and home button event.I have tried with onKeyEvent but in vain. As we can't capture the back pressed event in a service, how to achieve this?
Since it's a service that hosting an overlay window, It's a bit tricky solution but it is possible.
You should handle these 2 cases separately (overriding home button press, and back button press).
1. Overriding home button press:
Create this HomeWatcher class which contains a BroadcastReceiver that will notify when home button was pressed. Register this receiver only when your window comes up.
Android: associate a method to home button of smartphone
Inside your service onCreate method use this:
HomeWatcher mHomeWatcher = new HomeWatcher(this);
mHomeWatcher.setOnHomePressedListener(new OnHomePressedListener() {
#Override
public void onHomePressed() {
yourWindow.hide() //means: windowManager.removeView(view);
}
#Override
public void onHomeLongPressed() {
}
});
mHomeWatcher.startWatch();
2. Overriding back button press:
The idea is creating an empty layout as a data member of your window class,
and attach your view to it (even if its an inflated XML layout).
For example, this is gonna be your window class:
public class MyWindow
{
private WindowManager windowManager;
private WindowManager.LayoutParams params;
private View view;
// Add this empty layout:
private MyLayout myLayout;
public MyWindow()
{
windowManager = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.your_original_window_layout, null);
// Add your original view to the new empty layout:
myLayout = new MyLayout(this);
myLayout.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
// And show this layout instead of your original view:
public void show()
{
windowManager.addView(myLayout, params);
}
public void hide()
{
windowManager.removeView(myLayout);
}
}
And now create the MyLayout class to override the back button press:
public class MyLayout extends LinearLayout
{
private MyWindow myWindow;
public MyLayout(MyWindow myWindow)
{
super(myWindow.context);
this.myWindow = myWindow;
}
#Override public boolean dispatchKeyEvent(KeyEvent event)
{
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
{
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0)
{
getKeyDispatcherState().startTracking(event, this);
return true;
}
else if (event.getAction() == KeyEvent.ACTION_UP)
{
getKeyDispatcherState().handleUpEvent(event);
if (event.isTracking() && !event.isCanceled())
{
// dismiss your window:
myWindow.hide();
return true;
}
}
}
return super.dispatchKeyEvent(event);
}
}
I know it's a bit complicated as I said since it's a system alert window hosted by a service, BUT it's working. I have the same issue as well and it has been solved exactly like that.
Good luck.
use below method to handle back button pressed.
public void onBackPressed()
{
super.onBackPressed();
}
You need to overwrite the onBackPressed method.
#Override
public void onBackPressed() {
super.onBackPressed(); // remove this if u want to handle this event
}
Use the code below
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
exitByBackKey();
//moveTaskToBack(false);
return true;
}
return super.onKeyDown(keyCode, event);
}
protected void exitByBackKey() {
AlertDialog alertbox = new AlertDialog.Builder(this)
.setMessage("Do you want to exit application?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
// do something when the button is clicked
public void onClick(DialogInterface arg0, int arg1) {
finish();
//close();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
// do something when the button is clicked
public void onClick(DialogInterface arg0, int arg1) {
}
})
.show();
}
#Override
public void onBackPressed()
{
super.onBackPressed();
}
Declare this on your activity. super.OnBackPressed automatically calls back method in android. it will surely cancel your dialog.
in addition, your dialog must look like this.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder1.setMessage("TEST DIALOG.\n");
builder1.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
Toast.makeText(MainActivity.this, "This Is test Dialog", Toast.LENGTH_SHORT).show();
}
});
AlertDialog alert11 = builder1.create();
alert11.show();
or you can set Negative button..
Hope this helps!
Define a custom layout and override dispatchKeyEvent, for example:
public class CustomSystemAlertWindow extends FrameLayout {
public static final String TAG = "CustomSystemAlertWindow";
private WeakReference<Context> mContext;
public CustomSystemAlertWindow(Context context) {
super(context);
mContext = new WeakReference<Context>(context);
// Set a background color to identify the view on the screen
this.setBackgroundColor(getResources().getColor(android.R.color.holo_red_light));
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
Log.d(TAG, "back button pressed");
if (mContext != null && mContext.get() != null) {
WindowManager wm = (WindowManager) mContext.get().getSystemService(Context.WINDOW_SERVICE);
wm.removeView(this);
}
return true;
}
return super.dispatchKeyEvent(event);
}
}
Then add the view with this code:
CustomSystemAlertWindow customSystemAlertWindow = new CustomSystemAlertWindow(context);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
wm.addView(customSystemAlertWindow, params);
When you press the back button the view will dismiss.
Show the Alert window through the Activity so you can detect it.
Implement the code to detect easily Back Button or Home Button pressed.
public class alertPopup extends Activity {
Context context;
final AlertDialog alertDialog;
String TAG = "your Activity Name"
boolean homePressed = false; // to detect the Homebutton pressed
#Override
public void onCreate(Bundle savedInstanceState) {
AlertDialog.Builder builder = newAlertDialog.Builder(YourActivity.this, R.style.AppCompatAlertDialogStyle);
builder.setTitle("AlertDialog Title");
..........
....... // Build ur AlertDialog
alertDialog= builder.create();
alertDialog.show();
//to detect Alert Dialog cancel when user touches outside the Dialog prompt
alertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
Log.v(TAG,"Alert Dialog cancelled when user touches outside the Dialog prompt")
}
});
}
#Override
public void onBackPressed()
{
Log.v(TAG,"Back Button Pressed");
super.onBackPressed();
alertDialog.dismiss(); //dismiss the alertDialog
alertPopup.this.finish(); // Destroy the current activity
homePressed = false;
}
#Override
public void onResume() {
super.onResume();
homePressed = true; // default: other wise onBackPressed will set it to false
}
#Override
public void onPause() {
super.onPause();
if(homePressed) {
alertDialog.dismiss(); //dismiss the alertDialog
alertPopup.this.finish(); // Destroy the current activity
Log.v(TAG, "Home Button Pressed"); }
}
public void onDestroy(){
super.onDestroy();
}
}
Note:
Add this Permission in Android Manifest to show the alert Window .
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Happy Coding :)
I understand that you are using the <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> permission for showing a floating view.
Using a floating view you can intercept the back button press, but the home button press cannot be intercepted (android won't let you primarily because of security reasons).
To intercept the back button press you need to add a wrapper when you inflate your floating view.
Your wrapper should look like this:
// Wrapper for intercepting System/Hardware key events
ViewGroup wrapper = new FrameLayout(this) {
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
hideAddNotesFloatingView();
return true;
}
return super.dispatchKeyEvent(event);
}
};
Then you add it to your floating view as a root:
mAddNoteFloatingView = mInflater.inflate(R.layout.floating_add_note, wrapper);
My complete code looks like this:
private void addFloatingView() {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
0,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER | Gravity.LEFT;
params.x = 0;
params.y = 0;
// Wrapper for intercepting System/Hardware key events
FrameLayout wrapper = new FrameLayout(this) {
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
// Add your code for handling the back button press
return true; // Return true means that the event was handled
}
return super.dispatchKeyEvent(event);
}
};
mAddNoteFloatingView = mInflater.inflate(R.layout.floating_view, wrapper);
mWindowManager.addView(mAddNoteFloatingView, params);
}
It's simple. Follow these steps:
Create a view like Relative Layout, Linear Layout or Frame Layout Dynamically. 2. Override the dispatchKeyEvent while creating the view.
Add your original view into this dynamically created view with addView() method.
Add the dynamically created view to your Window Manager or Alert Dialog whichever you want.
In addition to #Eliran Kuta's solution, this is more simple answer for Back button.
val view = getAlertView()
val windowParam = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT, // whatever
WindowManager.LayoutParams.WRAP_CONTENT, // whatever
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // use WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY before Oreo
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // whatever
PixelFormat.TRANSLUCENT // whatever
)
view.isFocusableInTouchMode = true
view.setOnKeyListener { view, keyCode, event ->
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
// do your work here
true
}
else -> false
}
}
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
windowManager.addView(view, windowParam)

Categories

Resources