Before

…lines 1–4 unchanged (4 lines)
5
6import android.content.ClipData;
7import android.content.IOnPrimaryClipChangedListener;
8import android.os.Build;
9import android.os.IInterface;
10
11import java.lang.reflect.InvocationTargetException;
12import java.lang.reflect.Method;
13
14public final class ClipboardManager {
15 private final IInterface manager;
16 private Method getPrimaryClipMethod;
17 private Method setPrimaryClipMethod;
…lines 18–95 unchanged (78 lines)
96 }
97 }
98 return setPrimaryClipMethod;
99 }
100
101 private static ClipData getPrimaryClip(Method method, int methodVersion, IInterface manager)
102 throws InvocationTargetException, IllegalAccessException {
103 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
104 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME);
105 }
106
107 switch (methodVersion) {
108 case 0:
109 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID);
110 case 1:
111 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
112 case 2:
113 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
114 case 3:
115 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID, null);
116 case 4:
117 // The last boolean parameter is "userOperate"
118 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0, true);
119 default:
120 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, null, null, FakeContext.ROOT_UID, 0, true);
121 }
122 }
123
124 private static void setPrimaryClip(Method method, int methodVersion, IInterface manager, ClipData clipData)
125 throws InvocationTargetException, IllegalAccessException {
126 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
127 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME);
128 return;
129 }
130
131 switch (methodVersion) {
132 case 0:
133 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID);
134 break;
135 case 1:
136 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
137 break;
138 default:
139 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
140 break;
141 }
142 }
143
144 public CharSequence getText() {
145 try {
146 Method method = getGetPrimaryClipMethod();
147 ClipData clipData = getPrimaryClip(method, getMethodVersion, manager);
148 if (clipData == null || clipData.getItemCount() == 0) {
149 return null;
150 }
151 return clipData.getItemAt(0).getText();
152 } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
153 Ln.e("Could not invoke method", e);
154 return null;
155 }
156 }
157
158 public boolean setText(CharSequence text) {
159 try {
160 Method method = getSetPrimaryClipMethod();
161 ClipData clipData = ClipData.newPlainText(null, text);
162 setPrimaryClip(method, setMethodVersion, manager, clipData);
163 return true;
164 } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
165 Ln.e("Could not invoke method", e);
166 return false;
167 }
168 }
169
170 private static void addPrimaryClipChangedListener(Method method, int methodVersion, IInterface manager, IOnPrimaryClipChangedListener listener)
171 throws InvocationTargetException, IllegalAccessException {
172 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
173 method.invoke(manager, listener, FakeContext.PACKAGE_NAME);
174 return;
175 }
176
177 switch (methodVersion) {
178 case 0:
179 method.invoke(manager, listener, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID);
180 break;
181 case 1:
182 method.invoke(manager, listener, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
183 break;
184 default:
185 method.invoke(manager, listener, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
186 break;
187 }
188 }
189
190 private Method getAddPrimaryClipChangedListener() throws NoSuchMethodException {
191 if (addPrimaryClipChangedListener == null) {
192 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
193 addPrimaryClipChangedListener = manager.getClass()
194 .getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class);
…lines 195–216 unchanged (22 lines)
217
218 public boolean addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
219 try {
220 Method method = getAddPrimaryClipChangedListener();
221 addPrimaryClipChangedListener(method, addListenerMethodVersion, manager, listener);
222 return true;
223 } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
224 Ln.e("Could not invoke method", e);
225 return false;
226 }
227 }
228}
229

After

