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/**