Skip to content

Commit

Permalink
it doesn't work because now i'm sending stay awake that does work onl…
Browse files Browse the repository at this point in the history
…y with usb plugged in
  • Loading branch information
cagnulein committed Jul 3, 2024
1 parent 19403a8 commit e2220cc
Show file tree
Hide file tree
Showing 12 changed files with 1,100 additions and 2 deletions.
Binary file modified app/src/main/assets/scrcpy-server.jar
Binary file not shown.
150 changes: 150 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/CleanUp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package org.cagnulein.android_remote;

import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

/**
* Handle the cleanup of scrcpy, even if the main process is killed.
* <p>
* This is useful to restore some state when scrcpy is closed, even on device disconnection (which kills the scrcpy process).
*/
public final class CleanUp {

private static final int MSG_TYPE_MASK = 0b11;
private static final int MSG_TYPE_RESTORE_STAY_ON = 0;
private static final int MSG_TYPE_DISABLE_SHOW_TOUCHES = 1;
private static final int MSG_TYPE_RESTORE_NORMAL_POWER_MODE = 2;
private static final int MSG_TYPE_POWER_OFF_SCREEN = 3;

private static final int MSG_PARAM_SHIFT = 2;

private final OutputStream out;

public CleanUp(OutputStream out) {
this.out = out;
}

public static CleanUp configure(int displayId) throws IOException {
String[] cmd = {"app_process", "/", CleanUp.class.getName(), String.valueOf(displayId)};

ProcessBuilder builder = new ProcessBuilder(cmd);
builder.environment().put("CLASSPATH", Server.SERVER_PATH);
Process process = builder.start();
return new CleanUp(process.getOutputStream());
}

private boolean sendMessage(int type, int param) {
assert (type & ~MSG_TYPE_MASK) == 0;
int msg = type | param << MSG_PARAM_SHIFT;
try {
out.write(msg);
out.flush();
return true;
} catch (IOException e) {
Log.w("Cleanup", "Could not configure cleanup (type=" + type + ", param=" + param + ")", e);
return false;
}
}

public boolean setRestoreStayOn(int restoreValue) {
// Restore the value (between 0 and 7), -1 to not restore
// <https://developer.android.com/reference/android/provider/Settings.Global#STAY_ON_WHILE_PLUGGED_IN>
assert restoreValue >= -1 && restoreValue <= 7;
return sendMessage(MSG_TYPE_RESTORE_STAY_ON, restoreValue & 0b1111);
}

public boolean setDisableShowTouches(boolean disableOnExit) {
return sendMessage(MSG_TYPE_DISABLE_SHOW_TOUCHES, disableOnExit ? 1 : 0);
}

public boolean setRestoreNormalPowerMode(boolean restoreOnExit) {
return sendMessage(MSG_TYPE_RESTORE_NORMAL_POWER_MODE, restoreOnExit ? 1 : 0);
}

public boolean setPowerOffScreen(boolean powerOffScreenOnExit) {
return sendMessage(MSG_TYPE_POWER_OFF_SCREEN, powerOffScreenOnExit ? 1 : 0);
}

public static void unlinkSelf() {
try {
new File(Server.SERVER_PATH).delete();
} catch (Exception e) {
Ln.e("Could not unlink server", e);
}
}

public static void main(String... args) {
unlinkSelf();

int displayId = Integer.parseInt(args[0]);

int restoreStayOn = -1;
boolean disableShowTouches = false;
boolean restoreNormalPowerMode = false;
boolean powerOffScreen = false;

try {
// Wait for the server to die
int msg;
while ((msg = System.in.read()) != -1) {
int type = msg & MSG_TYPE_MASK;
int param = msg >> MSG_PARAM_SHIFT;
switch (type) {
case MSG_TYPE_RESTORE_STAY_ON:
restoreStayOn = param > 7 ? -1 : param;
break;
case MSG_TYPE_DISABLE_SHOW_TOUCHES:
disableShowTouches = param != 0;
break;
case MSG_TYPE_RESTORE_NORMAL_POWER_MODE:
restoreNormalPowerMode = param != 0;
break;
case MSG_TYPE_POWER_OFF_SCREEN:
powerOffScreen = param != 0;
break;
default:
Ln.w("Unexpected msg type: " + type);
break;
}
}
} catch (IOException e) {
// Expected when the server is dead
}

Ln.i("Cleaning up");

if (disableShowTouches) {
Ln.i("Disabling \"show touches\"");
try {
Settings.putValue(Settings.TABLE_SYSTEM, "show_touches", "0");
} catch (SettingsException e) {
Ln.e("Could not restore \"show_touches\"", e);
}
}

if (restoreStayOn != -1) {
Ln.i("Restoring \"stay awake\"");
try {
Settings.putValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(restoreStayOn));
} catch (SettingsException e) {
Ln.e("Could not restore \"stay_on_while_plugged_in\"", e);
}
}

/* VIOLA
if (Device.isScreenOn()) {
if (powerOffScreen) {
Ln.i("Power off screen");
Device.powerOffScreen(displayId);
} else if (restoreNormalPowerMode) {
Ln.i("Restoring normal power mode");
Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
}
}*/

System.exit(0);
}
}
43 changes: 43 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.cagnulein.android_remote;

import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;

public final class Command {
private Command() {
// not instantiable
}

public static void exec(String... cmd) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(cmd);
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IOException("Command " + Arrays.toString(cmd) + " returned with value " + exitCode);
}
}

public static String execReadLine(String... cmd) throws IOException, InterruptedException {
String result = null;
Process process = Runtime.getRuntime().exec(cmd);
Scanner scanner = new Scanner(process.getInputStream());
if (scanner.hasNextLine()) {
result = scanner.nextLine();
}
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IOException("Command " + Arrays.toString(cmd) + " returned with value " + exitCode);
}
return result;
}

public static String execReadOutput(String... cmd) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(cmd);
String output = IO.toString(process.getInputStream());
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IOException("Command " + Arrays.toString(cmd) + " returned with value " + exitCode);
}
return output;
}
}
53 changes: 53 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/FakeContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.cagnulein.android_remote;

import android.annotation.TargetApi;
import android.content.AttributionSource;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Build;
import android.os.Process;

public final class FakeContext extends ContextWrapper {

public static final String PACKAGE_NAME = "com.android.shell";
public static final int ROOT_UID = 0; // Like android.os.Process.ROOT_UID, but before API 29

private static final FakeContext INSTANCE = new FakeContext();

public static FakeContext get() {
return INSTANCE;
}

private FakeContext() {
super(Workarounds.getSystemContext());
}

@Override
public String getPackageName() {
return PACKAGE_NAME;
}

@Override
public String getOpPackageName() {
return PACKAGE_NAME;
}

@TargetApi(Build.VERSION_CODES.S)
@Override
public AttributionSource getAttributionSource() {
AttributionSource.Builder builder = new AttributionSource.Builder(Process.SHELL_UID);
builder.setPackageName(PACKAGE_NAME);
return builder.build();
}

// @Override to be added on SDK upgrade for Android 14
@SuppressWarnings("unused")
public int getDeviceId() {
return 0;
}

@Override
public Context getApplicationContext() {
return this;
}
}
58 changes: 58 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/IO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.cagnulein.android_remote;

import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;

import com.genymobile.scrcpy.BuildConfig;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Scanner;

public final class IO {
private IO() {
// not instantiable
}

public static void writeFully(FileDescriptor fd, ByteBuffer from) throws IOException {
// ByteBuffer position is not updated as expected by Os.write() on old Android versions, so
// count the remaining bytes manually.
// See <https://github.com/Genymobile/scrcpy/issues/291>.
int remaining = from.remaining();
while (remaining > 0) {
try {
int w = Os.write(fd, from);
if (BuildConfig.DEBUG && w < 0) {
// w should not be negative, since an exception is thrown on error
throw new AssertionError("Os.write() returned a negative value (" + w + ")");
}
remaining -= w;
} catch (ErrnoException e) {
if (e.errno != OsConstants.EINTR) {
throw new IOException(e);
}
}
}
}

public static void writeFully(FileDescriptor fd, byte[] buffer, int offset, int len) throws IOException {
writeFully(fd, ByteBuffer.wrap(buffer, offset, len));
}

public static String toString(InputStream inputStream) {
StringBuilder builder = new StringBuilder();
Scanner scanner = new Scanner(inputStream);
while (scanner.hasNextLine()) {
builder.append(scanner.nextLine()).append('\n');
}
return builder.toString();
}

public static boolean isBrokenPipe(IOException e) {
Throwable cause = e.getCause();
return cause instanceof ErrnoException && ((ErrnoException) cause).errno == OsConstants.EPIPE;
}
}
32 changes: 32 additions & 0 deletions server/src/main/java/org/cagnulein/android_remote/Server.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
package org.cagnulein.android_remote;

import android.os.BatteryManager;

import java.io.File;
import java.io.IOException;

public final class Server {

private static String ip = null;
public static final String SERVER_PATH;

private Server() {
// not instantiable
}

static {
String[] classPaths = System.getProperty("java.class.path").split(File.pathSeparator);
// By convention, scrcpy is always executed with the absolute path of scrcpy-server.jar as the first item in the classpath
SERVER_PATH = classPaths[0];
}


private static void scrcpy(Options options) throws IOException {
final Device device = new Device(options);

/*if (options.getStayAwake())*/ {
int stayOn = BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS;
try {
String oldValue = Settings.getAndPutValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(stayOn));
try {
int restoreStayOn = Integer.parseInt(oldValue);
if (restoreStayOn != stayOn) {
// Restore only if the current value is different
if (!cleanUp.setRestoreStayOn(restoreStayOn)) {
Ln.e("Could not restore stay on on exit");
}
}
} catch (NumberFormatException e) {
// ignore
}
} catch (SettingsException e) {
Ln.e("Could not change \"stay_on_while_plugged_in\"", e);
}
}

try (DroidConnection connection = DroidConnection.open(ip)) {
ScreenEncoder screenEncoder = new ScreenEncoder(options.getBitRate());

Expand Down
Loading

0 comments on commit e2220cc

Please sign in to comment.