fix, I think, problems with launch mode and non-main activities.

singleTop is necessary, as with singleTask we get the whole actvity
stack nuked on every launch.  Open a game into BoardActivity then
background Crosswords; when you re-launch from the launcher or hold
the home key you're back to GamesList.  But with singleTop incoming
invite schemes would launch a second instance because though there was
one running it wasn't in the same task as the browser firing the url
to redir.php.  The solution there is to move the scheme intent from
GamesList to DispatchNotify, which is already handling notifications.
There the addition of a second launch flag means that an existing
instance will always see the launch through its onNewIntent -- under
tests I've come up with so far, anyway.
This commit is contained in:
Andy2 2011-07-13 18:42:03 -07:00
parent ea205ebf97
commit cd15a9e6e3
3 changed files with 104 additions and 73 deletions

View file

@ -41,19 +41,12 @@
<activity android:name="GamesList"
android:label="@string/title_games_list"
android:launchMode="singleTask"
android:launchMode="singleTop"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="newxwgame"/>
</intent-filter>
</activity>
<activity android:name="DictsActivity"
@ -92,7 +85,16 @@
</intent-filter>
</receiver>
<activity android:name="DispatchNotify" />
<activity android:name="DispatchNotify"
>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="newxwgame"/>
</intent-filter>
</activity>
<!-- downloading dicts -->
<activity android:name=".DictImportActivity"

View file

@ -21,13 +21,14 @@
package org.eehouse.android.xw4;
import android.app.Activity;
import android.content.Intent;
import android.content.Context;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;
import android.os.Bundle;
import java.util.HashSet;
import junit.framework.Assert;
import org.eehouse.android.xw4.jni.CommonPrefs;
@ -37,6 +38,7 @@ public class DispatchNotify extends Activity {
public interface HandleRelaysIface {
void HandleRelaysIDs( final String[] relayIDs );
void HandleInvite( final Uri invite );
}
private static HashSet<Activity> s_running = new HashSet<Activity>();
@ -45,29 +47,40 @@ public class DispatchNotify extends Activity {
@Override
protected void onCreate( Bundle savedInstanceState )
{
Utils.logf( "DispatchNotify.onCreate()" );
boolean mustLaunch = false;
super.onCreate( savedInstanceState );
Intent intent = getIntent();
String[] relayIDs = intent.getStringArrayExtra( RELAYIDS_EXTRA );
String[] relayIDs = getIntent().getStringArrayExtra( RELAYIDS_EXTRA );
Uri data = getIntent().getData();
if ( !tryHandle( this, relayIDs ) ) {
if ( null != relayIDs ) {
if ( !tryHandle( relayIDs ) ) {
mustLaunch = true;
}
} else if ( null != data ) {
if ( !tryHandle( data ) ) {
mustLaunch = true;
}
}
if ( mustLaunch ) {
Utils.logf( "DispatchNotify: nothing running" );
intent = new Intent( this, GamesList.class );
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
intent.putExtra( RELAYIDS_EXTRA, relayIDs );
Intent intent = new Intent( this, GamesList.class );
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK );
if ( null != relayIDs ) {
intent.putExtra( RELAYIDS_EXTRA, relayIDs );
} else if ( null != data ) {
intent.setData( data );
} else {
Assert.fail();
}
startActivity( intent );
}
finish();
}
@Override
protected void onNewIntent( Intent intent )
{
Utils.logf( "DispatchNotify.onNewIntent() called" );
}
public static void SetRunning( Activity running )
{
s_running.add( running );
@ -83,13 +96,31 @@ public class DispatchNotify extends Activity {
s_handler = iface;
}
public static boolean tryHandle( Context context, String[] relayIDs )
private static boolean tryHandle( Uri data )
{
boolean handled = false;
if ( null != s_handler ) {
// This means the GamesList activity is frontmost
s_handler.HandleInvite( data );
handled = true;
} else {
for ( Activity activity : s_running ) {
if ( activity instanceof DispatchNotify.HandleRelaysIface ) {
DispatchNotify.HandleRelaysIface iface =
(DispatchNotify.HandleRelaysIface)activity;
iface.HandleInvite( data );
handled = true;
}
}
}
return handled;
}
public static boolean tryHandle( String[] relayIDs )
{
Utils.logf( "tryHandle()" );
boolean handled = false;
if ( null != s_handler ) {
// This means the GamesList activity is frontmost
Utils.logf( "calling m_handler" );
s_handler.HandleRelaysIDs( relayIDs );
handled = true;
} else {
@ -102,7 +133,6 @@ public class DispatchNotify extends Activity {
}
}
}
Utils.logf( "DispatchNotify.tryHandle()=>%s", handled?"true":"false" );
return handled;
}
}

View file

@ -230,7 +230,6 @@ public class GamesList extends XWListActivity
Intent intent = getIntent();
startFirstHasDict( intent );
startNewNetGameIf( intent );
askDefaultNameIf();
DBUtils.setDBChangeListener( this );
@ -245,7 +244,7 @@ public class GamesList extends XWListActivity
invalRelayIDs( intent.
getStringArrayExtra( DispatchNotify.RELAYIDS_EXTRA ) );
startFirstHasDict( intent );
startNewNetGameIf( intent );
startNewNetGame( intent );
}
@Override
@ -302,6 +301,19 @@ public class GamesList extends XWListActivity
} );
}
public void HandleInvite( final Uri invite )
{
final NetLaunchInfo nli = new NetLaunchInfo( invite );
if ( nli.isValid() ) {
m_handler.post( new Runnable() {
@Override
public void run() {
startNewNetGame( nli );
}
} );
}
}
// DBUtils.DBChangeListener interface
public void pathSaved( final String path )
{
@ -582,53 +594,40 @@ public class GamesList extends XWListActivity
startActivity( new Intent( this, NewGameActivity.class ) );
}
private void startNewNetGameIf( Intent intent )
private void startNewNetGame( final NetLaunchInfo info )
{
if ( null != intent ) {
Uri data = intent.getData();
if ( null != data ) {
String path = DBUtils.getPathForOpen( this, info.room, info.lang,
info.nPlayers );
NetLaunchInfo info = new NetLaunchInfo( data );
if ( info.isValid() ) {
// Find out if the game already exists. If it does,
// just open it. Otherwise create a new one and open
// that. NOTE: this test makes it impossible to start
// two halves of the same game on one device using
// this feature. But it'd be worse to have a bunch of
// games stacking up when somebody taps the same URL
// multiple times.
// No. If the game already exists, warn the user, but
// give him choice to open new or existing game.
String path =
DBUtils.getPathForOpen( this, info.room, info.lang,
info.nPlayers );
if ( null == path ) {
path = GameUtils.makeNewNetGame( this, info );
GameUtils.launchGame( this, path, true );
} else {
final NetLaunchInfo finfo = info;
DialogInterface.OnClickListener then =
new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg,
int ii ) {
String path = GameUtils.
makeNewNetGame( GamesList.this, finfo );
GameUtils.launchGame( GamesList.this,
path, true );
}
};
String fmt = getString( R.string.dup_game_queryf );
String msg = String.format( fmt, finfo.room );
showConfirmThen( msg, then );
if ( null == path ) {
path = GameUtils.makeNewNetGame( this, info );
GameUtils.launchGame( this, path, true );
} else {
DialogInterface.OnClickListener then =
new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg,
int ii ) {
String path = GameUtils.
makeNewNetGame( GamesList.this, info );
GameUtils.launchGame( GamesList.this,
path, true );
}
}
}
};
String fmt = getString( R.string.dup_game_queryf );
String msg = String.format( fmt, info.room );
showConfirmThen( msg, then );
}
} // startNewNetGameIf
} // startNewNetGame
private void startNewNetGame( Intent intent )
{
Uri data = intent.getData();
Assert.assertNotNull( intent );
NetLaunchInfo info = new NetLaunchInfo( data );
if ( info.isValid() ) {
startNewNetGame( info );
}
} // startNewNetGame
private void askDefaultNameIf()
{