Android: Fix race condition in AppLinkActivity
https://bugs.dolphin-emu.org/issues/11767
This commit is contained in:
parent
c34388f75b
commit
e4ef2193e0
|
@ -1,5 +1,7 @@
|
|||
package org.dolphinemu.dolphinemu.activities;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
|
@ -26,6 +28,7 @@ public class AppLinkActivity extends FragmentActivity
|
|||
|
||||
private AppLinkHelper.PlayAction playAction;
|
||||
private DirectoryStateReceiver directoryStateReceiver;
|
||||
private BroadcastReceiver gameFileCacheReceiver;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
|
@ -63,16 +66,19 @@ public class AppLinkActivity extends FragmentActivity
|
|||
*/
|
||||
private void initResources()
|
||||
{
|
||||
IntentFilter statusIntentFilter = new IntentFilter(
|
||||
IntentFilter directoryStateIntentFilter = new IntentFilter(
|
||||
DirectoryInitialization.BROADCAST_ACTION);
|
||||
|
||||
IntentFilter gameFileCacheIntentFilter = new IntentFilter(
|
||||
GameFileCacheService.BROADCAST_ACTION);
|
||||
|
||||
directoryStateReceiver =
|
||||
new DirectoryStateReceiver(directoryInitializationState ->
|
||||
{
|
||||
if (directoryInitializationState ==
|
||||
DirectoryInitialization.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||
{
|
||||
play(playAction);
|
||||
tryPlay(playAction);
|
||||
}
|
||||
else if (directoryInitializationState ==
|
||||
DirectoryInitialization.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
||||
|
@ -88,10 +94,23 @@ public class AppLinkActivity extends FragmentActivity
|
|||
}
|
||||
});
|
||||
|
||||
// Registers the DirectoryStateReceiver and its intent filters
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
directoryStateReceiver,
|
||||
statusIntentFilter);
|
||||
gameFileCacheReceiver =
|
||||
new BroadcastReceiver()
|
||||
{
|
||||
@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);
|
||||
GameFileCacheService.startLoad(this);
|
||||
}
|
||||
|
@ -107,17 +126,31 @@ public class AppLinkActivity extends FragmentActivity
|
|||
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
|
||||
*/
|
||||
private void play(AppLinkHelper.PlayAction action)
|
||||
private void play(AppLinkHelper.PlayAction action, GameFile game)
|
||||
{
|
||||
Log.d(TAG, "Playing game "
|
||||
+ action.getGameId()
|
||||
+ " from channel "
|
||||
+ action.getChannelId());
|
||||
|
||||
GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
|
||||
if (game == null)
|
||||
Log.e(TAG, "Invalid Game: " + action.getGameId());
|
||||
else
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.io.File;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
|
@ -27,6 +28,8 @@ public final class GameFileCacheService extends IntentService
|
|||
|
||||
private static GameFileCache gameFileCache = null;
|
||||
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()
|
||||
{
|
||||
|
@ -81,6 +84,16 @@ public final class GameFileCacheService extends IntentService
|
|||
return matchWithoutRevision;
|
||||
}
|
||||
|
||||
public static boolean hasLoadedCache()
|
||||
{
|
||||
return hasLoadedCache.get();
|
||||
}
|
||||
|
||||
public static boolean hasScannedLibrary()
|
||||
{
|
||||
return hasScannedLibrary.get();
|
||||
}
|
||||
|
||||
private static void startService(Context context, String action)
|
||||
{
|
||||
Intent intent = new Intent(context, GameFileCacheService.class);
|
||||
|
@ -130,6 +143,8 @@ public final class GameFileCacheService extends IntentService
|
|||
gameFileCache = temp;
|
||||
gameFileCache.load();
|
||||
updateGameFileArray();
|
||||
hasLoadedCache.set(true);
|
||||
sendBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,10 +153,11 @@ public final class GameFileCacheService extends IntentService
|
|||
{
|
||||
synchronized (gameFileCache)
|
||||
{
|
||||
if (gameFileCache.scanLibrary(this))
|
||||
{
|
||||
boolean changed = gameFileCache.scanLibrary(this);
|
||||
if (changed)
|
||||
updateGameFileArray();
|
||||
}
|
||||
hasScannedLibrary.set(true);
|
||||
sendBroadcast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -151,6 +167,10 @@ public final class GameFileCacheService extends IntentService
|
|||
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
|
||||
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
|
||||
gameFiles.set(gameFilesTemp);
|
||||
}
|
||||
|
||||
private void sendBroadcast()
|
||||
{
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue