Routing key input to different Activities - android

Let me first start off by explaining my problem -
I am working on an application that is lying between the a system activity (com.google.tv.player.PlayerActivity) and user-space.
The system activity has a certain behaviour that happens when I press the MENU button. Because of my newly deployed application in-between, I am trying really hard to send that MENU keyevent to the "activity above me". Otherwise, it's just intercepted and consumed by my app.
I have no references to the activity. I have somewhat examined it's old code to figure out that the menu button press eventually calls void openOptionsMenu(); and most attempts have been fruitless. Here's a short list of what I tried, I catch the MENU press in MyActivity.onKeyDown() and tried doing the following
super.onKeyDown(keyEvent); got me really nowhere.
dispatching the key with dispatchKey caused stackoverflows depending on use
dispatching the event with menuEvent.dispatch((Activity) getRefByReflection());
grabbing the WindowManager and dispatchin the key to it.
overriding dispatchKey obviously, which just ended in a stackoverflow :)
I have read online that there is/was a way to dispatch a key via a PID - I can get the player's pid, but lack the method to use to dispatch the key! I simply have no dispatchKey(KeyEvent event, int recvPID, int recvUID) that they have seem to be using.
I am also aware that I will get a few faking user-input is shaky and it's better to refactor the button behaviour than to simulate pressing it and I agree but, I am in no position to even get the source, much less afford changes to it. Reversing it would be an option, if only to know what members I need to reflect against.
To me, it seems that there simply is no way to route the keypress as a passthru and let it sink into the activity below, so I really do have to SEND / DISPATCH it somehow. Any help would be really appreciated.
Once again, I'm looking for a way to allow pass-through of keypresses, all for sake of opening a menu that i have no way of reaching programatically through my code.
The last, not-completely-explored option is the InputManager's injectInputEvent method - but without a way of 'directing' it anywhere, I do not know if it'll bare fruit to explore that venue thoroughly. Then again, it's the only thing left to explore.
It might be worth noting that the reflection approach failed due to
Caused by: java.lang.ClassNotFoundException: Didn't find class
"com.google.tv.player.PlayerActivity" on path: /system/app/myAPK.apk
so maybe (hopefully) it's some sort of class loader issue?
I'll be awarding 100 bounty on this question as soon as I can, in the meantime - please help :) I have searched SO high and low, and tried all things suggested and what I could think of. At the moment i'm really stumped.

According to Diane Hackborne on a discussion had on android-developers mailing list quoting
From: Dianne Hackborn (hack...#android.com)
Date: Mar 11, 2011 5:24:06 pm
List: com.googlegroups.android-developers
Correct you can't do this, very much by design.
It turns out that it is a major security risk to allow foreign apps to dispatch key events to other apps. Therefore, apps that need to work together this way also need to share either the GroupID or the PID.
Conclusion: unfortunately, what you are asking doesn't seem possible at the moment.

If there is any encapsulating code you could post it would greatly help in understanding your call stack. From the description you gave my thought is that you should return false from your key handler (what ever method is actually capturing the key press) this would allow it to bubble up from the middleware you mentioned. Again I'm not sure of your key entry point since you did not provide a signature or indicate what method is trapping the key press.

If you unpack the GTV TV Player APK, the manifest references several libraries:
<uses-library android:name="com.google.android.tv" />
<uses-library android:name="com.google.tv" />
<uses-library android:name="com.google.tv.epg" />
<uses-library android:name="com.google.tv.mediadevices" />
Not sure if this will resolve the reflection class loader issue, but it is worth a try.

Related

Hooking to override Settings.Global.* values

I'm using the app DevOptsHide to make other apps think the developer mode is disabled. To summarize, we are hooking into Settings.Global.getInt() and Settings.Secure.getInt(), and override values of Settings.Global/Secure.ADB_ENABLED and Settings.Global/Secure.DEVELOPMENT_SETTINGS_ENABLED constants.
I found some points of interest, but I'm not an Android developer, and the app author isn't willing to spend much time working on the app anymore, thus I'm asking the questions here in hope to find some insights.
The originating discussion can be found on DevOptsHide issue #17. The main code is at HideDevOpts.kt.
My questions are:
I am right when I spotted that when hooking into Settings.Secure.getInt(), in the hook param equals Settings.Secure.* thus detection of access to the desired constants fails, as currently the only checked names are Settings.Global.*?
I am right when I pointed out that as handleLoadPackage() is executed for each and every package loaded, Settings.Global.getInt() and Settings.Secure.getInt() end up with a huge stack of registered hooks?
But maybe there is some singleton mechanism?
On the other hand, if you confirm there is an issue, how could it be fixed? Could initZygote() be used instead (maybe it runs too soon)?

Where does an event go when injecting it into /dev/input/eventx?

I think I have read all post related with my query, some of them helped but I still can´t find the correct approach.
Im trying to develope an app which has to inject touch events into the system. As I was reading if you dont have system signature you can´t use the "logic" way, so we have to manage it using /dev/input/eventX.
Said that, I also attach photo of how events go through the system:
http://imageshack.us/f/201/eventosenandroid.png/
So I want to be sure that I understand how system manage events.
What I suppose is: When you inject a touch event in /dev/input/eventX the sequence for the event will finish into the activity which is currently "in the screen"
I just need to be sure if I can assume that it works like that or not really.
Thanks in advance
You managed to get somewhere with that? If not, did you have a look here?
Android INJECT_EVENTS permission
http://developer.android.com/reference/android/Manifest.permission.html#INJECT_EVENTS

Android Key Handling (Framework)

There are some parts of the framework which are not quite clear to me yet. I am well known with the flow of an input event (Kernel -> Eventhub -> InputReader -> InputDispatcher -> ...).
Situation
(Requirements: Handle input keys without changing the Android Framework.)
I want to handle key events coming from a device (keyboard/gamepad/controller/...) but there are some requirements. For one, I don't want to change the Android framework. This means, I don't want to extends the WindowManagerPolicy and its functions like interceptKeyBeforeDispatching where the home-key is being handled. This would result in the key event being dispatched into the application layer which is fine. The downside is, I have another tricky requirement here.
Example: When I am playing Angry Birds and I press my GoToAlpha-button on my connected input device, the Alpha-application has to start. Angry Birds has no clue which button GoToAlpha is, will not handle/recognize it and there will be for example no intent broadcasted to start my Alpha-application.
Question
Is there a way to handle my (custom) key event after it is being dispatched, knowing that the application in the foreground can not handle the key?
My (failed) solutions
Create a service which will handle the key events. This is not possible because an application like Angry Birds will not bind to my service and the key event will not be caught inside my service. If I am wrong, please provide more information :).
Create an external library where I allow my application's activities to inherit from my own ActivityBase. All the key events and there default behavior can be handled here. Downside, existing applications will not support my custom key events because they don't use the library.
Extend the framework would be in my eyes the cleanest solution but that will result in not meeting my requirement.
Any help or useful information would be appreciated
Extra
If the first question could be solved on one way or another.. I want
to customize my Intent behind the GoToAlpha-button. This means.. By
default the Alpha-application will be started but after the user has
customized it, the Beta-application will be started from now on.. Any
thoughts?
Thanks
Thanks for the comment Victor.
Using the InputMethodService will not provide me with enough freedom and functionality to handle my problems.
My Solution / Compromise
Within the Android Framework, there is a PhoneWindowManager which is responsible for handling InputEvents. The WindowManagerService which is started by the SystemServer, is owner of this manager and creates an instance.
By creating my own custom WindowManager and let it inherit from Android's PhoneWindowManager, I don't lose any default functionality and this allows me to add my own implementation within this class. This results is adding a new file to the framework and changing only one line inside the Android Framework: The WindowManagerService will not create a PhoneWindowManager, but will create a CustomPhoneWindowManager (extends PhoneWindowManager).
If anyone sees a better solution or has any specific thoughts about my compromis, don't hesitate to comment. :)
I doubt that it's possible with public API's (Boy and Martijn pointed out security concerns).
Most like your best bets (if you don't want to customize Android) would be
a) Try to use InputMethodService (http://developer.android.com/reference/android/inputmethodservice/InputMethodService.html)
It doesn't give that kind of control which you wish, but it could be enough for some needs.
b) Try to go through whole stack (from Kernel to Application) and find some vulnerabilities to use.
This definitely will take a lot of time and doesn't guarantee to bring any fruits.

