├── demo ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── ru │ │ │ └── spbstu │ │ │ └── icc │ │ │ └── kspt │ │ │ └── andrei │ │ │ └── mydemoapplication │ │ │ ├── ExampleInstrumentedTest.java │ │ │ └── UiAutomatorTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── ru │ │ │ │ └── spbstu │ │ │ │ └── icc │ │ │ │ └── kspt │ │ │ │ └── andrei │ │ │ │ └── mydemoapplication │ │ │ │ ├── Activity1.java │ │ │ │ ├── Activity2.java │ │ │ │ ├── Activity3.java │ │ │ │ ├── ArticleListActivity.java │ │ │ │ ├── ArticleListFragment.java │ │ │ │ ├── DetailsActivity.java │ │ │ │ ├── DetailsFragment.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MyBroadcastReceiver.java │ │ │ │ └── MyNewActivity.java │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ ├── gradient.xml │ │ │ ├── ic_assistant_black_24dp.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── ic_launcher_square.png │ │ │ └── shape.xml │ │ │ ├── layout-land │ │ │ ├── list_activity.xml │ │ │ └── test.xml │ │ │ ├── layout │ │ │ ├── activity_1.xml │ │ │ ├── activity_2.xml │ │ │ ├── activity_3.xml │ │ │ ├── activity_main.xml │ │ │ ├── content_main.xml │ │ │ ├── details_activity.xml │ │ │ ├── details_view.xml │ │ │ ├── layouts_test.xml │ │ │ ├── list_activity.xml │ │ │ └── test.xml │ │ │ ├── menu │ │ │ └── menu_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values-ru │ │ │ └── strings.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── ru │ │ └── spbstu │ │ └── icc │ │ └── kspt │ │ └── andrei │ │ └── mydemoapplication │ │ ├── ArticleListFragmentTest.java │ │ ├── ArticleRobolectricListFragmentTest.java │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── labs ├── 01 │ ├── .gitignore │ ├── .idea │ │ ├── kotlinc.xml │ │ ├── libraries │ │ │ └── KotlinJavaRuntime.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── vcs.xml │ ├── 01.iml │ ├── TASK.md │ ├── comment01.png │ ├── constraint │ │ ├── lab01_constraint_v01.png │ │ ├── lab01_constraint_v02.png │ │ ├── lab01_constraint_v03.png │ │ ├── lab01_constraint_v04.png │ │ ├── lab01_constraint_v05.png │ │ ├── lab01_constraint_v06.png │ │ ├── lab01_constraint_v07.png │ │ ├── lab01_constraint_v08.png │ │ ├── lab01_constraint_v09.png │ │ ├── lab01_constraint_v10.png │ │ ├── lab01_constraint_v11.png │ │ ├── lab01_constraint_v12.png │ │ ├── lab01_constraint_v13.png │ │ ├── lab01_constraint_v14.png │ │ ├── lab01_constraint_v15.png │ │ ├── lab01_constraint_v16.png │ │ ├── lab01_constraint_v17.png │ │ ├── lab01_constraint_v18.png │ │ ├── lab01_constraint_v19.png │ │ ├── lab01_constraint_v20.png │ │ ├── lab01_constraint_v21.png │ │ ├── lab01_constraint_v22.png │ │ ├── lab01_constraint_v23.png │ │ ├── lab01_constraint_v24.png │ │ ├── lab01_constraint_v25.png │ │ ├── lab01_constraint_v26.png │ │ ├── lab01_constraint_v27.png │ │ ├── lab01_constraint_v28.png │ │ ├── lab01_constraint_v29.png │ │ ├── lab01_constraint_v30.png │ │ └── meta.txt │ ├── generator │ │ └── Lab01Task02.kt │ ├── linear │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.png │ │ ├── 06.png │ │ ├── 07.png │ │ ├── 08.png │ │ ├── 09.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 20.png │ │ ├── 21.png │ │ └── 22.png │ └── variants.txt ├── 02 │ ├── TASK.md │ ├── VARIANTS02.md │ ├── VARIANTS03.txt │ ├── continuewatch │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── ru │ │ │ │ │ └── spbstu │ │ │ │ │ └── icc │ │ │ │ │ └── kspt │ │ │ │ │ └── lab2 │ │ │ │ │ └── continuewatch │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res │ │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ ├── drawable │ │ │ │ └── ic_launcher_background.xml │ │ │ │ ├── layout-land │ │ │ │ └── activity_main.xml │ │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle │ └── stat │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ └── sum.png ├── 03 │ ├── ANSWER02.md │ ├── TASK.md │ ├── activities.dia │ ├── activities.svg │ └── stat │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ └── sum.png ├── 04 │ ├── TASK.md │ └── res │ │ └── reference │ │ ├── .gitignore │ │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── myapplication │ │ │ │ ├── AboutUtils.kt │ │ │ │ └── NavigationTest.kt │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── myapplication │ │ │ │ ├── AboutActivity.kt │ │ │ │ ├── BaseFragment.kt │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ ├── ic_home_black_24dp.xml │ │ │ ├── ic_launcher_background.xml │ │ │ └── ic_notifications_black_24dp.xml │ │ │ ├── layout │ │ │ ├── activity_about.xml │ │ │ ├── activity_main.xml │ │ │ ├── fragment1.xml │ │ │ ├── fragment2.xml │ │ │ └── fragment3.xml │ │ │ ├── menu │ │ │ └── bottom_nav_menu.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── navigation │ │ │ └── mobile_navigation.xml │ │ │ ├── values-night │ │ │ └── themes.xml │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle ├── 06 │ └── TASK.md ├── 07 │ └── TASK.md └── RecyclerView │ ├── TASK.md │ ├── biblib │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── src │ │ ├── main │ │ └── java │ │ │ └── name │ │ │ └── ank │ │ │ └── lab4 │ │ │ ├── BibConfig.java │ │ │ ├── BibDatabase.java │ │ │ ├── BibEntry.java │ │ │ ├── Keys.java │ │ │ └── Types.java │ │ └── test │ │ ├── java │ │ └── name │ │ │ └── ank │ │ │ └── lab4 │ │ │ └── BibDatabaseTest.java │ │ └── resources │ │ ├── mixed.bib │ │ └── references.bib │ └── samples │ ├── articles.bib │ └── mixed.bib ├── lectures ├── .gitignore ├── Lecture01_Introduction.md ├── Lecture02_Resources.md ├── Lecture03_AltRes_Activity.md ├── Lecture04_interacting.md ├── Lecture05_navigation.md ├── Lecture06-08_fragments.md ├── Lecture09_Testing.md ├── Lecture10_Implicit_Intents.md ├── Lecture11_threads_coroutines.md ├── Lecture13_services.md ├── Lecture14_schedulers_receivers.md ├── Lecture15_providers.md ├── LectureX_room.md ├── LectureY_ART.md ├── README.md ├── TASK.md └── res │ ├── 01-android-com.png │ ├── 01-arch.png │ ├── 01-build-new.png │ ├── 01-build-pkg.png │ ├── 01-build.png │ ├── 01-perm-sample.png │ ├── 01-project.png │ ├── 01-qr-lectures.png │ ├── 01-uses-feature-sample.png │ ├── 02-adapter-layouts.png │ ├── 02-buttons.png │ ├── 02-checkbox.png │ ├── 02-common-layouts.png │ ├── 02-cross.png │ ├── 02-edittext.png │ ├── 02-imeoptions.png │ ├── 02-layerlist.png │ ├── 02-levellist.png │ ├── 02-pat-a-cat.png │ ├── 02-radiobutton.png │ ├── 02-res-types.png │ ├── 02-spinner.png │ ├── 02-statelist.png │ ├── 03-activity-backstack.png │ ├── 03-activity-fw.png │ ├── 03-dpi-bitmap-sizes.png │ ├── 03-generalized-sizes.png │ ├── 03-layout-dp.png │ ├── 03-layout-px.png │ ├── 03-win-ar.jpg │ ├── Motorola-milestone-wikipedia.png │ ├── Nexus_5_(1).jpg │ ├── activity-lifecycle.png │ ├── activity-states.png │ ├── activity_fragment_lifecycle.png │ ├── am_instrument.png │ ├── android-profiler-no-safepoint.png │ ├── android-startup.png │ ├── android_test_orchestrator_flow.png │ ├── anr.png │ ├── ape_fwk_all.png │ ├── app-architecture-gdd.png │ ├── art-overview.png │ ├── bottom-navigation.png │ ├── c1-vs-tired.png │ ├── camera2.png │ ├── cms-major-gc.png │ ├── content-provider-overview.png │ ├── control-schematics.svg │ ├── dalvik-gc-for-alloc.png │ ├── dalvik-oom-on-halffull-heap.png │ ├── dalvik-oom.png │ ├── definework-flex-period.png │ ├── densities-phone_2x.png │ ├── diagram_backstack.png │ ├── diagram_backstack_singletask_multiactivity.png │ ├── diagram_multiple_instances.png │ ├── diagram_multitasking.png │ ├── doc_intent-filter-element.png │ ├── espresso-cheatsheet.png │ ├── espresso_sync.png │ ├── fragment_lifecycle.png │ ├── fragment_lifecycle_1.png │ ├── fragment_lifecycle_2.png │ ├── fragments.png │ ├── g1-heap-structure.png │ ├── g1-mixed-gc.png │ ├── gen-full-gc.png │ ├── gen-heap.png │ ├── gen-minor-gc.png │ ├── happens-before.png │ ├── install-time-perms.png │ ├── intents-common.png │ ├── keeps-stopping.png │ ├── kotlin-elizarov.png │ ├── lab_qr.png │ ├── layout-adaptive-breakpoints_2x.png │ ├── layoutparams.png │ ├── lifecycle-states.svg │ ├── lifecycleowner-implementations.png │ ├── navigation-graph_2x-callouts.png │ ├── navigation-idioms.png │ ├── notification.png │ ├── nursery-schematic-unlabeled.svg │ ├── observer-diagram.png │ ├── observer-pattern.gif │ ├── observer-sequence.png │ ├── oreo-gc-regions.png │ ├── overview-criteria.png │ ├── postfix-arithmetics.jpg │ ├── profiling-jug-async.png │ ├── profiling-jug-jvisualvm.png │ ├── profiling-jug-prog.png │ ├── profiling-jug-safepoints.png │ ├── pyramid.png │ ├── recents.png │ ├── res-selection-flowchart.png │ ├── room_architecture.png │ ├── run-time-perms.png │ ├── save-restore-instance-state.png │ ├── sequential-and-go-to-schematic.svg │ ├── service-lc-bound.png │ ├── service-lc-started.png │ ├── service_binding_tree_lifecycle.png │ ├── service_lifecycle.png │ ├── share_via.png │ ├── start-activity-for-result.svg │ ├── storage_dataflow.png │ ├── storage_datamodel.png │ ├── storage_picker.svg │ ├── studio-profiler.png │ ├── synchronizes-with.png │ ├── t-mobile-g1.jpg │ ├── task-category-tree.png │ ├── test_manifest.png │ ├── testing-workflow.png │ ├── top-app-bar.png │ ├── user-data-overview-permissions-flow01.jpg │ ├── viewgroup_2x.png │ ├── viewmodel-lifecycle.png │ ├── weak-gen-hypothesis.png │ └── x2eq25.png ├── multithreading-demo.bundle └── navigation-demo-2019.bundle /demo/.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | *.aab 5 | 6 | # Files for the ART/Dalvik VM 7 | *.dex 8 | 9 | # Java class files 10 | *.class 11 | 12 | # Generated files 13 | bin/ 14 | gen/ 15 | out/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # IntelliJ 37 | *.iml 38 | .idea 39 | 40 | # Keystore files 41 | # Uncomment the following lines if you do not want to check your keystore files in. 42 | #*.jks 43 | #*.keystore 44 | .DS_Store 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | 57 | # fastlane 58 | fastlane/report.xml 59 | fastlane/Preview.html 60 | fastlane/screenshots 61 | fastlane/test_output 62 | fastlane/readme.md -------------------------------------------------------------------------------- /demo/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /demo/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "ru.spbstu.icc.kspt.andrei.mydemoapplication" 7 | minSdkVersion 18 8 | targetSdkVersion 27 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | compileOptions { 20 | targetCompatibility 1.8 21 | sourceCompatibility 1.8 22 | } 23 | testOptions { 24 | unitTests { 25 | unitTests.includeAndroidResources = true 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation 'com.android.support:appcompat-v7:27.1.1' 33 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 34 | implementation 'com.android.support:design:27.1.1' 35 | testImplementation 'junit:junit:4.12' 36 | 37 | testImplementation 'org.mockito:mockito-core:1.10.19' 38 | testImplementation 'androidx.test:core:1.0.0' 39 | testImplementation 'org.robolectric:robolectric:4.0.2' 40 | 41 | androidTestImplementation 'androidx.test:rules:1.1.0' 42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' 43 | androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' 44 | } 45 | -------------------------------------------------------------------------------- /demo/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /demo/app/src/androidTest/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.os.RemoteException; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import androidx.test.espresso.Espresso; 11 | import androidx.test.espresso.action.ViewActions; 12 | import androidx.test.espresso.assertion.ViewAssertions; 13 | import androidx.test.espresso.matcher.ViewMatchers; 14 | import androidx.test.platform.app.InstrumentationRegistry; 15 | import androidx.test.rule.ActivityTestRule; 16 | import androidx.test.runner.AndroidJUnit4; 17 | import androidx.test.uiautomator.UiDevice; 18 | 19 | import static org.hamcrest.Matchers.is; 20 | 21 | /** 22 | * Instrumented test, which will execute on an Android device. 23 | * 24 | * @see Testing documentation 25 | */ 26 | @RunWith(AndroidJUnit4.class) 27 | public class ExampleInstrumentedTest { 28 | 29 | @Rule 30 | public ActivityTestRule mActivityRule 31 | = new ActivityTestRule<>(ArticleListActivity.class); 32 | 33 | @Test 34 | public void itemSelectedPort() throws RemoteException { 35 | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).setOrientationNatural(); 36 | Espresso.onData(is("Item1")) 37 | .perform(ViewActions.click()); 38 | 39 | Espresso.onView(ViewMatchers.withId(R.id.details_text)) 40 | .check(ViewAssertions.matches(ViewMatchers.withText("Item1"))); 41 | } 42 | 43 | @Test 44 | public void itemSelectedLand() throws RemoteException { 45 | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).setOrientationLeft(); 46 | Espresso.onData(is("Item1")) 47 | .perform(ViewActions.click()); 48 | 49 | Espresso.onView(ViewMatchers.withId(R.id.details_text)) 50 | .check(ViewAssertions.matches(ViewMatchers.withText("Item1"))); 51 | } 52 | 53 | @Test 54 | public void rotationTest() throws RemoteException { 55 | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).setOrientationNatural(); 56 | 57 | Espresso.onData(is("Item1")) 58 | .perform(ViewActions.click()); 59 | 60 | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).setOrientationLeft(); 61 | 62 | Espresso.onView(ViewMatchers.withId(R.id.details_text)) 63 | .check(ViewAssertions.matches(ViewMatchers.isDisplayed())); 64 | 65 | Espresso.onView(ViewMatchers.withId(android.R.id.list)) 66 | .check(ViewAssertions.matches(ViewMatchers.isDisplayed())); 67 | 68 | Espresso.pressBackUnconditionally(); 69 | 70 | Assert.assertTrue(mActivityRule.getActivity().isFinishing()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /demo/app/src/androidTest/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/UiAutomatorTest.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.graphics.Point; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | 9 | import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner; 10 | import androidx.test.platform.app.InstrumentationRegistry; 11 | import androidx.test.uiautomator.UiDevice; 12 | import androidx.test.uiautomator.UiObject; 13 | import androidx.test.uiautomator.UiSelector; 14 | 15 | @RunWith(AndroidJUnit4ClassRunner.class) 16 | public class UiAutomatorTest { 17 | @Test 18 | public void testIcons() throws Exception { 19 | UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 20 | device.pressHome(); 21 | 22 | device.waitForIdle(); 23 | Point sz = device.getDisplaySizeDp(); 24 | device.swipe(sz.x / 2, sz.y / 2 + sz.y / 4, sz.x / 2, sz.y / 2 - sz.y / 4, 5); 25 | 26 | device.waitForIdle(); 27 | UiObject obj = device.findObject(new UiSelector().description("ListActivity")); 28 | // UiObject obj = device.findObject(new UiSelector().description("Calculator")); 29 | // UiScrollable launcherItem = new UiScrollable(new UiSelector().className("android.support.v7.widget.RecyclerView")); 30 | // launcherItem.scrollForward(); 31 | // launcherItem.scrollDescriptionIntoView("YouTube"); 32 | // UiObject obj = device.findObject(new UiSelector().description("YouTube")); 33 | obj.clickAndWaitForNewWindow(); 34 | 35 | Assert.assertTrue( 36 | device.findObject(new UiSelector().packageName("ru.spbstu.icc.kspt.andrei.mydemoapplication")).exists() 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /demo/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/Activity1.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.view.View; 8 | 9 | public class Activity1 extends Activity { 10 | @Override 11 | protected void onCreate(@Nullable Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_1); 14 | findViewById(R.id.create_2).setOnClickListener(this::onCreate2Clicked); 15 | findViewById(R.id.create_3).setOnClickListener(this::onCreate3Clicked); 16 | } 17 | 18 | private void onCreate2Clicked(View view) { 19 | Intent i = new Intent(this, Activity2.class); 20 | startActivity(i); 21 | } 22 | 23 | private void onCreate3Clicked(View view) { 24 | Intent i = new Intent(this, Activity3.class); 25 | startActivity(i); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/Activity2.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.view.View; 8 | 9 | public class Activity2 extends Activity { 10 | private static final int RQ_BN1 = 1; 11 | 12 | @Override 13 | protected void onCreate(@Nullable Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_2); 16 | findViewById(R.id.create_3).setOnClickListener(this::onCreate3Clicked); 17 | findViewById(R.id.back_1).setOnClickListener(this::onBack1Clicked); 18 | } 19 | 20 | private void onBack1Clicked(View view) { 21 | finish(); 22 | } 23 | 24 | private void onCreate3Clicked(View view) { 25 | Intent i = new Intent(this, Activity3.class); 26 | startActivityForResult(i, RQ_BN1); 27 | } 28 | 29 | @Override 30 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 31 | super.onActivityResult(requestCode, resultCode, data); 32 | if (requestCode == RQ_BN1){ 33 | if (resultCode == Activity3.RESULT_TO_1){ 34 | finish(); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/Activity3.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.View; 7 | 8 | public class Activity3 extends Activity { 9 | public static final int RESULT_TO_1 = RESULT_FIRST_USER + 0; 10 | private static final int RESULT_TO_2 = RESULT_FIRST_USER + 1; 11 | private static final int RESULT_TO_3 = RESULT_FIRST_USER + 2; 12 | 13 | @Override 14 | protected void onCreate(@Nullable Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_3); 17 | findViewById(R.id.back_1).setOnClickListener(this::onBack1Clicked); 18 | findViewById(R.id.back_2).setOnClickListener(this::onBack2Clicked); 19 | } 20 | 21 | private void onBack2Clicked(View view) { 22 | finish(); 23 | } 24 | 25 | private void onBack1Clicked(View view) { 26 | setResult(RESULT_TO_1); 27 | finish(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/ArticleListActivity.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.app.FragmentManager; 6 | import android.app.FragmentTransaction; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | import android.content.pm.PackageManager; 10 | import android.content.res.Configuration; 11 | import android.os.Bundle; 12 | import android.provider.Telephony; 13 | import android.support.annotation.NonNull; 14 | import android.support.annotation.Nullable; 15 | 16 | public class ArticleListActivity extends Activity implements ArticleListFragment.ArticleListener { 17 | public static final String DETAILS_TX = "initial"; 18 | public static final String LIST_FRAGMENT = "listFragment"; 19 | public static final String DETAILS_FRAGMENT = "detailsFragment"; 20 | public static final String NONE = "None"; 21 | public static final int REQUEST_CODE = 1; 22 | private boolean twoPanes = false; 23 | 24 | @Override 25 | protected void onCreate(@Nullable Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.list_activity); 28 | 29 | twoPanes = 30 | (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); 31 | 32 | FragmentManager mgr = getFragmentManager(); 33 | mgr.popBackStack(DETAILS_TX, FragmentManager.POP_BACK_STACK_INCLUSIVE); 34 | 35 | FragmentTransaction tx = mgr.beginTransaction(); 36 | 37 | if (mgr.findFragmentByTag(LIST_FRAGMENT) == null) { 38 | tx.add(R.id.fragment_holder, new ArticleListFragment(), LIST_FRAGMENT); 39 | } 40 | 41 | if (twoPanes) { 42 | tx.replace(R.id.fragment_holder_right, DetailsFragment.newInstance(NONE), DETAILS_FRAGMENT); 43 | } 44 | 45 | tx.commit(); 46 | 47 | registerBroadcast(); 48 | } 49 | 50 | private void registerBroadcast() { 51 | if (checkSelfPermission(Manifest.permission.RECEIVE_SMS) == PackageManager.PERMISSION_GRANTED) { 52 | IntentFilter filter = new IntentFilter(); 53 | filter.addAction(Intent.ACTION_POWER_CONNECTED); 54 | filter.addAction(Intent.ACTION_POWER_DISCONNECTED); 55 | filter.addAction(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); 56 | registerReceiver(new MyBroadcastReceiver(), filter); 57 | } else { 58 | requestPermissions(new String[]{Manifest.permission.RECEIVE_SMS}, REQUEST_CODE); 59 | } 60 | } 61 | 62 | @Override 63 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 64 | if (requestCode == REQUEST_CODE) { 65 | for (int grantResult : grantResults) { 66 | if (grantResult == PackageManager.PERMISSION_GRANTED) { 67 | registerBroadcast(); 68 | } 69 | } 70 | } 71 | } 72 | 73 | @Override 74 | public void onArticle(String text) { 75 | FragmentManager mgr = getFragmentManager(); 76 | 77 | if (twoPanes) { 78 | DetailsFragment detailsFragment = (DetailsFragment) mgr.findFragmentById(R.id.fragment_holder_right); 79 | detailsFragment.setText(text); 80 | } else { 81 | FragmentTransaction tx = mgr.beginTransaction(); 82 | tx.replace(R.id.fragment_holder, DetailsFragment.newInstance(text), DETAILS_FRAGMENT); 83 | tx.addToBackStack(DETAILS_TX); 84 | tx.commit(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/ArticleListFragment.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.app.Fragment; 4 | import android.app.ListFragment; 5 | import android.content.Context; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.view.View; 9 | import android.widget.ArrayAdapter; 10 | import android.widget.ListAdapter; 11 | import android.widget.ListView; 12 | 13 | public class ArticleListFragment extends ListFragment { 14 | interface ArticleListener { 15 | void onArticle(String text); 16 | } 17 | 18 | private String[] items = {"Item1", "Item2", "Item3"}; 19 | 20 | private ArticleListener listener; 21 | 22 | @Override 23 | public void onAttach(Context context) { 24 | super.onAttach(context); 25 | try { 26 | listener = (ArticleListener) context; 27 | } catch (ClassCastException e) { 28 | throw new IllegalStateException("Activity must implement ArticleListener", e); 29 | } 30 | } 31 | 32 | ArticleListener getListener() { 33 | return listener; 34 | } 35 | 36 | void setListener(ArticleListener listener) { 37 | this.listener = listener; 38 | } 39 | 40 | @Override 41 | public void onListItemClick(ListView l, View v, int position, long id) { 42 | if (listener != null) { 43 | String text = items[position]; 44 | listener.onArticle(text); 45 | } 46 | } 47 | 48 | @Override 49 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 50 | super.onActivityCreated(savedInstanceState); 51 | ListAdapter adapter = new ArrayAdapter<>( 52 | getActivity(), 53 | android.R.layout.simple_list_item_1, 54 | items 55 | ); 56 | 57 | setListAdapter(adapter); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/DetailsActivity.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.app.Activity; 4 | import android.app.FragmentManager; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | 8 | public class DetailsActivity extends Activity { 9 | public static final String DETAILS_KEY = "ru.spbstu.icc.kspt.andrei.mydemoapplication.articletext"; 10 | 11 | @Override 12 | protected void onCreate(@Nullable Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.details_activity); 15 | 16 | FragmentManager mgr = getFragmentManager(); 17 | DetailsFragment detailsFragment = 18 | (DetailsFragment) mgr.findFragmentById(R.id.details_fragment); 19 | String text = getIntent().getStringExtra(DETAILS_KEY); 20 | detailsFragment.setText(text); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/DetailsFragment.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | public class DetailsFragment extends Fragment { 12 | 13 | public static final String KEY_DETAILS_TEXT = "ru.spbstu.icc.kspt.andrei.mydemoapplication.detailsText"; 14 | 15 | public DetailsFragment() { 16 | 17 | } 18 | 19 | @Nullable 20 | @Override 21 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { 22 | return inflater.inflate(R.layout.details_view, container, false); 23 | } 24 | 25 | @Override 26 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 27 | super.onActivityCreated(savedInstanceState); 28 | Bundle args = getArguments(); 29 | setText(args.getString(KEY_DETAILS_TEXT)); 30 | } 31 | 32 | public void setText(String text) { 33 | TextView detailsText = getActivity().findViewById(R.id.details_text); 34 | if (detailsText != null) { 35 | detailsText.setText(text); 36 | } 37 | } 38 | 39 | public static DetailsFragment newInstance(String text) { 40 | DetailsFragment res = new DetailsFragment(); 41 | Bundle args = new Bundle(); 42 | args.putString(KEY_DETAILS_TEXT, text); 43 | res.setArguments(args); 44 | return res; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/MainActivity.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.design.widget.Snackbar; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.widget.Button; 14 | import android.widget.Toast; 15 | 16 | public class MainActivity extends AppCompatActivity { 17 | 18 | public static final String TAG = "App"; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_main); 24 | 25 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 26 | setSupportActionBar(toolbar); 27 | 28 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 29 | fab.setOnClickListener(new View.OnClickListener() { 30 | @Override 31 | public void onClick(View view) { 32 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 33 | .setAction("Action", null).show(); 34 | } 35 | }); 36 | } 37 | 38 | @Override 39 | public boolean onCreateOptionsMenu(Menu menu) { 40 | // Inflate the menu; this adds items to the action bar if it is present. 41 | getMenuInflater().inflate(R.menu.menu_main, menu); 42 | return true; 43 | } 44 | 45 | @Override 46 | public boolean onOptionsItemSelected(MenuItem item) { 47 | // Handle action bar item clicks here. The action bar will 48 | // automatically handle clicks on the Home/Up button, so long 49 | // as you specify a parent activity in AndroidManifest.xml. 50 | int id = item.getItemId(); 51 | 52 | //noinspection SimplifiableIfStatement 53 | if (id == R.id.action_settings) { 54 | return true; 55 | } 56 | 57 | return super.onOptionsItemSelected(item); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/MyBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | public class MyBroadcastReceiver extends BroadcastReceiver { 9 | 10 | public static final String TAG = "BROADCAST"; 11 | 12 | @Override 13 | public void onReceive(Context context, Intent intent) { 14 | Log.i(TAG, "Received intent: " + intent); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demo/app/src/main/java/ru/spbstu/icc/kspt/andrei/mydemoapplication/MyNewActivity.java: -------------------------------------------------------------------------------- 1 | package ru.spbstu.icc.kspt.andrei.mydemoapplication; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.Button; 11 | 12 | public class MyNewActivity extends Activity { 13 | 14 | public static final String LIFECYCLE = "lifecycle"; 15 | public static final String KEY_COUNTER = "counter"; 16 | 17 | private int counter = 0; 18 | 19 | @Override 20 | protected void onSaveInstanceState(Bundle outState) { 21 | super.onSaveInstanceState(outState); 22 | outState.putInt(KEY_COUNTER, counter); 23 | } 24 | 25 | @Override 26 | protected void onCreate(@Nullable Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | this.setContentView(R.layout.test); 29 | 30 | if (savedInstanceState != null) { 31 | counter = savedInstanceState.getInt(KEY_COUNTER); 32 | } 33 | 34 | Button bn = findViewById(R.id.button); 35 | if (bn != null) { 36 | bn.setOnClickListener(this::myBnClicked); 37 | refreshBnText(bn); 38 | } 39 | } 40 | 41 | @Override 42 | protected void onStart() { 43 | super.onStart(); 44 | Log.i(LIFECYCLE, "onStart"); 45 | } 46 | 47 | @Override 48 | protected void onResume() { 49 | super.onResume(); 50 | Log.i(LIFECYCLE, "onResume"); 51 | } 52 | 53 | @Override 54 | protected void onPause() { 55 | super.onPause(); 56 | Log.i(LIFECYCLE, "onPause"); 57 | } 58 | 59 | @Override 60 | protected void onStop() { 61 | super.onStop(); 62 | Log.i(LIFECYCLE, "onStop"); 63 | } 64 | 65 | @Override 66 | protected void onDestroy() { 67 | super.onDestroy(); 68 | Log.i(LIFECYCLE, "onDestroy"); 69 | } 70 | 71 | public void myBnClicked(View view) { 72 | Button bn = (Button) view; 73 | counter++; 74 | refreshBnText(bn); 75 | 76 | Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:123")); 77 | startActivity(intent); 78 | } 79 | 80 | private void refreshBnText(Button bn) { 81 | String title = getResources().getString(R.string.title_click_count, counter); 82 | bn.setText(title); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /demo/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /demo/app/src/main/res/drawable/gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo/app/src/main/res/drawable/ic_assistant_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /demo/app/src/main/res/drawable/ic_launcher_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrei-kuznetsov/android-lectures/1eb200723828d30706abb0f450956b4ab6795d80/demo/app/src/main/res/drawable/ic_launcher_square.png -------------------------------------------------------------------------------- /demo/app/src/main/res/drawable/shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo/app/src/main/res/layout-land/list_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /demo/app/src/main/res/layout-land/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | -------------------------------------------------------------------------------- /demo/app/src/main/res/layout/activity_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |