diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9ba989ce..487c8d85 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -51,6 +51,15 @@ + + + + diff --git a/app/src/main/java/com/limelight/AppView.java b/app/src/main/java/com/limelight/AppView.java index a85c91fa..673d4a2e 100644 --- a/app/src/main/java/com/limelight/AppView.java +++ b/app/src/main/java/com/limelight/AppView.java @@ -49,12 +49,11 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { private ComputerDetails computer; private ComputerManagerService.ApplistPoller poller; - private SpinnerDialog blockingLoadSpinner, blockingServerinfoSpinner; + private SpinnerDialog blockingLoadSpinner; private String lastRawApplist; private int lastRunningAppId; private boolean suspendGridUpdates; private boolean inForeground; - private boolean launchedFromShortcut; private final static int START_OR_RESUME_ID = 1; private final static int QUIT_ID = 2; @@ -63,7 +62,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { public final static String NAME_EXTRA = "Name"; public final static String UUID_EXTRA = "UUID"; - public final static String SHORTCUT_EXTRA = "Shortcut"; private ComputerManagerService.ComputerManagerBinder managerBinder; private final ServiceConnection serviceConnection = new ServiceConnection() { @@ -183,30 +181,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { return; } - if (launchedFromShortcut) { - if (details.state == ComputerDetails.State.ONLINE) { - if (blockingServerinfoSpinner != null) { - blockingServerinfoSpinner.dismiss(); - blockingServerinfoSpinner = null; - } - - if (details.runningGameId != 0) { - AppView.this.runOnUiThread(new Runnable() { - @Override - public void run() { - // We have to finish this activity here otherwise we'll get into a loop - // when the user hits back - finish(); - - // When launched from shortcut, resume the running game - ServerHelper.doStart(AppView.this, new NvApp("app", details.runningGameId), computer, managerBinder); - } - }); - return; - } - } - } - // App list is the same or empty if (details.rawAppList == null || details.rawAppList.equals(lastRawApplist)) { @@ -274,13 +248,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks { uuidString = getIntent().getStringExtra(UUID_EXTRA); - launchedFromShortcut = getIntent().getBooleanExtra(SHORTCUT_EXTRA, false); - if (launchedFromShortcut) { - // Display blocking loading spinner - blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title), - getResources().getString(R.string.applist_connect_msg), true); - } - shortcutHelper.reportShortcutUsed(uuidString); String labelText = getResources().getString(R.string.title_applist)+" "+getIntent().getStringExtra(NAME_EXTRA); diff --git a/app/src/main/java/com/limelight/AppViewShortcutTrampoline.java b/app/src/main/java/com/limelight/AppViewShortcutTrampoline.java new file mode 100644 index 00000000..19c136ad --- /dev/null +++ b/app/src/main/java/com/limelight/AppViewShortcutTrampoline.java @@ -0,0 +1,119 @@ +package com.limelight; + +import android.app.Activity; +import android.app.Service; +import android.content.ComponentName; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; + +import com.limelight.computers.ComputerManagerListener; +import com.limelight.computers.ComputerManagerService; +import com.limelight.nvstream.http.ComputerDetails; +import com.limelight.nvstream.http.NvApp; +import com.limelight.utils.ServerHelper; +import com.limelight.utils.SpinnerDialog; +import com.limelight.utils.UiHelper; + +import java.util.UUID; + +public class AppViewShortcutTrampoline extends Activity { + private String uuidString; + + private ComputerDetails computer; + private SpinnerDialog blockingLoadSpinner; + + public final static String UUID_EXTRA = "UUID"; + + private ComputerManagerService.ComputerManagerBinder managerBinder; + private final ServiceConnection serviceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder binder) { + final ComputerManagerService.ComputerManagerBinder localBinder = + ((ComputerManagerService.ComputerManagerBinder)binder); + + // Wait in a separate thread to avoid stalling the UI + new Thread() { + @Override + public void run() { + // Wait for the binder to be ready + localBinder.waitForReady(); + + // Now make the binder visible + managerBinder = localBinder; + + // Get the computer object + computer = managerBinder.getComputer(UUID.fromString(uuidString)); + + // Force CMS to repoll this machine + managerBinder.invalidateStateForComputer(computer.uuid); + + // Start polling + managerBinder.startPolling(new ComputerManagerListener() { + @Override + public void notifyComputerUpdated(final ComputerDetails details) { + // Don't care about other computers + if (!details.uuid.toString().equalsIgnoreCase(uuidString)) { + return; + } + + if (details.state != ComputerDetails.State.UNKNOWN) { + // Close this activity + finish(); + + if (details.runningGameId != 0) { + // A game is running so launch straight to the game activity + ServerHelper.doStart(AppViewShortcutTrampoline.this, + new NvApp("app", details.runningGameId), details, managerBinder); + } + else { + // No game running or computer offline - launch to the AppView + Intent i = new Intent(getIntent()); + i.setClass(AppViewShortcutTrampoline.this, AppView.class); + startActivity(i); + } + } + } + }); + } + }.start(); + } + + public void onServiceDisconnected(ComponentName className) { + managerBinder = null; + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + UiHelper.notifyNewRootView(this); + + uuidString = getIntent().getStringExtra(UUID_EXTRA); + + // Bind to the computer manager service + bindService(new Intent(this, ComputerManagerService.class), serviceConnection, + Service.BIND_AUTO_CREATE); + + blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title), + getResources().getString(R.string.applist_connect_msg), true); + } + + @Override + protected void onPause() { + super.onPause(); + + blockingLoadSpinner.dismiss(); + + if (managerBinder != null) { + unbindService(serviceConnection); + } + + if (managerBinder != null) { + managerBinder.stopPolling(); + } + + finish(); + } +} diff --git a/app/src/main/java/com/limelight/utils/ShortcutHelper.java b/app/src/main/java/com/limelight/utils/ShortcutHelper.java index f7465027..538a6cb9 100644 --- a/app/src/main/java/com/limelight/utils/ShortcutHelper.java +++ b/app/src/main/java/com/limelight/utils/ShortcutHelper.java @@ -5,9 +5,12 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; +import android.graphics.drawable.Icon; import android.os.Build; import com.limelight.AppView; +import com.limelight.AppViewShortcutTrampoline; +import com.limelight.R; import com.limelight.nvstream.http.ComputerDetails; import java.util.Collections; @@ -75,16 +78,16 @@ public class ShortcutHelper { public void createAppViewShortcut(String id, ComputerDetails details) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - Intent i = new Intent(context, AppView.class); + Intent i = new Intent(context, AppViewShortcutTrampoline.class); i.putExtra(AppView.NAME_EXTRA, details.name); i.putExtra(AppView.UUID_EXTRA, details.uuid.toString()); - i.putExtra(AppView.SHORTCUT_EXTRA, true); i.setAction(Intent.ACTION_DEFAULT); ShortcutInfo sinfo = new ShortcutInfo.Builder(context, id) .setIntent(i) .setShortLabel(details.name) .setLongLabel(details.name) + .setIcon(Icon.createWithResource(context, R.mipmap.ic_pc_scut)) .build(); ShortcutInfo existingSinfo = getInfoForId(id); @@ -98,7 +101,7 @@ public class ShortcutHelper { reapShortcutsForDynamicAdd(); // Add the new shortcut - //TODO: Testing and proper icon - sm.addDynamicShortcuts(Arrays.asList(sinfo)); + sm.addDynamicShortcuts(Collections.singletonList(sinfo)); } } } diff --git a/app/src/main/res/mipmap-hdpi/ic_pc_scut.png b/app/src/main/res/mipmap-hdpi/ic_pc_scut.png new file mode 100644 index 00000000..edd9a152 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_pc_scut.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_pc_scut.png b/app/src/main/res/mipmap-mdpi/ic_pc_scut.png new file mode 100644 index 00000000..ff3ae496 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_pc_scut.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_pc_scut.png b/app/src/main/res/mipmap-xhdpi/ic_pc_scut.png new file mode 100644 index 00000000..6d9195d8 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_pc_scut.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_pc_scut.png b/app/src/main/res/mipmap-xxhdpi/ic_pc_scut.png new file mode 100644 index 00000000..9c7799b4 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_pc_scut.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_pc_scut.png b/app/src/main/res/mipmap-xxxhdpi/ic_pc_scut.png new file mode 100644 index 00000000..fe196ebf Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_pc_scut.png differ