Android: Get Time Spent Per Activity

Firstly, I'm not looking for time spent on a given application. There is already "an app for that", com.android.settings/.UsageStats, and a good deal of supporting code in the AOSP frameworks/base/services/java/com/android/server/am/UsageStatsService.java, etc.
The code that I've examined so far does not seem to record elapsed time spent on particular <activity>s. I have thought to get this information two ways, but feel there must be something cleaner and simpler, that leverages more existing code. The ideas have been:
Instrument the base Activity class onPause() and onResume(), to hack in a timestamp, and log the info some place (probably a SQLite database.)
Instrument the Context class, to make note whenever startActivity() and friends are called.
So what do you think -- anything better than those options? Thank you in advance!
So what do you think -- anything better than those options?
Anything is better than #2, which requires custom firmware.
#1 is your only option within the SDK for API Level 13 on down AFAIK.
API Level 14 (a.k.a., Android 4.0) added in Application.ActivityLifecycleCallbacks, which you can register via registerActivityLifecycleCallbacks() called on your Application (e.g., getApplicationContext()). I haven't used these yet, but it would appear that you can arrange for a single listener to be notified of activities coming and going, avoiding forcing you to extend some common base Activity class with your desired logging.

Call Back button from service Android (system-wide)

I need to remap the Honeycomb "Back" button to a button in my app (service) but after hours of search I'm still nowhere. The functionality must be there system-wise like the back button in ButtonSaviour (see market)
Most solutions for emulating the Back button are based on calling finish(). Not sure if it will work in my case since I have to call finish() from whatever activity I find on the foreground. I do manage to get the foreground application with the code
ActivityManager am = (ActivityManager) getContext().getSystemService(getContext().ACTIVITY_SERVICE);
List<RunningTaskInfo> T = am.getRunningTasks(5);
System.out.println("top activity: "+T.get(0).topActivity);
but I'm not sure how I should send a finish() intent to that..
I also tried the solution posted here http://www.anddev.org/throwing-simulating_keystrokes_programatically-t717.html but I couldn't get around the IWindowManager (has it been removed in Honeycomb?). That solution, however, looks interesting because with that I could send KeyEvent.KEYCODE_BACK from anywhere, anytime.
Please let me know which is the best way to implement this functionality SYSTEM-WIDE, i.e. from a service rather than from a specific application of mine.
cheers
PS: The app is meant to run on my own rooted tablet rather than for distribution to others.
Why does people spam the thread with advises about designs and good practices when the question clearly states that this will not be used for the market?!
Replacing android nav bar is sometimes required in some applications, even if no more than for own pleasure (or programmer satisfaction).
try from java Runtime exec
input keyevent 4
4 means back
button savior most likely uses hidden api, I had encountered that somewere, but don't remember now. When I will find it, I will post back.
The reason you're not finding an answer to this is that this is a terribly hacky way to do things and it indicates that there is something majorly broken with the design of your app. You should not be able to "call the back button," that doesn't make any sense at all. In fact, you really shouldn't change the behavior of the back button at all, users get really upset when you do that. If you have a service, and you need to send messages to an Activity, then use a messenger. But you should certainly not (and certainly cannot) be changing the behavior of other apps from your service. (This would indicate a major security flaw in the system, and would let you hijack someone else's UI, doing potentially dangerous, or at least annoying, things.)
Will the activity be open when you want to simulate the back button? If so, you could set up a timer inside your activity that checks for an exit file every 5 seconds or so. Then, from your service, create the exit file when you want to simulate the back press. When the activity sees that the exit file was created, delete that file and call finish().
As others have suggested, though, doing things this way means that you might need to rethink the app's design. What exactly are you trying to achieve?

Categories

Resources