I have created some activity which is transparent when some different app opens my activity starts and opens on top of that activity (Intent.FLAG_ACTIVITY_NEW_TASK).
What i am trying to achieve is what action happens on my activity will reflect to other activity.I mean when i scroll down underlaying view will scroll.
I could NOT do that i have used some flags combinations but it did not work.
I could not pass touch events both activities at the same time. It just works at one view, i need to do what happens on top (transparent) activity , underlaying activity has get to same events.
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
// window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
window.addFlags(WindowManager.LayoutParams.FLAG_SPLIT_TOUCH);
// window.addFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
//window.addFlags(WindowManager.LayoutParams.TYPE_PHONE);
setContentView(R.layout.trans);
final View v = getWindow().getDecorView().findViewById(android.R.id.content);
v.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.i("TAG", View !!!!!!!!");
return false;
}
});
This is not possible. You can neither inject input events to other apps' Activities nor can you receive their input events (known as tapjacking).
You cannot do that with touch events, I am also not sure why would you want to do so.
That said, you can use local broadcasts or EventBus but it is a really bad idea, catch touch events in one Activity and pass to the other one after that.
Related
I Wonder if the issue I mentioned about in title is possible. I do not want floating action button to be grayed out because it would not be active for long clicks. I want it to be intact when onClick, but reacting on onLongClick. How to do that?
FAB lays on top of custom SurfaceView so It intercepts the click of the place it is located, but I want this behaviour only when onLongClick, if simple onClick I do not want want it to react.
Solution can be both in Java or Kotlin.
Thank you!
If your problem is that you don't want the FAB to prevent clicking on the view behind it, you can just delegate the click event on to the other view using a touch listener to prevent the "click" behavior:
fab.setOnTouchListener { view, event ->
surfaceView.performOnClick() // Pretend the other view was clicked
return true // Consume event to prevent "click"
}
fab.setOnLongClickListener {
doMoreImportantThings()
}
I just started coding in AndroidStudio and Java so I don't have a great grasp yet. Basically, when I click the withdrawBtn I have it switch to a different layout, then when I click it should switch back to the activity_main layout. The problem is once I am back in the activity_main layout, clicking the withdrawBtn no longer does anything. How can I fix this so it works once I've returned to the main layout.
withdrawBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setContentView(R.layout.popup_window);
text = (TextView) findViewById(R.id.textView);
RelativeLayout rlayout = (RelativeLayout) findViewById(R.id.popup);
rlayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
setContentView(R.layout.activity_main);
return true;
}
});
The reason why the withdrawBtn isn't working anymore is because you're re-inflating the layout upon a button press.
What is currently happening is:
In the original Activity, you've inflated the R.layout.activity_main and set withdrawBtn.setOnClickListener() after that layout has been inflated.
You inflate R.layout.popup_window and this actually replaces everything from the previous layout with the new layout.
You set rlayout.setOnTouchListener() and have it switch to the previous layout.
However, keep in mind that what's happening is that you're replacing old layouts with new layouts... so all the setOnClickListeners and setOnTouchListeners are actually gone. This is why your withdrawBtn doesn't work anymore. It's because it doesn't have an onClickListener anymore. To fix this, you simply have to add an onClickListener to it.
HOWEVER, although that is the solution to your question, I MUST point out that your way of navigating through your app is a HUGE problem.
DO NOT CONTINUE WITH WHAT YOU ARE DOING.
The way you're inflating layouts upon a button press is not how Android is meant to open new screens. By constantly inflating a new layout, you're essentially disregarding all previous code meant for that layout... which can easily cause crashes to occur due to code referencing Views that don't exist anymore.
In a way, you're making your code messier just to achieve a result that gives you inefficient and potentially buggy results.
For Android, there's actually two commonly used solutions for navigating to new screens:
Start a new Activity - You're allowed to create multiple Activities in your app. Every Activity should inflate exactly one layout. If you have a MainActivity and a PopUpWindowActivity, you can simply use startActivity(new Intent(MainActivity.this, PopUpWindowActivity.class)); to open the new PopupWindow Activity. When you're done in PopupWindowActivity, you can simply call finish(); to close that Activity and return to MainActivity. Optionally, you can use startActivity() too to return to MainActivity if you don't wish to close PopUpWindowActivity. Here's more info about this: https://developer.android.com/training/basics/firstapp/starting-activity#java
Use a single Activity with multiple Fragments - Similarly, each Activity and Fragments should inflate only one layout. However, the whole concept around Fragments is too much to explain in simple words, so read more about it here: https://developer.android.com/guide/components/fragments
Avoid using setContentView() more than once per Activity and only do it if there's no other choice... which I can safely say with 100% confidence that there is always a better option.
i create a system overlay app using this way
but i have a problem .... when i move my button to corner of screen, i can't touch system's view like Call button in the following image
image
how can i disable any touch in my button ? ( ignore my view's touch and touch system's view )
in somewhere i find this code but it isn't work
bl.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
Always visit developer.android.com first, it's really well documented with fundamental concepts.
The onTouch method will pass the event to the layer below it, if it returns false.
If you've extended a default touchable View class, you should use return super.onTouch()
Here's the link you're looking for:
https://developer.android.com/reference/android/view/View.OnTouchListener.html
Imagine a layout with 4 buttons
_______________________________
| | |
| A | B |
|______________|________________|
| | |
| C | D |
|______________|________________|
I'd like to detect the fling gesture over the whole layout but when the fling starts over a button is no detected.
I'm using:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gesturedetector= new GestureDetector(this, this);
findViewById(R.id.touchContainer).setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("","TouchEvent");
return gesturedetector.onTouchEvent(event);
}
});
}
It when there is no clickable items but fails if the fling start over a clickable item.
How can I solve that? Offering a bounty of 50 point for a complete working answer
One way I have achieved this is to override the following method:
public boolean onInterceptTouchEvent(MotionEvent event){
super.onInterceptTouchEvent(event);
...
You can override this method in your layout container (e.g. ViewGroup, or whatever you're holding the buttons with) and continue to return false from it in order to 'intercept' touch events that are being consumed by child Views (i.e. your buttons). Within that overridden method you can then call your gesture detector object with the MotionEvents. This method also 'sees' events that target the ViewGroup itself as well, which means - if I remember correctly - you would only need to call your gesture detector from within that method, and in doing so the gesture detector will 'see' all events, no matter whether they'er over the buttons or not. So if you drag your finger starting over a button and then ending at some point on the layout background, the gesture detector should see the entire swipe. You would not need to feed the gesture detector with the events from the layout's own onTouchEvent() because it'll have already seen them.
A second way:
I just looked at my project where I used this, and realised that I switched to a different way of doing it. What I actually did was I designed all of my child Views such that the parent Activity (or the containing ViewGroup) could register the same gesture detector object with all of those child Views (each of my special Views have a method called registerGestureDetector()). Then, in the overridden 'onTouchEvent()' in my child Views, I pass the MotionEvents to the gesture detector that has been registered with that View. In other words, the parent ViewGroup layout and all the child Views simply share the same gesture detector.
I realise that this may sound like a bit of hassle and not necessary considering it could be done using onInterceptTouchEvent(), but my application deals with some pretty complicated rules regarding how my Views need to respond to touch events and gestures, and it allowed me to apply some additional logic that I needed specific for my application. However, both of these methods I've used achieve the same basic objective here: to channel the MotionEvents that targetted various Views to the same gesture detector object.
I have a tabhost. One of the tab's activity is a ViewGroup. This viewgroup manages two different activities. I do this so I can navigate between activities within a tab. I add the activities like so:
if (videoViewLive == null)
videoViewLive = getLocalActivityManager().startActivity("VideoPlayerLive", new Intent(this,VideoPlayerLive.class).
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
videoViewLive.setVisibility(View.VISIBLE);
this.addContentView(videoViewLive, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.FILL_PARENT));
Each of my content view activities receives asynchronous notifications. What I would like to do is somehow remove the activity/content view that is not being used. So in essence, I load content view A, B dies, becomes null, or whatever, and vice versa. I want to do this because the way I am managing these views seems problematic. (errors when loading a view, loading the other view, then loading the first again, etc.)
Have you tried ViewGroup.removeAllViews()?
This is kind of tangential to the issue here, but why are you doing this with separate Activities?
This is exactly the kind of thing Fragments were designed for. There is actually a class called ViewPager included in the android support library (see also FragmentStatePagerAdapter) which allows the same kind of behavior via tabs (potentially in the ActionBar) or swiping. The adapter automagically handles the lifecycles of the Fragments as you navigate between them, all within the context of a single Activity, such that you can use the top-level Activity for routing events and maintaining overarching state if necessary.
I would try following approach:
//Add OnGlobalLayout Listener using ViewTreeObserver
View rootView = (android.R.id.content);
//Assuming you are managing these two activities inside the ViewGroup
Activity activityA = <someRef Value>;
Activity activityB = <someRef Value>;
rootView.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
//try couple of things here
// 1. determine which activity has focus
// 2. you could also check position of View on screen to determine which one is active or on the top
if (activityA.hasWindowFocus())
{
//do some action --remove other content from ViewGroup
}
});