How to properly terminate an activity from a custom view class? - java

Similar to this post. Have a custom view (extends EditText) which must have the ability to call the finish() method of the parent activity if the user presses the END key.
How can I access the activity object of the host activity in order to call its finish() method from within the custom view class?
public class SuppressInputEditText extends androidx.appcompat.widget.AppCompatEditText {
public SuppressInputEditText(Context context) {
super(context);
}
public SuppressInputEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SuppressInputEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
return true;
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return true;
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode){
case 6: //end key
//todo: call finish() method of parent activity.
break;
}
return true;
}
}
I can use the getContext() method of my class, available because it inherits from view, to get a context, but I don't know how to use that to access the finish() method. Any help or pointers would be greatly appreciated.
UPDATE:
Looking for a solution that can keep the class independent. Thanks!

if you know the host i.e the activity where it's custom view is showing then you can do something like this.
(getContext() as? MainActivity)?.finish()
java
((MainActivity)getContext()).finish()
place this under try and catch
Edit: Create an interface which your Host activity implements and pass this as a listener yo your custom view then whenever needed to call this.
for ex.
interface CustomInputEditListener{
public void onFinish();
}
in your Host activity implement this.
MainActivity extends AppCompatActivity() implements CustomInputEditListener{
//call this from onCreate()
public void setHostListener(){
suppressInputEditText.setHostEditListener(this);
}
#Override public void onFinish(){
finish() ;
}
}
in your SuppressInputEditText class create a method like this.
public void setHostEditListener(CustomInputEditListener listener){
this.hostListener = listener;
}
and whenever you need to call finish just call
hostListener.onFinish();

Cast context to Activity then call finish like below
Kotlin
(context as? Activity)?.finish()
Java
((Activity) context).finish()

Related

The correct way to edit internal java files in Android

I would like to implement changes in the functionality of GestureDetector.java. The easy way should be just to create a custom GestureDetector that extends from the original one, and to implement the changes:
public class CustomGestureDetector extends GestureDetector {
public CustomGestureDetector(OnGestureListener listener, Handler handler) {
super(listener, handler);
}
public CustomGestureDetector(OnGestureListener listener) {
super(listener);
}
public CustomGestureDetector(Context context, OnGestureListener listener) {
super(context, listener);
}
public CustomGestureDetector(Context context, OnGestureListener listener, Handler handler) {
super(context, listener, handler);
}
public CustomGestureDetector(Context context, OnGestureListener listener, Handler handler, boolean unused) {
super(context, listener, handler, unused);
}
#Override
public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {
super.setOnDoubleTapListener(onDoubleTapListener);
}
#Override
public void setContextClickListener(OnContextClickListener onContextClickListener) {
super.setContextClickListener(onContextClickListener);
}
#Override
public void setIsLongpressEnabled(boolean isLongpressEnabled) {
super.setIsLongpressEnabled(isLongpressEnabled);
}
#Override
public boolean isLongpressEnabled() {
return super.isLongpressEnabled();
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(ev);
}
#Override
public boolean onGenericMotionEvent(MotionEvent ev) {
return super.onGenericMotionEvent(ev);
}
}
But I would like to override the function onTouchEvent and implement very specific changes so I cannot just implement them here and then call the super class, nor take the whole code for this function and copy it here because it relies on other variables.
In such case, should I create an alternative GestureDetector and then import the custom one in my project, instead of the regular one?
If it matters, the default behavior of the detector is to disable the scrolling function when long pressed it triggered:
case MotionEvent.ACTION_MOVE:
if (mInLongPress || mInContextClick) {
break;
}
But I would like it to still fire while the user is long pressing, and then scrolling.
Also, another problem is that I cannot just copy the code from GestureDetector.java to my own class in my project, since it actually contains many errors and then it won't compile anymore.

Prevent Style Change of Button

I initially set background of button with this code at onCreateView.
uc.setBackgroundResource(R.drawable.saat_button_none);
If I initially set background or textColor of button I want to prevent style change when I use onClick
public void onClick(View v) {
switch (v.getId()) {
case R.id.bir:
uc.setBackgroundResource(R.drawable.saat_button); //Should not work
dort.setBackgroundResource(R.drawable.saat_button_sel);
bes.setBackgroundResource(R.drawable.saat_button_sel);
}
}
Is that possible?
Edit: I don't want to use if statement since I have lots of buttons I just want to lock style of button.
To do this, create a custom view simply by extending View and override all methods related to background and put your logic their if background has changed once then overridden method should throw exception saying that you can't change the style as it has been changed while setup the default look and feel.
public class CustomButton extends Button {
boolean backgroundChanged = true;
public CustomButton(Context context) {
this(context, null);
}
public CustomButton(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomButton(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void setBackgroundResource(int resid) {
if(backgroundChanged){
throw new RuntimeException("you can't change the style as it has been changed while setup the default look and feel");
}
super.setBackgroundResource(resid);
}
}
At last in layout file replace <Button tag with <CustomButton

Android adding onClick on soft keyboard on activity

I am trying to add an onClick on the soft keyboard for an activity. The reason why is that i want to check if the user is currently active. So what i have done is that if the user clicks on the app i will reset a inactivity timer. The problem is that when a user interacts with the soft keyboard it doesn't call the function onUserInteraction() which is a function I override in the activity. So i need help to find a way to keep track if the soft keyboard has been clicked for every textfield etc I have in the activity. (I know that i can insert a onclick listerner on every EditText field but i rather not do that, because if I would use many EditText fields it would not be so nice)
So this is what i ended up with. I was hoping for something else, but this solves the problem. Thanks for the help!
public class ActivityEditText extends android.support.v7.widget.AppCompatEditText {
private TextWatcher tw;
public ActivityEditText(Context c)
{
super(c);
this.setOurTCL();
}
public ActivityEditText(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOurTCL();
}
public ActivityEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setOurTCL();
}
private void setOurTCL()
{
this.tw = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
InactivityManager.resetTime();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
}
};
this.addTextChangedListener(this.tw);
}
#Override
public void removeTextChangedListener(TextWatcher watcher) {
if(!watcher.equals(this.tw))
super.removeTextChangedListener(watcher);
}
}
To handle an individual key press, implement onKeyDown() or onKeyUp() as appropriate. Usually, you should use onKeyUp() if you want to be sure that you receive only one event. If the user presses and holds the button, then onKeyDown() is called multiple times.
Create a class some thing like UserInteractionEditText and extend EditText and set the onclick lisetener in that class use that class in all the XML layouts as you use EditText you can do some thing like this:
public class UserInteractionEditText extends EditText implements View.OnClickListener {
public UserInteractionEditText(Context context) {
super(context);
}
public UserInteractionEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UserInteractionEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void onClick(View v) {
//TODO:: Handle user Click Events
}
}
You can use onUserInteraction() function of activity. You need to override this function in your activity.
This function get calls when you perform any kind of interaction with your activity.
#Override
public void onUserInteraction() {
super.onUserInteraction();
// Your code goes here
}
You can refer this example and also this answer, refer the docs here
Hope this helps.

How does Android's setOnCLickListener() works?

I wonder how Android OnClik Listener works? What Pattern is it? Observer?
I cant imagine how I can Implement it in my App! It needs to be a custom implementation because I want to do it with my Objects not with views.
So how can I achieve to call obj.setOnClickListener(new Class(){});
in my code?
I mean ok I could have a methode in my baseclass from which the derived classes implement and then just havin a static ArrayList or so. But how can I add new Classes to this List at runtime?
The definiton of this class OnClickListener(){} is strange.
How is it possible to define an existing class and overriding a method?
My Java is not that good never done this...
EDIT: THIS QUESTION IS NOT ABOUT HOW TO USE ONCLICKLISTENER. I KNOW HOW TO USE THAT...
What i want:
I want a Super Class having an implementation of a method like this:
public void setMyOnclickListener(MyOnClickListener myListener)
{
//magic code
}
and now I want to have an Object of this class lets call it
Subclass obj;
and now I want to do this:
obj.setMyOnClickLister(new MyOnClickListener()
{
//defined method at runtime
public void aDefinedMethod()
{
//here goes in some code
}
});
how can I have a method with a class as a parameter which only exist as an anonymous class?
EDIT2:
Ok I get it OnClickListener is just an Interface -.- not a class defintion
That was my confusion!!!
Each View contains ListenerInfo static class which holds callbacks, OnClickListener too actually.
How it works?
System always holds all views on screen.
When user tap on screen we have a recursive foreach cycle :
switch(event) {
...
case ON_CLICK:
process(ViewRoot);
}
void process(View view) {
for(View view : view.getChilds()) {
if(view instanceOf ViewGroup && ((ViewGroup)view).getChildCount() > 0) {
process(view);
}
if(view.getListenerInfo().mOnClickListener != null)
view.getListenerInfo().mOnClickListener.onClick(view)
}
}
When you call setOnClickListener you actually say "hey Android! here it callback. And when user make click, please use it."
View.class also have getListenerInfo method which returns ListenerInfo object.
System use this method to dispatch events.
So no Observer pattern here. It just simple check of existing callback.
you need to initialize your object (button) first
public class SomeActivity {
...
private Button subButton1, subButton2;
...
protected void onCreate(Bundle savedInstanceState) {
...
init();
}
private void init() {
subButton1 = (Subclass) findViewById(R.id.home_button1);
subButton2 = (Subclass) findViewById(R.id.home_button2);
}
// next is the onClickListener
private void init() {
...
subButton1.setOnClickListener(new MyOnClickListener() {
#Override
public void myOnClick(View v) {
System.out.println("Your own on click 1");
Toast.makeText(HomeActivity.this, "Your own on click 1", Toast.LENGTH_SHORT).show();
}
});
subButton2.setOnClickListener(new MyOnClickListener() {
#Override
public void myOnClick(View v) {
System.out.println("Your own on click 2");
Toast.makeText(HomeActivity.this, "Your own on click 2", Toast.LENGTH_SHORT).show();
}
});
}
private void methodCall() {
// some more code...
}
// Subclass
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Button;
/**
* Created by roelsuntjens on 01-10-15.
*/
public class Subclass extends Button {
public Subclass(Context context) {
super(context);
}
public Subclass(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Subclass(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public Subclass(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setOnClickListener(MyOnClickListener l) {
super.setOnClickListener(l);
}
#Override
public void setOnClickListener(OnClickListener l) {
super.setOnClickListener(l);
}
}
// MyOnClickListener
import android.view.View;
/**
* Created by roelsuntjens on 01-10-15.
*/
public abstract class MyOnClickListener implements View.OnClickListener {
public MyOnClickListener() {
}
public abstract void myOnClick(View v);
#Override
public void onClick(View v) {
myOnClick(v);
}
}
// In XML I used this:
<View3D.Subclass
android:id="#+id/home_button1"
android:layout_width="match_parent"
android:text="Button1"
android:layout_height="wrap_content" />
<View3D.Subclass
android:id="#+id/home_button2"
android:layout_width="match_parent"
android:text="Button2"
android:layout_height="wrap_content" />
You can implement onClickListener like that by implementing interface OnClickListener.
Set to your button on setOnClickListner(this) in your activity will listening the click event on the onClick method.
You can also create your on listener by declaring a private OnClickListener like that :
private OnClickListener listener = new OnClickListener() {
#Override
public void onClick(View view) {
// Click occurs, do something
}
};
Then set button.setOnClickListener(listener);
It's very easy...just in your activity_main.xml layout create a button
like this
<Button
android:id="#+id/btnTake"
android:layout_width="wrap_content"
// android:onClick="onClick" (It will automatically create the method if u use onclic)//
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
/>
Now just call the button with its id(IF u r not writing android:onClick="onClick" )
now in Main Activity do this
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnTack = (Button) findViewById(R.id.btnTakePic);
btnTack.setOnClickListener(this);
//call intent or do what u want
Now do what ever you want to do..

CordovaWebView messes up with onBackPressed method in android

As title says CordovaWebView and onBackPressed in android in combination are giving weird results.
I have hybrid app. My main activity has DrawerLayout and CordovaWebView.
My onBackPressed:
#Override
public void onBackPressed(){
if(drawerIsOpen){
//close drawer
}else if(webviewIsIn){
//hide webview
}else{
super.onBackPressed();
}
}
When I use android's WebView the overridden method is called as expected. And when I change to CordovaWebView the method wouldn't even get called, instead native onBackPressed would be called instead.
I have tried overriding onKeyDown and onKeyUp but it gives me the same result, the methods are just not being called.
I'm using Cordova 2.9.0 and testing device is Galaxy Note 2, Android jellybean 4.2.2
DrawerLayout has the close on back pressed functionality I've just disabled it.
I hope you guys can understand the problem.
I encountered the same issue. My solution was to derive from CordovaWebView and override public boolean onKeyUp(int keyCode, KeyEvent event) with something like this (for Cordova 3.4.0, the code is a part of the CordovaWebView.onKeyUp(int, KeyEvent)):
public class CustomCordovaWebView extends CordovaWebView {
protected View mCustomView;
protected boolean bound;
public CustomCordovaWebView(final Context context) {
super(context);
}
public CustomCordovaWebView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public CustomCordovaWebView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
#TargetApi(11)
public CustomCordovaWebView(final Context context, final AttributeSet attrs, final int defStyle, final boolean privateBrowsing) {
super(context, attrs, defStyle, privateBrowsing);
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// If back key
if (keyCode == KeyEvent.KEYCODE_BACK) {
// A custom view is currently displayed (e.g. playing a video)
if (mCustomView!=null){
this.hideCustomView();
}else{
// The webview is currently displayed
// If back key is bound, then send event to JavaScript
if (this.bound) {
this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
return true;
} else {
// If not bound
// Go to previous page in webview if it is possible to go back
if (this.backHistory()) {
return true;
}
// If not, then invoke default behavior
else {
//this.activityState = ACTIVITY_EXITING;
//return false;
// If they hit back button when app is initializing, app should exit instead of hang until initialization (CB2-458)
// this.cordova.getActivity().finish();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this thing is closing your activity in CordovaWebView
}
}
}
} else {
return super.onKeyUp(keyCode, event);
}
return false;
}
#Override
public void hideCustomView() {
mCustomView = null;
super.hideCustomView();
}
#Override
public void showCustomView(final View view, final WebChromeClient.CustomViewCallback callback) {
mCustomView = view;
super.showCustomView(view, callback);
}
#Override
public void bindButton(final boolean override) {
bound = override;
super.bindButton(override);
}
}
If there is a better solution, I would be interested in it.

Categories