mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-19 02:53:05 +00:00
Fix and enable launcher shortcuts on Android 7.1
This commit is contained in:
parent
0f0b83badc
commit
b6e4d5528b
@ -51,6 +51,15 @@
|
|||||||
<category android:name="tv.ouya.intent.category.APP" />
|
<category android:name="tv.ouya.intent.category.APP" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<!-- Small hack to support launcher shortcuts without relaunching over and over again when the back button is pressed -->
|
||||||
|
<activity
|
||||||
|
android:name=".AppViewShortcutTrampoline"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="com.limelight.PcView" />
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".AppView"
|
android:name=".AppView"
|
||||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||||
|
@ -49,12 +49,11 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
|
|
||||||
private ComputerDetails computer;
|
private ComputerDetails computer;
|
||||||
private ComputerManagerService.ApplistPoller poller;
|
private ComputerManagerService.ApplistPoller poller;
|
||||||
private SpinnerDialog blockingLoadSpinner, blockingServerinfoSpinner;
|
private SpinnerDialog blockingLoadSpinner;
|
||||||
private String lastRawApplist;
|
private String lastRawApplist;
|
||||||
private int lastRunningAppId;
|
private int lastRunningAppId;
|
||||||
private boolean suspendGridUpdates;
|
private boolean suspendGridUpdates;
|
||||||
private boolean inForeground;
|
private boolean inForeground;
|
||||||
private boolean launchedFromShortcut;
|
|
||||||
|
|
||||||
private final static int START_OR_RESUME_ID = 1;
|
private final static int START_OR_RESUME_ID = 1;
|
||||||
private final static int QUIT_ID = 2;
|
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 NAME_EXTRA = "Name";
|
||||||
public final static String UUID_EXTRA = "UUID";
|
public final static String UUID_EXTRA = "UUID";
|
||||||
public final static String SHORTCUT_EXTRA = "Shortcut";
|
|
||||||
|
|
||||||
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
||||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||||
@ -183,30 +181,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
return;
|
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
|
// App list is the same or empty
|
||||||
if (details.rawAppList == null || details.rawAppList.equals(lastRawApplist)) {
|
if (details.rawAppList == null || details.rawAppList.equals(lastRawApplist)) {
|
||||||
|
|
||||||
@ -274,13 +248,6 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
|
|||||||
|
|
||||||
uuidString = getIntent().getStringExtra(UUID_EXTRA);
|
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);
|
shortcutHelper.reportShortcutUsed(uuidString);
|
||||||
|
|
||||||
String labelText = getResources().getString(R.string.title_applist)+" "+getIntent().getStringExtra(NAME_EXTRA);
|
String labelText = getResources().getString(R.string.title_applist)+" "+getIntent().getStringExtra(NAME_EXTRA);
|
||||||
|
119
app/src/main/java/com/limelight/AppViewShortcutTrampoline.java
Normal file
119
app/src/main/java/com/limelight/AppViewShortcutTrampoline.java
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,12 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
import android.content.pm.ShortcutManager;
|
import android.content.pm.ShortcutManager;
|
||||||
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import com.limelight.AppView;
|
import com.limelight.AppView;
|
||||||
|
import com.limelight.AppViewShortcutTrampoline;
|
||||||
|
import com.limelight.R;
|
||||||
import com.limelight.nvstream.http.ComputerDetails;
|
import com.limelight.nvstream.http.ComputerDetails;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -75,16 +78,16 @@ public class ShortcutHelper {
|
|||||||
|
|
||||||
public void createAppViewShortcut(String id, ComputerDetails details) {
|
public void createAppViewShortcut(String id, ComputerDetails details) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
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.NAME_EXTRA, details.name);
|
||||||
i.putExtra(AppView.UUID_EXTRA, details.uuid.toString());
|
i.putExtra(AppView.UUID_EXTRA, details.uuid.toString());
|
||||||
i.putExtra(AppView.SHORTCUT_EXTRA, true);
|
|
||||||
i.setAction(Intent.ACTION_DEFAULT);
|
i.setAction(Intent.ACTION_DEFAULT);
|
||||||
|
|
||||||
ShortcutInfo sinfo = new ShortcutInfo.Builder(context, id)
|
ShortcutInfo sinfo = new ShortcutInfo.Builder(context, id)
|
||||||
.setIntent(i)
|
.setIntent(i)
|
||||||
.setShortLabel(details.name)
|
.setShortLabel(details.name)
|
||||||
.setLongLabel(details.name)
|
.setLongLabel(details.name)
|
||||||
|
.setIcon(Icon.createWithResource(context, R.mipmap.ic_pc_scut))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ShortcutInfo existingSinfo = getInfoForId(id);
|
ShortcutInfo existingSinfo = getInfoForId(id);
|
||||||
@ -98,7 +101,7 @@ public class ShortcutHelper {
|
|||||||
reapShortcutsForDynamicAdd();
|
reapShortcutsForDynamicAdd();
|
||||||
|
|
||||||
// Add the new shortcut
|
// Add the new shortcut
|
||||||
//TODO: Testing and proper icon - sm.addDynamicShortcuts(Arrays.asList(sinfo));
|
sm.addDynamicShortcuts(Collections.singletonList(sinfo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
app/src/main/res/mipmap-hdpi/ic_pc_scut.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/ic_pc_scut.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_pc_scut.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/ic_pc_scut.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_pc_scut.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/ic_pc_scut.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_pc_scut.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_pc_scut.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_pc_scut.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/ic_pc_scut.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
Loading…
x
Reference in New Issue
Block a user