1package com.genymobile.scrcpy.wrappers;
2
3import com.genymobile.scrcpy.FakeContext;
4import com.genymobile.scrcpy.Ln;
5
6import android.content.ClipData;
7import android.content.IOnPrimaryClipChangedListener;
8import android.os.Build;
9import android.os.IInterface;
10
11import java.lang.reflect.Method;
12
13public final class ClipboardManager {
14 private final IInterface manager;
15 private Method getPrimaryClipMethod;
16 private Method setPrimaryClipMethod;
…lines 17–93 unchanged (77 lines)
94 }
95 }
96 }
97 return setPrimaryClipMethod;
98 }
99
100 private static ClipData getPrimaryClip(Method method, int methodVersion, IInterface manager) throws ReflectiveOperationException {
101 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
102 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME);
103 }
104
105 switch (methodVersion) {
106 case 0:
107 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID);
108 case 1:
109 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
110 case 2:
111 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
112 case 3:
113 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID, null);
114 case 4:
115 // The last boolean parameter is "userOperate"
116 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0, true);
117 default:
118 return (ClipData) method.invoke(manager, FakeContext.PACKAGE_NAME, null, null, null, FakeContext.ROOT_UID, 0, true);
119 }
120 }
121
122 private static void setPrimaryClip(Method method, int methodVersion, IInterface manager, ClipData clipData) throws ReflectiveOperationException {
123 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
124 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME);
125 return;
126 }
127
128 switch (methodVersion) {
129 case 0:
130 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID);
131 break;
132 case 1:
133 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
134 break;
135 default:
136 method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
137 break;
138 }
139 }
140
141 public CharSequence getText() {
142 try {
143 Method method = getGetPrimaryClipMethod();
144 ClipData clipData = getPrimaryClip(method, getMethodVersion, manager);
145 if (clipData == null || clipData.getItemCount() == 0) {
146 return null;
147 }
148 return clipData.getItemAt(0).getText();
149 } catch (ReflectiveOperationException e) {
150 Ln.e("Could not invoke method", e);
151 return null;
152 }
153 }
154
155 public boolean setText(CharSequence text) {
156 try {
157 Method method = getSetPrimaryClipMethod();
158 ClipData clipData = ClipData.newPlainText(null, text);
159 setPrimaryClip(method, setMethodVersion, manager, clipData);
160 return true;
161 } catch (ReflectiveOperationException e) {
162 Ln.e("Could not invoke method", e);
163 return false;
164 }
165 }
166
167 private static void addPrimaryClipChangedListener(Method method, int methodVersion, IInterface manager, IOnPrimaryClipChangedListener listener)
168 throws ReflectiveOperationException {
169 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
170 method.invoke(manager, listener, FakeContext.PACKAGE_NAME);
171 return;
172 }
173
174 switch (methodVersion) {
175 case 0:
176 method.invoke(manager, listener, FakeContext.PACKAGE_NAME, FakeContext.ROOT_UID);
177 break;
178 case 1:
179 method.invoke(manager, listener, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
180 break;
181 default:
182 method.invoke(manager, listener, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
183 break;
184 }
185 }
186
187 private Method getAddPrimaryClipChangedListener() throws NoSuchMethodException {
188 if (addPrimaryClipChangedListener == null) {
189 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
190 addPrimaryClipChangedListener = manager.getClass()
191 .getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class);
…lines 192–213 unchanged (22 lines)
214
215 public boolean addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
216 try {
217 Method method = getAddPrimaryClipChangedListener();
218 addPrimaryClipChangedListener(method, addListenerMethodVersion, manager, listener);
219 return true;
220 } catch (ReflectiveOperationException e) {
221 Ln.e("Could not invoke method", e);
222 return false;
223 }
224 }
225}
226

Before

program
package_declaration
package "package"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "com"
. "."
identifier "genymobile"
. "."
identifier "scrcpy"
. "."
identifier "wrappers"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "com"
. "."
identifier "genymobile"
. "."
identifier "scrcpy"
. "."
identifier "FakeContext"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "com"
. "."
identifier "genymobile"
. "."
identifier "scrcpy"
. "."
identifier "Ln"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "content"
. "."
identifier "ClipData"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "content"
. "."
identifier "IOnPrimaryClipChangedListener"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "os"
. "."
identifier "Build"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "os"
. "."
identifier "IInterface"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "lang"
. "."
identifier "reflect"
. "."
identifier "InvocationTargetException"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "lang"
. "."
identifier "reflect"
. "."
identifier "Method"
; ";"
class_declaration
modifiers
public "public"
final "final"
class "class"
identifier "ClipboardManager"
class_body
{ "{"
field_declaration
modifiers
private "private"
final "final"
type_identifier "IInterface"
variable_declarator
identifier "manager"
; ";"
field_declaration
modifiers
private "private"
type_identifier "Method"
variable_declarator
identifier "getPrimaryClipMethod"
; ";"
field_declaration
modifiers
private "private"
type_identifier "Method"
variable_declarator
identifier "setPrimaryClipMethod"
; ";"
field_declaration
modifiers
private "private"
type_identifier "Method"
variable_declarator
identifier "addPrimaryClipChangedListener"
; ";"
field_declaration
modifiers
private "private"
integral_type
int "int"
variable_declarator
identifier "getMethodVersion"
; ";"
field_declaration
modifiers
private "private"
integral_type
int "int"
variable_declarator
identifier "setMethodVersion"
; ";"
field_declaration
modifiers
private "private"
integral_type
int "int"
variable_declarator
identifier "addListenerMethodVersion"
; ";"
method_declaration (+62 nodes collapsed)
constructor_declaration (+22 nodes collapsed)
method_declaration (+462 nodes collapsed)
method_declaration (+270 nodes collapsed)
method_declaration
modifiers
private "private"
static "static"
type_identifier "ClipData"
identifier "getPrimaryClip"
formal_parameters
( "("
formal_parameter
type_identifier "Method"
identifier "method"
, ","
formal_parameter
integral_type
int "int"
identifier "methodVersion"
, ","
formal_parameter
type_identifier "IInterface"
identifier "manager"
) ")"
throws
throws "throws"
type_identifier "InvocationTargetException"
, ","
type_identifier "IllegalAccessException"
block (+260 nodes collapsed)
method_declaration
modifiers
private "private"
static "static"
void_type "void"
identifier "setPrimaryClip"
formal_parameters
( "("
formal_parameter
type_identifier "Method"
identifier "method"
, ","
formal_parameter
integral_type
int "int"
identifier "methodVersion"
, ","
formal_parameter
type_identifier "IInterface"
identifier "manager"
, ","
formal_parameter
type_identifier "ClipData"
identifier "clipData"
) ")"
throws
throws "throws"
type_identifier "InvocationTargetException"
, ","
type_identifier "IllegalAccessException"
block (+151 nodes collapsed)
method_declaration
modifiers
public "public"
type_identifier "CharSequence"
identifier "getText"
formal_parameters
( "("
) ")"
block
{ "{"
try_statement
try "try"
block (+75 nodes collapsed)
catch_clause
catch "catch"
( "("
catch_formal_parameter
catch_type
type_identifier "InvocationTargetException"
| "|"
type_identifier "IllegalAccessException"
| "|"
type_identifier "NoSuchMethodException"
identifier "e"
) ")"
block (+22 nodes collapsed)
} "}"
method_declaration
modifiers
public "public"
boolean_type "boolean"
identifier "setText"
formal_parameters
( "("
formal_parameter
type_identifier "CharSequence"
identifier "text"
) ")"
block
{ "{"
try_statement
try "try"
block (+48 nodes collapsed)
catch_clause
catch "catch"
( "("
catch_formal_parameter
catch_type
type_identifier "InvocationTargetException"
| "|"
type_identifier "IllegalAccessException"
| "|"
type_identifier "NoSuchMethodException"
identifier "e"
) ")"
block (+22 nodes collapsed)
} "}"
method_declaration
modifiers
private "private"
static "static"
void_type "void"
identifier "addPrimaryClipChangedListener"
formal_parameters
( "("
formal_parameter
type_identifier "Method"
identifier "method"
, ","
formal_parameter
integral_type
int "int"
identifier "methodVersion"
, ","
formal_parameter
type_identifier "IInterface"
identifier "manager"
, ","
formal_parameter
type_identifier "IOnPrimaryClipChangedListener"
identifier "listener"
) ")"
throws
throws "throws"
type_identifier "InvocationTargetException"
, ","
type_identifier "IllegalAccessException"
block (+151 nodes collapsed)
method_declaration (+270 nodes collapsed)
method_declaration
modifiers
public "public"
boolean_type "boolean"
identifier "addPrimaryClipChangedListener"
formal_parameters
( "("
formal_parameter
type_identifier "IOnPrimaryClipChangedListener"
identifier "listener"
) ")"
block
{ "{"
try_statement
try "try"
block (+32 nodes collapsed)
catch_clause
catch "catch"
( "("
catch_formal_parameter
catch_type
type_identifier "InvocationTargetException"
| "|"
type_identifier "IllegalAccessException"
| "|"
type_identifier "NoSuchMethodException"
identifier "e"
) ")"
block (+22 nodes collapsed)
} "}"
} "}"

After

