Merge pull request #8196 from JosJuice/android-applinkactivity-race
Android: Fix race condition in AppLinkActivity
This commit is contained in:
commit
998c171b65
|
@ -1,5 +1,7 @@
|
||||||
package org.dolphinemu.dolphinemu.activities;
|
package org.dolphinemu.dolphinemu.activities;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
@ -26,6 +28,7 @@ public class AppLinkActivity extends FragmentActivity
|
||||||
|
|
||||||
private AppLinkHelper.PlayAction playAction;
|
private AppLinkHelper.PlayAction playAction;
|
||||||
private DirectoryStateReceiver directoryStateReceiver;
|
private DirectoryStateReceiver directoryStateReceiver;
|
||||||
|
private BroadcastReceiver gameFileCacheReceiver;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
@ -63,16 +66,19 @@ public class AppLinkActivity extends FragmentActivity
|
||||||
*/
|
*/
|
||||||
private void initResources()
|
private void initResources()
|
||||||
{
|
{
|
||||||
IntentFilter statusIntentFilter = new IntentFilter(
|
IntentFilter directoryStateIntentFilter = new IntentFilter(
|
||||||
DirectoryInitialization.BROADCAST_ACTION);
|
DirectoryInitialization.BROADCAST_ACTION);
|
||||||
|
|
||||||
|
IntentFilter gameFileCacheIntentFilter = new IntentFilter(
|
||||||
|
GameFileCacheService.BROADCAST_ACTION);
|
||||||
|
|
||||||
directoryStateReceiver =
|
directoryStateReceiver =
|
||||||
new DirectoryStateReceiver(directoryInitializationState ->
|
new DirectoryStateReceiver(directoryInitializationState ->
|
||||||
{
|
{
|
||||||
if (directoryInitializationState ==
|
if (directoryInitializationState ==
|
||||||
DirectoryInitialization.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
DirectoryInitialization.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||||
{
|
{
|
||||||
play(playAction);
|
tryPlay(playAction);
|
||||||
}
|
}
|
||||||
else if (directoryInitializationState ==
|
else if (directoryInitializationState ==
|
||||||
DirectoryInitialization.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
DirectoryInitialization.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
||||||
|
@ -88,10 +94,23 @@ public class AppLinkActivity extends FragmentActivity
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Registers the DirectoryStateReceiver and its intent filters
|
gameFileCacheReceiver =
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
new BroadcastReceiver()
|
||||||
directoryStateReceiver,
|
{
|
||||||
statusIntentFilter);
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
if (DirectoryInitialization.areDolphinDirectoriesReady())
|
||||||
|
{
|
||||||
|
tryPlay(playAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
|
||||||
|
broadcastManager.registerReceiver(directoryStateReceiver, directoryStateIntentFilter);
|
||||||
|
broadcastManager.registerReceiver(gameFileCacheReceiver, gameFileCacheIntentFilter);
|
||||||
|
|
||||||
DirectoryInitialization.start(this);
|
DirectoryInitialization.start(this);
|
||||||
GameFileCacheService.startLoad(this);
|
GameFileCacheService.startLoad(this);
|
||||||
}
|
}
|
||||||
|
@ -107,17 +126,31 @@ public class AppLinkActivity extends FragmentActivity
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tryPlay(AppLinkHelper.PlayAction action)
|
||||||
|
{
|
||||||
|
// TODO: This approach of getting the game from the game file cache without rescanning
|
||||||
|
// the library means that we can fail to launch games if the cache file has been deleted.
|
||||||
|
|
||||||
|
GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
|
||||||
|
|
||||||
|
// If game == null and the load isn't done, wait for the next GameFileCacheService broadcast.
|
||||||
|
// If game == null and the load is done, call play with a null game, making us exit in failure.
|
||||||
|
if (game != null || GameFileCacheService.hasLoadedCache())
|
||||||
|
{
|
||||||
|
play(action, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action if program(game) is selected
|
* Action if program(game) is selected
|
||||||
*/
|
*/
|
||||||
private void play(AppLinkHelper.PlayAction action)
|
private void play(AppLinkHelper.PlayAction action, GameFile game)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "Playing game "
|
Log.d(TAG, "Playing game "
|
||||||
+ action.getGameId()
|
+ action.getGameId()
|
||||||
+ " from channel "
|
+ " from channel "
|
||||||
+ action.getChannelId());
|
+ action.getChannelId());
|
||||||
|
|
||||||
GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
|
|
||||||
if (game == null)
|
if (game == null)
|
||||||
Log.e(TAG, "Invalid Game: " + action.getGameId());
|
Log.e(TAG, "Invalid Game: " + action.getGameId());
|
||||||
else
|
else
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +28,8 @@ public final class GameFileCacheService extends IntentService
|
||||||
|
|
||||||
private static GameFileCache gameFileCache = null;
|
private static GameFileCache gameFileCache = null;
|
||||||
private static AtomicReference<GameFile[]> gameFiles = new AtomicReference<>(new GameFile[]{});
|
private static AtomicReference<GameFile[]> gameFiles = new AtomicReference<>(new GameFile[]{});
|
||||||
|
private static AtomicBoolean hasLoadedCache = new AtomicBoolean(false);
|
||||||
|
private static AtomicBoolean hasScannedLibrary = new AtomicBoolean(false);
|
||||||
|
|
||||||
public GameFileCacheService()
|
public GameFileCacheService()
|
||||||
{
|
{
|
||||||
|
@ -81,6 +84,16 @@ public final class GameFileCacheService extends IntentService
|
||||||
return matchWithoutRevision;
|
return matchWithoutRevision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasLoadedCache()
|
||||||
|
{
|
||||||
|
return hasLoadedCache.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasScannedLibrary()
|
||||||
|
{
|
||||||
|
return hasScannedLibrary.get();
|
||||||
|
}
|
||||||
|
|
||||||
private static void startService(Context context, String action)
|
private static void startService(Context context, String action)
|
||||||
{
|
{
|
||||||
Intent intent = new Intent(context, GameFileCacheService.class);
|
Intent intent = new Intent(context, GameFileCacheService.class);
|
||||||
|
@ -130,6 +143,8 @@ public final class GameFileCacheService extends IntentService
|
||||||
gameFileCache = temp;
|
gameFileCache = temp;
|
||||||
gameFileCache.load();
|
gameFileCache.load();
|
||||||
updateGameFileArray();
|
updateGameFileArray();
|
||||||
|
hasLoadedCache.set(true);
|
||||||
|
sendBroadcast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,10 +153,11 @@ public final class GameFileCacheService extends IntentService
|
||||||
{
|
{
|
||||||
synchronized (gameFileCache)
|
synchronized (gameFileCache)
|
||||||
{
|
{
|
||||||
if (gameFileCache.scanLibrary(this))
|
boolean changed = gameFileCache.scanLibrary(this);
|
||||||
{
|
if (changed)
|
||||||
updateGameFileArray();
|
updateGameFileArray();
|
||||||
}
|
hasScannedLibrary.set(true);
|
||||||
|
sendBroadcast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,6 +167,10 @@ public final class GameFileCacheService extends IntentService
|
||||||
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
|
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
|
||||||
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
|
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
|
||||||
gameFiles.set(gameFilesTemp);
|
gameFiles.set(gameFilesTemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendBroadcast()
|
||||||
|
{
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
|
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue