chore: initialize repository with gitignore
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
configurations.configureEach {
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
|
||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.example.task3intentnavigation'
|
||||
compileSdk 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.example.task3intentnavigation'
|
||||
minSdk 26
|
||||
targetSdk 34
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
testOptions {
|
||||
animationsDisabled true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'androidx.core:core:1.13.1'
|
||||
|
||||
androidTestImplementation 'androidx.test:core:1.5.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.5.2'
|
||||
androidTestImplementation 'androidx.test:rules:1.5.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1'
|
||||
androidTestImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.example.task3intentnavigation;
|
||||
|
||||
import static androidx.test.espresso.Espresso.onView;
|
||||
import static androidx.test.espresso.action.ViewActions.click;
|
||||
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
|
||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
|
||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.app.UiAutomation;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MainActivityIntentTest {
|
||||
|
||||
@Rule
|
||||
public IntentsTestRule<MainActivity> intentsTestRule = new IntentsTestRule<>(MainActivity.class);
|
||||
|
||||
/**
|
||||
* 完整流程应覆盖页面跳转、Intent 数据验证、详情展示与返回清空输入框。
|
||||
*/
|
||||
@Test
|
||||
public void testSubmitFlow_VerifyIntentDataAndClearInputsOnReturn() {
|
||||
String name = "周八";
|
||||
String age = "23";
|
||||
|
||||
onView(withId(R.id.et_name)).perform(replaceText(name), closeSoftKeyboard());
|
||||
onView(withId(R.id.et_age)).perform(replaceText(age), closeSoftKeyboard());
|
||||
|
||||
onView(withId(R.id.btn_submit)).perform(click());
|
||||
|
||||
intended(allOf(
|
||||
hasComponent(DetailActivity.class.getName()),
|
||||
hasExtra(MainActivity.EXTRA_NAME, name),
|
||||
hasExtra(MainActivity.EXTRA_AGE, age)
|
||||
));
|
||||
|
||||
onView(withId(R.id.tv_name)).check(matches(withText("姓名:" + name)));
|
||||
onView(withId(R.id.tv_age)).check(matches(withText("年龄:" + age)));
|
||||
|
||||
onView(withId(R.id.btn_back)).perform(click());
|
||||
|
||||
onView(withId(R.id.btn_submit)).check(matches(isDisplayed()));
|
||||
onView(withId(R.id.et_name)).check(matches(withText("")));
|
||||
onView(withId(R.id.et_age)).check(matches(withText("")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 年龄为空时应提示用户输入年龄,且不发生页面跳转。
|
||||
*/
|
||||
@Test
|
||||
public void testEmptyAge_ShowToastAndStayOnMainPage() {
|
||||
onView(withId(R.id.et_name)).perform(replaceText("周八"), closeSoftKeyboard());
|
||||
onView(withId(R.id.et_age)).perform(replaceText(""), closeSoftKeyboard());
|
||||
|
||||
clickAndAssertToast("请输入年龄");
|
||||
onView(withId(R.id.btn_submit)).check(matches(isDisplayed()));
|
||||
onView(withId(R.id.tv_name)).check(doesNotExist());
|
||||
}
|
||||
|
||||
private void clickAndAssertToast(String message) {
|
||||
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
|
||||
|
||||
try {
|
||||
AccessibilityEvent event = uiAutomation.executeAndWaitForEvent(
|
||||
() -> onView(withId(R.id.btn_submit)).perform(click()),
|
||||
candidate -> candidate.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED
|
||||
&& containsText(candidate, message),
|
||||
5000
|
||||
);
|
||||
assertNotNull(event);
|
||||
} catch (TimeoutException exception) {
|
||||
fail("Toast not shown: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsText(AccessibilityEvent event, String message) {
|
||||
for (CharSequence text : event.getText()) {
|
||||
if (message.contentEquals(text)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Task3IntentNavigation">
|
||||
<activity
|
||||
android:name=".DetailActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.example.task3intentnavigation;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class DetailActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_detail);
|
||||
|
||||
TextView tvName = findViewById(R.id.tv_name);
|
||||
TextView tvAge = findViewById(R.id.tv_age);
|
||||
Button btnBack = findViewById(R.id.btn_back);
|
||||
|
||||
String name = getIntent().getStringExtra(MainActivity.EXTRA_NAME);
|
||||
String age = getIntent().getStringExtra(MainActivity.EXTRA_AGE);
|
||||
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
if (age == null) {
|
||||
age = "";
|
||||
}
|
||||
|
||||
tvName.setText(getString(R.string.label_name_value, name));
|
||||
tvAge.setText(getString(R.string.label_age_value, age));
|
||||
|
||||
btnBack.setOnClickListener(view -> {
|
||||
setResult(RESULT_OK, new Intent());
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.example.task3intentnavigation;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
public static final String EXTRA_NAME = "extra_name";
|
||||
public static final String EXTRA_AGE = "extra_age";
|
||||
private static final int REQUEST_DETAIL = 1001;
|
||||
|
||||
private EditText etName;
|
||||
private EditText etAge;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
etName = findViewById(R.id.et_name);
|
||||
etAge = findViewById(R.id.et_age);
|
||||
Button btnSubmit = findViewById(R.id.btn_submit);
|
||||
|
||||
btnSubmit.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
submitInfo();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void submitInfo() {
|
||||
String name = etName.getText().toString().trim();
|
||||
String age = etAge.getText().toString().trim();
|
||||
|
||||
if (name.isEmpty()) {
|
||||
Toast.makeText(this, R.string.toast_input_name, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (age.isEmpty()) {
|
||||
Toast.makeText(this, R.string.toast_input_age, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// 通过 Intent 向详情页传递姓名和年龄,供测试校验页面跳转与数据内容。
|
||||
Intent intent = new Intent(this, DetailActivity.class);
|
||||
intent.putExtra(EXTRA_NAME, name);
|
||||
intent.putExtra(EXTRA_AGE, age);
|
||||
startActivityForResult(intent, REQUEST_DETAIL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == REQUEST_DETAIL && resultCode == RESULT_OK) {
|
||||
clearInputs();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearInputs() {
|
||||
etName.setText("");
|
||||
etAge.setText("");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/title_detail_page"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_age"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_back"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_back" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:text="@string/title_input_page"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="@string/hint_name"
|
||||
android:inputType="textPersonName" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_age"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:hint="@string/hint_age"
|
||||
android:inputType="number" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_submit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_submit" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Task 3 Intent Navigation</string>
|
||||
<string name="title_input_page">信息录入页</string>
|
||||
<string name="title_detail_page">详情展示页</string>
|
||||
<string name="hint_name">请输入姓名</string>
|
||||
<string name="hint_age">请输入年龄</string>
|
||||
<string name="action_submit">提交</string>
|
||||
<string name="action_back">返回</string>
|
||||
<string name="toast_input_name">请输入姓名</string>
|
||||
<string name="toast_input_age">请输入年龄</string>
|
||||
<string name="label_name_value">姓名:%1$s</string>
|
||||
<string name="label_age_value">年龄:%1$s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.Task3IntentNavigation" parent="Theme.AppCompat.Light.NoActionBar" />
|
||||
</resources>
|
||||
Reference in New Issue
Block a user