Chrome to WP7 is now Send to WP7

December 13, 2010

Just an FYI – Chrome to WP7 is now Send to WP7.  This was just a logical name change.  Clearly I shot far too low in limiting to just Chrome.  I’ve updated the app in the Windows Phone Marketplace – but unfortunately the old logo is still being shown in the store.  Later this week I will update Send to WP7 for local cache and deleting links.  Setup Send to WP7.

6 Comments

Chrome to WP7: Support for Firefox, Opera, Safari, IE8/9

December 6, 2010

I’ve clearly named Chrome to WP7 poorly, because now it supports all major browsers.

I’ve created an accelerator for IE8 and IE9, and a bookmarklet for all other browsers (Firefox, Opera, Safari, et al).

You’ll need Chrome to WP7 first, then set up your browser.

Coming in v1.2: the ability to delete links and store data offline.

16 Comments

GVNotifier 1.4.1.159

November 24, 2010

A quick update today to GVNotifier:

- Reduction in bandwidth usage.  I’d really like to reduce this more, but I’m not finding what I need, even Google’s services don’t seem to have an API for message counts.  The one API I have found is mostly useless since it only indicates new conversations, not new messages.

- Fix for logout on tray icon.

- Fix for Google Talk calling option.

I have some ideas for realtime call notifications, but it is too early to see if it’s possible.

12 Comments

Chrome to Windows Phone 7

November 19, 2010

I’ve just submitted my second app, Chrome to WP7 to the Windows Phone marketplace.  The app has a very simple purpose, to give you the ability to quickly send links and selected text from within the Chrome browser, to your Windows Phone.

The Chrome extension may be downloaded here.

Chrome to WP7 is in the marketplace!

Chrome to WP7 works similarly to Chrome to Phone for Android.  A push notification is sent to the phone, which will show up as a toast, and upon opening the app, a list of your most recent links and text are available, regardless of whether or not the push notification succeeded.  From within the app, you may email the Title/URL/Text, or open the link.

Update! Now supporting Firefox, IE8/9, Safari and Opera.

Screenshots

Screenshots (Phone)

Chrome to WP7 is free.

19 Comments

Send Push Notifications to Windows Phone 7 from PHP

November 15, 2010

I couldn’t find a library for sending Push Notifications to Windows Phone 7 from PHP.  Most samples were using an ASP.NET web service.  For those of us who would like to run Push Notifications from cheaper PHP and cURL enabled hosting, I’ve created a little helper class: (The XML may be break below, so here is the Text Version)

class WindowsPhonePushPriority
{
    const TileImmediately = 1;
    const ToastImmediately = 2;
    const RawImmediately = 3;
    const TileWait450 = 11;
    const ToastWait450 = 12;
    const RawWait450 = 13;
    const TileWait900 = 21;	
    const ToastWait900 = 22;	
    const RawWait900 = 23;
}
 
class WindowsPhonePushClient
{
    private $device_url = '';
    private $debug_mode = false;
 
    function __construct($device_url)
    {
        $this->device_url = $device_url;
    }
 
    public function send_raw_update($msg, $priority = WindowsPhonePushPriority::RawImmediately)
    {
        return $this->_send_push(array('X-NotificationClass: ' . $priority), $msg);
    }
 
    public function send_tile_update($image_url, $count, $title, $priority = WindowsPhonePushPriority::TileImmediately)
    {
        $msg = "< ?xml version=\"1.0\" encoding=\"utf-8\"?>" .
                "<wp :Notification xmlns:wp=\"WPNotification\">" .
                   "</wp><wp :Tile>".
                      "</wp><wp :BackgroundImage>" . $image_url . "</wp>" .
                      "<wp :Count>" . $count . "</wp>" .
                      "<wp :Title>" . $title . "</wp>" .
                   " " .
                "";
 
        return $this->_send_push(array(
                                    'X-WindowsPhone-Target: token',
                                    'X-NotificationClass: ' . $priority,
                                ), $msg);
    }
 
    private function send_toast($title, $message, $priority = WindowsPhonePushPriority::ToastImmediately)
    {
        $msg = "< ?xml version=\"1.0\" encoding=\"utf-8\"?>" .
            "<wp :Notification xmlns:wp=\"WPNotification\">" .
                "</wp><wp :Toast>" .
                    "</wp><wp :Text1>" . $title . "</wp>" .
                    "<wp :Text2>" . $message . "</wp>" .
                "" .
            "";
 
        return $this->_send_push($url, array(
                                      'X-WindowsPhone-Target: toast',
                                      'X-NotificationClass: ' . $priority, 
                                      ), $msg);
    }
 
    private function _send_push($headers, $msg)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->device_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HEADER, true); 
        curl_setopt($ch, CURLOPT_HTTPHEADER,    // Add these headers to all requests
            $headers + array(
                            'Content-Type: text/xml',
                            'Accept: application/*'
                            )
            ); 
        curl_setopt($ch, CURLOPT_POSTFIELDS, $msg);
 
        if ($this->debug_mode)
        {
            curl_setopt($ch, CURLOPT_VERBOSE, $this->debug_mode);
            curl_setopt($ch, CURLOPT_STDERR, fopen('debug.log','w'));
        }
        $output = curl_exec($ch);
        curl_close($ch);
 
        return array(
            'X-SubscriptionStatus'     => $this->_get_header_value($output, 'X-SubscriptionStatus'),
            'X-NotificationStatus'     => $this->_get_header_value($output, 'X-NotificationStatus'),
            'X-DeviceConnectionStatus' => $this->_get_header_value($output, 'X-DeviceConnectionStatus')
            );
    }
 
    private function _get_header_value($content, $header)
    {
        return preg_match_all("/$header: (.*)/i", $content, $match) ? $match[1][0] : "";
    }
}

This code supports sending all three types of push notifications, Tile, Toast and Raw.

To use the class, simply include the file and call the constructor with the Device URL, which has already been uploaded to your server from the devices themselves.

15 Comments

Coming Soon: MediaRemote for Windows Phone

November 12, 2010

This app is still moving through the Windows Phone Marketplace approval process, so I’m adding this post as a placeholder.

MediaRemote has a simple purpose, it lets you control any generic media player running on your Windows XP/Vsita/7 computer, so long as the media player responds to the media keys (if your keyboard supports them).  This includes Zune, Windows Media Player, iTunes, foobar2000 and more.  Supported actions include: Play/Pause, Previous Track, Next Track, Volume Up/Down and Mute.

Download MediaRemote for Windows Phone (Windows Software)

Download MediaRemote for Windows Phone (Windows Phone 7 Software)

Leave a Comment

Zune Now Playing support for Digsby and Winamp-compatible nowplaying software.

July 17, 2010

The Zune media player delivers Now Playing information to Windows Live Messenger, but other software isn’t able to pick up these messages.  Quite a few users have asked for Zune Now Playing support in Digsby, so I put together this little app that lets this work.  The application itself is generic, converting Zune now playing messages into the more widely implemented Winamp now playing method.

Download the executable and source (C++).

Code Listing:

#include "stdafx.h"
#include "ZuneNowPlaying.h"
#include "LimitSingleInstance.h" // KB243953
#include <regex>
 
const std::tr1::wregex pattern(L".*?\\\\0Music\\\\0.*?\\\\0.*?\\\\0(.*?)\\\\0(.*?)\\\\0");
 
CLimitSingleInstance g_SingleInstanceObj(L"{24F3CD83-9FFE-4DE6-951D-63958942F834}");
 
HWND hWndWinamp;
HWND hWndWindowsLiveMessenger;
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_COPYDATA:
			{
				COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lParam;
				wchar_t *str = (wchar_t*)cds-&gt;lpData;
 
				std::tr1::wcmatch result;
				if(std::tr1::regex_search(str, result, pattern))
				{
					std::wstring ret = result[2].str() + L" - " + result[1].str();
					SetWindowText(hWndWinamp, ret.c_str());
				}
				else
				{
					SetWindowText(hWndWinamp, L"");
				}
				break;
			}
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_USER:
			if (lParam == 104)
			{
				return 1; // Winamp=Playing (always)
			}
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}
 
void RegisterClasses(HINSTANCE hInstance)
{
	WNDCLASSEX wcex = WNDCLASSEX();
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.lpfnWndProc	= WndProc;
	wcex.hInstance		= hInstance;
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszClassName	= L"MsnMsgrUIManager";
	RegisterClassEx(&amp;wcex);
 
	wcex.lpszClassName	= L"Winamp v1.x";
	RegisterClassEx(&amp;wcex);
}
 
