summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAoJ Architecture Team <aoj-architecture-team@google.com>2023-10-13 04:04:10 -0700
committerCopybara-Service <copybara-worker@google.com>2023-10-13 07:13:48 -0700
commit2d7142cc382b15b24ddc1797e40a3f05b18ed09d (patch)
tree0016f20e557ebc8211043f2343ce44d356af07cb
parentd88f19ae25c9e587bb976af4f821f95492c5a78e (diff)
downloadandroid_onboarding-2d7142cc382b15b24ddc1797e40a3f05b18ed09d.tar.gz
external/android_onboarding: Android Onboarding ❤️ AOSP
PiperOrigin-RevId: 573173319 Change-Id: I2581fc3cca0df7794a1eaed0b367dbec10e8bebd
-rw-r--r--src/com/android/onboarding/contracts/ActivityUtil.kt2
-rw-r--r--src/com/android/onboarding/contracts/IdentifyExecutingContract.kt29
-rw-r--r--src/com/android/onboarding/contracts/OnboardingActivityApiContract.kt12
-rw-r--r--src/com/android/onboarding/nodes/OnboardingGraph.kt5
-rw-r--r--src/com/android/onboarding/nodes/OnboardingGraphLog.kt13
-rw-r--r--src/com/android/onboarding/nodes/onboarding_nodes.proto5
-rw-r--r--src/com/android/onboarding/nodes/testing/testapp/AndroidManifest.xml19
-rw-r--r--src/com/android/onboarding/nodes/testing/testapp/MainActivity.kt198
-rw-r--r--src/com/android/onboarding/nodes/testing/testapp/res/layout/activity_main.xml100
9 files changed, 243 insertions, 140 deletions
diff --git a/src/com/android/onboarding/contracts/ActivityUtil.kt b/src/com/android/onboarding/contracts/ActivityUtil.kt
index 3b87c2f..426be93 100644
--- a/src/com/android/onboarding/contracts/ActivityUtil.kt
+++ b/src/com/android/onboarding/contracts/ActivityUtil.kt
@@ -27,5 +27,5 @@ val Activity.nodeId: Long
/** Mark the executing node as failed with [reason]. */
fun Activity.failNode(reason: String? = null) {
- AndroidOnboardingGraphLog.log(ActivityNodeFail(nodeId, this.javaClass, reason))
+ AndroidOnboardingGraphLog.log(ActivityNodeFail(nodeId, reason))
}
diff --git a/src/com/android/onboarding/contracts/IdentifyExecutingContract.kt b/src/com/android/onboarding/contracts/IdentifyExecutingContract.kt
new file mode 100644
index 0000000..9a83f69
--- /dev/null
+++ b/src/com/android/onboarding/contracts/IdentifyExecutingContract.kt
@@ -0,0 +1,29 @@
+package com.android.onboarding.contracts
+
+import android.content.Intent
+
+/**
+ * Interface implemented by a [OnboardingActivityApiContract] to allow it to be used with
+ * [findExecutingContract].
+ *
+ * This allows a single activity to implement multiple contracts, as long as those contracts
+ * can be distinguished based on properties of the [Intent].
+ *
+ * Recommended usage:
+ * ```
+ * val contracts = arrayOf(RedContract(), BlueContract(), GreenContract())
+ * val contract = intent?.findExecutingContract(*contracts) ?: RedContract()
+ * ```
+ */
+interface IdentifyExecutingContract {
+ /** Returns true if this [OnboardingActivityApiContract] is currently executing. */
+ fun isExecuting(intent: Intent): Boolean
+}
+
+/**
+ * Find which of multiple non-overlapping contracts are executing.
+ *
+ * See [IdentifyExecutingContract] for usage.
+ */
+fun <I : IdentifyExecutingContract> Intent.findExecutingContract(vararg contracts: I) =
+ contracts.firstOrNull { it.isExecuting(this) }
diff --git a/src/com/android/onboarding/contracts/OnboardingActivityApiContract.kt b/src/com/android/onboarding/contracts/OnboardingActivityApiContract.kt
index 147f613..f513fd1 100644
--- a/src/com/android/onboarding/contracts/OnboardingActivityApiContract.kt
+++ b/src/com/android/onboarding/contracts/OnboardingActivityApiContract.kt
@@ -20,6 +20,7 @@ import com.android.onboarding.nodes.OnboardingGraphLog.OnboardingEvent.ActivityN
import com.android.onboarding.nodes.OnboardingGraphLog.OnboardingEvent.ActivityNodeSetResult
import com.android.onboarding.nodes.OnboardingGraphLog.OnboardingEvent.ActivityNodeStartExecuteSynchronously
import com.android.onboarding.nodes.OnboardingGraphLog.OnboardingEvent.ActivityNodeValidating
+import com.google.errorprone.annotations.CanIgnoreReturnValue
import java.util.UUID
/**
@@ -109,9 +110,7 @@ abstract class OnboardingActivityApiContract<I, O> : ActivityResultContract<I, O
var contractResult = performSetResult(result)
if (contractResult is Failure) {
- AndroidOnboardingGraphLog.log(
- ActivityNodeFail(activity.nodeId, this.javaClass, contractResult.reason)
- )
+ AndroidOnboardingGraphLog.log(ActivityNodeFail(activity.nodeId, contractResult.reason))
}
val intent = contractResult.intent ?: Intent()
@@ -125,18 +124,21 @@ abstract class OnboardingActivityApiContract<I, O> : ActivityResultContract<I, O
*
* <p>When parsing fails, the failure will be recorded so that it can be fixed.
*/
- fun validate(activity: Activity, intent: Intent = activity.intent) {
+ @CanIgnoreReturnValue
+ fun validate(activity: Activity, intent: Intent = activity.intent): Boolean {
try {
AndroidOnboardingGraphLog.log(
ActivityNodeValidating(activity.nodeId, this.javaClass, intentToIntentData(intent))
)
val unused = extractArgument(intent)
+ return true
} catch (e: Exception) {
AndroidOnboardingGraphLog.log(
ActivityNodeFailedValidation(activity.nodeId, this.javaClass, e, intentToIntentData(intent))
)
}
+ return false
}
private fun extractNodeId(context: Context) =
@@ -185,7 +187,7 @@ abstract class OnboardingActivityApiContract<I, O> : ActivityResultContract<I, O
AndroidOnboardingGraphLog.log(ActivityNodeResultReceived(id, this.javaClass, result))
if (result is Failure) {
- AndroidOnboardingGraphLog.log(ActivityNodeFail(id, this.javaClass, result.reason))
+ AndroidOnboardingGraphLog.log(ActivityNodeFail(id, result.reason))
}
return result
diff --git a/src/com/android/onboarding/nodes/OnboardingGraph.kt b/src/com/android/onboarding/nodes/OnboardingGraph.kt
index 1d878d1..094045e 100644
--- a/src/com/android/onboarding/nodes/OnboardingGraph.kt
+++ b/src/com/android/onboarding/nodes/OnboardingGraph.kt
@@ -138,15 +138,12 @@ class OnboardingGraph(events: Set<OnboardingGraphLog.OnboardingEvent>) {
if (e is ActivityNodeResultReceived) {
nodeMap.updateNode(e, e.nodeId, e.timestamp, e.nodeName, result = e.result)
val node = nodeMap[e.nodeId]!!
- node._incomingEdge?.let {
- nodeMap.updateNode(id = it.id, timestamp = e.timestamp)
- }
+ node._incomingEdge?.let { nodeMap.updateNode(id = it.id, timestamp = e.timestamp) }
} else if (e is ActivityNodeFail) {
nodeMap.updateNode(
e,
e.nodeId,
e.timestamp,
- e.nodeName,
failureReason = IllegalStateException(e.reason)
)
val node = nodeMap[e.nodeId]!!
diff --git a/src/com/android/onboarding/nodes/OnboardingGraphLog.kt b/src/com/android/onboarding/nodes/OnboardingGraphLog.kt
index a39936a..b100923 100644
--- a/src/com/android/onboarding/nodes/OnboardingGraphLog.kt
+++ b/src/com/android/onboarding/nodes/OnboardingGraphLog.kt
@@ -371,27 +371,17 @@ interface OnboardingGraphLog {
* At [timestamp], an [android.app.Activity] with id [nodeId] has failed the [nodeName] contract
* because of [reason].
*/
- data class ActivityNodeFail
- private constructor(
+ data class ActivityNodeFail(
val nodeId: Long,
- val nodeName: String,
val reason: String?,
val timestamp: Instant = Instant.now()
) : OnboardingEvent() {
- constructor(
- nodeId: Long,
- nodeClass: Class<*>,
- reason: String?,
- timestamp: Instant = Instant.now()
- ) : this(nodeId, extractNodeNameFromClass(nodeClass), reason, timestamp)
-
override fun serialize(): OnboardingProtos.LogProto {
return OnboardingProtos.LogProto.newBuilder()
.setActivityNodeFail(
OnboardingProtos.ActivityNodeFailProto.newBuilder()
.setNodeId(nodeId)
- .setNodeName(nodeName)
.setReason(reason ?: "")
.setTimestamp(timestamp.toEpochMilli())
.build()
@@ -403,7 +393,6 @@ interface OnboardingGraphLog {
fun fromProto(proto: OnboardingProtos.ActivityNodeFailProto) =
ActivityNodeFail(
nodeId = proto.nodeId,
- nodeName = proto.nodeName,
reason = proto.reason,
timestamp = Instant.ofEpochMilli(proto.timestamp)
)
diff --git a/src/com/android/onboarding/nodes/onboarding_nodes.proto b/src/com/android/onboarding/nodes/onboarding_nodes.proto
index ee9d25b..9e25eda 100644
--- a/src/com/android/onboarding/nodes/onboarding_nodes.proto
+++ b/src/com/android/onboarding/nodes/onboarding_nodes.proto
@@ -69,9 +69,8 @@ message ActivityNodeSetResultProto {
message ActivityNodeFailProto {
optional int64 node_id = 1;
- optional string node_name = 2;
- optional string reason = 3;
- optional int64 timestamp = 4;
+ optional string reason = 2;
+ optional int64 timestamp = 3;
}
message ActivityNodeResultReceivedProto {
diff --git a/src/com/android/onboarding/nodes/testing/testapp/AndroidManifest.xml b/src/com/android/onboarding/nodes/testing/testapp/AndroidManifest.xml
index 1f45db1..8272cb5 100644
--- a/src/com/android/onboarding/nodes/testing/testapp/AndroidManifest.xml
+++ b/src/com/android/onboarding/nodes/testing/testapp/AndroidManifest.xml
@@ -8,14 +8,16 @@
android:minSdkVersion="21"
android:targetSdkVersion="33"/>
+ <queries>
+ <intent>
+ <!-- used to detect test apps -->
+ <action android:name="com.android.onboarding.nodes.testing.testapp.red" />
+ </intent>
+ </queries>
+
<application
android:label="Onboarding Graph TestApp" android:theme="@style/Theme.AppCompat.Light" android:taskAffinity="">
- <activity android:name=".MainActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
+ <activity android:name=".MainActivity" android:exported="false">
</activity>
<activity-alias
@@ -25,6 +27,11 @@
<action android:name="com.android.onboarding.nodes.testing.testapp.red"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
</activity-alias>
<activity-alias
diff --git a/src/com/android/onboarding/nodes/testing/testapp/MainActivity.kt b/src/com/android/onboarding/nodes/testing/testapp/MainActivity.kt
index 5d25d95..3a12441 100644
--- a/src/com/android/onboarding/nodes/testing/testapp/MainActivity.kt
+++ b/src/com/android/onboarding/nodes/testing/testapp/MainActivity.kt
@@ -1,17 +1,27 @@
package com.android.onboarding.nodes.testing.testapp
-import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.Intent.CATEGORY_DEFAULT
+import android.content.Intent.FLAG_ACTIVITY_FORWARD_RESULT
+import android.content.pm.PackageManager.ResolveInfoFlags
import android.graphics.Color
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
+import android.widget.ArrayAdapter
import android.widget.Button
+import android.widget.EditText
import android.widget.LinearLayout
+import android.widget.Spinner
+import android.widget.TextView
import com.android.onboarding.common.TEST_APP
import com.android.onboarding.contracts.ContractResult
+import com.android.onboarding.contracts.IdentifyExecutingContract
import com.android.onboarding.contracts.OnboardingActivityApiContract
import com.android.onboarding.contracts.annotations.OnboardingNode
+import com.android.onboarding.contracts.failNode
+import com.android.onboarding.contracts.findExecutingContract
+import com.android.onboarding.contracts.registerForActivityLaunch
class MainActivity : AppCompatActivity() {
@@ -20,91 +30,157 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)
- val redLauncher = registerForActivityResult(RedContract()) { onResult(it) }
+ val contracts = arrayOf(RedContract(), BlueContract(), GreenContract())
+ val contract = intent?.findExecutingContract(*contracts) ?: RedContract()
- val blueLauncher = registerForActivityResult(BlueContract()) { onResult(it) }
+ if (contract.validate(this, intent)) {
+ findViewById<TextView>(R.id.status).text =
+ "Received argument: ${contract.extractArgument(intent).arg}"
+ }
+
+ val processSpinner = findViewById<Spinner>(R.id.processSpinner)
+ val packages =
+ packageManager
+ .queryIntentActivities(
+ Intent("com.android.onboarding.nodes.testing.testapp.red"),
+ ResolveInfoFlags.of(0)
+ )
+ .map { it.activityInfo.packageName }
+ .toSet()
+ .toList()
+ val packageNames =
+ packages
+ .map { packageManager.getApplicationLabel(packageManager.getApplicationInfo(it, 0)) }
+ .toList()
+ processSpinner.adapter =
+ ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, packageNames)
+ processSpinner.setSelection(packages.indexOf(packageName))
+
+ val contractSpinner = findViewById<Spinner>(R.id.contractSpinner)
+ contractSpinner.adapter =
+ ArrayAdapter(
+ this,
+ android.R.layout.simple_spinner_dropdown_item,
+ contracts.map { it.javaClass.getAnnotation(OnboardingNode::class.java)?.name ?: "Unknown" }
+ )
+ contractSpinner.setSelection(contracts.indexOf(contract))
+
+ val noResultLaunchers = contracts.map { registerForActivityLaunch(it) }
+ val resultLaunchers = contracts.map { registerForActivityResult(it, this::onResult) }
- val greenLauncher = registerForActivityResult(GreenContract()) { onResult(it) }
+ findViewById<TextView>(R.id.packageName).text =
+ packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName, 0))
- when (intent?.component?.className) {
- "com.android.onboarding.nodes.testing.testapp.RedActivity" -> {
+ findViewById<LinearLayout>(R.id.bg).setBackgroundColor(contract.colour)
+
+ when (contract) {
+ is RedContract -> {
findViewById<LinearLayout>(R.id.bg).setBackgroundColor(Color.RED)
- RedContract().validate(this, intent)
}
- "com.android.onboarding.nodes.testing.testapp.BlueActivity" -> {
+ is BlueContract -> {
findViewById<LinearLayout>(R.id.bg).setBackgroundColor(Color.BLUE)
- BlueContract().validate(this, intent)
}
- "com.android.onboarding.nodes.testing.testapp.GreenActivity" -> {
+ is GreenContract -> {
findViewById<LinearLayout>(R.id.bg).setBackgroundColor(Color.GREEN)
- GreenContract().validate(this, intent)
}
}
- findViewById<Button>(R.id.redButton).setOnClickListener { redLauncher.launch(10) }
- findViewById<Button>(R.id.blueButton).setOnClickListener { blueLauncher.launch(10) }
- findViewById<Button>(R.id.greenButton).setOnClickListener { greenLauncher.launch(10) }
- }
+ findViewById<Button>(R.id.startActivityAndFinishButton).setOnClickListener {
+ val arg = findViewById<EditText>(R.id.argument).text.toString()
+ val contractId = findViewById<Spinner>(R.id.contractSpinner).selectedItemId.toInt()
+ val contract = noResultLaunchers[contractId]
+ val targetPackageName = packages[processSpinner.selectedItemPosition]!!.toString()
- fun onResult(result: Int) {}
-}
-
-@OnboardingNode(component = TEST_APP, name = "Red", hasUi = OnboardingNode.HasUi.YES)
-class RedContract : OnboardingActivityApiContract<Int, Int>() {
- override fun performCreateIntent(context: Context, arg: Int): Intent =
- Intent("com.android.onboarding.nodes.testing.testapp.red").apply {
- setComponent(
- ComponentName(
- context.packageName,
- "com.android.onboarding.nodes.testing.testapp.RedActivity"
- )
- )
- putExtra("KEY", arg)
+ contract.launch(ContractArg(arg, targetPackageName))
+ finish()
}
- override fun performExtractArgument(intent: Intent): Int = intent.getIntExtra("KEY", -1)
+ findViewById<Button>(R.id.startActivityAndForwardButton).setOnClickListener {
+ val arg = findViewById<EditText>(R.id.argument).text.toString()
+ val contractId = findViewById<Spinner>(R.id.contractSpinner).selectedItemId.toInt()
+ val contract = noResultLaunchers[contractId]
+ val targetPackageName = packages[processSpinner.selectedItemPosition]!!.toString()
- override fun performParseResult(result: ContractResult): Int = result.resultCode
+ contract.launch(ContractArg(arg, targetPackageName, shouldForward = true))
+ finish()
+ }
- override fun performSetResult(result: Int): ContractResult = ContractResult.Success(result)
-}
+ findViewById<Button>(R.id.startActivityButton).setOnClickListener {
+ val arg = findViewById<EditText>(R.id.argument).text.toString()
+ val contractId = findViewById<Spinner>(R.id.contractSpinner).selectedItemId.toInt()
+ val contract = noResultLaunchers[contractId]
+ val targetPackageName = packages[processSpinner.selectedItemPosition]!!.toString()
-@OnboardingNode(component = TEST_APP, name = "Blue", hasUi = OnboardingNode.HasUi.YES)
-class BlueContract : OnboardingActivityApiContract<Int, Int>() {
- override fun performCreateIntent(context: Context, arg: Int): Intent =
- Intent("com.android.onboarding.nodes.testing.testapp.blue").apply {
- setComponent(
- ComponentName(
- context.packageName,
- "com.android.onboarding.nodes.testing.testapp.BlueActivity"
- )
- )
- putExtra("KEY", arg)
+ contract.launch(ContractArg(arg, targetPackageName))
}
- override fun performExtractArgument(intent: Intent): Int = intent.getIntExtra("KEY", -1)
+ findViewById<Button>(R.id.startActivityForResultButton).setOnClickListener {
+ val arg = findViewById<EditText>(R.id.argument).text.toString()
+ val contractId = findViewById<Spinner>(R.id.contractSpinner).selectedItemId.toInt()
+ val contract = resultLaunchers[contractId]
+ val targetPackageName = packages[processSpinner.selectedItemPosition]!!.toString()
- override fun performParseResult(result: ContractResult): Int = result.resultCode
+ contract.launch(ContractArg(arg, targetPackageName))
+ }
- override fun performSetResult(result: Int): ContractResult = ContractResult.Success(result)
+ findViewById<Button>(R.id.finishButton).setOnClickListener { finish() }
+ findViewById<Button>(R.id.crashButton).setOnClickListener { null!! }
+ findViewById<Button>(R.id.failNodeButton).setOnClickListener {
+ failNode(findViewById<EditText>(R.id.argument).text.toString())
+ }
+ findViewById<Button>(R.id.setResultAndFinishButton).setOnClickListener {
+ contract.setResult(this, findViewById<EditText>(R.id.argument).text.toString())
+ finish()
+ }
+ }
+
+ fun onResult(result: String) {
+ findViewById<TextView>(R.id.status).text = "Received result: $result"
+ }
}
-@OnboardingNode(component = TEST_APP, name = "Green", hasUi = OnboardingNode.HasUi.YES)
-class GreenContract : OnboardingActivityApiContract<Int, Int>() {
- override fun performCreateIntent(context: Context, arg: Int): Intent =
- Intent("com.android.onboarding.nodes.testing.testapp.green").apply {
- setComponent(
- ComponentName(
- context.packageName,
- "com.android.onboarding.nodes.testing.testapp.GreenActivity"
- )
- )
- putExtra("KEY", arg)
+data class ContractArg(
+ val arg: String,
+ val targetPackageName: String,
+ val shouldForward: Boolean = false
+)
+
+abstract class ColourContract(val colour: Int, private val name: String) :
+ OnboardingActivityApiContract<ContractArg, String>(), IdentifyExecutingContract {
+ override fun isExecuting(intent: Intent) = intent.action?.endsWith(".$name") ?: false
+
+ override fun performCreateIntent(context: Context, arg: ContractArg): Intent =
+ Intent("com.android.onboarding.nodes.testing.testapp.$name").apply {
+ setPackage(arg.targetPackageName)
+ putExtra("KEY", arg.arg)
+ addCategory(CATEGORY_DEFAULT)
+
+ if (arg.shouldForward) {
+ addFlags(FLAG_ACTIVITY_FORWARD_RESULT)
+ }
}
- override fun performExtractArgument(intent: Intent): Int = intent.getIntExtra("KEY", -1)
+ override fun performExtractArgument(intent: Intent): ContractArg =
+ ContractArg(
+ intent.getStringExtra("KEY")!!,
+ intent.`package` ?: "",
+ intent.hasFlag(FLAG_ACTIVITY_FORWARD_RESULT)
+ )
- override fun performParseResult(result: ContractResult): Int = result.resultCode
+ override fun performParseResult(result: ContractResult): String =
+ result.intent?.getStringExtra("KEY")!!
- override fun performSetResult(result: Int): ContractResult = ContractResult.Success(result)
+ override fun performSetResult(result: String): ContractResult =
+ ContractResult.Success(1, Intent().apply { putExtra("KEY", result) })
}
+
+@OnboardingNode(component = TEST_APP, name = "Red", hasUi = OnboardingNode.HasUi.YES)
+class RedContract : ColourContract(Color.RED, "red")
+
+@OnboardingNode(component = TEST_APP, name = "Blue", hasUi = OnboardingNode.HasUi.YES)
+class BlueContract : ColourContract(Color.BLUE, "blue")
+
+@OnboardingNode(component = TEST_APP, name = "Green", hasUi = OnboardingNode.HasUi.YES)
+class GreenContract : ColourContract(Color.GREEN, "green")
+
+fun Intent.hasFlag(flag: Int) = (this.flags and flag) == flag
diff --git a/src/com/android/onboarding/nodes/testing/testapp/res/layout/activity_main.xml b/src/com/android/onboarding/nodes/testing/testapp/res/layout/activity_main.xml
index 5127e92..2473c36 100644
--- a/src/com/android/onboarding/nodes/testing/testapp/res/layout/activity_main.xml
+++ b/src/com/android/onboarding/nodes/testing/testapp/res/layout/activity_main.xml
@@ -4,67 +4,71 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
-
- <LinearLayout
+ <TextView
+ android:id="@+id/packageName"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="" />
+ <TextView
+ android:id="@+id/status"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="" />
+ <EditText
+ android:id="@+id/argument"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-<!-- <LinearLayout-->
-<!-- android:layout_width="match_parent"-->
-<!-- android:layout_height="match_parent"-->
-<!-- android:orientation="vertical">-->
-<!-- <TextView-->
-<!-- android:id="@+id/app1Label"-->
-<!-- android:layout_width="match_parent"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:text="App 1" />-->
-<!-- <Button-->
-<!-- android:id="@+id/redButton2"-->
-<!-- android:layout_width="match_parent"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:text="Launch Red" />-->
-<!-- <Button-->
-<!-- android:id="@+id/blueButton2"-->
-<!-- android:layout_width="match_parent"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:text="Launch Blue" />-->
-<!-- <Button-->
-<!-- android:id="@+id/greenButton2"-->
-<!-- android:layout_width="match_parent"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:text="Launch Green" />-->
-<!-- </LinearLayout>-->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-<!-- <TextView-->
-<!-- android:id="@+id/app2Label"-->
-<!-- android:layout_width="match_parent"-->
-<!-- android:layout_height="wrap_content"-->
-<!-- android:text="App 2" />-->
+ android:layout_height="wrap_content"
+ android:ems="10"
+ android:inputType="text"
+ android:hint="Argument/Result" />
+ <Spinner
+ android:id="@+id/processSpinner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <Spinner
+ android:id="@+id/contractSpinner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
<Button
- android:id="@+id/redButton"
+ android:id="@+id/startActivityButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="Launch Red" />
+ android:text="Start Activity" />
+ <Button
+ android:id="@+id/startActivityAndForwardButton"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Start Activity and Forward" />
<Button
- android:id="@+id/blueButton"
+ android:id="@+id/startActivityForResultButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="Launch Blue" />
+ android:text="Start Activity For Result" />
<Button
- android:id="@+id/greenButton"
+ android:id="@+id/startActivityAndFinishButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="Launch Green" />
- </LinearLayout>
- </LinearLayout>
+ android:text="Start Activity And Finish" />
<Button
android:id="@+id/failNodeButton"
- android:layout_width="wrap_content"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:text="Fail Node" />
+ <Button
+ android:id="@+id/crashButton"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Crash" />
+ <Button
+ android:id="@+id/finishButton"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Finish" />
+ <Button
+ android:id="@+id/setResultAndFinishButton"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Set Result and Finish" />
</LinearLayout>