Skip to content
This repository was archived by the owner on Feb 2, 2021. It is now read-only.

Commit 99ae8cc

Browse files
authored
Merge pull request #995 from telerik/plamen5kov/use-am-instead-of-monkey
use am start instead of monkey to start application
2 parents 4de56f7 + e92d53e commit 99ae8cc

File tree

2 files changed

+162
-4
lines changed

2 files changed

+162
-4
lines changed

mobile/android/android-application-manager.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { EOL } from "os";
22
import { ApplicationManagerBase } from "../application-manager-base";
33
import { LiveSyncConstants, TARGET_FRAMEWORK_IDENTIFIERS } from "../../constants";
44
import { hook } from "../../helpers";
5+
import { cache } from "../../decorators";
56

67
export class AndroidApplicationManager extends ApplicationManagerBase {
78

@@ -44,10 +45,31 @@ export class AndroidApplicationManager extends ApplicationManagerBase {
4445
}
4546

4647
public async startApplication(appIdentifier: string): Promise<void> {
47-
await this.adb.executeShellCommand(["monkey",
48-
"-p", appIdentifier,
49-
"-c", "android.intent.category.LAUNCHER",
50-
"1"]);
48+
49+
/*
50+
Example "pm dump <app_identifier> | grep -A 1 MAIN" output"
51+
android.intent.action.MAIN:
52+
3b2df03 org.nativescript.cliapp/com.tns.NativeScriptActivity filter 50dd82e
53+
Action: "android.intent.action.MAIN"
54+
Category: "android.intent.category.LAUNCHER"
55+
--
56+
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.nativescript.cliapp/com.tns.NativeScriptActivity}
57+
realActivity=org.nativescript.cliapp/com.tns.NativeScriptActivity
58+
--
59+
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.nativescript.cliapp/com.tns.NativeScriptActivity }
60+
frontOfTask=true task=TaskRecord{fe592ac #449 A=org.nativescript.cliapp U=0 StackId=1 sz=1}
61+
*/
62+
const pmDumpOutput = await this.adb.executeShellCommand(["pm", "dump", appIdentifier, "|", "grep", "-A", "1", "MAIN"]);
63+
const activityMatch = this.getFullyQualifiedActivityRegex();
64+
const match = activityMatch.exec(pmDumpOutput);
65+
const possibleIdentifier = match && match[0];
66+
67+
if (possibleIdentifier) {
68+
await this.adb.executeShellCommand(["am", "start", "-n", possibleIdentifier]);
69+
} else {
70+
this.$logger.trace(`Tried starting activity for: ${appIdentifier}, using activity manager but failed.`);
71+
await this.adb.executeShellCommand(["monkey", "-p", appIdentifier, "-c", "android.intent.category.LAUNCHER", "1"]);
72+
}
5173

5274
if (!this.$options.justlaunch) {
5375
const deviceIdentifier = this.identifier;
@@ -102,4 +124,13 @@ export class AndroidApplicationManager extends ApplicationManagerBase {
102124

103125
return applicationViews;
104126
}
127+
128+
@cache()
129+
private getFullyQualifiedActivityRegex(): RegExp {
130+
const androidPackageName = "([A-Za-z]{1}[A-Za-z\\d_]*\\.)*[A-Za-z][A-Za-z\\d_]*";
131+
const packageActivitySeparator = "\\/";
132+
const fullJavaClassName = "([a-z][a-z_0-9]*\\.)*[A-Z_$]($[A-Z_$]|[$_\\w_])*";
133+
134+
return new RegExp(`${androidPackageName}${packageActivitySeparator}${fullJavaClassName}`, `m`);
135+
}
105136
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { AndroidApplicationManager } from "../../mobile/android/android-application-manager";
2+
import { Yok } from "../../yok";
3+
import { assert } from "chai";
4+
import { CommonLoggerStub } from "./stubs";
5+
const invalidIdentifier: string = "invalid.identifier";
6+
7+
class AndroidDebugBridgeStub {
8+
public startedWithActivityManager: Boolean = false;
9+
public validIdentifierPassed: Boolean = false;
10+
public static methodCallCount: number = 0;
11+
private expectedValidTestInput: string[] = [
12+
"org.nativescript.testApp/com.tns.TestClass",
13+
"org.nativescript.testApp/com.tns.$TestClass",
14+
"org.nativescript.testApp/com.tns._TestClass",
15+
"org.nativescript.testApp/com.tns.$_TestClass",
16+
"org.nativescript.testApp/com.tns._$TestClass",
17+
"org.nativescript.testApp/com.tns.NativeScriptActivity"
18+
];
19+
private validTestInput: string[] = [
20+
"other.stuff/ org.nativescript.testApp/com.tns.TestClass asdaas.dasdh2",
21+
"other.stuff.the.regex.might.fail.on org.nativescript.testApp/com.tns.$TestClass other.stuff.the.regex.might.fail.on",
22+
"/might.fail.on org.nativescript.testApp/com.tns._TestClass /might.fail.on",
23+
"might.fail.on/ org.nativescript.testApp/com.tns.$_TestClass might.fail.on//",
24+
"/might.fail org.nativescript.testApp/com.tns._$TestClass something/might.fail.on/",
25+
"android.intent.action.MAIN: \
26+
3b2df03 org.nativescript.testApp/com.tns.NativeScriptActivity filter 50dd82e \
27+
Action: \"android.intent.action.MAIN\" \
28+
Category: \"android.intent.category.LAUNCHER\" \
29+
-- \
30+
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.nativescript.testApp/com.tns.NativeScriptActivity} \
31+
realActivity=org.nativescript.testApp/com.tns.NativeScriptActivity \
32+
-- \
33+
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.nativescript.testApp/com.tns.NativeScriptActivity } \
34+
frontOfTask=true task=TaskRecord{fe592ac #449 A=org.nativescript.testApp U=0 StackId=1 sz=1}"
35+
];
36+
37+
public async executeShellCommand(args: string[]): Promise<any> {
38+
if (args && args.length > 0) {
39+
if (args[0] === "pm") {
40+
const passedIdentifier = args[2];
41+
if (passedIdentifier === invalidIdentifier) {
42+
return "invalid output string";
43+
} else {
44+
const testString = this.validTestInput[AndroidDebugBridgeStub.methodCallCount];
45+
return testString;
46+
}
47+
} else {
48+
this.startedWithActivityManager = this.checkIfStartedWithActivityManager(args);
49+
if (this.startedWithActivityManager) {
50+
this.validIdentifierPassed = this.checkIfValidIdentifierPassed(args);
51+
}
52+
}
53+
}
54+
AndroidDebugBridgeStub.methodCallCount++;
55+
}
56+
57+
public getInputLength(): number {
58+
return this.validTestInput.length;
59+
}
60+
61+
private checkIfStartedWithActivityManager(args: string[]): Boolean {
62+
const firstArgument = args[0].trim();
63+
switch (firstArgument) {
64+
case "am": return true;
65+
case "monkey": return false;
66+
default: return false;
67+
}
68+
}
69+
70+
private checkIfValidIdentifierPassed(args: string[]): Boolean {
71+
if (args && args.length) {
72+
const possibleIdentifier = args[args.length - 1];
73+
const validTestString = this.expectedValidTestInput[AndroidDebugBridgeStub.methodCallCount];
74+
75+
return possibleIdentifier === validTestString;
76+
}
77+
return false;
78+
}
79+
}
80+
81+
function createTestInjector(): IInjector {
82+
let testInjector = new Yok();
83+
testInjector.register("androidApplicationManager", AndroidApplicationManager);
84+
testInjector.register("adb", AndroidDebugBridgeStub);
85+
testInjector.register('childProcess', {});
86+
testInjector.register("logger", CommonLoggerStub);
87+
testInjector.register("config", {});
88+
testInjector.register("staticConfig", {});
89+
testInjector.register("androidDebugBridgeResultHandler", {});
90+
testInjector.register("options", {justlaunch: true});
91+
testInjector.register("errors", {});
92+
testInjector.register("identifier", {});
93+
testInjector.register("logcatHelper", {});
94+
testInjector.register("androidProcessService", {});
95+
testInjector.register("httpClient", {});
96+
testInjector.register("deviceLogProvider", {});
97+
testInjector.register("hooksService", {});
98+
return testInjector;
99+
}
100+
101+
describe("android-application-manager", () => {
102+
103+
let testInjector: IInjector,
104+
androidApplicationManager:AndroidApplicationManager,
105+
androidDebugBridge:AndroidDebugBridgeStub;
106+
107+
beforeEach(() => {
108+
testInjector = createTestInjector();
109+
androidApplicationManager = testInjector.resolve("androidApplicationManager");
110+
androidDebugBridge = testInjector.resolve("adb");
111+
});
112+
describe("startApplication", () => {
113+
it("fires up the right application", async () => {
114+
for (let i = 0; i < androidDebugBridge.getInputLength(); i++) {
115+
androidDebugBridge.validIdentifierPassed = false;
116+
117+
await androidApplicationManager.startApplication("valid.identifier");
118+
assert.isTrue(androidDebugBridge.validIdentifierPassed);
119+
assert.isTrue(androidDebugBridge.startedWithActivityManager);
120+
}
121+
});
122+
it("if regex fails monkey is called to start application", async () => {
123+
await androidApplicationManager.startApplication(invalidIdentifier);
124+
assert.isFalse(androidDebugBridge.startedWithActivityManager);
125+
});
126+
});
127+
});

0 commit comments

Comments
 (0)