Skip to content

Commit cf9bb93

Browse files
Dor-blKazuCocoa
andauthored
feat: implement StartActivity method for Android activities (#986)
* feat: implement StartActivity method for Android activities * feat: validate intent parameter in activity launch method * feat: simplify CurrentActivityTest by using StartActivity method directly * feat: add optional arguments parameter to StartActivity method for enhanced flexibility * feat: add StartActivityWithDictionaryTest to validate activity launch with arguments --------- Co-authored-by: Kazuaki Matsuo <fly.49.89.over@gmail.com>
1 parent 6f94f2f commit cf9bb93

File tree

4 files changed

+159
-41
lines changed

4 files changed

+159
-41
lines changed

src/Appium.Net/Appium/Android/AndroidCommandExecutionHelper.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,101 @@ public static float GetDisplayDensity(IExecuteMethod executeMethod)
172172

173173
#endregion
174174

175+
#region Activity
176+
177+
/// <summary>
178+
/// Start an Android activity by providing its package name and activity name.
179+
/// For documentation, see <see href="https://github.com/appium/appium-uiautomator2-driver#mobile-startactivity">mobile:startActivity</see>.
180+
/// </summary>
181+
/// <param name="executeMethod">The execute method</param>
182+
/// <param name="intent">The full name of the activity intent to start, e.g. "com.myapp/.MyActivity"</param>
183+
/// <param name="arguments">Optional dictionary of additional arguments. Values from this dictionary take priority over other parameters.</param>
184+
/// <param name="user">The user ID for which the activity is started. The current user is used by default.</param>
185+
/// <param name="wait">Set to true to block the method call until the Activity Manager's process returns the control to the system. false by default.</param>
186+
/// <param name="stop">Set to true to force stop the target app before starting the activity. false by default.</param>
187+
/// <param name="windowingMode">The windowing mode to launch the activity into. Check WindowConfiguration.java for possible values (constants starting with WINDOWING_MODE_).</param>
188+
/// <param name="activityType">The activity type to launch the activity as. Check WindowConfiguration.java for possible values (constants starting with ACTIVITY_TYPE_).</param>
189+
/// <param name="action">Action name. The actual value for the Activity Manager's -a argument.</param>
190+
/// <param name="uri">Unified resource identifier. The actual value for the Activity Manager's -d argument.</param>
191+
/// <param name="mimeType">Mime type. The actual value for the Activity Manager's -t argument.</param>
192+
/// <param name="identifier">Optional identifier. The actual value for the Activity Manager's -i argument.</param>
193+
/// <param name="categories">One or more category names. The actual value(s) for the Activity Manager's -c argument.</param>
194+
/// <param name="component">Component name. The actual value for the Activity Manager's -n argument.</param>
195+
/// <param name="package">Package name. The actual value for the Activity Manager's -p argument.</param>
196+
/// <param name="extras">Optional intent arguments. Must be represented as an array of arrays, where each subarray contains two or three string items: value type, key (variable name) and the value itself. Supported value types: s (string), sn (null), z (boolean), i (integer), l (long), f (float), u (uri), cn (component name), ia (Integer[]), ial (List&lt;Integer&gt;), la (Long[]), lal (List&lt;Long&gt;), fa (Float[]), fal (List&lt;Float&gt;), sa (String[]), sal (List&lt;String&gt;).</param>
197+
/// <param name="flags">Intent startup-specific flags as a hexadecimal string. Check Intent documentation for available flag values (constants starting with FLAG_ACTIVITY_). Flag values can be merged using logical 'or' operation, e.g. "0x10200000".</param>
198+
public static void StartActivity(
199+
IExecuteMethod executeMethod,
200+
string intent,
201+
Dictionary<string, object> arguments = null,
202+
string user = null,
203+
bool? wait = null,
204+
bool? stop = null,
205+
int? windowingMode = null,
206+
int? activityType = null,
207+
string action = null,
208+
string uri = null,
209+
string mimeType = null,
210+
string identifier = null,
211+
string[] categories = null,
212+
string component = null,
213+
string package = null,
214+
string[][] extras = null,
215+
string flags = null)
216+
{
217+
if (string.IsNullOrEmpty(intent))
218+
{
219+
throw new ArgumentException("Activity intent must be set to a non-empty string", nameof(intent));
220+
}
221+
var args = new Dictionary<string, object> { ["intent"] = intent };
222+
223+
if (!string.IsNullOrEmpty(user))
224+
args["user"] = user;
225+
if (wait.HasValue)
226+
args["wait"] = wait.Value;
227+
if (stop.HasValue)
228+
args["stop"] = stop.Value;
229+
if (windowingMode.HasValue)
230+
args["windowingMode"] = windowingMode.Value;
231+
if (activityType.HasValue)
232+
args["activityType"] = activityType.Value;
233+
if (!string.IsNullOrEmpty(action))
234+
args["action"] = action;
235+
if (!string.IsNullOrEmpty(uri))
236+
args["uri"] = uri;
237+
if (!string.IsNullOrEmpty(mimeType))
238+
args["mimeType"] = mimeType;
239+
if (!string.IsNullOrEmpty(identifier))
240+
args["identifier"] = identifier;
241+
if (categories != null && categories.Length > 0)
242+
args["categories"] = categories;
243+
if (!string.IsNullOrEmpty(component))
244+
args["component"] = component;
245+
if (!string.IsNullOrEmpty(package))
246+
args["package"] = package;
247+
if (extras != null && extras.Length > 0)
248+
args["extras"] = extras;
249+
if (!string.IsNullOrEmpty(flags))
250+
args["flags"] = flags;
251+
252+
// Apply arguments dictionary last to give it priority over other parameters
253+
if (arguments != null)
254+
{
255+
foreach (var kvp in arguments)
256+
{
257+
args[kvp.Key] = kvp.Value;
258+
}
259+
}
260+
261+
executeMethod.Execute(DriverCommand.ExecuteScript, new Dictionary<string, object>
262+
{
263+
["script"] = "mobile:startActivity",
264+
["args"] = new object[] { args }
265+
});
266+
}
267+
268+
#endregion
269+
175270
/// <summary>
176271
/// Install an app on the Android device using mobile: installApp script.
177272
/// For documentation, see <see href="https://github.com/appium/appium-uiautomator2-driver?tab=readme-ov-file#mobile-installapp">mobile: installApp</see>.

src/Appium.Net/Appium/Android/AndroidDriver.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,50 @@ public AndroidDriver(AppiumLocalService service, DriverOptions driverOptions, Ti
182182

183183
public string CurrentPackage => AndroidCommandExecutionHelper.GetCurrentPackage(this);
184184

185+
#region Activity
186+
187+
/// <summary>
188+
/// Start an Android activity by providing its package name and activity name.
189+
/// For documentation, see <see href="https://github.com/appium/appium-uiautomator2-driver#mobile-startactivity">mobile:startActivity</see>.
190+
/// </summary>
191+
/// <param name="intent">The full name of the activity intent to start, e.g. "com.myapp/.MyActivity"</param>
192+
/// <param name="arguments">Optional dictionary of additional arguments. Values from this dictionary take priority over other parameters.</param>
193+
/// <param name="user">The user ID for which the activity is started. The current user is used by default.</param>
194+
/// <param name="wait">Set to true to block the method call until the Activity Manager's process returns the control to the system. false by default.</param>
195+
/// <param name="stop">Set to true to force stop the target app before starting the activity. false by default.</param>
196+
/// <param name="windowingMode">The windowing mode to launch the activity into. Check WindowConfiguration.java for possible values (constants starting with WINDOWING_MODE_).</param>
197+
/// <param name="activityType">The activity type to launch the activity as. Check WindowConfiguration.java for possible values (constants starting with ACTIVITY_TYPE_).</param>
198+
/// <param name="action">Action name. The actual value for the Activity Manager's -a argument.</param>
199+
/// <param name="uri">Unified resource identifier. The actual value for the Activity Manager's -d argument.</param>
200+
/// <param name="mimeType">Mime type. The actual value for the Activity Manager's -t argument.</param>
201+
/// <param name="identifier">Optional identifier. The actual value for the Activity Manager's -i argument.</param>
202+
/// <param name="categories">One or more category names. The actual value(s) for the Activity Manager's -c argument.</param>
203+
/// <param name="component">Component name. The actual value for the Activity Manager's -n argument.</param>
204+
/// <param name="package">Package name. The actual value for the Activity Manager's -p argument.</param>
205+
/// <param name="extras">Optional intent arguments. Must be represented as an array of arrays, where each subarray contains two or three string items: value type, key (variable name) and the value itself. Supported value types: s (string), sn (null), z (boolean), i (integer), l (long), f (float), u (uri), cn (component name), ia (Integer[]), ial (List&lt;Integer&gt;), la (Long[]), lal (List&lt;Long&gt;), fa (Float[]), fal (List&lt;Float&gt;), sa (String[]), sal (List&lt;String&gt;).</param>
206+
/// <param name="flags">Intent startup-specific flags as a hexadecimal string. Check Intent documentation for available flag values (constants starting with FLAG_ACTIVITY_). Flag values can be merged using logical 'or' operation, e.g. "0x10200000".</param>
207+
public void StartActivity(
208+
string intent,
209+
Dictionary<string, object> arguments = null,
210+
string user = null,
211+
bool? wait = null,
212+
bool? stop = null,
213+
int? windowingMode = null,
214+
int? activityType = null,
215+
string action = null,
216+
string uri = null,
217+
string mimeType = null,
218+
string identifier = null,
219+
string[] categories = null,
220+
string component = null,
221+
string package = null,
222+
string[][] extras = null,
223+
string flags = null) =>
224+
AndroidCommandExecutionHelper.StartActivity(
225+
this, intent, arguments, user, wait, stop, windowingMode, activityType, action, uri, mimeType, identifier, categories, component, package, extras, flags);
226+
227+
#endregion
228+
185229
#region App Management
186230

187231
/// <summary>

test/integration/Android/ActivityTest.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,22 @@ public void TearDown()
4242
[Test]
4343
public void CurrentActivityTest()
4444
{
45-
_driver.ExecuteScript(
46-
"mobile:startActivity",
47-
new object[] {
48-
new Dictionary<string, object>() {
49-
["intent"] = "io.appium.android.apis/.ApiDemos",
50-
["wait"] = true,
51-
}
52-
}
53-
);
45+
_driver.StartActivity("io.appium.android.apis/.ApiDemos", wait: true);
46+
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(5));
47+
wait.Until(drv => {
48+
return ((AndroidDriver) drv).CurrentActivity == ".ApiDemos";
49+
});
50+
}
51+
52+
[Test]
53+
public void StartActivityWithDictionaryTest()
54+
{
55+
var arguments = new Dictionary<string, object>
56+
{
57+
["wait"] = true,
58+
["stop"] = true
59+
};
60+
_driver.StartActivity("io.appium.android.apis/.ApiDemos", arguments: arguments);
5461
var wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(5));
5562
wait.Until(drv => {
5663
return ((AndroidDriver) drv).CurrentActivity == ".ApiDemos";

test/integration/Android/ElementTest.cs

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,7 @@ public void BeforeAll()
2626
[SetUp]
2727
public void SetUp()
2828
{
29-
_driver.ExecuteScript(
30-
"mobile:startActivity",
31-
[
32-
new Dictionary<string, object>() {
33-
["intent"] = "io.appium.android.apis/.ApiDemos",
34-
}
35-
]
36-
);
29+
_driver.StartActivity("io.appium.android.apis/.ApiDemos");
3730
}
3831

3932
[Test]
@@ -74,14 +67,7 @@ public void FindByAndroidUiAutomatorBuilderTest()
7467
[Test]
7568
public void CanFindByDescriptionUsingBuilderWhenNewlineCharacterIncluded()
7669
{
77-
_driver.ExecuteScript(
78-
"mobile:startActivity",
79-
new object[] {
80-
new Dictionary<string, object>() {
81-
["intent"] = "io.appium.android.apis/.accessibility.TaskListActivity",
82-
}
83-
}
84-
);
70+
_driver.StartActivity("io.appium.android.apis/.accessibility.TaskListActivity");
8571
By byAndroidUiAutomator = new ByAndroidUIAutomator(new AndroidUiSelector().DescriptionEquals(
8672
"1. Enable QueryBack (Settings -> Accessibility -> QueryBack). \n\n" +
8773
"2. Enable Explore-by-Touch (Settings -> Accessibility -> Explore by Touch). \n\n" +
@@ -97,14 +83,7 @@ public void CanFindByDescriptionUsingBuilderWhenNewlineCharacterIncluded()
9783
[Test]
9884
public void CanFindByDescriptionUsingBuilderWhenDoubleQuoteCharacterIncluded()
9985
{
100-
_driver.ExecuteScript(
101-
"mobile:startActivity",
102-
new object[] {
103-
new Dictionary<string, object>() {
104-
["intent"] = "io.appium.android.apis/.text.Link",
105-
}
106-
}
107-
);
86+
_driver.StartActivity("io.appium.android.apis/.text.Link");
10887
By byAndroidUiAutomator = new ByAndroidUIAutomator(new AndroidUiSelector()
10988
.DescriptionContains("Use a \"tel:\" URL"));
11089

@@ -121,14 +100,7 @@ public void ReplaceValueTest()
121100
var originalValue = "original value";
122101
var replacedValue = "replaced value";
123102

124-
_driver.ExecuteScript(
125-
"mobile:startActivity",
126-
new object[] {
127-
new Dictionary<string, object>() {
128-
["intent"] = "io.appium.android.apis/.view.Controls1",
129-
}
130-
}
131-
);
103+
_driver.StartActivity("io.appium.android.apis/.view.Controls1");
132104
var editElement =
133105
_driver.FindElement(MobileBy.AndroidUIAutomator("resourceId(\"io.appium.android.apis:id/edit\")"));
134106

0 commit comments

Comments
 (0)