mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-07-28 11:49:10 +00:00
Add --list-apps
Add an option to list all apps installed on the device: scrcpy --list-apps PR #5370 <https://github.com/Genymobile/scrcpy/pull/5370>
This commit is contained in:
parent
408a388fc5
commit
9c9d92fb1c
11 changed files with 154 additions and 1 deletions
|
@ -61,6 +61,7 @@ public class Options {
|
|||
private boolean listDisplays;
|
||||
private boolean listCameras;
|
||||
private boolean listCameraSizes;
|
||||
private boolean listApps;
|
||||
|
||||
// Options not used by the scrcpy client, but useful to use scrcpy-server directly
|
||||
private boolean sendDeviceMeta = true; // send device name and size
|
||||
|
@ -213,7 +214,7 @@ public class Options {
|
|||
}
|
||||
|
||||
public boolean getList() {
|
||||
return listEncoders || listDisplays || listCameras || listCameraSizes;
|
||||
return listEncoders || listDisplays || listCameras || listCameraSizes || listApps;
|
||||
}
|
||||
|
||||
public boolean getListEncoders() {
|
||||
|
@ -232,6 +233,10 @@ public class Options {
|
|||
return listCameraSizes;
|
||||
}
|
||||
|
||||
public boolean getListApps() {
|
||||
return listApps;
|
||||
}
|
||||
|
||||
public boolean getSendDeviceMeta() {
|
||||
return sendDeviceMeta;
|
||||
}
|
||||
|
@ -395,6 +400,9 @@ public class Options {
|
|||
case "list_camera_sizes":
|
||||
options.listCameraSizes = Boolean.parseBoolean(value);
|
||||
break;
|
||||
case "list_apps":
|
||||
options.listApps = Boolean.parseBoolean(value);
|
||||
break;
|
||||
case "camera_id":
|
||||
if (!value.isEmpty()) {
|
||||
options.cameraId = value;
|
||||
|
|
|
@ -292,6 +292,11 @@ public final class Server {
|
|||
Workarounds.apply();
|
||||
Ln.i(LogUtils.buildCameraListMessage(options.getListCameraSizes()));
|
||||
}
|
||||
if (options.getListApps()) {
|
||||
Workarounds.apply();
|
||||
Ln.i("Processing Android apps... (this may take some time)");
|
||||
Ln.i(LogUtils.buildAppListMessage());
|
||||
}
|
||||
// Just print the requested data, do not mirror
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.genymobile.scrcpy.device;
|
||||
|
||||
import com.genymobile.scrcpy.AndroidVersions;
|
||||
import com.genymobile.scrcpy.FakeContext;
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
import com.genymobile.scrcpy.wrappers.ClipboardManager;
|
||||
import com.genymobile.scrcpy.wrappers.DisplayControl;
|
||||
|
@ -9,6 +10,10 @@ import com.genymobile.scrcpy.wrappers.ServiceManager;
|
|||
import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
||||
import com.genymobile.scrcpy.wrappers.WindowManager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemClock;
|
||||
|
@ -17,6 +22,9 @@ import android.view.InputEvent;
|
|||
import android.view.KeyCharacterMap;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class Device {
|
||||
|
||||
public static final int DISPLAY_ID_NONE = -1;
|
||||
|
@ -202,4 +210,37 @@ public final class Device {
|
|||
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
|
||||
return displayInfo.getRotation();
|
||||
}
|
||||
|
||||
public static List<DeviceApp> listApps() {
|
||||
List<DeviceApp> apps = new ArrayList<>();
|
||||
PackageManager pm = FakeContext.get().getPackageManager();
|
||||
for (ApplicationInfo appInfo : getLaunchableApps(pm)) {
|
||||
String name = pm.getApplicationLabel(appInfo).toString();
|
||||
boolean system = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
||||
apps.add(new DeviceApp(appInfo.packageName, name, system));
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
@SuppressLint("QueryPermissionsNeeded")
|
||||
private static List<ApplicationInfo> getLaunchableApps(PackageManager pm) {
|
||||
List<ApplicationInfo> result = new ArrayList<>();
|
||||
for (ApplicationInfo appInfo : pm.getInstalledApplications(PackageManager.GET_META_DATA)) {
|
||||
if (appInfo.enabled && getLaunchIntent(pm, appInfo.packageName) != null) {
|
||||
result.add(appInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Intent getLaunchIntent(PackageManager pm, String packageName) {
|
||||
Intent launchIntent = pm.getLaunchIntentForPackage(packageName);
|
||||
if (launchIntent != null) {
|
||||
return launchIntent;
|
||||
}
|
||||
|
||||
return pm.getLeanbackLaunchIntentForPackage(packageName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package com.genymobile.scrcpy.device;
|
||||
|
||||
public final class DeviceApp {
|
||||
|
||||
private final String packageName;
|
||||
private final String name;
|
||||
private final boolean system;
|
||||
|
||||
public DeviceApp(String packageName, String name, boolean system) {
|
||||
this.packageName = packageName;
|
||||
this.name = name;
|
||||
this.system = system;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isSystem() {
|
||||
return system;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
package com.genymobile.scrcpy.util;
|
||||
|
||||
import com.genymobile.scrcpy.device.Device;
|
||||
import com.genymobile.scrcpy.device.DeviceApp;
|
||||
import com.genymobile.scrcpy.device.DisplayInfo;
|
||||
import com.genymobile.scrcpy.device.Size;
|
||||
import com.genymobile.scrcpy.wrappers.DisplayManager;
|
||||
import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.camera2.CameraAccessException;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
|
@ -13,7 +16,9 @@ import android.hardware.camera2.params.StreamConfigurationMap;
|
|||
import android.media.MediaCodec;
|
||||
import android.util.Range;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
@ -154,4 +159,53 @@ public final class LogUtils {
|
|||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@SuppressLint("QueryPermissionsNeeded")
|
||||
public static String buildAppListMessage() {
|
||||
StringBuilder builder = new StringBuilder("List of apps:");
|
||||
|
||||
List<DeviceApp> apps = Device.listApps();
|
||||
|
||||
// Sort by:
|
||||
// 1. system flag (system apps are before non-system apps)
|
||||
// 2. name
|
||||
// 3. package name
|
||||
// Comparator.comparing() was introduced in API 24, so it cannot be used here to simplify the code
|
||||
Collections.sort(apps, (thisApp, otherApp) -> {
|
||||
// System apps first
|
||||
int cmp = -Boolean.compare(thisApp.isSystem(), otherApp.isSystem());
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = Objects.compare(thisApp.getName(), otherApp.getName(), String::compareTo);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return Objects.compare(thisApp.getPackageName(), otherApp.getPackageName(), String::compareTo);
|
||||
});
|
||||
|
||||
final int column = 30;
|
||||
for (DeviceApp app : apps) {
|
||||
String name = app.getName();
|
||||
int padding = column - name.length();
|
||||
builder.append("\n ");
|
||||
if (app.isSystem()) {
|
||||
builder.append("* ");
|
||||
} else {
|
||||
builder.append("- ");
|
||||
|
||||
}
|
||||
builder.append(name);
|
||||
if (padding > 0) {
|
||||
builder.append(String.format("%" + padding + "s", " "));
|
||||
} else {
|
||||
builder.append("\n ").append(String.format("%" + column + "s", " "));
|
||||
}
|
||||
builder.append(" [").append(app.getPackageName()).append(']');
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue