diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java index ca1197bc73..5b5c310f75 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java @@ -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 diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheService.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheService.java index 17aef0cd35..5cddf93f5d 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheService.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheService.java @@ -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 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)); } }