Fix icon click

This commit is contained in:
chengjian.scj 2025-02-21 14:39:17 +08:00
parent 4026c9884e
commit 93abcff312
7 changed files with 537 additions and 5 deletions

View file

@ -47,6 +47,10 @@ EOF
echo "Generating java from aidl..."
cd "$SERVER_DIR/src/main/aidl"
"$BUILD_TOOLS_DIR/aidl" -o"$GEN_DIR" -I. \
android/app/ActivityManager.aidl
"$BUILD_TOOLS_DIR/aidl" -o"$GEN_DIR" -I. -p "$ANDROID_AIDL" \
android/app/ITaskStackListener.aidl
"$BUILD_TOOLS_DIR/aidl" -o"$GEN_DIR" -I. \
android/content/IOnPrimaryClipChangedListener.aidl
"$BUILD_TOOLS_DIR/aidl" -o"$GEN_DIR" -I. -p "$ANDROID_AIDL" \
@ -54,6 +58,7 @@ cd "$SERVER_DIR/src/main/aidl"
# Fake sources to expose hidden Android types to the project
FAKE_SRC=( \
android/app/*java \
android/content/*java \
)
@ -90,6 +95,7 @@ if [[ $PLATFORM -lt 31 ]]
then
# use dx
"$BUILD_TOOLS_DIR/dx" --dex --output "$BUILD_DIR/classes.dex" \
android/app/*.class \
android/view/*.class \
android/content/*.class \
${CLASSES[@]}
@ -102,6 +108,7 @@ else
# use d8
"$BUILD_TOOLS_DIR/d8" --classpath "$ANDROID_JAR" \
--output "$BUILD_DIR/classes.zip" \
android/app/*.class \
android/view/*.class \
android/content/*.class \
${CLASSES[@]}

View file

@ -0,0 +1,20 @@
/**
* Copyright (c) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
parcelable ActivityManager.RunningTaskInfo;
parcelable ActivityManager.TaskSnapshot;

View file

@ -0,0 +1,230 @@
/**
* Copyright (c) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.app.ActivityManager;
import android.content.ComponentName;
oneway interface ITaskStackListener {
/** Activity was resized to be displayed in split-screen. */
const int FORCED_RESIZEABLE_REASON_SPLIT_SCREEN = 1;
/** Activity was resized to be displayed on a secondary display. */
const int FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY = 2;
/** Called whenever there are changes to the state of tasks in a stack. */
void onTaskStackChanged();
/** Called whenever an Activity is moved to the pinned stack from another stack. */
void onActivityPinned(String packageName, int userId, int taskId, int stackId);
/** Called whenever an Activity is moved from the pinned stack to another stack. */
void onActivityUnpinned();
/**
* Called whenever IActivityManager.startActivity is called on an activity that is already
* running, but the task is either brought to the front or a new Intent is delivered to it.
*
* @param task information about the task the activity was relaunched into
* @param homeVisible whether or not the home task is visible
* @param clearedTask whether or not the launch activity also cleared the task as a part of
* starting
* @param wasVisible whether the activity was visible before the restart attempt
*/
void onActivityRestartAttempt(in ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
boolean clearedTask, boolean wasVisible);
/**
* Called when we launched an activity that we forced to be resizable.
*
* @param packageName Package name of the top activity in the task.
* @param taskId Id of the task.
* @param reason {@link #FORCED_RESIZEABLE_REASON_SPLIT_SCREEN} or
* {@link #FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY}.
*/
void onActivityForcedResizable(String packageName, int taskId, int reason);
/**
* Called when we launched an activity that dismissed the docked stack.
*/
void onActivityDismissingDockedStack();
/**
* Called when an activity was requested to be launched on a secondary display but was not
* allowed there.
*
* @param taskInfo info about the Activity's task
* @param requestedDisplayId the id of the requested launch display
*/
void onActivityLaunchOnSecondaryDisplayFailed(in ActivityManager.RunningTaskInfo taskInfo,
int requestedDisplayId);
/**
* Called when an activity was requested to be launched on a secondary display but was rerouted
* to default display.
*
* @param taskInfo info about the Activity's task
* @param requestedDisplayId the id of the requested launch display
*/
void onActivityLaunchOnSecondaryDisplayRerouted(in ActivityManager.RunningTaskInfo taskInfo,
int requestedDisplayId);
/**
* Called when a task is added.
*
* @param taskId id of the task.
* @param componentName of the activity that the task is being started with.
*/
void onTaskCreated(int taskId, in ComponentName componentName);
/**
* Called when a task is removed.
*
* @param taskId id of the task.
*/
void onTaskRemoved(int taskId);
/**
* Called when a task is moved to the front of its stack.
*
* @param taskInfo info about the task which moved
*/
void onTaskMovedToFront(in ActivityManager.RunningTaskInfo taskInfo);
/**
* Called when a tasks description is changed due to an activity calling
* ActivityManagerService.setTaskDescription
*
* @param taskInfo info about the task which changed, with {@link TaskInfo#taskDescription}
*/
void onTaskDescriptionChanged(in ActivityManager.RunningTaskInfo taskInfo);
/**
* Called when a activitys orientation is changed due to it calling
* ActivityManagerService.setRequestedOrientation
*
* @param taskId id of the task that the activity is in.
* @param requestedOrientation the new requested orientation.
*/
void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation);
/**
* Called when the task is about to be finished but before its surfaces are
* removed from the window manager. This allows interested parties to
* perform relevant animations before the window disappears.
*
* @param taskInfo info about the task being removed
*/
void onTaskRemovalStarted(in ActivityManager.RunningTaskInfo taskInfo);
/**
* Called when the task has been put in a locked state because one or more of the
* activities inside it belong to a managed profile user, and that user has just
* been locked.
*/
void onTaskProfileLocked(int taskId, int userId);
/**
* Called when a task snapshot got updated.
*/
void onTaskSnapshotChanged(int taskId, in ActivityManager.TaskSnapshot snapshot);
/**
* Called when the resumed activity is in size compatibility mode and its override configuration
* is different from the current one of system.
*
* @param displayId Id of the display where the activity resides.
* @param activityToken Token of the size compatibility mode activity. It will be null when
* switching to a activity that is not in size compatibility mode or the
* configuration of the activity.
* @see com.android.server.wm.ActivityRecord#inSizeCompatMode
*/
void onSizeCompatModeActivityChanged(int displayId, in IBinder activityToken);
/**
* Reports that an Activity received a back key press when there were no additional activities
* on the back stack.
*
* @param taskInfo info about the task which received the back press
*/
void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
/*
* Called when contents are drawn for the first time on a display which can only contain one
* task.
*
* @param displayId the id of the display on which contents are drawn.
*/
void onSingleTaskDisplayDrawn(int displayId);
/*
* Called when the last task is removed from a display which can only contain one task.
*
* @param displayId the id of the display from which the window is removed.
*/
void onSingleTaskDisplayEmpty(int displayId);
/**
* Called when a task is reparented to a stack on a different display.
*
* @param taskId id of the task which was moved to a different display.
* @param newDisplayId id of the new display.
*/
void onTaskDisplayChanged(int taskId, int newDisplayId);
/**
* Called when any additions or deletions to the recent tasks list have been made.
*/
void onRecentTaskListUpdated();
/**
* Called when Recent Tasks list is frozen or unfrozen.
*
* @param frozen if true, Recents Tasks list is currently frozen, false otherwise
*/
void onRecentTaskListFrozenChanged(boolean frozen);
/**
* Called when a task gets or loses focus.
*
* @param taskId id of the task.
* @param {@code true} if the task got focus, {@code false} if it lost it.
*/
void onTaskFocusChanged(int taskId, boolean focused);
/**
* Called when a task changes its requested orientation. It is different from {@link
* #onActivityRequestedOrientationChanged(int, int)} in the sense that this method is called
* when a task changes requested orientation due to activity launch, dimiss or reparenting.
*
* @param taskId id of the task.
* @param requestedOrientation the new requested orientation of this task as screen orientations
* in {@link android.content.pm.ActivityInfo}.
*/
void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation);
/**
* Called when a rotation is about to start on the foreground activity.
* This applies for:
* * free sensor rotation
* * forced rotation
* * rotation settings set through adb command line
* * rotation that occurs when rotation tile is toggled in quick settings
*
* @param displayId id of the display where activity will rotate
*/
void onActivityRotation(int displayId);
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.os.Parcel;
import android.os.Parcelable;
public class ActivityManager {
public static class RunningTaskInfo extends TaskInfo implements Parcelable {
public RunningTaskInfo() {
}
private RunningTaskInfo(Parcel source) {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() {
public RunningTaskInfo createFromParcel(Parcel source) {
return new RunningTaskInfo(source);
}
public RunningTaskInfo[] newArray(int size) {
return new RunningTaskInfo[size];
}
};
}
public static class TaskSnapshot implements Parcelable {
public TaskSnapshot() {
}
private TaskSnapshot(Parcel source) {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
public TaskSnapshot createFromParcel(Parcel source) {
return new TaskSnapshot(source);
}
public TaskSnapshot[] newArray(int size) {
return new TaskSnapshot[size];
}
};
}
}

View file

@ -14,9 +14,11 @@ import com.genymobile.scrcpy.opengl.OpenGLRunner;
import com.genymobile.scrcpy.util.AffineMatrix;
import com.genymobile.scrcpy.util.Ln;
import com.genymobile.scrcpy.wrappers.ServiceManager;
import com.genymobile.scrcpy.wrappers.TaskStackListener;
import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@ -46,6 +48,7 @@ public class NewDisplayCapture extends SurfaceCapture {
private static final int VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP = 1 << 15;
private final VirtualDisplayListener vdListener;
private ITaskStackListener taskStackListener;
private final NewDisplay newDisplay;
private final DisplaySizeMonitor displaySizeMonitor = new DisplaySizeMonitor();
@ -247,6 +250,11 @@ public class NewDisplayCapture extends SurfaceCapture {
virtualDisplay.release();
virtualDisplay = null;
}
if (taskStackListener != null) {
ServiceManager.getActivityManager().unregisterTaskStackListener(taskStackListener);
taskStackListener = null;
}
}
@Override
@ -280,11 +288,9 @@ public class NewDisplayCapture extends SurfaceCapture {
Intent secondaryHomeIntent = new Intent(Intent.ACTION_MAIN);
secondaryHomeIntent.addCategory(Intent.CATEGORY_SECONDARY_HOME);
secondaryHomeIntent.addCategory(Intent.CATEGORY_DEFAULT);
ResolveInfo secondaryHomeResolveInfo = (ResolveInfo) pm.resolveActivity(secondaryHomeIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (secondaryHomeResolveInfo.activityInfo.packageName.equals(homeResolveInfo.activityInfo.packageName)) {
Intent launcherIntent = new Intent();
launcherIntent.setClassName(secondaryHomeResolveInfo.activityInfo.packageName, secondaryHomeResolveInfo.activityInfo.name);
if (secondaryHomeResolveInfo.activityInfo.packageName.equals(homeResolveInfo.activityInfo.packageName)) {
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(virtualDisplayId);
try {
@ -294,7 +300,28 @@ public class NewDisplayCapture extends SurfaceCapture {
Ln.e("Could not invoke method", e);
}
ServiceManager.getActivityManager().startActivity(launcherIntent, options.toBundle());
ServiceManager.getActivityManager().startActivity(secondaryHomeIntent, options.toBundle());
if (Build.VERSION.SDK_INT < AndroidVersions.API_31_ANDROID_12) {
taskStackListener = new TaskStackListener() {
@Override
public void onActivityLaunchOnSecondaryDisplayFailed(android.app.ActivityManager.RunningTaskInfo taskInfo,
int requestedDisplayId) {
if (requestedDisplayId == virtualDisplayId) {
String packageName = taskInfo.baseIntent.getComponent().getPackageName();
String className = taskInfo.baseIntent.getComponent().getClassName();
Intent launcherIntent = new Intent();
launcherIntent.setClassName(packageName, className);
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(virtualDisplayId);
ServiceManager.getActivityManager().startActivity(launcherIntent, options.toBundle());
}
}
};
ServiceManager.getActivityManager().registerTaskStackListener(taskStackListener);
}
}
}
}

View file

@ -6,6 +6,7 @@ import com.genymobile.scrcpy.util.Ln;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ITaskStackListener;
import android.content.IContentProvider;
import android.content.Intent;
import android.os.Binder;
@ -162,4 +163,19 @@ public final class ActivityManager {
Ln.e("Could not invoke method", e);
}
}
public void registerTaskStackListener(ITaskStackListener listener) {
try {
manager.getClass().getMethod("registerTaskStackListener", ITaskStackListener.class).invoke(manager, listener);
} catch (Exception e) {
Ln.e("Could not register task stack listener", e);
}
}
public void unregisterTaskStackListener(ITaskStackListener listener) {
try {
manager.getClass().getMethod("unregisterTaskStackListener", ITaskStackListener.class).invoke(manager, listener);
} catch (Exception e) {
Ln.e("Could not register task stack listener", e);
}
}
}

View file

@ -0,0 +1,158 @@
/**
* Copyright (c) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.genymobile.scrcpy.wrappers;
import android.app.ActivityManager;
import android.app.ITaskStackListener;
import android.content.ComponentName;
import android.os.IBinder;
public class TaskStackListener extends ITaskStackListener.Stub {
@Override
public void onTaskStackChanged() {
// empty default implementation
}
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
// empty default implementation
}
@Override
public void onActivityUnpinned() {
// empty default implementation
}
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
boolean clearedTask, boolean wasVisible) {
// empty default implementation
}
@Override
public void onActivityForcedResizable(String packageName, int taskId, int reason) {
// empty default implementation
}
@Override
public void onActivityDismissingDockedStack() {
// empty default implementation
}
@Override
public void onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo taskInfo,
int requestedDisplayId) {
// empty default implementation
}
@Override
public void onActivityLaunchOnSecondaryDisplayRerouted(ActivityManager.RunningTaskInfo taskInfo,
int requestedDisplayId) {
// empty default implementation
}
@Override
public void onTaskCreated(int taskId, ComponentName componentName) {
// empty default implementation
}
@Override
public void onTaskRemoved(int taskId) {
// empty default implementation
}
@Override
public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
// empty default implementation
}
@Override
public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
// empty default implementation
}
@Override
public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
// empty default implementation
}
@Override
public void onTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo) {
// empty default implementation
}
@Override
public void onTaskProfileLocked(int taskId, int userId) {
// empty default implementation
}
@Override
public void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) {
// empty default implementation
}
@Override
public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
// empty default implementation
}
@Override
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
// empty default implementation
}
@Override
public void onSingleTaskDisplayDrawn(int displayId) {
// empty default implementation
}
@Override
public void onSingleTaskDisplayEmpty(int displayId) {
// empty default implementation
}
@Override
public void onTaskDisplayChanged(int taskId, int newDisplayId) {
// empty default implementation
}
@Override
public void onRecentTaskListUpdated() {
// empty default implementation
}
@Override
public void onRecentTaskListFrozenChanged(boolean frozen) {
// empty default implementation
}
@Override
public void onTaskFocusChanged(int taskId, boolean focused) {
// empty default implementation
}
@Override
public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
// empty default implementation
}
@Override
public void onActivityRotation(int displayId) {
// empty default implementation
}
}