diff --git a/android/.classpath b/android/.classpath index 3da8292..abb5e98 100644 --- a/android/.classpath +++ b/android/.classpath @@ -4,5 +4,5 @@ - + diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 4877db7..994d8db 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,10 @@ + android:versionCode="13" + android:versionName="2.3.1"> + + @@ -71,6 +73,11 @@ + + + + + + - diff --git a/android/src/com/google/android/apps/chrometophone/C2DMReceiver.java b/android/src/com/google/android/apps/chrometophone/C2DMReceiver.java index c8e5392..9a09d85 100644 --- a/android/src/com/google/android/apps/chrometophone/C2DMReceiver.java +++ b/android/src/com/google/android/apps/chrometophone/C2DMReceiver.java @@ -21,7 +21,6 @@ import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -86,12 +85,8 @@ public class C2DMReceiver extends C2DMBaseReceiver { // Notify and optionally start activity if (settings.getBoolean("launchBrowserOrMaps", true) && launchIntent != null) { - try { - context.startActivity(launchIntent); - LauncherUtils.playNotificationSound(context); - } catch (ActivityNotFoundException e) { - return; - } + LauncherUtils.playNotificationSound(context); + LauncherUtils.sendIntentToApp(context, launchIntent); } else { LauncherUtils.generateNotification(context, url, title, launchIntent); } diff --git a/android/src/com/google/android/apps/chrometophone/LauncherUtils.java b/android/src/com/google/android/apps/chrometophone/LauncherUtils.java index 30b8a3e..cfbe64c 100644 --- a/android/src/com/google/android/apps/chrometophone/LauncherUtils.java +++ b/android/src/com/google/android/apps/chrometophone/LauncherUtils.java @@ -1,8 +1,14 @@ package com.google.android.apps.chrometophone; +import java.util.LinkedHashSet; +import java.util.Set; + +import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -11,6 +17,7 @@ import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; +import android.os.PowerManager; import android.text.ClipboardManager; /** @@ -19,6 +26,7 @@ import android.text.ClipboardManager; public class LauncherUtils { private static final String GMM_PACKAGE_NAME = "com.google.android.apps.maps"; private static final String GMM_CLASS_NAME = "com.google.android.maps.MapsActivity"; + private static final String YT_PACKAGE_NAME = "com.google.android.youtube"; public static Intent getLaunchIntent(Context context, String title, String url, String sel) { Intent intent = null; @@ -32,6 +40,8 @@ public class LauncherUtils { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (isMapsURL(url)) { intent.setClassName(GMM_PACKAGE_NAME, GMM_CLASS_NAME); + } else if (isYouTubeURL(url)) { + intent.setPackage(YT_PACKAGE_NAME); } // Fall back if we can't resolve intent (i.e. app missing) @@ -110,11 +120,49 @@ public class LauncherUtils { } public static boolean isMapsURL(String url) { - return url.matches("http://maps\\.google\\.[a-z]{2,3}(\\.[a-z]{2})?[/?].*") || - url.matches("http://www\\.google\\.[a-z]{2,3}(\\.[a-z]{2})?/maps.*"); + return url.matches("http[s]://maps\\.google\\.[a-z]{2,3}(\\.[a-z]{2})?[/?].*") || + url.matches("http[s]://www\\.google\\.[a-z]{2,3}(\\.[a-z]{2})?/maps.*"); } public static boolean isYouTubeURL(String url) { - return url.matches("http://www\\.youtube\\.[a-z]{2,3}(\\.[a-z]{2})?/.*"); + return url.matches("http[s]://www\\.youtube\\.[a-z]{2,3}(\\.[a-z]{2})?/.*"); + } + + public static void sendIntentToApp(Context context, Intent intent) { + // Defer browser URLs until screen else the browser might drop the intent for security + // reasons. This is a little racey but in practice works fine. + if (isScreenOffOrLocked(context) && + intent.getAction().equals(Intent.ACTION_VIEW) && + (intent.getPackage() == null)) { + // Stuff away the intent URL + SharedPreferences prefs = Prefs.get(context); + SharedPreferences.Editor editor = prefs.edit(); + Set queuedUrls = + prefs.getStringSet("queuedUrls", new LinkedHashSet()); + queuedUrls.add(intent.getDataString()); + editor.putStringSet("queuedUrls", queuedUrls); + editor.commit(); + + // Enable broadcast receiver for user present - it will pick up the stored intent URL + PackageManager pm = context.getPackageManager(); + ComponentName componentName = new ComponentName(context, UserPresentReceiver.class); + pm.setComponentEnabledSetting(componentName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + } else { // user present, so send immediately + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { } + } + } + + private static boolean isScreenOffOrLocked(Context context) { + KeyguardManager keyguardManager = + (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); + PowerManager powerManager = + (PowerManager) context.getSystemService(Context.POWER_SERVICE); + boolean off = !powerManager.isScreenOn(); + off |= keyguardManager.inKeyguardRestrictedInputMode(); + return off; } } diff --git a/appengine/.classpath b/appengine/.classpath index 7cc2b56..3b83848 100644 --- a/appengine/.classpath +++ b/appengine/.classpath @@ -3,6 +3,6 @@ - + diff --git a/appengine/.settings/com.google.appengine.eclipse.core.prefs b/appengine/.settings/com.google.appengine.eclipse.core.prefs index 7531271..829a840 100644 --- a/appengine/.settings/com.google.appengine.eclipse.core.prefs +++ b/appengine/.settings/com.google.appengine.eclipse.core.prefs @@ -1,4 +1,4 @@ -#Tue May 10 23:32:51 BST 2011 +#Sun Aug 21 01:00:53 BST 2011 eclipse.preferences.version=1 -filesCopiedToWebInfLib=appengine-api-1.0-sdk-1.5.0.jar|appengine-api-labs-1.5.0.jar|appengine-jsr107cache-1.5.0.jar|jsr107cache-1.1.jar|datanucleus-appengine-1.0.8.final.jar|datanucleus-core-1.1.5.jar|datanucleus-jpa-1.1.5.jar|geronimo-jpa_3.0_spec-1.1.1.jar|geronimo-jta_1.1_spec-1.1.1.jar|jdo2-api-2.3-eb.jar +filesCopiedToWebInfLib=appengine-api-1.0-sdk-1.5.2.jar|appengine-api-labs-1.5.2.jar|appengine-jsr107cache-1.5.2.jar|jsr107cache-1.1.jar|datanucleus-appengine-1.0.9.final.jar|datanucleus-core-1.1.5.jar|datanucleus-jpa-1.1.5.jar|geronimo-jpa_3.0_spec-1.1.1.jar|geronimo-jta_1.1_spec-1.1.1.jar|jdo2-api-2.3-eb.jar ormEnhancementInclusions=src/**|c2dm/**