program
package_declaration
package "package"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "com"
. "."
identifier "genymobile"
. "."
identifier "scrcpy"
. "."
identifier "wrappers"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "com"
. "."
identifier "genymobile"
. "."
identifier "scrcpy"
. "."
identifier "FakeContext"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "com"
. "."
identifier "genymobile"
. "."
identifier "scrcpy"
. "."
identifier "Ln"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "content"
. "."
identifier "ClipData"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "content"
. "."
identifier "IOnPrimaryClipChangedListener"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "os"
. "."
identifier "Build"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
identifier "android"
. "."
identifier "os"
. "."
identifier "IInterface"
; ";"
import_declaration
import "import"
scoped_identifier
scoped_identifier
scoped_identifier
identifier "java"
. "."
identifier "lang"
. "."
identifier "reflect"
. "."
identifier "Method"
; ";"
class_declaration
modifiers
public "public"
final "final"
class "class"
identifier "ClipboardManager"
class_body
{ "{"
field_declaration
modifiers
private "private"
final "final"
type_identifier "IInterface"
variable_declarator
identifier "manager"
; ";"
field_declaration
modifiers
private "private"
type_identifier "Method"
variable_declarator
identifier "getPrimaryClipMethod"
; ";"
field_declaration
modifiers
private "private"
type_identifier "Method"
variable_declarator
identifier "setPrimaryClipMethod"
; ";"
field_declaration
modifiers
private "private"
type_identifier "Method"
variable_declarator
identifier "addPrimaryClipChangedListener"
; ";"
field_declaration
modifiers
private "private"
integral_type
int "int"
variable_declarator
identifier "getMethodVersion"
; ";"
field_declaration
modifiers
private "private"
integral_type
int "int"
variable_declarator
identifier "setMethodVersion"
; ";"
field_declaration
modifiers
private "private"
integral_type
int "int"
variable_declarator
identifier "addListenerMethodVersion"
; ";"
method_declaration (+62 nodes collapsed)
constructor_declaration (+22 nodes collapsed)
method_declaration (+462 nodes collapsed)
method_declaration (+270 nodes collapsed)
method_declaration
modifiers
private "private"
static "static"
type_identifier "ClipData"
identifier "getPrimaryClip"
formal_parameters
( "("
formal_parameter
type_identifier "Method"
identifier "method"
, ","
formal_parameter
integral_type
int "int"
identifier "methodVersion"
, ","
formal_parameter
type_identifier "IInterface"
identifier "manager"
) ")"
throws
throws "throws"
type_identifier "ReflectiveOperationException"
block (+260 nodes collapsed)
method_declaration
modifiers
private "private"
static "static"
void_type "void"
identifier "setPrimaryClip"
formal_parameters
( "("
formal_parameter
type_identifier "Method"
identifier "method"
, ","
formal_parameter
integral_type
int "int"
identifier "methodVersion"
, ","
formal_parameter
type_identifier "IInterface"
identifier "manager"
, ","
formal_parameter
type_identifier "ClipData"
identifier "clipData"
) ")"
throws
throws "throws"
type_identifier "ReflectiveOperationException"
block (+151 nodes collapsed)
method_declaration
modifiers
public "public"
type_identifier "CharSequence"
identifier "getText"
formal_parameters
( "("
) ")"
block
{ "{"
try_statement
try "try"
block (+75 nodes collapsed)
catch_clause
catch "catch"
( "("
catch_formal_parameter
catch_type
type_identifier "ReflectiveOperationException"
identifier "e"
) ")"
block (+22 nodes collapsed)
} "}"
method_declaration
modifiers
public "public"
boolean_type "boolean"
identifier "setText"
formal_parameters
( "("
formal_parameter
type_identifier "CharSequence"
identifier "text"
) ")"
block
{ "{"
try_statement
try "try"
block (+48 nodes collapsed)
catch_clause
catch "catch"
( "("
catch_formal_parameter
catch_type
type_identifier "ReflectiveOperationException"
identifier "e"
) ")"
block (+22 nodes collapsed)
} "}"
method_declaration
modifiers
private "private"
static "static"
void_type "void"
identifier "addPrimaryClipChangedListener"
formal_parameters
( "("
formal_parameter
type_identifier "Method"
identifier "method"
, ","
formal_parameter
integral_type
int "int"
identifier "methodVersion"
, ","
formal_parameter
type_identifier "IInterface"
identifier "manager"
, ","
formal_parameter
type_identifier "IOnPrimaryClipChangedListener"
identifier "listener"
) ")"
throws
throws "throws"
type_identifier "ReflectiveOperationException"
block (+151 nodes collapsed)
method_declaration (+270 nodes collapsed)
method_declaration
modifiers
public "public"
boolean_type "boolean"
identifier "addPrimaryClipChangedListener"
formal_parameters
( "("
formal_parameter
type_identifier "IOnPrimaryClipChangedListener"
identifier "listener"
) ")"
block
{ "{"
try_statement
try "try"
block (+32 nodes collapsed)
catch_clause
catch "catch"
( "("
catch_formal_parameter
catch_type
type_identifier "ReflectiveOperationException"
identifier "e"
) ")"
block (+22 nodes collapsed)
} "}"
} "}"