Software Development [FYT units] FytHWOneKey: non-rooted app to assign other apps to the unit hardware buttons - FYT Android Head Units

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Hi,
I created an app (first release March 2019) that works on standard FYT ROMs (Joying, T'eyes, KingBeats, NaviFly, Funrover, some Witsons, some Sinosmarts, iDoing, etc) and allows to modify the standard actions (started apps) of a number of the hardware buttons on the units.
See on my github repository.
It does not (always) work in combination with the Steering Wheel keys if they are controlled by the CANbus..
It is simple but has the great benefit that you do not need a rooted unit (YOU DON'T NEED ROOT, but it functions just as well on a rooted unit).
The app is < 50 Kb and starts therefore extremely fast.
Again: See on my github repository.
New release 1.6.0 18 December 2022:
Changelog:
giladg (Gilad S.) added functionality for Llamalab Automate. A tool to automate various tasks and app flows on your Android device.
Download this 1.6.0 version.
For a "Changelog" about this and previous versions, you can visit the general Releases page.
Currently there are 4 options to "start something" with the "Call method"
by package name
by intent (package name / intent)
by system call (terminal command(s) or script)
by LlamaLab Automate Flow URI (Automate various tasks; Added by giladgd (Gilad S.)
by package name: This is NOT the name of the apk but the internal package name. How do you get this "package name"?
Use the "List all Installed apps" option in the main screen of the settings. It shows the app icon, the app name and the package name. This package name is what you need. You can select it and copy & paste it into the field.
Search in play.google.com for the app you want to start. Say you want to start the navigation app "Magic Earth" and you have selected that one in the play store (in a browser, not the android app). In the address bar you will then see "https://play.google.com/store/apps/details?id=com.generalmagic.magicearth". The bold part behind the "id=" is your package name.
by intent: Every app has a "launch" intent to start the app. Some apps can also be started with other intents to immediately start a specific function. Google Search can be started with the launch intent, but you can also start it with the Google Voice search option intent. The Google (Search) package name is "com.google.android.googlequicksearchbox", the specific intent for google voice search is "com.google.android.googlequicksearchbox.VoiceSearchActivity". The combined "String to be used" is therefore "com.google.android.googlequicksearchbox/com.google.android.googlequicksearchbox.VoiceSearchActivity".
Another example is the Joying Bluetooth apk having intents for the dialer (default launch), the call receiver, the bluetooth streaming, the pairing and a few more.
by system call: A system call can be a direct (linux) command or a shell script or a binary (to do something).
= Commands can be a single command as in:
"ls -l > /sdcard/some_file.txt" to capture a directory listing to a file
"input keyevent 3" => Go to the Home screen (of the default launcher)
"am start -a android.intent.action.MAIN -c android.intent.category.HOME" => Go to the Home screen (of the default launcher)
"input keyevent 127" => pause active media player (any media player)
"input key event 126" => (re)start last used media player.
"am start com.syu.radio/com.syu.radio.Launch" => Start the radio app with the default launch intent (or better use "by package name": com.syu.radio; Or use "by intent": com.syu.radio/com.syu.radio.Launch)
As you can see from the 2nd and 3rd example, there are multiple ways to do something.
From the 6th example you can see that you can start an app (the radio) from the command line with "am start <full intent>", or by package name, or by intent directly.
by Automate Flow URI: Every Flow in LlamaLab Automate has a URI you can find in its Flow Beginning block.
For example: content://com.llamalab.automate.provider/flows/7/statements/1.
If you want to start one Flow on a short button press and a different Flow on a long button press, you can set the value to be the short press Flow URI, followed by a new line with the maximum time to wait for a second button press in milliseconds, followed by a new line with the long press Flow URI.
For examples on how to use a created flow from FytHWOneKey, see the Readme on the github repository site. On how to use LlamaLab Automate itself you have to visit the LlamaLab website.

** Reserved **
(You never know)

Hi Surfer.
I will check this app tonight.
My unit has 5 HW buttons: FF, REW, DVD, MUTE, MODE.
I want to change function for DVD (as the HU has no DVD drive), mute (as it repeats function of volume knob press) and Mode(to change it to app of my choice).
Will mute button work separately of volume knob press?
Is it possible to call specific activity on some app (if that app has several ones)?
Can you share the methods you have used in this app for rerouting button presses (short, in technical terms)?
Thanks in advance.

IG_Vasilich said:
Hi Surfer.
I will check this app tonight.
My unit has 5 HW buttons: FF, REW, DVD, MUTE, MODE.
I want to change function for DVD (as the HU has no DVD drive), mute (as it repeats function of volume knob press) and Mode(to change it to app of my choice).
Will mute button work separately of volume knob press?
Is it possible to call specific activity on some app (if that app has several ones)?
Can you share the methods you have used in this app for rerouting button presses (short, in technical terms)?
Thanks in advance.
Click to expand...
Click to collapse
The "application" buttons simply call the app connected to it. I could easily capture that.
Mode will not work as it is an internally arranged "carroussel" function in the server apk. I can't capture that.
I don't know whether the mute button acts differently from the volume knob press. Also in that case I can't capture it as it is a direct android keyevent call. You would really need Xposed to capture the entire function.
Currently my app only allows for calling an app by package name, which will always start the default launching activity. I have already the layout ready for a "call by intent" which allows you to call any activity which is defined in the AndroidManifest of that app: This is what you are asking for. I will also add a system call.
The point is that I wanted to wait how many people would use my app before putting more time in it. It has only been downloaded 4 times: 2x by me, 1x by you (I assume), and someone else (I guess Paul Borges).
Of course the "audience" is rather limited as it only deals with those units having hardware buttons.
This apk is really a non-rooted "poor mans" Xposed spin off. The options are really limited in comparison with Xposed, but then of course you need root and Xposed.
The working:
- I checked in the AndroidManifest.xml of the radio, music, dvd and eq apk what their launch intents/activities were.
- Then I created aliases for them in the AndroidManifest.xml of my OneKey app "targeting" those original intents/activities to activities in my app, which then call the configured apps.
- In that case Android finds two intents doing the same and therefore asking which app to start. It is actually exactly the same as clicking an html file where the Android Browser and Google Chrome (and/or firefox/opera/etc) have an intent defined which takes care of an html file. Or in case of a gpx file in case of several navigation apps.
Please have a look on my github at my AndroidManifest.xml. I think i put it quite understandably in there
Edit: If you investigate the launch intents for for example TomTom or PowerAmp or whatever app, you could also capture them via aliases in "your" app if you would want that. That is also what the Google package installer does when you compare it to the default AOSP android package installer.

Thank you for explanation, got the trick with package names, and all the restrictions related to it. Nice idea!
Will report whether it will work for my DVD hw key.
Will also test it with media key - maybe it will help to replace some apps, hardcoded in the caroussel, with calls to my apps (though in that case your app has to be extended to the package names used in the caroussel).

Tested it. As it appeared, my HU has EJECT button, not DVD, so this button stays dead.
But i tested MODE button, and it calls following packages:
com.syu.radio
com.syu.bt - BT phone
com.syu.bt - BT AV
com.syu.video
com.syu.av
com.syu.music
????? - smth like ipod (i don't have ipod)
SO for that case i have already changed music player to the app i use for music. Maybe you can implement other package names as well, to be able to change some apps in caroussel mode to other ones (e.g. i don't use video on this unit, so i would like to change call to video player to call to DAB software).
And another question: in the list of installed apps with package names is it possible to copy package name, to later paste it in configuration dialog for replacing?
Thanks in advance

IG_Vasilich said:
Tested it. As it appeared, my HU has EJECT button, not DVD, so this button stays dead.
But i tested MODE button, and it calls following packages:
com.syu.radio
com.syu.bt - BT phone
com.syu.bt - BT AV
com.syu.video
com.syu.av
com.syu.music
????? - smth like ipod (i don't have ipod)
SO for that case i have already changed music player to the app i use for music. Maybe you can implement other package names as well, to be able to change some apps in caroussel mode to other ones (e.g. i don't use video on this unit, so i would like to change call to video player to call to DAB software).
And another question: in the list of installed apps with package names is it possible to copy package name, to later paste it in configuration dialog for replacing?
Thanks in advance
Click to expand...
Click to collapse
W.r.t. to the MODE carrousel: Yes, I can capture the activities/intents for the BT phone/AV options (one app, 2 launch intents) and the video and av apk. Music is already captured.
Eject does not call an app, but performs a "physical" action in the device (if a DVDplayer is installed). I captured that in Xposed where I capture the entire function. I'm afraid that won't be possible in this app.
Copying of package names: I already experienced that myself but it was not high on my priority list. I do not know why that doesn't work. It is a standard text field, which should allow copy&paste. I will google for it.

surfer63 said:
Copying of package names: I already experienced that myself but it was not high on my priority list. I do not know why that doesn't work. It is a standard text field, which should allow copy&paste. I will google for it.
Click to expand...
Click to collapse
Stupid. It requires 2 enties in the layout per textview. I did some copy&paste from one of my other apps and I did not copy that.
Code:
android:longClickable="true"
android:textIsSelectable="true"
So copy&paste now works in my local version. Not uploaded yet.

Not on release page, only in attached version:
- Added copy&paste
- Added BT phone and BT AV options for the MODE "carrousel" button.
@IG_Vasilich: As I do not have a MODE button on either of my 2 units, I can't test myself. Can you please test if the BT phone and BT AV options work? If so, I will also add video and av.
EDIT: Sorry. I made an error. File temporarily removed.
EDIT2: New version attached. With BT AV, BT Phone, Video and AV
Attachment removed. Version not correct.

Sorry for late reply.
My HW button seems to be broken - nothing happens when i press it. And it worked the day before yesterday. Even with uninstalled HWOneKey app. So i tested it with Mode button from steering wheel (or actually any SW key mapped to Mode function - this way you can also test it ).
And there are the differences to previous version:
1. package name copy works!
2. Rado app starts instantly - no request for OneKey or Radio. in previous version i got a selection menu what to use. Have you changed anything related to radio?
And now the rest of report:
* Media button override works - i got selection dialog once, and then it just started the player i have selected in OneKey. Good.
* No other selection dialogs - neither for BT Phone, nor for BT AV. Just as before.
So with your last version only media(music) override works.

IG_Vasilich said:
Sorry for late reply.
My HW button seems to be broken - nothing happens when i press it. And it worked the day before yesterday. Even with uninstalled HWOneKey app. So i tested it with Mode button from steering wheel (or actually any SW key mapped to Mode function - this way you can also test it ).
And there are the differences to previous version:
1. package name copy works!
2. Rado app starts instantly - no request for OneKey or Radio. in previous version i got a selection menu what to use. Have you changed anything related to radio?
And now the rest of report:
* Media button override works - i got selection dialog once, and then it just started the player i have selected in OneKey. Good.
* No other selection dialogs - neither for BT Phone, nor for BT AV. Just as before.
So with your last version only media(music) override works.
Click to expand...
Click to collapse
2. This can happen if you selected "Always" for the action to start the radio. Then you will have to undo the "default" activity/app/action. I assume somewhere from the settings, but I can't find it right now. I will do some googling. Normally you should be able to do this from Settings -> Apps -> "specific app" -> Clear Defaults.
I will check again on my unit, but as far as I can remember it did work for me.
The BT AV and BT phone and others: I will check this weekend. I can't test it myself, so it is a theoretical approach (and of course I could have made some other ordinary mistake).

I will check radio defaults tonight (completely forgotten about this setting, just assumed that if other app is uninstalled then installed again, that setting should be reset)

IG_Vasilich said:
Tested it. As it appeared, my HU has EJECT button, not DVD, so this button stays dead.
But i tested MODE button, and it calls following packages:
com.syu.radio
com.syu.bt - BT phone
com.syu.bt - BT AV
com.syu.video
com.syu.av
com.syu.music
????? - smth like ipod (i don't have ipod)
Click to expand...
Click to collapse
I had a quick look in the "000000000_com.syu.ms.apk" (PX5), which is called " Sofia-1-C9-Server-V1.0.apk" on the Sofia 3GR and called "190000000_com.syu.ms.apk" on the i9853
the actual code is:
Code:
public static int AppByAppId(int value) {
if (DataBt.sPhoneWork != 0 && value != 2) {
return 2;
}
switch (value) {
case 1:
radio();
return 2;
case 2:
btPageDialByKey();
return 2;
case 3:
btPageBtAvForce();
return 2;
case 4:
return dvd();
case 5:
return aux();
case 6:
return tv();
case 7:
return ipod();
case 8:
return audioPlayer();
case 9:
return videoPlayer();
case 11:
return carRadio();
case 12:
carUsb();
return 2;
case 13:
carUsbCd();
return 2;
default:
return 0;
}
}
I assume that based on the installed components it can rotate through a whole lot of options.

IG_Vasilich said:
I will check radio defaults tonight (completely forgotten about this setting, just assumed that if other app is uninstalled then installed again, that setting should be reset)
Click to expand...
Click to collapse
Hmm. I would expect that as well. It should.
If you have two apps where one is the default, and you install a 3rd app being able to do the same, Android should ask again.

i have checked MODE/carousel on my SoFIA unit - it has 6 items:
radio
BT Phone
BT AV
Aux
Music
Video.
acc to code
Java:
public static synchronized void mcuKeyMode() {
synchronized (HandlerMain.class) {
if (LOCK_KEY_MODE.unlock(800)) {
int index = (DataMain.sAppIdSequnceIndex + 1) % FinalMain.APP_ID_CNT_MAX;
int endIndex = ((DataMain.sAppIdSequnceIndex - 1) + FinalMain.APP_ID_CNT_MAX) % FinalMain.APP_ID_CNT_MAX;
while (index != endIndex && (JumpPage.AppByAppId(DataMain.APP_ID_SEQUENCE[index]) != JumpPage.RESULT_OK || DataMain.APP_ID_SEQUENCE[index] == -1)) {
index = (index + 1) % FinalMain.APP_ID_CNT_MAX;
}
DataMain.sAppIdSequnceIndex = index;
}
}
}
and to
Java:
public static final int APP_ID_NULL = 0;
public static final int APP_ID_RADIO = 1;
public static final int APP_ID_BTPHONE = 2;
public static final int APP_ID_BTAV = 3;
public static final int APP_ID_DVD = 4;
public static final int APP_ID_AUX = 5;
public static final int APP_ID_TV = 6;
public static final int APP_ID_IPOD = 7;
public static final int APP_ID_AUDIO_PLAYER= 8;
public static final int APP_ID_VIDEO_PLAYER= 9;
public static final int APP_ID_THIRD_PLAYER= 10;
public static final int APP_ID_CAR_RADIO = 11;
public static final int APP_ID_CAR_BTPHONE = 12;
public static final int APP_ID_CAR_USB = 13;
public static final int APP_ID_DVR = 14;
public static final int APP_ID_3GPHONE = 15;
public static final int APP_ID_SPECIAL = 16;
public static final int APP_ID_CNT_MAX = 20;
...
for (int i = 0; i < 20; i++) {
APP_ID_SEQUENCE[i] = i;
}
APP_ID_SEQUENCE[10] = -1;
APP_ID_SEQUENCE[11] = -1;
APP_ID_SEQUENCE[12] = -1;
APP_ID_SEQUENCE[13] = -1;
and to code AppByAppId you have posted, this works exactly as expected.
Java:
public static int AppByAppId(int value) {
if (DataBt.sPhoneWork != 0 && value != FinalMain.APP_ID_BTPHONE) {
return RESULT_OK;
}
switch (value) {
case FinalMain.APP_ID_RADIO:
radio();
return RESULT_OK;
case FinalMain.APP_ID_BTPHONE:
btPageDialByKey();
return RESULT_OK;
case FinalMain.APP_ID_BTAV:
btPageBtAvForce();
return RESULT_OK;
case FinalMain.APP_ID_DVD:
return dvd();
case FinalMain.APP_ID_AUX:
return aux();
case FinalMain.APP_ID_TV:
return tv();
case FinalMain.APP_ID_IPOD:
return ipod();
case FinalMain.APP_ID_AUDIO_PLAYER:
return audioPlayer();
case FinalMain.APP_ID_VIDEO_PLAYER:
return videoPlayer();
case FinalMain.APP_ID_CAR_RADIO:
return carRadio();
case FinalMain.APP_ID_CAR_BTPHONE:
carUsb();
return RESULT_OK;
case FinalMain.APP_ID_CAR_USB:
carUsbCd();
return RESULT_OK;
default:
return RESULT_NO_INTENT;
}
}

after resetting of default settings for OneKey and Radio my MediaKey from steering wheel asked about radio and media. SO far OK, but it hadn't ask about BT.

IG_Vasilich said:
after resetting of default settings for OneKey and Radio my MediaKey from steering wheel asked about radio and media. SO far OK, but it hadn't ask about BT.
Click to expand...
Click to collapse
I made this actually for the hardware buttons on the unit, but it is good to hear that it also (partly) works on the steering wheel buttons.
The BTPhone and BT AV both have double intent filters. I combined those doubles into one for each. Now I split them up again.
Please try attached.
EDIT: I attached a new one at 11:58 CET

tested the last attached APK - radio, Aux, video and music can be overriden, BT - not. I tried to stop BT app, clead all defaults, and test again - no luck Do you have some ideas more to try?
For those, that working - can it be possible to send "play" intent/MediaKey event to the app after start? I assume that after FM Radio starts, all other sources stop. That is why i need to press "play" button for music app (AIMP in my case) and reselect radio station in app instead of video player (in my case DAB-Z).
Thanks.

IG_Vasilich said:
tested the last attached APK - radio, Aux, video and music can be overriden, BT - not. I tried to stop BT app, clead all defaults, and test again - no luck Do you have some ideas more to try?
For those, that working - can it be possible to send "play" intent/MediaKey event to the app after start? I assume that after FM Radio starts, all other sources stop. That is why i need to press "play" button for music app (AIMP in my case) and reselect radio station in app instead of video player (in my case DAB-Z).
Thanks.
Click to expand...
Click to collapse
I will first look in my XFytTweaker to see what function is captured an see what that function does. Stupid that I did not think about that earlier
Otherwise, I will write a small test app that "should" do what the BT function does. And then see what activity/intent is selected/started.
In my code I already made options for starting an app by intent and for a system call, just like in the XSofiaTweaker and XFytTweaker.
That will take a few hours to work out and I will do that somewhere this week.

just FYI - i have tapped EQ button in MCU settings and got selection dialog - OneKey or Built-in Equalizer.
So the only things that do not work are BT (and i cannot test DVD).
Your prebeta description on GitHub states that aux doesn't work, but it works here (i have written it in one of previous posts)

Related

Combobox with Smartphones vs. WinMo

With the help of the peeps here, i got my little program working on the WinMo (touch screen) platform. Now im working on converting it into the Smartphone (non-touchscreen) platform. Seems with each medium im go, its more and more restrictive :|
anyway. I have a combobox on the screen. I has a few numbered values used to generate a random number. On the windows and winmo verson, i can just select the number from the drop down combobox, and it will generate a random number based on the selected item..
However in the Smartphone version, despite having the combobox and dispite selecting a number from it, when i hit the generate button (ie the enter button) it brings up a window with all the values in the combo box, asking me to select one from it. One when i pick one and hit "Done" does it process.
How can i get it to pull from the combobox list and Not bring up the extra screen?
Also, When the program first starts, despite me defining a default index, there is no number displayed in the combobox when it first starts up. And ideas on how to fix this?
Thanks in advance.
Good fun isn't it?
When you move from PPC to Smartphone some of the .NET objects dissappear and others behave completely differently.
OK lets do these one at a time. The Enter/Action key causes the ComboBox to display its list of contents, as a new window. It is coded into the object itself. To bypass it, you have to trick it into thinking it has already been dealt with. On the KeyDown event of the ComboBox add
Code:
private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == System.Windows.Forms.Keys.Enter)
{
e.Handled = true;
}
}
Voila!
The enter key is ignored and nothing happens. Add any processing code here to deal with the selected item if required, as the control itself will never see that the 'Enter' key has been pressed.
To get the box to display its value when your application starts, use :
Code:
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.SelectedIndex = 0;
}
It doesn't actually change anything as it zero to start with, but it will trigger the ComboBox to redraw itself as it thinks it has changed.
Good luck.
The "comboBox1.SelectedIndex = 0;" ive tried already, didn't seem to help. Ill try the other when i get a moment..
I should also mention ( thought i did before, sorry) that im working with VB (for school) tho converting that code to vb shouldn't be too hard
OK I'll code it up in VB and post it. But it will have to wait until I can get to a suitable machine on which to do it. Monday onwards....... Watch this space.
Here it is. VS 2005. (2008 will update it). Both problems mentioned in the original post are corrected. All the extra lines of code added by VS for the KeyDown event have been removed.

[Q] Turning off microphone AGC?

Does anyone know of an app for Android that can turn off the microphone AGC (Auto-Gain Control)? It's impossible to do through the system settings.
I've only encountered one audio recording software called "TapeMachine" that can do it. But it only works within the software. It would be great to be able to record videos with the camera while the AGC is off.
Well, I have some technical information, but I can't do much with it because I'm not a programmer.
The programmer of an app called "Break Speed" uses a code in his app to disable AGC and he wrote me what the code he uses is.
Maybe someone can use this information to create an app that can disable AGC. This is what he wrote me:
I found that in Android 2.2 (and higher), they introduced an undocumented flag in the AudioRecord() class, called “VoiceRecogntionQuality”. In the code, there is a note to expose and document that flag (it just hasn’t been done yet.) So I expect that it is supported (and will continue to be.) My guess is that AGC was added to 2.2 and this is the flag that disables it.
Here’s the code I used to adjust my recordings for it:
// We use our version to attempt "VoiceRecogntionQuality" recordings (to disable AGC)
int version = Integer.parseInt(android.os.Build.VERSION.SDK);
// Try to get the audio record for Android 2.2 and greater using 'voice recognition quality'
if (version >= 7)
{
recordInstance = new AudioRecord(6, m_frequency, m_channelConfiguration, m_audioEncoding, bufferSizeBytes * m_bufferCount);
}
// For older versions of Android (or failed attempts of the voice recognition quality recordings)
if (version < 7 || recordInstance.getState() == AudioRecord.STATE_UNINITIALIZED)
{
recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, m_frequency, m_channelConfiguration, m_audioEncoding, bufferSizeBytes * m_bufferCount);
}
Click to expand...
Click to collapse

[Q] GPS-tracking acting weird.

Hello!
Firstly, I don’t speak english very well. But I beg your indulgence.
I have some troubles with every GPS tracking apps I’ve installed on my Omnia W (I8350). While I start the tracking and locking my phone, it’s tracking quite well.
BUT, if I want to write a SMS or something. I have to press on the Windows-button to come out to the main menu, and the GPS-tracking will stop. But the time counter continues unaffected.
I think it’s a bit weird behavior. I have testet, Endomondo, Sports Tracker, SmartRunner, Runtastic. And all of these apps acts at same way.
Is this normally? Is it the OS, which stops the GPS-device, while the app is minimized?
It's the OS, yes. In theory, an app could continue GPS tracking in the background, but since that's not officially allowed (you'd need to mess with the APIs in ways Microsoft doesn't approve of) it wouldn't be allowed into the Marketplace.
@GoodDayToDie
Do you know any working hack that will allow app continue tracking in the background? Maybe some registry changing?
If app cannot get to Marketplace, it is not problem for me. I want to create GPS tracking in background only for myself.
At the max it will work with screen lock though Endomodo doesnt support but others do. And Yes its a problem with Windows Phone API not allowing intensive tasks to run in background.
May be a custom app can do which somebody can sideload but then its for one few people.
Well, the dehydration tweak that Jaxbot found (and yes, it's a registry change) allows an app to keep running in the background. That doesn't guarantee it will actually keep tracking - the app still gets notified that it's leaving the foreground, and a "well behaved" app might stop using resources like the GPS when it gets that notification - but it makes it possible. Normally I'd direct you to my MultiTaskToggle app, which is a very simple and user-friendly way to change this value, but it doesn't work on second-gen Samsung phones at this time.
GoodDayToDie said:
Well, the dehydration tweak that Jaxbot found (and yes, it's a registry change) allows an app to keep running in the background. That doesn't guarantee it will actually keep tracking - the app still gets notified that it's leaving the foreground, and a "well behaved" app might stop using resources like the GPS when it gets that notification - but it makes it possible. Normally I'd direct you to my MultiTaskToggle app, which is a very simple and user-friendly way to change this value, but it doesn't work on second-gen Samsung phones at this time.
Click to expand...
Click to collapse
I am pretty sure that just keeps it in memory, but not actually running. I downloaded the source code to see what it does and manually applied the registry change. It allows fast resume from any app, even if it was not recompiled for Mango. This is good for apps, such as Angry Birds, which would otherwise dehydrate, and need to restart. But, when using it, you can see that if you launch a bird, and then switch out. Wait a while. Then switch back to it. You can see that the launched bird has not moved since switching to a different app. It is possible that the app is suspending by responding to the fact that it is being pushed into the background.
Most apps that display time, or a timer that counts are not actually counting. What they do to display it get an initial time value when the timer starts. Then they get the time and subtract the initial time from it. So, an app that seems to count seconds, even when in the background is really just successfully get the current time and subtracting the original time before suspension. They may use a timer control to schedule the frequency that this calculation is made.
To verify, it would be good to test with a simple program that does something like:
Code:
[FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]namespace[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] TestCountApp
{
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] public[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]partial[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]class[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]Form1[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] : [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]Form
[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] {
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] public[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] Form1()
{
InitializeComponent();
}
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] int[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] i = 0;
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] private[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] btnStart_Click([/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]object[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] sender, [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]EventArgs[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] e)
{
timer1.Start();
}
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] private[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] timer1_Tick([/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]object[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] sender, [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]EventArgs[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] e)
{
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] int[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] val = 0;
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] try
[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] {
val = [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2].Parse(tbText.Text.ToString());
}
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] catch[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] ([/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]Exception[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] ex)
{
}
i++;
tbText.Text = i.ToString();
}
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] private[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] btnStop_Click([/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]object[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] sender, [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]EventArgs[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] e)
{
timer1.Stop();
}
}
}
of course the timer class might automatically suspend for Windows Phone.
So, a simple for loop might be better.
Code:
[FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]namespace[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] TestCountApp
{
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] public[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]partial[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]class[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]Form1[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] : [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]Form
[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] {
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] public[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] Form1()
{
InitializeComponent();
}
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2][/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] private[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] btnStart_Click([/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]object[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] sender, [/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]EventArgs[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] e)
{
[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff] for[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] ([/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff][FONT=Consolas][SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] i = 0; i < 60; i++)
{
tbText.Text = i.ToString();
System.Threading.[/SIZE][/FONT][/SIZE][/FONT][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af][FONT=Consolas][SIZE=2][COLOR=#2b91af]Thread[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2].Sleep(1000);
}
}
[/SIZE][/FONT][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Consolas][SIZE=2][FONT=Consolas][SIZE=2] }
}
If it is background processing, you should see 59, after returning to the app. It will remain blank until the end.
[/SIZE][/SIZE][/FONT][/FONT][/SIZE][/FONT][/SIZE][/FONT]
GoodDayToDie said:
Well, the dehydration tweak that Jaxbot found (and yes, it's a registry change) allows an app to keep running in the background. That doesn't guarantee it will actually keep tracking - the app still gets notified that it's leaving the foreground, and a "well behaved" app might stop using resources like the GPS when it gets that notification - but it makes it possible. Normally I'd direct you to my MultiTaskToggle app, which is a very simple and user-friendly way to change this value, but it doesn't work on second-gen Samsung phones at this time.
Click to expand...
Click to collapse
Unfortunatelly it doesn't help, because OS is suspending app executing. OS is just keeping app in memory.
Anyway I can use background task in debug build with LaunchForTest method that will allow me execute background code as often I want. However background task cannot access fresh GPS data. It can only used cached data which is refreshed every 15 minutes. Is any way to force GPS to refresh it's data when using GPS from background agent?
OK, in reverse order:
@Mendoza32: You are quite incorrect; the change to the registry I was talking about actually causes the OS to *not* suspend apps. It can cause problems for some of them. In Mango, an app is *always* kept in memory when it's backgrounded. Apps that weren't recompiled for Mango can't take advantage of this and will do a full rehydrate anyhow, but they don't hve to (using a process listing, you can see that the suspended processes are still in memory). However, even with the tweak, a few things are cut off, like audio (and possibly GPS). See my response to JVH3 for more info...
As for a background agent, there's no official way. I think if you abuse one of the background audio decoder agent classes, you might be able to make an agent that runs in the background and can access the GPS. I haven't tried, though, and there's no chance of it getting into the Marketplace.
@JVH3: If you read the really old threads on the subject, you'll see that the app really does keep running in the background. For example, you can create an app that will pop a MessageBox (which always goes to the foreground) after 10 seconds, start it and immediately hit the Windows key. A few seconds later, you'll get the message box. More practically, you can use this hack to do things like run the WebServer app (any version) in the background, and browse it in the foreground on the phone's IE (pointing to 127.0.0.1). This would be impossible if the app were suspened, obviously...
As for Angry Birds, the game is in fact pausing the XNA update/render loop when notified that it's going into the background. In theory, this allows it to save the entire current game state, including the flying bird, such that when you resume the app (from dehydration, or so it thinks), that bird is exactly where it was and you've lost no progress. I suspect it is actually doing this. On the other hand, a game like Puzzle Quest 2 (which is rather poorly behaved regarding dehydration) quite obviously does *not* suspend the update/render loop. It's a turn-based game, so there is no gameplay problem, but there are certain real-time graphical effects that, when you "resume" the game, will all render simultaneously. Additionally, the phone will get quite warm and use a lot of battery (and other games will run slowly) because Puzzle Quest 2 still eating CPU and GPU time in the background.
GoodDayToDie said:
As for a background agent, there's no official way. I think if you abuse one of the background audio decoder agent classes, you might be able to make an agent that runs in the background and can access the GPS. I haven't tried, though, and there's no chance of it getting into the Marketplace.
Click to expand...
Click to collapse
I do not want put app in Marketplace. It's only for me
GoodDayToDie said:
@JVH3: If you read the really old threads on the subject, you'll see that the app really does keep running in the background. For example, you can create an app that will pop a MessageBox (which always goes to the foreground) after 10 seconds, start it and immediately hit the Windows key. A few seconds later, you'll get the message box.
Click to expand...
Click to collapse
Could you provide some sample code how to display this message box when app is in background? I tried this but without any luck. Maybe I'm missing something.
Did you have the no-suspend/dehydrate tweak enabled? It should be simple (event handler for a button or something:
Thread.Sleep(10000); MessageBox.Show("Alert from background app");
Thank you very much GoodDayToDie. I see how it works now. As long as GUI thread is blocked, then background threads keep working (also the GPS). One drawback is that I cannot go back to my app. It just keep displaying "Resuming...", but this is because GUI thread is blocked.
@GoodDayToDie
I was all wrong. Blocking GUI thread doesn't help in anything, because OS is killing app.
Please take a look at this sample code:
Code:
using System;
using System.Diagnostics;
using System.IO.IsolatedStorage;
using System.Threading;
using System.Windows;
using Microsoft.Phone.Controls;
namespace PhoneAppBackgroundTest
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
this.Loaded -= this.MainPage_Loaded;
this.DisplayLastUpdateTime();
}
private void buttonBackgroundThread_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((s) =>
{
while (true)
{
this.UpdateLastUpdateTime();
Debug.WriteLine(DateTime.Now.ToString());
Thread.Sleep(1000);
}
});
}
private void buttonBlockGUIThread_Click(object sender, RoutedEventArgs e)
{
while (true)
{
Thread.Sleep(1000);
}
}
private string lastUpdateKey = "lastUpdate";
private void DisplayLastUpdateTime()
{
string value;
if (IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>(this.lastUpdateKey, out value))
{
MessageBox.Show("last update time: " + value);
}
}
private void UpdateLastUpdateTime()
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(this.lastUpdateKey))
IsolatedStorageSettings.ApplicationSettings.Remove(this.lastUpdateKey);
IsolatedStorageSettings.ApplicationSettings.Add(this.lastUpdateKey, DateTime.Now.ToString());
IsolatedStorageSettings.ApplicationSettings.Save();
}
}
}
Button "buttonBackgroundThread" is starting new background thread which updates settings value and display current time to Output window. When you press this button you will see in Ouput, that current time is displaying each second. When you use window key, then current time is no longer displaying in Output. So the thread gets suspended. When you go back to app it start to work again.
When you press on button "buttonBackgroundThread" and "buttonBlockGUIThread" and use window key, you will see that current time is keep displaying in Output. This works when you have debugger attached. If you follow this scenario on device without attached degubber you will see that app is getting killed by OS. To prove that app is displaing last update time at start.
So my question is: how to get managed threads keep running while app is in background? I'm attaching sample project, so you can test on your device and see that managed thread get suspended when you use window key.
Is maybe some way to use native threads that won't get suspended? I see your WebServer can run while app is in background. However you used native listeners.

Link contact adress to Nokia Drive

I use my7rom on my Omnia 7.
Is there anyway to link a contacts adress to Nokia Drive instead of Maps (stock wp7 app). It would be much more practical if Nokia Drive opened a navigation session instead.
Anyone up for the challenge? A reg-tweak perhaps?
// Manneman
Skickat från Windows Phone 7.8
There's two parts here. The first is identifying the correct "filetype" or URI scheme that is used for navigation. That shouldn't be too hard; a little digging in HKCU should reveal it. We already know about ones like callto: and http: and I'm actually (slowly) working on an app to allow people to easily change them. The second part is finding the correct command to load that address or route in the Nokia Maps app. If the app supports pinning routes or destinations to Start, this is probably possible. If not, it may not be possible in the app. Most apps aren't designed to accept command-line parameters, so even if you make them the default handler for a given filetype or URI scheme, they ignore the value you send them and just start as though launched from Start.
GoodDayToDie said:
If the app supports pinning routes or destinations to Start, this is probably possible.
Click to expand...
Click to collapse
Nokia Drive supports pinning to start so it should be possible. Unfortunately I can't tell you exact command line parameters 'cause my Lumia 900 still "in jail"
Let me see if I have a copy of the Nokia Drive XAP handy. I'll need to decompile it to figure out the correct parameters for launching it with the intent of navigating to a specific location. Note also that this might not be possible directly - for example, the app might store a list of locations internally, and the tiles only provide an index into that list rather than providing the location directly - but that just requires another layer of indirection.
In that case, you create an app that gets registered as the navigation handler, and in response to a navigation request, it writes the requested location into the Nokia Drive app and then chain-launches Nokia Drive with the index of the newly written location. That's just an example of one way that this might go wrong, but overall, the odds are actually pretty good. Obviously, all of this will require, at a minimum, write access to the HKCR hive in the registry.
Ah, guys! You are so kind helping me out. I´m really certain alot of members in the WP7 section would love for this to work!
// Manneman
GoodDayToDie said:
I'll need to decompile it to figure out the correct parameters for launching it with the intent of navigating to a specific location
Click to expand...
Click to collapse
GoodDayToDie, you may try much simpler solution. Just create assembly (dll) to show startup parameters in message box, and replace main Nokia Drive dll (but pin some location first).
That's actually harder than it sounds; even if the app is sideloaded (which would mean I already have the DLL) my fake would have to mimic the internal structure of the real app to a degree (namespaces, class names, default actions, etc.). That's not hard, but decompiling .NET is pretty trivial too.
AFAIR, Nokia Drive is obfuscated (but I'm not 100% sure). Also, you don't need to duplicate all names and structures; just a stuff mentioned in WMAppManifest (I hope so). BTW, I forgot: I still have unlocked handset; if I'll found time, will try today later.
Update: tried but without of luck What I did:
- installed Nokia Drive first;
- downloaded map and pinned current location;
- created fake app with same app guid and namespace name ("Drive"), and performed app update (that operation completely override whole solution but NokiaDrive tile still pinned to the start screen);
- tried a few different page names (_default.xaml, QuickStartPage.xaml, DestinationPickerPage.xaml, FavoritesPage.xaml) with code
Code:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
MessageBox.Show("Hello from fake dll");
if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New)
{
string[] keys = NavigationContext.QueryString.Keys.ToArray();
string[] values = NavigationContext.QueryString.Values.ToArray();
string param = "";
for (int i = 0; i < keys.Length; i++)
{
param += keys[i] + " -> " + values[i] + "\n";
}
MessageBox.Show("parameters: " + param);
}
}
But result always the same: app doesn't start from the pinned tile
Update 2: Finally, I did it
The trick is:
- do the same as I've described above (you should have pinned tile from ND);
- add following code to the start page:
Code:
public MainPage()
{
InitializeComponent();
var appTile = ShellTile.ActiveTiles.Last();
if (appTile != null)
{
//MessageBox.Show(appTile.NavigationUri.OriginalString);
EmailComposeTask emailTask = new EmailComposeTask();
emailTask.Subject = "NokiaDrive pinned parameters";
emailTask.Body = appTile.NavigationUri.OriginalString;
try
{
emailTask.Show();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK);
}
}
}
- run app as usual (not from tile);
We allset - all params are sent to our email (I'm too lazy to manually copy all stuff )
Here we are (start parameters; bold values are changed for privacy reason ):
/_default?destination.name=200 SomeName Street&destination.latitude=49.5255378801376&destination.longitude=-72.4296837244183&destination.address.street=SomeName Street&destination.address.houseno=200&destination.address.district=&destination.address.county=&destination.address.city=SomeCity&destination.address.state=&destination.address.country=USA&destination.address.postcode=05720&destination.hashCode=371767793destination.address.statecode=MA&pinnedFrom=Favorites
P.S. Just found: Navigon also has ability to pin address to the start tile So, if you find the way to modify map protocol (or how it calls), it will be a really nice hack! BTW, could you remind me: do we have ability to launch assembly by GUID (on the full-/policy-unlocked phones)? If "yes", it's possible to write a real nice "proxy" app to handle map requests
I don't know about launching assemblies directly, but it's certainly possible to launch apps by GUID. It doesn't even require anything more than dev-unlock in fact (although of course you can only launch apps that you could launch anyhow). So yes, a proxy app is totally possible. That's actually what I'm working on (started as a project to make a Kindle ebook file loader, that would pur .mobi/.prc file in the Kindle app's folder and then launch the app).
GoodDayToDie, could you please, take a look to the registry, for default map protocol handler and figure out how to change that stuff? I'm pretty busy these days (and probably will be extremely busy couple of next months) but we can cooperate and create this app...
I'll investigate, but you're not the only one busy. If you've noticed a lack of software from me recently, it's due to the nex job I got some months back; I love it, but it leaves me with a lot less time for phone hacking if I want to still have a life outside of that.
With that said, this actually ties into the work I'm already doing with things like filetype handling and default browser switching. I can send you my HKCRlib, at a minimum; it's a library that simplifies interacting with HKCR, including creating backups of important values when they change, and reverting the backups.
GoodDayToDie, truly, I'm not much interested (personally) in that hack 'cause I can't use it for my Lumia 900. So it's only for the community needs but because of lack of time, I believe, we may put it on hold.

reading vechicle sensor data in Android app? (CANBUS input)

Dear devs,
I have MTCD PX5 MX (Witson).
I would like to make some small utility apps to enhance HU functionality based on vehicle data.
I would like for example to read the vehicle speed in my app (without using GPS or OBD). I know it's available somewhere in the OS because you can see it in the factory "Vehicle Info" app which seems to be the same for all MTCD units.
Is it some /proc file to be read? Some broadcasts? Some android API additions or some native library calls?
Thanks!
rumburake said:
Dear devs,
I have MTCD PX5 MX (Witson).
I would like to make some small utility apps to enhance HU functionality based on vehicle data.
I would like for example to read the vehicle speed in my app (without using GPS or OBD). I know it's available somewhere in the OS because you can see it in the factory "Vehicle Info" app which seems to be the same for all MTCD units.
Is it some /proc file to be read? Some broadcasts? Some android API additions or some native library calls?
Thanks!
Click to expand...
Click to collapse
The only way is decompilation of an app (you have to find one which deals with CANBUS) and analysis of decompiled source code. There is no API for such things in these devices.
rumburake said:
Dear devs,
I have MTCD PX5 MX (Witson).
I would like to make some small utility apps to enhance HU functionality based on vehicle data.
I would like for example to read the vehicle speed in my app (without using GPS or OBD). I know it's available somewhere in the OS because you can see it in the factory "Vehicle Info" app which seems to be the same for all MTCD units.
Is it some /proc file to be read? Some broadcasts? Some android API additions or some native library calls?
Thanks!
Click to expand...
Click to collapse
You need a canbus decoder. If you buy a canbus decoder for VW golf/Jetta mk5/mk6 I can tell you which messages you need to send to the canbus decoder for the vehicle info apk and for door information, and you can easily send messages with Arduino (with canbus board) or with teensy 3.1 (with can transeiver) or other microcontroller.
I notice by default, (after installing Titanium Backup) that the Vehicle App is "frozen" and when I unfreeze it to run, it doesn't really stay open. I do have a CANBus interface for my 08 Mitsubishi Lancer Evolution X. I noticed in Factory Settings>CANBus, it has options (standard/swap) for front door, back door and air conditioning. Is there any way to have the data displayed somehow? Is the vehicle info app supposed to show it?
Sent from my Nexus 9 using Tapatalk
verkion said:
I notice by default, (after installing Titanium Backup) that the Vehicle App is "frozen" and when I unfreeze it to run, it doesn't really stay open. I do have a CANBus interface for my 08 Mitsubishi Lancer Evolution X. I noticed in Factory Settings>CANBus, it has options (standard/swap) for front door, back door and air conditioning. Is there any way to have the data displayed somehow? Is the vehicle info app supposed to show it?
Sent from my Nexus 9 using Tapatalk
Click to expand...
Click to collapse
In my case (mazda cx5) the vehicle.apk is not the one for showing information
When I open any door it is displayed on the unit.
Even having the same options (air conditioning) like you air conditioning info is not displayed.
Enviado desde mi D6603 mediante Tapatalk
Oh. OK. Hrm...must be controlled somewhere else then. I wonder how I can get it to begin to display that type of info.
Sent from my Nexus 9 using Tapatalk
I'm also in the topic for some weeks, and there is no api or information to access the canbus from the unit.
To reverse engineer the can bus app was the only suggestion provided also.
I think the aim should be to create a android socket can bus api driver for the unit.
Thanks for your interest guys, I managed to get the data by examining the "Vehicle" app (MTCControlInfo.apk). :victory:
There's a broadcast "com.microntek.sync" which contains a byte[] extra called "syncdata". The array has 20 byte values of which I decoded the speed, revs, voltage, temperature and total mileage. When data[2] == 2, the data is:
Code:
// RPM
int rpm = (0xFF & data[3]) * 256 + (0xFF & data[4]);
// SPEED
double speed = ((0xFF & data[5]) * 256 + (0xFF & data[6])) * 0.01d;
// BATTERY
double battery = ((0xFF & data[7]) * 256 + (0xFF & data[8])) * 0.01d;
// TEMP
double temp = (0xFF & data[9]) * 256 + (0xFF & data[10]);
if (temp >= 32768) {
temp -= 65536;
}
temp /= 10;
// DISTANCE
int distance = (0xFF & data[11]) * 65536 + (0xFF & data[12]) * 256 + (0xFF & data[13]);
The problem is the Broadcast doesn't come unless the "Vehicle" app is started. They seem to either:
flip a switch like this:
Code:
Settings.System.putInt(this.getContentResolver(), "com.microntek.controlinfo.door", 1); // in onCreate() and onStart()
and
Code:
Settings.System.putInt(this.getContentResolver(), "com.microntek.controlinfo.door", 0); // in onStop()
I couldn't get my app to do this, you're not allowed to do this unless you're a system app.
or get the CarManager (which is in another app which I didn't get yet to examine), to do some command, perhaps another Broadcast.
I can get continuous data Broadcasts if I start the "Vehicle" app, then go to home screen, then start my app. Since onStop() would be called I believe it's the second method of switch that really happens.
As soon as you explicitely exit the "Vehicle" app the Broadcasts stop coming.
I'm using Bytecode Viewer, but it has quite a few errors translating to Java. A better disassembler would come in handy.
TBC...
rumburake said:
Thanks for your interest guys, I managed to get the data by examining the "Vehicle" app (MTCControlInfo.apk). :victory:
There's a broadcast "com.microntek.sync" which contains a byte[] extra called "syncdata". The array has 20 byte values of which I decoded the speed, revs, voltage, temperature and total mileage. When data[2] == 2, the data is:
Code:
// RPM
int rpm = (0xFF & data[3]) * 256 + (0xFF & data[4]);
// SPEED
double speed = ((0xFF & data[5]) * 256 + (0xFF & data[6])) * 0.01d;
// BATTERY
double battery = ((0xFF & data[7]) * 256 + (0xFF & data[8])) * 0.01d;
// TEMP
double temp = (0xFF & data[9]) * 256 + (0xFF & data[10]);
if (temp >= 32768) {
temp -= 65536;
}
temp /= 10;
// DISTANCE
int distance = (0xFF & data[11]) * 65536 + (0xFF & data[12]) * 256 + (0xFF & data[13]);
The problem is the Broadcast doesn't come unless the "Vehicle" app is started. They seem to either:
flip a switch like this:
Code:
Settings.System.putInt(this.getContentResolver(), "com.microntek.controlinfo.door", 1); // in onCreate() and onStart()
and
Code:
Settings.System.putInt(this.getContentResolver(), "com.microntek.controlinfo.door", 0); // in onStop()
I couldn't get my app to do this, you're not allowed to do this unless you're a system app.
or get the CarManager (which is in another app which I didn't get yet to examine), to do some command, perhaps another Broadcast.
I can get continuous data Broadcasts if I start the "Vehicle" app, then go to home screen, then start my app. Since onStop() would be called I believe it's the second method of switch that really happens.
As soon as you explicitely exit the "Vehicle" app the Broadcasts stop coming.
I'm using Bytecode Viewer, but it has quite a few errors translating to Java. A better disassembler would come in handy.
TBC...
Click to expand...
Click to collapse
Use this decompiler:
http://www.javadecompilers.com/apk
According to CarManager - it is located inside framework.jar. You can see example usage in my app here:
https://github.com/f1xpl/MtcdTools
To use it in your project, simply copy source code loated at app/src/main/java/android/microntek/ except f1x dir to your project directory.
Cool you've got something.
But it looks like some processed data and not the raw can you will need for full controll so you have to mine deeper.
iwl said:
But it looks like some processed data and not the raw can you will need for full controll so you have to mine deeper.
Click to expand...
Click to collapse
As said in the original post what I want is this data. Don't put your hopes into me digging into the canbus as it's not my purpose.
rumburake said:
As said in the original post what I want is this data. Don't put your hopes into me digging into the canbus as it's not my purpose.
Click to expand...
Click to collapse
I have been looking into this also.
My unit is an MTCD PX5 MX, currently using Malaysk rom 5.0 and MX mcu 2.59. The car is a Peugeot 407.
I get air condition data: temperature readings from both sides of the car, air flow direction only from the driver's side, and the temperatures are off by 4 degrees (ie. showing 17C when the temp is set at 21C).
Steering wheel keys: Volume up/down always work, the other keys, Next, Prev, Source, and the "clicky wheel button" (which should change radio preset, change folder in music player etc.) only work if they are the very first button pressed after a reboot - it seems like something crashes on the first press, and after that only the volume buttons work.
I tried going into setup, factory settings, and using 'logcan' as password, the can logger starts, showing me that it does receive data on all the steering wheel keys, even if they no longer perform any action on the head unit after the first press.
The keys send data like the following:
Source: 2e 02 11 ...
Next: 2e 02 12 ...
Prev: 2e 02 13 ...
Volume up: 2e 02 14 ...
Volume down: 2e 02 15 ...
Volume up+down (should do Mute): 2e 02 16 ...
Clicky wheel button: 2e 02 03 ... or 2e 02 04 ... depending on the direction.
I want to modify the can bus apk, making it add 4 to air con temperature readings before showing, and I would also like to figure out, what happens when I press a steering wheel key for the first time, since everything works initially and then stops after the first press.
My unit is an MTCD PX5 MX, currently using Malaysk rom 5.0 and MX mcu 2.59. The car is a Peugeot 407.
Click to expand...
Click to collapse
Where did you get this MCU? AFAIK 2.55 is the latest MCU available for MX (according to: https://forum.xda-developers.com/an...opment/mtcd-px5-headunits-repository-t3619906)
MCUs from different models (HA etc) present minor incompatibilities such as different key setups / fascias between models. It may well be your problem with the buttons!
OK I got it now to work properly. :victory:
To get messages you need to send a request using CarManager. I have used the CarManager code from MTCDTools (thank you @f1x !)
In the case of a canbus adapter config 1 (VW/Skoda) you can send this message periodically to receive a data response (including the speed, rpm etc):
Code:
canbus_rsp=46,144,2,65,2,42
These numbers are made by functions specific to the canbus adapter type which you can find in the "Vehicle" app. I could obviously test this only on my car.
For this canbus config there are 2 other sequences, that return other data too:
Code:
canbus_rsp=46,144,2,65,3,41
canbus_rsp=46,144,2,65,1,43
To send a message you can call:
Code:
CarManager.setParameters(String par);
I hope this helps other people.... I will post again when I build something useful on this.
Interesting thread, would be nice to see the speed data applied to other apps (like Graser's Dasaita or F1x' sound to speed adjust, or Malaysk's screensaver), without the need to get GPS data.
But I guess not all MTCx units will have the speed data, so using GPS will be more generic. I do think the speed data from canbus will be more reliable when the unit supports it.
rumburake said:
Code:
canbus_rsp=46,144,2,65,2,42
Code:
CarManager.setParameters(String par);
Click to expand...
Click to collapse
Does this altogether mean : ?
Code:
CarManager.setParameters("canbus_rsp=46,144,2,65,2,42");
logcan as factory settings password is such valuable information....
---------- Post added at 01:48 ---------- Previous post was at 01:31 ----------
if code logcan starts the canlog app, may be this app is to find, smaller and more easy to decompile / hack.
logcan Can Bus Logger How To ?
KlausBJ said:
'logcan'
Click to expand...
Click to collapse
I'm just playing around with the factory settings pw logcan Can-Logger, but get nothing shown.
I've tried to send with 125000 Baud and 500000 Baud.
What number do you have choosen in the upper right corner there is No, 01, ..., FF ?
How have you used the bottom Buttons, I pressend Start, changing to stop then, what is TX RX for?
I'm also confused.
What's supposed to be inside the String when
Code:
CarManager.setParameters()
is called?
With this method is it possible to write to the CanBus or just read from it?
I'm asking because I'm trying to find a way to control the fade on my factory amp and this seems like the perfect way to do it if writes are possible.
I am now working on a volume setting app using the car speed and rpm. The volume is relative to the one set by user. I got promising results so far.
But I'm stuck at setting the HU volume, it does not sync with the manual controls: suppose volume is 5, then I set it programmatically to 10, then the user turns the knob up it becomes 6 (because it starts from 5)!
 @f1x you do have experience with this, could you please advise? I have tried all of the following:
This is for setting the real volume in the hardware (a volume value mapped from 0% to 100%):
Code:
carManager.setParameters("av_volume="+mtcLevel);
This is temporary and the Android OS doesn't know the volume was changed.
This setting seems to be used for saving the system known volume (0-30):
Code:
android.provider.Settings.System.putInt(ctx.getContentResolver(),"av_volume=",level);
But doesn't seem to have effect and I get this warning: You shouldn't keep your settings in the secure settings. This will soon become an error.
The same volume used to send a broadcast (also 0-30):
Code:
Intent intent = new Intent("com.microntek.VOLUME_CHANGED");
intent.putExtra("volume",level);
ctx.sendBroadcast(intent);
This probably it's just for notifying other apps (it's also how I get the volume changes in my app).
Anyhow what I mean is to set the volume to 10 and when I turn the knob up to find it at 11. Thanks!
rumburake said:
I am now working on a volume setting app using the car speed and rpm. The volume is relative to the one set by user. I got promising results so far.
But I'm stuck at setting the HU volume, it does not sync with the manual controls: suppose volume is 5, then I set it programmatically to 10, then the user turns the knob up it becomes 6 (because it starts from 5)!
@f1x you do have experience with this, could you please advise? I have tried all of the following:
This is for setting the real volume in the hardware (a volume value mapped from 0% to 100%):
Code:
carManager.setParameters("av_volume="+mtcLevel);
This is temporary and the Android OS doesn't know the volume was changed.
This setting seems to be used for saving the system known volume (0-30):
Code:
android.provider.Settings.System.putInt(ctx.getContentResolver(),"av_volume=",level);
But doesn't seem to have effect and I get this warning: You shouldn't keep your settings in the secure settings. This will soon become an error.
The same volume used to send a broadcast (also 0-30):
Code:
Intent intent = new Intent("com.microntek.VOLUME_CHANGED");
intent.putExtra("volume",level);
ctx.sendBroadcast(intent);
This probably it's just for notifying other apps (it's also how I get the volume changes in my app).
Anyhow what I mean is to set the volume to 10 and when I turn the knob up to find it at 11. Thanks!
Click to expand...
Click to collapse
Take a look at this remark:
Checks if the specified app can modify system settings. As of API level 23, an app cannot modify system settings unless it declares the WRITE_SETTINGS permission in its manifest, and the user specifically grants the app this capability. To prompt the user to grant this approval, the app must send an intent with the action ACTION_MANAGE_WRITE_SETTINGS, which causes the system to display a permission management screen.
Click to expand...
Click to collapse
https://developer.android.com/refer...System.html#canWrite(android.content.Context)

Categories

Resources