bool CreateWindows(HINSTANCE hInstance)
{
	// Pretend to be Windows Live Messenger, so WM_COPYDATA messages are sent to us.
	hWndWindowsLiveMessenger = CreateWindow(L"MsnMsgrUIManager", L"", WS_DISABLED,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
	// Pretend to be Winamp (any version), so apps will pick us up for Now Playing.
	hWndWinamp = CreateWindow(L"Winamp v1.x", L"", WS_DISABLED,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
 
	return hWndWinamp &amp;&amp; hWndWindowsLiveMessenger;
}
 
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int /*nCmdShow*/)
{
	MSG msg = MSG();
	if (!g_SingleInstanceObj.IsAnotherInstanceRunning())
	{
		RegisterClasses(hInstance);
 
		if (CreateWindows(hInstance))
		{
			while (GetMessage(&amp;msg, NULL, 0, 0))
			{
				TranslateMessage(&amp;msg);
				DispatchMessage(&amp;msg);
			}
		}
	}
	return (int)msg.wParam;
}</regex>

How it works:

It’s pretty simple, Zune software sends a WM_COPYDATA message to a window with class name MsnMsgrUIManager, the message contains a pointer to a unicode string, that looks something like this:

ZUNE\0Music\01\0{0} - {1}\0TRACK_TITLE\0TRACK_ARTIST\0TRACK_ALBUM\0zune:ZUNE_GUID\0
 
// TRACK_TITLE: Title
// TRACK_ARTIST: Artist
// TRACK_ALBUM: Album
// ZUNE_GUID:  A GUID that may refer to the Zune device, Zune account, or Zune software itself.
 
// Note:  {0} - {1} is the format of how the string should be displayed in WLM - I ignore this entirely.
// Note2:  This method is used by other software, so I don't gate on ZUNE for the sake of maximum flexibility.  
// Note3:  The "1" after Music specifies the playing state.  0=Stopped, 1=Playing.  I ignore this and instead just use whether or not the other fields exist.

Note:  The \0′s in the above string are literally \ and 0, not NULL characters.

Using a regular expression to match the fields, The artist and title are extracted from the string, and set as the window caption for a window with class name Winamp v1.x. Software (like Digsby, or other now playing apps) may use FindWindow to locate the fake Winamp player, and read the caption with GetWindowText.

You may need to install the Microsoft Visual C++ 2010 Redistributable Package (x86).

6 Comments

GVNotifier moving forward

July 10, 2010

Thanks to an update on Lifehacker, GVNotifier has been installed 3,000 times in the past few days.  I’ve been flooded with emails and IMs–I apologize if I didn’t respond to you.  I generally try to respond to everything, but with working full-time, I wasn’t around and many messages were missed.  Thanks to those who have donated, and also those that left kind words!  I appreciate the feedback, good and bad.

As I have indicated in some email exchanges, I’m working full-time for the summer and and don’t have much spare time for development.  I’ll be picking back up at the end of August, but things are pretty stable right now.  The rest of this posts contains my thoughts on moving forward, as well as documentation of known issues and other reasoning.

Known Issues & Bugs

  • GVNotifier does not work outside of the USA:  This is a long-standing issue, Google allows connections to google.com/voice from a non-US IP address, but the authentication process is different.  I’ve built a new Silverlight library for Windows Phone 7 that uses ClientLogin, so I will likely switch over to this system.  (Milestone 1.5)
  • Search Crash:  Some people experience an occasional crash when searching contacts.  I have a fix planned.  The good news is that this is the only known crash.  (Milestone 1.5)
  • Bandwidth Usage:  A couple people have reported that the bandwidth usage is heavy.  This is true if you’re using metered internet.  I have an idea of how I can reduce usage, but this is not a priority right now.  (Milestone 1.6-1.7)
  • Contacts Sync:  Updating a contact that already has a window open doesn’t always work.  If you must sync contacts completely, a restart is required.  (Milestone 1.5)
  • Area code 406 numbers are hidden:  Since there actually are people with Google Voice in Montana, I’ll bring back a setting for this.  (Milestone 1.5)

FAQ

  • Can I change the polling rate?  Yes.  Edit %localappdata%\GVNotifierWPF\settings.xml.  Look for UpdateFreq, which is in seconds.  Using a zero-value will disable updating completely.
  • Can I invoke a manual check?  Yes.  Call GVNotifier.net.exe /check.  (Other arguments include: /signout, /quit and /update_contacts)
  • Can I change the notification sound?  Yes.  Edit %localappdata%\GVNotifierWPF\new.wav
  • Can I dial a number that isn’t in my contacts?  Yes.  Type the number into contacts search.
  • My contacts aren’t all showing, why?  GVNotifier will show contacts only if they have one or more phone numbers that are NOT within the 406 area code.
  • GVNotifier is doing something weird, what can I do?  Check out the log file at %localappdata%\GVNotifierWPF\log.txt.
  • Is my personal data safe?  As of 1.4.1, passwords are encrypted.  Your Google Voice login information is sent only to Google.com, and only via SSL.  Contacts information is stored in plain text, along with other settings.  The password encryption is not impossibly strong, but if you are worried, use full disk encryption (like BitLocker or TrueCrypt).
  • Where is %localappdata%?  Windows Vista/7:  C:\Users\<UserName>\AppData\Local.  Windows XP:  C:\Documents and Settings\<UserName>\Local Settings\Application Data.
  • Can I disable SMS for a certain contact?  Yes – include the text nosms in their Google Contact information.  The input box will be disabled for this contact.

New Features

  • Dial pad:  I’ll probably add this, even though there is a way to insert new numbers–I neglected how valuable a Dial pad would be with a touch computer. (Milestone 1.5)
  • SMS History:  I’d like to sync history in the message window, along with some other enhancements (contact photo, other contact info).  I’m considering adding an SMS History tab, but I’m not crazy about this.  (Milestone 1.6)
  • Mass-messaging:  I’d like to integrate groups from Google Contacts, and on-demand group messaging. (Milestone 1.7)
  • Let me know if you don’t see something you want here.  I consider any requests that aren’t ridiculous.

Things that are not being considered

  • Please don’t ask me to “compile this is without the .NET framework,” or “compile with .NET 2.0 because it is better.”  GVNotifier requires .NET 3.5sp1 and utilizes the Windows Presentation Foundation.  There is certainly a performance hit, but you’re welcome to not use this software.  I’ll be upgrading to .NET 4.0 in the future.
  • Open Source.  I’m not open-sourcing this project unless someone is willing to dedicate a large amount of time to adding new–and reliable–features.
  • “Making the UI more compact.”  I’m mostly happy with the interface, I will not be doing any NCA drawing (at the very top of the window; like Firefox4, Chrome, Opera, et al).  Getting this working perfectly is a waste of effort that is better spent fixing bugs and adding useful functionality.
3 Comments

Pandora One Media Keys – Enable them!

June 27, 2010

I really enjoy Pandora – and I recently bought the upgrade to Pandora One, since I listen to it at work most of the day.  Aside from the player being AIR-based, my only gripe is the lack of media key support.  I’ve put together a simple application that runs in the background, redirecting media key input to the Pandora One player.

  • .NET 2.0 – Windows 2000 to Windows 7
  • Only the Next and PlayPause keys are mapped.  The attached source code includes Like and Dislike as well.
  • if the player is minimized, it will be restored, so you’ll want to keep the player behind your other windows.
  • The player needs to be in the now playing state, if you’re at the list of stations, the keys won’t work.
  • If you’d like to run the program at startup, create a shortcut and place it in your Startup folder, on the start menu.

Download Pandora One Media Keys.  This is a tiny project, so I’m sharing the relevant parts of the source code if you’d like to do something other than map the Next and PlayPause keys.

If this app is useful to you, please donate. :)

4 Comments

GVNotifier 1.4.1

June 27, 2010

GVNotifier 1.4.1 is live – auto-update to get it or download here.  This is a minor update, I’ve been very busy lately so this is a bugfixing release only.  Notable changes include:

  • Passwords are encrypted in the settings file, and in memory.  This is not strong encryption, but it’s better than plain text or simple encoding.
  • The old AppData directory is deleted if present (1.0-1.3)
  • Crash reporter – if the app crashes, a report is automatically sent the next time you run GVNotifier.

If you’re having trouble with ClickOnce, or need files for a portable version (create a blank settings.xml file), get the standalone version.  This version does not have auto-update!

7 Comments

« Previous PageNext Page »