Repository: nenick/android-gradle-template Branch: master Commit: 661f17d2a445 Files: 171 Total size: 231.7 KB Directory structure: gitextract_0g2gn4nz/ ├── .gitignore ├── app/ │ ├── build.generate-database.gradle │ ├── build.generate-json-objects.gradle │ ├── build.gradle │ ├── build.jacoco-test-report.gradle │ ├── build.robolectric.gradle │ ├── build.wiremock-replace-ip.gradle │ ├── lint.xml │ ├── proguard-rules.pro │ └── src/ │ ├── gen/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── project/ │ │ ├── database/ │ │ │ └── provider/ │ │ │ ├── ExampleProvider.java │ │ │ ├── ExampleSQLiteOpenHelper.java │ │ │ ├── ExampleSQLiteOpenHelperCallbacks.java │ │ │ ├── address/ │ │ │ │ ├── AddressColumns.java │ │ │ │ ├── AddressContentValues.java │ │ │ │ ├── AddressCursor.java │ │ │ │ ├── AddressModel.java │ │ │ │ └── AddressSelection.java │ │ │ ├── base/ │ │ │ │ ├── AbstractContentValues.java │ │ │ │ ├── AbstractCursor.java │ │ │ │ ├── AbstractSelection.java │ │ │ │ ├── BaseContentProvider.java │ │ │ │ └── BaseModel.java │ │ │ └── contact/ │ │ │ ├── ContactColumns.java │ │ │ ├── ContactContentValues.java │ │ │ ├── ContactCursor.java │ │ │ ├── ContactModel.java │ │ │ └── ContactSelection.java │ │ └── network/ │ │ └── json/ │ │ ├── ContactJson.java │ │ └── ContactListJson.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── project/ │ │ │ ├── business/ │ │ │ │ ├── contact/ │ │ │ │ │ ├── CreateContactFunction.java │ │ │ │ │ ├── DeleteContactFunction.java │ │ │ │ │ ├── QueryContactFunction.java │ │ │ │ │ ├── QueryContactListFunction.java │ │ │ │ │ └── UpdateContactFunction.java │ │ │ │ └── contact_sync/ │ │ │ │ └── SyncContactsFunction.java │ │ │ ├── database/ │ │ │ │ ├── ExampleDbProvider.java │ │ │ │ ├── ExampleSQLiteOpenHelperCallbacks.java │ │ │ │ └── contact/ │ │ │ │ ├── AddressDb.java │ │ │ │ └── ContactDb.java │ │ │ ├── network/ │ │ │ │ └── contact/ │ │ │ │ ├── ContactRestClient.java │ │ │ │ └── RootUrlInterceptor.java │ │ │ └── views/ │ │ │ ├── common/ │ │ │ │ ├── AppIdlingResources.java │ │ │ │ ├── cursorloader/ │ │ │ │ │ └── CursorAdapterWithCursorLoader.java │ │ │ │ ├── mvp/ │ │ │ │ │ ├── BaseActivityPresenter.java │ │ │ │ │ ├── BaseFragmentPresenter.java │ │ │ │ │ ├── BasePresenter.java │ │ │ │ │ └── BaseView.java │ │ │ │ └── testwrapper/ │ │ │ │ └── ViewFinisher.java │ │ │ ├── contact_details/ │ │ │ │ ├── DetailActivity.java │ │ │ │ ├── DetailActivityIntent.java │ │ │ │ ├── DetailFragment.java │ │ │ │ └── DetailView.java │ │ │ ├── contact_edit/ │ │ │ │ ├── EditActivity.java │ │ │ │ ├── EditActivityIntent.java │ │ │ │ ├── EditConfirmedListener.java │ │ │ │ ├── EditFragment.java │ │ │ │ └── EditView.java │ │ │ ├── contact_list/ │ │ │ │ ├── ContactAdapter.java │ │ │ │ ├── ContactAdapterLoader.java │ │ │ │ ├── ContactListActivity.java │ │ │ │ ├── ContactListActivityIntent.java │ │ │ │ ├── ContactListFragment.java │ │ │ │ ├── ContactListView.java │ │ │ │ └── ShowContactListener.java │ │ │ └── start/ │ │ │ └── StartActivity.java │ │ ├── json/ │ │ │ ├── database/ │ │ │ │ └── schema/ │ │ │ │ ├── _config.json │ │ │ │ ├── address.json │ │ │ │ └── contact.json │ │ │ └── network/ │ │ │ └── schema/ │ │ │ ├── contactJson.json │ │ │ └── contactListJson.json │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_detail.xml │ │ │ ├── activity_edit.xml │ │ │ ├── activity_main.xml │ │ │ ├── fragment_detail.xml │ │ │ ├── fragment_edit.xml │ │ │ └── fragment_list.xml │ │ ├── layout-land/ │ │ │ └── activity_main.xml │ │ ├── menu/ │ │ │ └── menu_main.xml │ │ ├── values/ │ │ │ ├── dimens.xml │ │ │ ├── string_api_url.xml │ │ │ ├── strings.xml │ │ │ ├── strings_details.xml │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── project/ │ ├── RoboTestCase.java │ ├── business/ │ │ └── contact/ │ │ └── QueryContactListFunctionTest.java │ ├── database/ │ │ └── contact/ │ │ ├── AddressDbInsertTest.java │ │ ├── AddressDbTest.java │ │ ├── ContactDbInsertTest.java │ │ └── ContactDbTest.java │ └── views/ │ ├── contact_edit/ │ │ ├── EditActivityTest.java │ │ └── EditFragmentTest.java │ ├── contact_list/ │ │ ├── ContactListActivityTest.java │ │ └── ContactListFragmentTest.java │ └── start/ │ └── StartActivityTest.java ├── appCt/ │ ├── build.gradle │ ├── build.jacoco-test-report.gradle │ ├── build.novoda-android-studio.gradle │ ├── build.robolectric.gradle │ └── src/ │ └── test/ │ └── java/ │ ├── android/ │ │ └── database/ │ │ └── ShadowContentObservable.java │ └── com/ │ └── example/ │ └── project/ │ ├── RobolectricTestCase.java │ ├── robolectric/ │ │ ├── CostomRobolectricTestRunner.java │ │ ├── RoboButton.java │ │ ├── RoboListView.java │ │ ├── RoboListViewEntry.java │ │ ├── RoboTextEdit.java │ │ └── ShadowBackgroundExecutor.java │ ├── testdata/ │ │ └── TestContactData.java │ └── views/ │ ├── contac_list/ │ │ ├── ContactListSpec.java │ │ └── RoboContactListPage.java │ ├── contact_details/ │ │ └── ContactDetailSpec.java │ └── contact_edit/ │ ├── ContactCreateSpec.java │ ├── ContactEditSpec.java │ └── RoboContactEditPage.java ├── appIt/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ └── java/ │ └── com/ │ └── example/ │ └── project/ │ ├── EspressoTestCase.java │ ├── espresso/ │ │ ├── CurrentActivity.java │ │ ├── EspButton.java │ │ ├── EspListView.java │ │ ├── EspMenuItem.java │ │ └── EspTextEdit.java │ ├── pages/ │ │ ├── EspContactListPage.java │ │ └── EspEditContactPage.java │ └── test/ │ ├── CreateContactTest.java │ └── SyncContactsTest.java ├── build.gradle ├── build.jacoco-test-report.gradle ├── circle.yml ├── docs/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── resources/ │ ├── adjust_project_to_your_needs.md │ ├── concepts/ │ │ ├── function_class.md │ │ ├── model_view_presenter.md │ │ ├── package_structure.md │ │ ├── project_structure.md │ │ └── testing.md │ ├── getting_started.md │ ├── index.md │ └── tools/ │ ├── android_contentprovider_generator.md │ ├── androidannotations.md │ ├── circleci.md │ ├── coveralls.md │ ├── espresso.md │ ├── espresso_test_module.md │ ├── fest_assertions.md │ ├── jacoco.md │ ├── joda_timedate.md │ ├── jsonschema2pojo.md │ ├── robolectric.md │ ├── robolectric_test_module.md │ └── wiremock.md ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── readme.md ├── settings.gradle ├── tools/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── resources/ │ ├── rename-packages(in development).sh │ ├── start-wiremock.sh │ ├── test-all-with-coverage.bat │ └── test-all-with-coverage.sh └── wiremock/ ├── build.gradle ├── src/ │ └── main/ │ └── resources/ │ ├── __files/ │ │ └── contacts-get.json │ └── mappings/ │ ├── contcts-delete.json │ ├── contcts-get.json │ ├── contcts-post.json │ └── contcts-put.json └── wiremock-1.57-standalone.jar ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store .idea .gradle *~ *.iml **/build GenerateJsonRestModel/gen/* local.properties ================================================ FILE: app/build.generate-database.gradle ================================================ def dbSchemaPath = "src/main/json/database/schema" def dbClassesPath = "src/gen/java" android.sourceSets.main.java.srcDirs += dbClassesPath android.sourceSets.main.java.srcDirs += "src/main/json" task generateDatabaseFiles << { def generatorVersion = "1.9.2" // download android contentprovider generator if (!file("$buildDir/android_contentprovider_generator-${generatorVersion}-bundle.jar").exists()) { download { src "https://github.com/BoD/android-contentprovider-generator/releases/download/v${generatorVersion}/android_contentprovider_generator-${generatorVersion}-bundle.jar" dest buildDir } } // delete last generated files // file(dbClassesPath).deleteDir() // execute the generator exec { executable "java" args = ["-jar", "$buildDir/android_contentprovider_generator-${generatorVersion}-bundle.jar", "-i", dbSchemaPath, "-o", dbClassesPath] } } ================================================ FILE: app/build.generate-json-objects.gradle ================================================ apply plugin: 'jsonschema2pojo' dependencies { compile 'com.fasterxml.jackson.core:jackson-databind:2.6.1' compile 'javax.annotation:javax.annotation-api:1.2' } jsonSchema2Pojo { source = files("${project.projectDir}/src/main/json/network/schema") targetDirectory = file("${project.projectDir}/src/gen/java") targetPackage = 'com.example.project.network.json' useCommonsLang3 = true } ================================================ FILE: app/build.gradle ================================================ buildscript { repositories { jcenter() } dependencies { // code generation support for android annotations classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' // code generation for json string - object mapping classpath 'org.jsonschema2pojo:jsonschema2pojo-gradle-plugin:0.4.14' } } plugins { // provide download task for gradle id "de.undercouch.download" version "1.2" } apply plugin: 'com.android.application' // code generation support for android annotations apply plugin: 'android-apt' // code generation for json object mapping apply from: 'build.generate-json-objects.gradle' // code generation database files apply from: 'build.generate-database.gradle' // test support for android specific unit tests like database checks apply from: 'build.robolectric.gradle' // support code coverage for the unit tests apply from: 'build.jacoco-test-report.gradle' // replace target ip for REST calls to use local wiremock apply from: "build.wiremock-replace-ip.gradle" android { compileSdkVersion projectAndroidVersion buildToolsVersion projectAndroidBuildToolsVersion defaultConfig { applicationId "com.example.project" minSdkVersion projectAndroidMinVersion targetSdkVersion projectAndroidVersion versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField "String", "MODULE_PATH", "\"$projectDir\"".replace('\\', '\\\\') // avoid warning for "Not all execution paths return a value" return true } debug { buildConfigField "String", "MODULE_PATH", "\"$projectDir\"".replace('\\', '\\\\') return true } } lintOptions { // GradleDependency Current we can't switch to support v23 tools because of robolectric disable 'GradleDependency' } dexOptions { if(isCi) { // CircleCi allow max 4G memory for all processes together and dex does exceed it // with his parallel execution. Shrink the javaMaxHeapSize does it only per dex process // but the combination exceed the max memory and to less value let it run for long time. // javaMaxHeapSize "1024M" // Speed up build for CI by ignoring extra build steps which should speed up build for developers. // Also reduce memory usage by avoiding multiple (pre) dex processes. incremental false preDexLibraries = false } } // instrumentation test module need to access the expected variant, default is only release publish publishNonDefault true packagingOptions { exclude 'META-INF/license.txt' exclude 'META-INF/LICENSE.txt' exclude 'META-INF/LICENSE' exclude 'META-INF/notice.txt' exclude 'META-INF/NOTICE.txt' exclude 'META-INF/NOTICE' } } apt { arguments { androidManifestFile variant.outputs.collect()[0].processResources.manifestFile } } repositories { jcenter() } dependencies { // ui design and backward compatibility compile "com.android.support:appcompat-v7:$projectAndroidSupportToolsVersion" compile "com.android.support:design:$projectAndroidSupportToolsVersion" // android annotations support apt "org.androidannotations:androidannotations:3.3.2" compile "org.androidannotations:androidannotations-api:3.3.2" // network support with android annotations compile "org.springframework.android:spring-android-rest-template:2.0.0.M3" // better time handling with DateTime compile 'net.danlew:android.joda:2.8.2' // java language tools like StringUtils compile 'org.apache.commons:commons-lang3:3.4' // Use CountIdlingResource class to avoid flaky espresso tests. // Interface is provided by own dependency but ready to use implementation comes with contrib library. // Looks like contrib library was only intended to be used within test scope. // Exclude transitiv dependencies to avoid conflicts with test support libraries. compile('com.android.support.test.espresso:espresso-idling-resource:2.2') compile('com.android.support.test.espresso:espresso-contrib:2.2') { exclude module: "*" } // force test dependencies to use the same support-annotations version testCompile "com.android.support:support-annotations:$projectAndroidSupportToolsVersion" // basic unit tests support + mocks + fluent assertions + android assertions testCompile 'junit:junit:4.12' testCompile 'com.squareup.assertj:assertj-android:1.1.0' testCompile 'org.mockito:mockito-all:2.0.2-beta' } ================================================ FILE: app/build.jacoco-test-report.gradle ================================================ apply plugin: "jacoco" jacoco { toolVersion = projectJacocoVersion } task jacocoTestReport(type: JacocoReport /*, dependsOn: ['test'] */ ) { description = "Generates Jacoco coverage reports: XML and HTML" group = "Reporting" // outputs.upToDateWhen { false } // use hidden configuration, for details look into JacocoPlugin.groovy jacocoClasspath = project.configurations['androidJacocoAnt'] // exclude auto-generated classes and tests def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] def debugTree = fileTree(dir: "${project.buildDir}/intermediates/classes/debug", excludes: fileFilter) def mainSrc = "${project.projectDir}/src/main/java" sourceDirectories = files([mainSrc]) classDirectories = files([debugTree]) executionData = fileTree(dir: project.projectDir, includes: ['**/*.exec', '**/*.ec']) reports { xml { enabled = true destination = "${project.buildDir}/reports/jacoco/test/jacocoTestReport.xml" } csv.enabled false html { enabled = true destination = "${project.buildDir}/reports/jacoco" } } } ================================================ FILE: app/build.robolectric.gradle ================================================ dependencies { testCompile 'org.robolectric:shadows-support-v4:3.0' testCompile 'org.robolectric:robolectric:3.0' } afterEvaluate { def isLintRun = false def isTestRun = false gradle.startParameter.taskNames.each { if (it.contains("lint")) { isLintRun = true } if (it.contains("test")) { isTestRun = true } } if (isLintRun && isTestRun) { println "WARNING: tests for release type are disabled for supporting jacoco" println "WARNING: run test and lint at same time is not supported" exit 1 } if (isTestRun) { tasks.each { if (it.name.contains("Release")) { it.enabled = false } } } } ================================================ FILE: app/build.wiremock-replace-ip.gradle ================================================ // may be used to check if wiremock is running Process p1 = Runtime.getRuntime().exec("curl " + obtainCurrentIpAddress() + ":1337/"); int returnVal = p1.waitFor(); boolean reachable = (returnVal == 0); println "\n Wiremock is reachable $reachable\n" // replace the #const_wiremock_ip# with your current ip address for test with wiremock android.applicationVariants.all { variant -> variant.mergeResources.doLast { def String localIp = obtainCurrentIpAddress() File valuesFile = file("${buildDir}/intermediates/res/merged/debug/values/values.xml") if (valuesFile.exists()) { String content = valuesFile.getText('UTF-8') content = content.replaceAll("#const_wiremock_ip#", localIp) valuesFile.write(content, 'UTF-8') } else { println "Warning: value.xml not found for replace current ip" } } } def String obtainCurrentIpAddress() { def wantedInterfaceDisplayName = System.getenv("TEST_MOCK_IFACE"); if ((wantedInterfaceDisplayName != null) && (!wantedInterfaceDisplayName.isEmpty())) { println "\n Interface wanted: " + wantedInterfaceDisplayName } else { println "\n No interface wanted, you can select one by setting the interface name to environment variable TEST_MOCK_IFACE" } def ipAddress = null; Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); while (networkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = (NetworkInterface) networkInterfaces.nextElement(); Enumeration inetAddresses = networkInterface.getInetAddresses(); InetAddress inetAddress = (InetAddress) inetAddresses.nextElement(); println " Found network [${networkInterface.getDisplayName()}] with IP ${inetAddress.getHostAddress()}" if (wantedInterfaceDisplayName?.trim() && !wantedInterfaceDisplayName.equalsIgnoreCase(networkInterface.displayName)) { continue; } if (ipAddress == null) { ipAddress = inetAddress.getHostAddress(); println " Selected network ${ipAddress}" } } ipAddress } ================================================ FILE: app/lint.xml ================================================ ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/nicokuechler/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} -dontwarn org.androidannotations.api.rest.* ================================================ FILE: app/src/gen/java/com/example/project/database/provider/ExampleProvider.java ================================================ package com.example.project.database.provider; import java.util.Arrays; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.support.annotation.NonNull; import android.util.Log; import com.example.project.BuildConfig; import com.example.project.database.provider.base.BaseContentProvider; import com.example.project.database.provider.address.AddressColumns; import com.example.project.database.provider.contact.ContactColumns; public class ExampleProvider extends BaseContentProvider { private static final String TAG = ExampleProvider.class.getSimpleName(); private static final boolean DEBUG = BuildConfig.DEBUG; private static final String TYPE_CURSOR_ITEM = "vnd.android.cursor.item/"; private static final String TYPE_CURSOR_DIR = "vnd.android.cursor.dir/"; public static final String AUTHORITY = "com.example.project"; public static final String CONTENT_URI_BASE = "content://" + AUTHORITY; private static final int URI_TYPE_ADDRESS = 0; private static final int URI_TYPE_ADDRESS_ID = 1; private static final int URI_TYPE_CONTACT = 2; private static final int URI_TYPE_CONTACT_ID = 3; private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); static { URI_MATCHER.addURI(AUTHORITY, AddressColumns.TABLE_NAME, URI_TYPE_ADDRESS); URI_MATCHER.addURI(AUTHORITY, AddressColumns.TABLE_NAME + "/#", URI_TYPE_ADDRESS_ID); URI_MATCHER.addURI(AUTHORITY, ContactColumns.TABLE_NAME, URI_TYPE_CONTACT); URI_MATCHER.addURI(AUTHORITY, ContactColumns.TABLE_NAME + "/#", URI_TYPE_CONTACT_ID); } @Override protected SQLiteOpenHelper createSqLiteOpenHelper() { return ExampleSQLiteOpenHelper.getInstance(getContext()); } @Override protected boolean hasDebug() { return DEBUG; } @Override public String getType(Uri uri) { int match = URI_MATCHER.match(uri); switch (match) { case URI_TYPE_ADDRESS: return TYPE_CURSOR_DIR + AddressColumns.TABLE_NAME; case URI_TYPE_ADDRESS_ID: return TYPE_CURSOR_ITEM + AddressColumns.TABLE_NAME; case URI_TYPE_CONTACT: return TYPE_CURSOR_DIR + ContactColumns.TABLE_NAME; case URI_TYPE_CONTACT_ID: return TYPE_CURSOR_ITEM + ContactColumns.TABLE_NAME; } return null; } @Override public Uri insert(Uri uri, ContentValues values) { if (DEBUG) Log.d(TAG, "insert uri=" + uri + " values=" + values); return super.insert(uri, values); } @Override public int bulkInsert(Uri uri, ContentValues[] values) { if (DEBUG) Log.d(TAG, "bulkInsert uri=" + uri + " values.length=" + values.length); return super.bulkInsert(uri, values); } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { if (DEBUG) Log.d(TAG, "update uri=" + uri + " values=" + values + " selection=" + selection + " selectionArgs=" + Arrays.toString(selectionArgs)); return super.update(uri, values, selection, selectionArgs); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { if (DEBUG) Log.d(TAG, "delete uri=" + uri + " selection=" + selection + " selectionArgs=" + Arrays.toString(selectionArgs)); return super.delete(uri, selection, selectionArgs); } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { if (DEBUG) Log.d(TAG, "query uri=" + uri + " selection=" + selection + " selectionArgs=" + Arrays.toString(selectionArgs) + " sortOrder=" + sortOrder + " groupBy=" + uri.getQueryParameter(QUERY_GROUP_BY) + " having=" + uri.getQueryParameter(QUERY_HAVING) + " limit=" + uri.getQueryParameter(QUERY_LIMIT)); return super.query(uri, projection, selection, selectionArgs, sortOrder); } @Override protected QueryParams getQueryParams(Uri uri, String selection, String[] projection) { QueryParams res = new QueryParams(); String id = null; int matchedId = URI_MATCHER.match(uri); switch (matchedId) { case URI_TYPE_ADDRESS: case URI_TYPE_ADDRESS_ID: res.table = AddressColumns.TABLE_NAME; res.idColumn = AddressColumns._ID; res.tablesWithJoins = AddressColumns.TABLE_NAME; if (ContactColumns.hasColumns(projection)) { res.tablesWithJoins += " LEFT OUTER JOIN " + ContactColumns.TABLE_NAME + " AS " + AddressColumns.PREFIX_CONTACT + " ON " + AddressColumns.TABLE_NAME + "." + AddressColumns.CONTACT_ID + "=" + AddressColumns.PREFIX_CONTACT + "." + ContactColumns._ID; } res.orderBy = AddressColumns.DEFAULT_ORDER; break; case URI_TYPE_CONTACT: case URI_TYPE_CONTACT_ID: res.table = ContactColumns.TABLE_NAME; res.idColumn = ContactColumns._ID; res.tablesWithJoins = ContactColumns.TABLE_NAME; res.orderBy = ContactColumns.DEFAULT_ORDER; break; default: throw new IllegalArgumentException("The uri '" + uri + "' is not supported by this ContentProvider"); } switch (matchedId) { case URI_TYPE_ADDRESS_ID: case URI_TYPE_CONTACT_ID: id = uri.getLastPathSegment(); } if (id != null) { if (selection != null) { res.selection = res.table + "." + res.idColumn + "=" + id + " and (" + selection + ")"; } else { res.selection = res.table + "." + res.idColumn + "=" + id; } } else { res.selection = selection; } return res; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/ExampleSQLiteOpenHelper.java ================================================ package com.example.project.database.provider; import android.annotation.TargetApi; import android.content.Context; import android.database.DatabaseErrorHandler; import android.database.DefaultDatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.Build; import android.util.Log; import com.example.project.BuildConfig; import com.example.project.database.provider.address.AddressColumns; import com.example.project.database.provider.contact.ContactColumns; public class ExampleSQLiteOpenHelper extends SQLiteOpenHelper { private static final String TAG = ExampleSQLiteOpenHelper.class.getSimpleName(); public static final String DATABASE_FILE_NAME = "example.db"; private static final int DATABASE_VERSION = 1; private static ExampleSQLiteOpenHelper sInstance; private final Context mContext; private final ExampleSQLiteOpenHelperCallbacks mOpenHelperCallbacks; // @formatter:off public static final String SQL_CREATE_TABLE_ADDRESS = "CREATE TABLE IF NOT EXISTS " + AddressColumns.TABLE_NAME + " ( " + AddressColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + AddressColumns.CONTACT_ID + " INTEGER NOT NULL, " + AddressColumns.STREET + " TEXT, " + AddressColumns.NUMBER + " TEXT, " + AddressColumns.CITY + " TEXT, " + AddressColumns.COUNTRY + " TEXT, " + AddressColumns.STATE + " TEXT, " + AddressColumns.POSTALCODE + " TEXT " + ", CONSTRAINT fk_contact_id FOREIGN KEY (" + AddressColumns.CONTACT_ID + ") REFERENCES contact (_id) ON DELETE CASCADE" + " );"; public static final String SQL_CREATE_TABLE_CONTACT = "CREATE TABLE IF NOT EXISTS " + ContactColumns.TABLE_NAME + " ( " + ContactColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + ContactColumns.UID + " TEXT, " + ContactColumns.FIRST_NAME + " TEXT, " + ContactColumns.LAST_NAME + " TEXT, " + ContactColumns.BIRTHDATE + " INTEGER " + ", CONSTRAINT first_or_last_name_must_be_given CHECK((first_name <> '' AND first_name IS NOT NULL) OR (last_name <> '' AND last_name IS NOT NULL)) ON CONFLICT FAIL" + " );"; // @formatter:on public static ExampleSQLiteOpenHelper getInstance(Context context) { // Use the application context, which will ensure that you // don't accidentally leak an Activity's context. // See this article for more information: http://bit.ly/6LRzfx if (sInstance == null) { sInstance = newInstance(context.getApplicationContext()); } return sInstance; } private static ExampleSQLiteOpenHelper newInstance(Context context) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return newInstancePreHoneycomb(context); } return newInstancePostHoneycomb(context); } /* * Pre Honeycomb. */ private static ExampleSQLiteOpenHelper newInstancePreHoneycomb(Context context) { return new ExampleSQLiteOpenHelper(context); } private ExampleSQLiteOpenHelper(Context context) { super(context, DATABASE_FILE_NAME, null, DATABASE_VERSION); mContext = context; mOpenHelperCallbacks = new ExampleSQLiteOpenHelperCallbacks(); } /* * Post Honeycomb. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) private static ExampleSQLiteOpenHelper newInstancePostHoneycomb(Context context) { return new ExampleSQLiteOpenHelper(context, new DefaultDatabaseErrorHandler()); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private ExampleSQLiteOpenHelper(Context context, DatabaseErrorHandler errorHandler) { super(context, DATABASE_FILE_NAME, null, DATABASE_VERSION, errorHandler); mContext = context; mOpenHelperCallbacks = new ExampleSQLiteOpenHelperCallbacks(); } @Override public void onCreate(SQLiteDatabase db) { if (BuildConfig.DEBUG) Log.d(TAG, "onCreate"); mOpenHelperCallbacks.onPreCreate(mContext, db); db.execSQL(SQL_CREATE_TABLE_ADDRESS); db.execSQL(SQL_CREATE_TABLE_CONTACT); mOpenHelperCallbacks.onPostCreate(mContext, db); } @Override public void onOpen(SQLiteDatabase db) { super.onOpen(db); if (!db.isReadOnly()) { setForeignKeyConstraintsEnabled(db); } mOpenHelperCallbacks.onOpen(mContext, db); } private void setForeignKeyConstraintsEnabled(SQLiteDatabase db) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { setForeignKeyConstraintsEnabledPreJellyBean(db); } else { setForeignKeyConstraintsEnabledPostJellyBean(db); } } private void setForeignKeyConstraintsEnabledPreJellyBean(SQLiteDatabase db) { db.execSQL("PRAGMA foreign_keys=ON;"); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void setForeignKeyConstraintsEnabledPostJellyBean(SQLiteDatabase db) { db.setForeignKeyConstraintsEnabled(true); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { mOpenHelperCallbacks.onUpgrade(mContext, db, oldVersion, newVersion); } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/ExampleSQLiteOpenHelperCallbacks.java ================================================ package com.example.project.database.provider; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import com.example.project.BuildConfig; /** * Implement your custom database creation or upgrade code here. * * This file will not be overwritten if you re-run the content provider generator. */ public class ExampleSQLiteOpenHelperCallbacks { private static final String TAG = ExampleSQLiteOpenHelperCallbacks.class.getSimpleName(); public void onOpen(final Context context, final SQLiteDatabase db) { if (BuildConfig.DEBUG) Log.d(TAG, "onOpen"); // Insert your db open code here. } public void onPreCreate(final Context context, final SQLiteDatabase db) { if (BuildConfig.DEBUG) Log.d(TAG, "onPreCreate"); // Insert your db creation code here. This is called before your tables are created. } public void onPostCreate(final Context context, final SQLiteDatabase db) { if (BuildConfig.DEBUG) Log.d(TAG, "onPostCreate"); // Insert your db creation code here. This is called after your tables are created. } public void onUpgrade(final Context context, final SQLiteDatabase db, final int oldVersion, final int newVersion) { if (BuildConfig.DEBUG) Log.d(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion); // Insert your upgrading code here. } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/address/AddressColumns.java ================================================ package com.example.project.database.provider.address; import android.net.Uri; import android.provider.BaseColumns; import com.example.project.database.provider.ExampleProvider; import com.example.project.database.provider.address.AddressColumns; import com.example.project.database.provider.contact.ContactColumns; /** * Columns for the {@code address} table. */ public class AddressColumns implements BaseColumns { public static final String TABLE_NAME = "address"; public static final Uri CONTENT_URI = Uri.parse(ExampleProvider.CONTENT_URI_BASE + "/" + TABLE_NAME); /** * Primary key. */ public static final String _ID = BaseColumns._ID; public static final String CONTACT_ID = "contact_id"; public static final String STREET = "street"; public static final String NUMBER = "number"; public static final String CITY = "city"; public static final String COUNTRY = "country"; public static final String STATE = "state"; public static final String POSTALCODE = "postalcode"; public static final String DEFAULT_ORDER = TABLE_NAME + "." +_ID; // @formatter:off public static final String[] ALL_COLUMNS = new String[] { _ID, CONTACT_ID, STREET, NUMBER, CITY, COUNTRY, STATE, POSTALCODE }; // @formatter:on public static boolean hasColumns(String[] projection) { if (projection == null) return true; for (String c : projection) { if (c.equals(CONTACT_ID) || c.contains("." + CONTACT_ID)) return true; if (c.equals(STREET) || c.contains("." + STREET)) return true; if (c.equals(NUMBER) || c.contains("." + NUMBER)) return true; if (c.equals(CITY) || c.contains("." + CITY)) return true; if (c.equals(COUNTRY) || c.contains("." + COUNTRY)) return true; if (c.equals(STATE) || c.contains("." + STATE)) return true; if (c.equals(POSTALCODE) || c.contains("." + POSTALCODE)) return true; } return false; } public static final String PREFIX_CONTACT = TABLE_NAME + "__" + ContactColumns.TABLE_NAME; } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/address/AddressContentValues.java ================================================ package com.example.project.database.provider.address; import java.util.Date; import android.content.ContentResolver; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.example.project.database.provider.base.AbstractContentValues; /** * Content values wrapper for the {@code address} table. */ public class AddressContentValues extends AbstractContentValues { @Override public Uri uri() { return AddressColumns.CONTENT_URI; } /** * Update row(s) using the values stored by this object and the given selection. * * @param contentResolver The content resolver to use. * @param where The selection to use (can be {@code null}). */ public int update(ContentResolver contentResolver, @Nullable AddressSelection where) { return contentResolver.update(uri(), values(), where == null ? null : where.sel(), where == null ? null : where.args()); } public AddressContentValues putContactId(long value) { mContentValues.put(AddressColumns.CONTACT_ID, value); return this; } public AddressContentValues putStreet(@Nullable String value) { mContentValues.put(AddressColumns.STREET, value); return this; } public AddressContentValues putStreetNull() { mContentValues.putNull(AddressColumns.STREET); return this; } public AddressContentValues putNumber(@Nullable String value) { mContentValues.put(AddressColumns.NUMBER, value); return this; } public AddressContentValues putNumberNull() { mContentValues.putNull(AddressColumns.NUMBER); return this; } public AddressContentValues putCity(@Nullable String value) { mContentValues.put(AddressColumns.CITY, value); return this; } public AddressContentValues putCityNull() { mContentValues.putNull(AddressColumns.CITY); return this; } public AddressContentValues putCountry(@Nullable String value) { mContentValues.put(AddressColumns.COUNTRY, value); return this; } public AddressContentValues putCountryNull() { mContentValues.putNull(AddressColumns.COUNTRY); return this; } public AddressContentValues putState(@Nullable String value) { mContentValues.put(AddressColumns.STATE, value); return this; } public AddressContentValues putStateNull() { mContentValues.putNull(AddressColumns.STATE); return this; } public AddressContentValues putPostalcode(@Nullable String value) { mContentValues.put(AddressColumns.POSTALCODE, value); return this; } public AddressContentValues putPostalcodeNull() { mContentValues.putNull(AddressColumns.POSTALCODE); return this; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/address/AddressCursor.java ================================================ package com.example.project.database.provider.address; import java.util.Date; import android.database.Cursor; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.example.project.database.provider.base.AbstractCursor; import com.example.project.database.provider.contact.*; /** * Cursor wrapper for the {@code address} table. */ public class AddressCursor extends AbstractCursor implements AddressModel { public AddressCursor(Cursor cursor) { super(cursor); } /** * Primary key. */ public long getId() { Long res = getLongOrNull(AddressColumns._ID); if (res == null) throw new NullPointerException("The value of '_id' in the database was null, which is not allowed according to the model definition"); return res; } /** * Get the {@code contact_id} value. */ public long getContactId() { Long res = getLongOrNull(AddressColumns.CONTACT_ID); if (res == null) throw new NullPointerException("The value of 'contact_id' in the database was null, which is not allowed according to the model definition"); return res; } /** * Get the {@code uid} value. * Can be {@code null}. */ @Nullable public String getContactUid() { String res = getStringOrNull(ContactColumns.UID); return res; } /** * Get the {@code first_name} value. * Can be {@code null}. */ @Nullable public String getContactFirstName() { String res = getStringOrNull(ContactColumns.FIRST_NAME); return res; } /** * Get the {@code last_name} value. * Can be {@code null}. */ @Nullable public String getContactLastName() { String res = getStringOrNull(ContactColumns.LAST_NAME); return res; } /** * Get the {@code birthdate} value. * Can be {@code null}. */ @Nullable public Date getContactBirthdate() { Date res = getDateOrNull(ContactColumns.BIRTHDATE); return res; } /** * Get the {@code street} value. * Can be {@code null}. */ @Nullable public String getStreet() { String res = getStringOrNull(AddressColumns.STREET); return res; } /** * Get the {@code number} value. * Can be {@code null}. */ @Nullable public String getNumber() { String res = getStringOrNull(AddressColumns.NUMBER); return res; } /** * Get the {@code city} value. * Can be {@code null}. */ @Nullable public String getCity() { String res = getStringOrNull(AddressColumns.CITY); return res; } /** * Get the {@code country} value. * Can be {@code null}. */ @Nullable public String getCountry() { String res = getStringOrNull(AddressColumns.COUNTRY); return res; } /** * Get the {@code state} value. * Can be {@code null}. */ @Nullable public String getState() { String res = getStringOrNull(AddressColumns.STATE); return res; } /** * Get the {@code postalcode} value. * Can be {@code null}. */ @Nullable public String getPostalcode() { String res = getStringOrNull(AddressColumns.POSTALCODE); return res; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/address/AddressModel.java ================================================ package com.example.project.database.provider.address; import com.example.project.database.provider.base.BaseModel; import java.util.Date; import android.support.annotation.NonNull; import android.support.annotation.Nullable; /** * Data model for the {@code address} table. */ public interface AddressModel extends BaseModel { /** * Get the {@code contact_id} value. */ long getContactId(); /** * Get the {@code street} value. * Can be {@code null}. */ @Nullable String getStreet(); /** * Get the {@code number} value. * Can be {@code null}. */ @Nullable String getNumber(); /** * Get the {@code city} value. * Can be {@code null}. */ @Nullable String getCity(); /** * Get the {@code country} value. * Can be {@code null}. */ @Nullable String getCountry(); /** * Get the {@code state} value. * Can be {@code null}. */ @Nullable String getState(); /** * Get the {@code postalcode} value. * Can be {@code null}. */ @Nullable String getPostalcode(); } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/address/AddressSelection.java ================================================ package com.example.project.database.provider.address; import java.util.Date; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import com.example.project.database.provider.base.AbstractSelection; import com.example.project.database.provider.contact.*; /** * Selection for the {@code address} table. */ public class AddressSelection extends AbstractSelection { @Override protected Uri baseUri() { return AddressColumns.CONTENT_URI; } /** * Query the given content resolver using this selection. * * @param contentResolver The content resolver to query. * @param projection A list of which columns to return. Passing null will return all columns, which is inefficient. * @param sortOrder How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort * order, which may be unordered. * @return A {@code AddressCursor} object, which is positioned before the first entry, or null. */ public AddressCursor query(ContentResolver contentResolver, String[] projection, String sortOrder) { Cursor cursor = contentResolver.query(uri(), projection, sel(), args(), sortOrder); if (cursor == null) return null; return new AddressCursor(cursor); } /** * Equivalent of calling {@code query(contentResolver, projection, null)}. */ public AddressCursor query(ContentResolver contentResolver, String[] projection) { return query(contentResolver, projection, null); } /** * Equivalent of calling {@code query(contentResolver, projection, null, null)}. */ public AddressCursor query(ContentResolver contentResolver) { return query(contentResolver, null, null); } public AddressSelection id(long... value) { addEquals("address." + AddressColumns._ID, toObjectArray(value)); return this; } public AddressSelection contactId(long... value) { addEquals(AddressColumns.CONTACT_ID, toObjectArray(value)); return this; } public AddressSelection contactIdNot(long... value) { addNotEquals(AddressColumns.CONTACT_ID, toObjectArray(value)); return this; } public AddressSelection contactIdGt(long value) { addGreaterThan(AddressColumns.CONTACT_ID, value); return this; } public AddressSelection contactIdGtEq(long value) { addGreaterThanOrEquals(AddressColumns.CONTACT_ID, value); return this; } public AddressSelection contactIdLt(long value) { addLessThan(AddressColumns.CONTACT_ID, value); return this; } public AddressSelection contactIdLtEq(long value) { addLessThanOrEquals(AddressColumns.CONTACT_ID, value); return this; } public AddressSelection contactUid(String... value) { addEquals(ContactColumns.UID, value); return this; } public AddressSelection contactUidNot(String... value) { addNotEquals(ContactColumns.UID, value); return this; } public AddressSelection contactUidLike(String... value) { addLike(ContactColumns.UID, value); return this; } public AddressSelection contactUidContains(String... value) { addContains(ContactColumns.UID, value); return this; } public AddressSelection contactUidStartsWith(String... value) { addStartsWith(ContactColumns.UID, value); return this; } public AddressSelection contactUidEndsWith(String... value) { addEndsWith(ContactColumns.UID, value); return this; } public AddressSelection contactFirstName(String... value) { addEquals(ContactColumns.FIRST_NAME, value); return this; } public AddressSelection contactFirstNameNot(String... value) { addNotEquals(ContactColumns.FIRST_NAME, value); return this; } public AddressSelection contactFirstNameLike(String... value) { addLike(ContactColumns.FIRST_NAME, value); return this; } public AddressSelection contactFirstNameContains(String... value) { addContains(ContactColumns.FIRST_NAME, value); return this; } public AddressSelection contactFirstNameStartsWith(String... value) { addStartsWith(ContactColumns.FIRST_NAME, value); return this; } public AddressSelection contactFirstNameEndsWith(String... value) { addEndsWith(ContactColumns.FIRST_NAME, value); return this; } public AddressSelection contactLastName(String... value) { addEquals(ContactColumns.LAST_NAME, value); return this; } public AddressSelection contactLastNameNot(String... value) { addNotEquals(ContactColumns.LAST_NAME, value); return this; } public AddressSelection contactLastNameLike(String... value) { addLike(ContactColumns.LAST_NAME, value); return this; } public AddressSelection contactLastNameContains(String... value) { addContains(ContactColumns.LAST_NAME, value); return this; } public AddressSelection contactLastNameStartsWith(String... value) { addStartsWith(ContactColumns.LAST_NAME, value); return this; } public AddressSelection contactLastNameEndsWith(String... value) { addEndsWith(ContactColumns.LAST_NAME, value); return this; } public AddressSelection contactBirthdate(Date... value) { addEquals(ContactColumns.BIRTHDATE, value); return this; } public AddressSelection contactBirthdateNot(Date... value) { addNotEquals(ContactColumns.BIRTHDATE, value); return this; } public AddressSelection contactBirthdate(Long... value) { addEquals(ContactColumns.BIRTHDATE, value); return this; } public AddressSelection contactBirthdateAfter(Date value) { addGreaterThan(ContactColumns.BIRTHDATE, value); return this; } public AddressSelection contactBirthdateAfterEq(Date value) { addGreaterThanOrEquals(ContactColumns.BIRTHDATE, value); return this; } public AddressSelection contactBirthdateBefore(Date value) { addLessThan(ContactColumns.BIRTHDATE, value); return this; } public AddressSelection contactBirthdateBeforeEq(Date value) { addLessThanOrEquals(ContactColumns.BIRTHDATE, value); return this; } public AddressSelection street(String... value) { addEquals(AddressColumns.STREET, value); return this; } public AddressSelection streetNot(String... value) { addNotEquals(AddressColumns.STREET, value); return this; } public AddressSelection streetLike(String... value) { addLike(AddressColumns.STREET, value); return this; } public AddressSelection streetContains(String... value) { addContains(AddressColumns.STREET, value); return this; } public AddressSelection streetStartsWith(String... value) { addStartsWith(AddressColumns.STREET, value); return this; } public AddressSelection streetEndsWith(String... value) { addEndsWith(AddressColumns.STREET, value); return this; } public AddressSelection number(String... value) { addEquals(AddressColumns.NUMBER, value); return this; } public AddressSelection numberNot(String... value) { addNotEquals(AddressColumns.NUMBER, value); return this; } public AddressSelection numberLike(String... value) { addLike(AddressColumns.NUMBER, value); return this; } public AddressSelection numberContains(String... value) { addContains(AddressColumns.NUMBER, value); return this; } public AddressSelection numberStartsWith(String... value) { addStartsWith(AddressColumns.NUMBER, value); return this; } public AddressSelection numberEndsWith(String... value) { addEndsWith(AddressColumns.NUMBER, value); return this; } public AddressSelection city(String... value) { addEquals(AddressColumns.CITY, value); return this; } public AddressSelection cityNot(String... value) { addNotEquals(AddressColumns.CITY, value); return this; } public AddressSelection cityLike(String... value) { addLike(AddressColumns.CITY, value); return this; } public AddressSelection cityContains(String... value) { addContains(AddressColumns.CITY, value); return this; } public AddressSelection cityStartsWith(String... value) { addStartsWith(AddressColumns.CITY, value); return this; } public AddressSelection cityEndsWith(String... value) { addEndsWith(AddressColumns.CITY, value); return this; } public AddressSelection country(String... value) { addEquals(AddressColumns.COUNTRY, value); return this; } public AddressSelection countryNot(String... value) { addNotEquals(AddressColumns.COUNTRY, value); return this; } public AddressSelection countryLike(String... value) { addLike(AddressColumns.COUNTRY, value); return this; } public AddressSelection countryContains(String... value) { addContains(AddressColumns.COUNTRY, value); return this; } public AddressSelection countryStartsWith(String... value) { addStartsWith(AddressColumns.COUNTRY, value); return this; } public AddressSelection countryEndsWith(String... value) { addEndsWith(AddressColumns.COUNTRY, value); return this; } public AddressSelection state(String... value) { addEquals(AddressColumns.STATE, value); return this; } public AddressSelection stateNot(String... value) { addNotEquals(AddressColumns.STATE, value); return this; } public AddressSelection stateLike(String... value) { addLike(AddressColumns.STATE, value); return this; } public AddressSelection stateContains(String... value) { addContains(AddressColumns.STATE, value); return this; } public AddressSelection stateStartsWith(String... value) { addStartsWith(AddressColumns.STATE, value); return this; } public AddressSelection stateEndsWith(String... value) { addEndsWith(AddressColumns.STATE, value); return this; } public AddressSelection postalcode(String... value) { addEquals(AddressColumns.POSTALCODE, value); return this; } public AddressSelection postalcodeNot(String... value) { addNotEquals(AddressColumns.POSTALCODE, value); return this; } public AddressSelection postalcodeLike(String... value) { addLike(AddressColumns.POSTALCODE, value); return this; } public AddressSelection postalcodeContains(String... value) { addContains(AddressColumns.POSTALCODE, value); return this; } public AddressSelection postalcodeStartsWith(String... value) { addStartsWith(AddressColumns.POSTALCODE, value); return this; } public AddressSelection postalcodeEndsWith(String... value) { addEndsWith(AddressColumns.POSTALCODE, value); return this; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/base/AbstractContentValues.java ================================================ package com.example.project.database.provider.base; import android.content.ContentResolver; import android.content.ContentValues; import android.net.Uri; public abstract class AbstractContentValues { protected final ContentValues mContentValues = new ContentValues(); /** * Returns the {@code uri} argument to pass to the {@code ContentResolver} methods. */ public abstract Uri uri(); /** * Returns the {@code ContentValues} wrapped by this object. */ public ContentValues values() { return mContentValues; } /** * Inserts a row into a table using the values stored by this object. * * @param contentResolver The content resolver to use. */ public Uri insert(ContentResolver contentResolver) { return contentResolver.insert(uri(), values()); } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/base/AbstractCursor.java ================================================ package com.example.project.database.provider.base; import java.util.Date; import java.util.HashMap; import android.database.Cursor; import android.database.CursorWrapper; import android.provider.BaseColumns; public abstract class AbstractCursor extends CursorWrapper { private final HashMap mColumnIndexes; public AbstractCursor(Cursor cursor) { super(cursor); mColumnIndexes = new HashMap(cursor.getColumnCount() * 4 / 3, .75f); } public abstract long getId(); protected int getCachedColumnIndexOrThrow(String colName) { Integer index = mColumnIndexes.get(colName); if (index == null) { index = getColumnIndexOrThrow(colName); mColumnIndexes.put(colName, index); } return index; } public String getStringOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return getString(index); } public Integer getIntegerOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return getInt(index); } public Long getLongOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return getLong(index); } public Float getFloatOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return getFloat(index); } public Double getDoubleOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return getDouble(index); } public Boolean getBooleanOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return getInt(index) != 0; } public Date getDateOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return new Date(getLong(index)); } public byte[] getBlobOrNull(String colName) { int index = getCachedColumnIndexOrThrow(colName); if (isNull(index)) return null; return getBlob(index); } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/base/AbstractSelection.java ================================================ package com.example.project.database.provider.base; import java.util.ArrayList; import java.util.Date; import java.util.List; import android.content.ContentResolver; import android.net.Uri; public abstract class AbstractSelection> { private static final String EQ = "=?"; private static final String PAREN_OPEN = "("; private static final String PAREN_CLOSE = ")"; private static final String AND = " AND "; private static final String OR = " OR "; private static final String IS_NULL = " IS NULL"; private static final String IS_NOT_NULL = " IS NOT NULL"; private static final String IN = " IN ("; private static final String NOT_IN = " NOT IN ("; private static final String COMMA = ","; private static final String GT = ">?"; private static final String LT = "=?"; private static final String LT_EQ = "<=?"; private static final String NOT_EQ = "<>?"; private static final String LIKE = " LIKE ?"; private static final String CONTAINS = " LIKE '%' || ? || '%'"; private static final String STARTS = " LIKE ? || '%'"; private static final String ENDS = " LIKE '%' || ?"; private final StringBuilder mSelection = new StringBuilder(); private final List mSelectionArgs = new ArrayList(5); Boolean mNotify; String mGroupBy; String mHaving; Integer mLimit; protected void addEquals(String column, Object[] value) { mSelection.append(column); if (value == null) { // Single null value mSelection.append(IS_NULL); } else if (value.length > 1) { // Multiple values ('in' clause) mSelection.append(IN); for (int i = 0; i < value.length; i++) { mSelection.append("?"); if (i < value.length - 1) { mSelection.append(COMMA); } mSelectionArgs.add(valueOf(value[i])); } mSelection.append(PAREN_CLOSE); } else { // Single value if (value[0] == null) { // Single null value mSelection.append(IS_NULL); } else { // Single not null value mSelection.append(EQ); mSelectionArgs.add(valueOf(value[0])); } } } protected void addNotEquals(String column, Object[] value) { mSelection.append(column); if (value == null) { // Single null value mSelection.append(IS_NOT_NULL); } else if (value.length > 1) { // Multiple values ('in' clause) mSelection.append(NOT_IN); for (int i = 0; i < value.length; i++) { mSelection.append("?"); if (i < value.length - 1) { mSelection.append(COMMA); } mSelectionArgs.add(valueOf(value[i])); } mSelection.append(PAREN_CLOSE); } else { // Single value if (value[0] == null) { // Single null value mSelection.append(IS_NOT_NULL); } else { // Single not null value mSelection.append(NOT_EQ); mSelectionArgs.add(valueOf(value[0])); } } } protected void addLike(String column, String[] values) { mSelection.append(PAREN_OPEN); for (int i = 0; i < values.length; i++) { mSelection.append(column); mSelection.append(LIKE); mSelectionArgs.add(values[i]); if (i < values.length - 1) { mSelection.append(OR); } } mSelection.append(PAREN_CLOSE); } protected void addContains(String column, String[] values) { mSelection.append(PAREN_OPEN); for (int i = 0; i < values.length; i++) { mSelection.append(column); mSelection.append(CONTAINS); mSelectionArgs.add(values[i]); if (i < values.length - 1) { mSelection.append(OR); } } mSelection.append(PAREN_CLOSE); } protected void addStartsWith(String column, String[] values) { mSelection.append(PAREN_OPEN); for (int i = 0; i < values.length; i++) { mSelection.append(column); mSelection.append(STARTS); mSelectionArgs.add(values[i]); if (i < values.length - 1) { mSelection.append(OR); } } mSelection.append(PAREN_CLOSE); } protected void addEndsWith(String column, String[] values) { mSelection.append(PAREN_OPEN); for (int i = 0; i < values.length; i++) { mSelection.append(column); mSelection.append(ENDS); mSelectionArgs.add(values[i]); if (i < values.length - 1) { mSelection.append(OR); } } mSelection.append(PAREN_CLOSE); } protected void addGreaterThan(String column, Object value) { mSelection.append(column); mSelection.append(GT); mSelectionArgs.add(valueOf(value)); } protected void addGreaterThanOrEquals(String column, Object value) { mSelection.append(column); mSelection.append(GT_EQ); mSelectionArgs.add(valueOf(value)); } protected void addLessThan(String column, Object value) { mSelection.append(column); mSelection.append(LT); mSelectionArgs.add(valueOf(value)); } protected void addLessThanOrEquals(String column, Object value) { mSelection.append(column); mSelection.append(LT_EQ); mSelectionArgs.add(valueOf(value)); } public void addRaw(String raw, Object... args) { mSelection.append(" "); mSelection.append(raw); mSelection.append(" "); for (Object arg : args) { mSelectionArgs.add(valueOf(arg)); } } private String valueOf(Object obj) { if (obj instanceof Date) { return String.valueOf(((Date) obj).getTime()); } else if (obj instanceof Boolean) { return (Boolean) obj ? "1" : "0"; } else if (obj instanceof Enum) { return String.valueOf(((Enum) obj).ordinal()); } return String.valueOf(obj); } @SuppressWarnings("unchecked") public T openParen() { mSelection.append(PAREN_OPEN); return (T) this; } @SuppressWarnings("unchecked") public T closeParen() { mSelection.append(PAREN_CLOSE); return (T) this; } @SuppressWarnings("unchecked") public T and() { mSelection.append(AND); return (T) this; } @SuppressWarnings("unchecked") public T or() { mSelection.append(OR); return (T) this; } protected Object[] toObjectArray(int... array) { Object[] res = new Object[array.length]; for (int i = 0; i < array.length; i++) { res[i] = array[i]; } return res; } protected Object[] toObjectArray(long... array) { Object[] res = new Object[array.length]; for (int i = 0; i < array.length; i++) { res[i] = array[i]; } return res; } protected Object[] toObjectArray(float... array) { Object[] res = new Object[array.length]; for (int i = 0; i < array.length; i++) { res[i] = array[i]; } return res; } protected Object[] toObjectArray(double... array) { Object[] res = new Object[array.length]; for (int i = 0; i < array.length; i++) { res[i] = array[i]; } return res; } protected Object[] toObjectArray(Boolean value) { return new Object[] { value }; } /** * Returns the selection produced by this object. */ public String sel() { return mSelection.toString(); } /** * Returns the selection arguments produced by this object. */ public String[] args() { int size = mSelectionArgs.size(); if (size == 0) return null; return mSelectionArgs.toArray(new String[size]); } /** * Returns the {@code uri} argument to pass to the {@code ContentResolver} methods. */ public Uri uri() { Uri uri = baseUri(); if (mNotify != null) uri = BaseContentProvider.notify(uri, mNotify); if (mGroupBy != null) uri = BaseContentProvider.groupBy(uri, mGroupBy); if (mHaving != null) uri = BaseContentProvider.having(uri, mHaving); if (mLimit != null) uri = BaseContentProvider.limit(uri, String.valueOf(mLimit)); return uri; } protected abstract Uri baseUri(); /** * Deletes row(s) specified by this selection. * * @param contentResolver The content resolver to use. * @return The number of rows deleted. */ public int delete(ContentResolver contentResolver) { return contentResolver.delete(uri(), sel(), args()); } @SuppressWarnings("unchecked") public T notify(boolean notify) { mNotify = notify; return (T) this; } @SuppressWarnings("unchecked") public T groupBy(String groupBy) { mGroupBy = groupBy; return (T) this; } @SuppressWarnings("unchecked") public T having(String having) { mHaving = having; return (T) this; } @SuppressWarnings("unchecked") public T limit(int limit) { mLimit = limit; return (T) this; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/base/BaseContentProvider.java ================================================ package com.example.project.database.provider.base; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashSet; import android.content.ContentProvider; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentValues; import android.content.OperationApplicationException; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.provider.BaseColumns; import android.support.annotation.NonNull; import android.util.Log; public abstract class BaseContentProvider extends ContentProvider { public static final String QUERY_NOTIFY = "QUERY_NOTIFY"; public static final String QUERY_GROUP_BY = "QUERY_GROUP_BY"; public static final String QUERY_HAVING = "QUERY_HAVING"; public static final String QUERY_LIMIT = "QUERY_LIMIT"; public static class QueryParams { public String table; public String tablesWithJoins; public String idColumn; public String selection; public String orderBy; } protected abstract QueryParams getQueryParams(Uri uri, String selection, String[] projection); protected abstract boolean hasDebug(); protected abstract SQLiteOpenHelper createSqLiteOpenHelper(); protected SQLiteOpenHelper mSqLiteOpenHelper; @Override public final boolean onCreate() { if (hasDebug()) { // Enable logging of SQL statements as they are executed. try { Class sqliteDebugClass = Class.forName("android.database.sqlite.SQLiteDebug"); Field field = sqliteDebugClass.getDeclaredField("DEBUG_SQL_STATEMENTS"); field.setAccessible(true); field.set(null, true); // Uncomment the following block if you also want logging of execution time (more verbose) // field = sqliteDebugClass.getDeclaredField("DEBUG_SQL_TIME"); // field.setAccessible(true); // field.set(null, true); } catch (Throwable t) { if (hasDebug()) Log.w(getClass().getSimpleName(), "Could not enable SQLiteDebug logging", t); } } mSqLiteOpenHelper = createSqLiteOpenHelper(); return false; } @Override public Uri insert(Uri uri, ContentValues values) { String table = uri.getLastPathSegment(); long rowId = mSqLiteOpenHelper.getWritableDatabase().insertOrThrow(table, null, values); if (rowId == -1) return null; String notify; if (((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) { getContext().getContentResolver().notifyChange(uri, null); } return uri.buildUpon().appendEncodedPath(String.valueOf(rowId)).build(); } @Override public int bulkInsert(Uri uri, ContentValues[] values) { String table = uri.getLastPathSegment(); SQLiteDatabase db = mSqLiteOpenHelper.getWritableDatabase(); int res = 0; db.beginTransaction(); try { for (ContentValues v : values) { long id = db.insert(table, null, v); db.yieldIfContendedSafely(); if (id != -1) { res++; } } db.setTransactionSuccessful(); } finally { db.endTransaction(); } String notify; if (res != 0 && ((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) { getContext().getContentResolver().notifyChange(uri, null); } return res; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { QueryParams queryParams = getQueryParams(uri, selection, null); int res = mSqLiteOpenHelper.getWritableDatabase().update(queryParams.table, values, queryParams.selection, selectionArgs); String notify; if (res != 0 && ((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) { getContext().getContentResolver().notifyChange(uri, null); } return res; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { QueryParams queryParams = getQueryParams(uri, selection, null); int res = mSqLiteOpenHelper.getWritableDatabase().delete(queryParams.table, queryParams.selection, selectionArgs); String notify; if (res != 0 && ((notify = uri.getQueryParameter(QUERY_NOTIFY)) == null || "true".equals(notify))) { getContext().getContentResolver().notifyChange(uri, null); } return res; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { String groupBy = uri.getQueryParameter(QUERY_GROUP_BY); String having = uri.getQueryParameter(QUERY_HAVING); String limit = uri.getQueryParameter(QUERY_LIMIT); QueryParams queryParams = getQueryParams(uri, selection, projection); projection = ensureIdIsFullyQualified(projection, queryParams.table, queryParams.idColumn); Cursor res = mSqLiteOpenHelper.getReadableDatabase().query(queryParams.tablesWithJoins, projection, queryParams.selection, selectionArgs, groupBy, having, sortOrder == null ? queryParams.orderBy : sortOrder, limit); res.setNotificationUri(getContext().getContentResolver(), uri); return res; } private String[] ensureIdIsFullyQualified(String[] projection, String tableName, String idColumn) { if (projection == null) return null; String[] res = new String[projection.length]; for (int i = 0; i < projection.length; i++) { if (projection[i].equals(idColumn)) { res[i] = tableName + "." + idColumn + " AS " + BaseColumns._ID; } else { res[i] = projection[i]; } } return res; } @Override public ContentProviderResult[] applyBatch(ArrayList operations) throws OperationApplicationException { HashSet urisToNotify = new HashSet(operations.size()); for (ContentProviderOperation operation : operations) { urisToNotify.add(operation.getUri()); } SQLiteDatabase db = mSqLiteOpenHelper.getWritableDatabase(); db.beginTransaction(); try { int numOperations = operations.size(); ContentProviderResult[] results = new ContentProviderResult[numOperations]; int i = 0; for (ContentProviderOperation operation : operations) { results[i] = operation.apply(this, results, i); if (operation.isYieldAllowed()) { db.yieldIfContendedSafely(); } i++; } db.setTransactionSuccessful(); for (Uri uri : urisToNotify) { getContext().getContentResolver().notifyChange(uri, null); } return results; } finally { db.endTransaction(); } } public static Uri notify(Uri uri, boolean notify) { return uri.buildUpon().appendQueryParameter(QUERY_NOTIFY, String.valueOf(notify)).build(); } public static Uri groupBy(Uri uri, String groupBy) { return uri.buildUpon().appendQueryParameter(QUERY_GROUP_BY, groupBy).build(); } public static Uri having(Uri uri, String having) { return uri.buildUpon().appendQueryParameter(QUERY_HAVING, having).build(); } public static Uri limit(Uri uri, String limit) { return uri.buildUpon().appendQueryParameter(QUERY_LIMIT, limit).build(); } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/base/BaseModel.java ================================================ package com.example.project.database.provider.base; public interface BaseModel { } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/contact/ContactColumns.java ================================================ package com.example.project.database.provider.contact; import android.net.Uri; import android.provider.BaseColumns; import com.example.project.database.provider.ExampleProvider; import com.example.project.database.provider.address.AddressColumns; import com.example.project.database.provider.contact.ContactColumns; /** * Columns for the {@code contact} table. */ public class ContactColumns implements BaseColumns { public static final String TABLE_NAME = "contact"; public static final Uri CONTENT_URI = Uri.parse(ExampleProvider.CONTENT_URI_BASE + "/" + TABLE_NAME); /** * Primary key. */ public static final String _ID = BaseColumns._ID; public static final String UID = "uid"; public static final String FIRST_NAME = "first_name"; public static final String LAST_NAME = "last_name"; public static final String BIRTHDATE = "birthdate"; public static final String DEFAULT_ORDER = TABLE_NAME + "." +_ID; // @formatter:off public static final String[] ALL_COLUMNS = new String[] { _ID, UID, FIRST_NAME, LAST_NAME, BIRTHDATE }; // @formatter:on public static boolean hasColumns(String[] projection) { if (projection == null) return true; for (String c : projection) { if (c.equals(UID) || c.contains("." + UID)) return true; if (c.equals(FIRST_NAME) || c.contains("." + FIRST_NAME)) return true; if (c.equals(LAST_NAME) || c.contains("." + LAST_NAME)) return true; if (c.equals(BIRTHDATE) || c.contains("." + BIRTHDATE)) return true; } return false; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/contact/ContactContentValues.java ================================================ package com.example.project.database.provider.contact; import java.util.Date; import android.content.ContentResolver; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.example.project.database.provider.base.AbstractContentValues; /** * Content values wrapper for the {@code contact} table. */ public class ContactContentValues extends AbstractContentValues { @Override public Uri uri() { return ContactColumns.CONTENT_URI; } /** * Update row(s) using the values stored by this object and the given selection. * * @param contentResolver The content resolver to use. * @param where The selection to use (can be {@code null}). */ public int update(ContentResolver contentResolver, @Nullable ContactSelection where) { return contentResolver.update(uri(), values(), where == null ? null : where.sel(), where == null ? null : where.args()); } public ContactContentValues putUid(@Nullable String value) { mContentValues.put(ContactColumns.UID, value); return this; } public ContactContentValues putUidNull() { mContentValues.putNull(ContactColumns.UID); return this; } public ContactContentValues putFirstName(@Nullable String value) { mContentValues.put(ContactColumns.FIRST_NAME, value); return this; } public ContactContentValues putFirstNameNull() { mContentValues.putNull(ContactColumns.FIRST_NAME); return this; } public ContactContentValues putLastName(@Nullable String value) { mContentValues.put(ContactColumns.LAST_NAME, value); return this; } public ContactContentValues putLastNameNull() { mContentValues.putNull(ContactColumns.LAST_NAME); return this; } public ContactContentValues putBirthdate(@Nullable Date value) { mContentValues.put(ContactColumns.BIRTHDATE, value == null ? null : value.getTime()); return this; } public ContactContentValues putBirthdateNull() { mContentValues.putNull(ContactColumns.BIRTHDATE); return this; } public ContactContentValues putBirthdate(@Nullable Long value) { mContentValues.put(ContactColumns.BIRTHDATE, value); return this; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/contact/ContactCursor.java ================================================ package com.example.project.database.provider.contact; import java.util.Date; import android.database.Cursor; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.example.project.database.provider.base.AbstractCursor; /** * Cursor wrapper for the {@code contact} table. */ public class ContactCursor extends AbstractCursor implements ContactModel { public ContactCursor(Cursor cursor) { super(cursor); } /** * Primary key. */ public long getId() { Long res = getLongOrNull(ContactColumns._ID); if (res == null) throw new NullPointerException("The value of '_id' in the database was null, which is not allowed according to the model definition"); return res; } /** * Get the {@code uid} value. * Can be {@code null}. */ @Nullable public String getUid() { String res = getStringOrNull(ContactColumns.UID); return res; } /** * Get the {@code first_name} value. * Can be {@code null}. */ @Nullable public String getFirstName() { String res = getStringOrNull(ContactColumns.FIRST_NAME); return res; } /** * Get the {@code last_name} value. * Can be {@code null}. */ @Nullable public String getLastName() { String res = getStringOrNull(ContactColumns.LAST_NAME); return res; } /** * Get the {@code birthdate} value. * Can be {@code null}. */ @Nullable public Date getBirthdate() { Date res = getDateOrNull(ContactColumns.BIRTHDATE); return res; } } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/contact/ContactModel.java ================================================ package com.example.project.database.provider.contact; import com.example.project.database.provider.base.BaseModel; import java.util.Date; import android.support.annotation.NonNull; import android.support.annotation.Nullable; /** * Data model for the {@code contact} table. */ public interface ContactModel extends BaseModel { /** * Get the {@code uid} value. * Can be {@code null}. */ @Nullable String getUid(); /** * Get the {@code first_name} value. * Can be {@code null}. */ @Nullable String getFirstName(); /** * Get the {@code last_name} value. * Can be {@code null}. */ @Nullable String getLastName(); /** * Get the {@code birthdate} value. * Can be {@code null}. */ @Nullable Date getBirthdate(); } ================================================ FILE: app/src/gen/java/com/example/project/database/provider/contact/ContactSelection.java ================================================ package com.example.project.database.provider.contact; import java.util.Date; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import com.example.project.database.provider.base.AbstractSelection; /** * Selection for the {@code contact} table. */ public class ContactSelection extends AbstractSelection { @Override protected Uri baseUri() { return ContactColumns.CONTENT_URI; } /** * Query the given content resolver using this selection. * * @param contentResolver The content resolver to query. * @param projection A list of which columns to return. Passing null will return all columns, which is inefficient. * @param sortOrder How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort * order, which may be unordered. * @return A {@code ContactCursor} object, which is positioned before the first entry, or null. */ public ContactCursor query(ContentResolver contentResolver, String[] projection, String sortOrder) { Cursor cursor = contentResolver.query(uri(), projection, sel(), args(), sortOrder); if (cursor == null) return null; return new ContactCursor(cursor); } /** * Equivalent of calling {@code query(contentResolver, projection, null)}. */ public ContactCursor query(ContentResolver contentResolver, String[] projection) { return query(contentResolver, projection, null); } /** * Equivalent of calling {@code query(contentResolver, projection, null, null)}. */ public ContactCursor query(ContentResolver contentResolver) { return query(contentResolver, null, null); } public ContactSelection id(long... value) { addEquals("contact." + ContactColumns._ID, toObjectArray(value)); return this; } public ContactSelection uid(String... value) { addEquals(ContactColumns.UID, value); return this; } public ContactSelection uidNot(String... value) { addNotEquals(ContactColumns.UID, value); return this; } public ContactSelection uidLike(String... value) { addLike(ContactColumns.UID, value); return this; } public ContactSelection uidContains(String... value) { addContains(ContactColumns.UID, value); return this; } public ContactSelection uidStartsWith(String... value) { addStartsWith(ContactColumns.UID, value); return this; } public ContactSelection uidEndsWith(String... value) { addEndsWith(ContactColumns.UID, value); return this; } public ContactSelection firstName(String... value) { addEquals(ContactColumns.FIRST_NAME, value); return this; } public ContactSelection firstNameNot(String... value) { addNotEquals(ContactColumns.FIRST_NAME, value); return this; } public ContactSelection firstNameLike(String... value) { addLike(ContactColumns.FIRST_NAME, value); return this; } public ContactSelection firstNameContains(String... value) { addContains(ContactColumns.FIRST_NAME, value); return this; } public ContactSelection firstNameStartsWith(String... value) { addStartsWith(ContactColumns.FIRST_NAME, value); return this; } public ContactSelection firstNameEndsWith(String... value) { addEndsWith(ContactColumns.FIRST_NAME, value); return this; } public ContactSelection lastName(String... value) { addEquals(ContactColumns.LAST_NAME, value); return this; } public ContactSelection lastNameNot(String... value) { addNotEquals(ContactColumns.LAST_NAME, value); return this; } public ContactSelection lastNameLike(String... value) { addLike(ContactColumns.LAST_NAME, value); return this; } public ContactSelection lastNameContains(String... value) { addContains(ContactColumns.LAST_NAME, value); return this; } public ContactSelection lastNameStartsWith(String... value) { addStartsWith(ContactColumns.LAST_NAME, value); return this; } public ContactSelection lastNameEndsWith(String... value) { addEndsWith(ContactColumns.LAST_NAME, value); return this; } public ContactSelection birthdate(Date... value) { addEquals(ContactColumns.BIRTHDATE, value); return this; } public ContactSelection birthdateNot(Date... value) { addNotEquals(ContactColumns.BIRTHDATE, value); return this; } public ContactSelection birthdate(Long... value) { addEquals(ContactColumns.BIRTHDATE, value); return this; } public ContactSelection birthdateAfter(Date value) { addGreaterThan(ContactColumns.BIRTHDATE, value); return this; } public ContactSelection birthdateAfterEq(Date value) { addGreaterThanOrEquals(ContactColumns.BIRTHDATE, value); return this; } public ContactSelection birthdateBefore(Date value) { addLessThan(ContactColumns.BIRTHDATE, value); return this; } public ContactSelection birthdateBeforeEq(Date value) { addLessThanOrEquals(ContactColumns.BIRTHDATE, value); return this; } } ================================================ FILE: app/src/gen/java/com/example/project/network/json/ContactJson.java ================================================ package com.example.project.network.json; import java.util.HashMap; import java.util.Map; import javax.annotation.Generated; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; /** * Simple single contact. * */ @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({ "id", "firstName", "lastName", "birthDate" }) public class ContactJson { @JsonProperty("id") private String id; @JsonProperty("firstName") private String firstName; @JsonProperty("lastName") private String lastName; @JsonProperty("birthDate") private String birthDate; @JsonIgnore private Map additionalProperties = new HashMap(); /** * * @return * The id */ @JsonProperty("id") public String getId() { return id; } /** * * @param id * The id */ @JsonProperty("id") public void setId(String id) { this.id = id; } /** * * @return * The firstName */ @JsonProperty("firstName") public String getFirstName() { return firstName; } /** * * @param firstName * The firstName */ @JsonProperty("firstName") public void setFirstName(String firstName) { this.firstName = firstName; } /** * * @return * The lastName */ @JsonProperty("lastName") public String getLastName() { return lastName; } /** * * @param lastName * The lastName */ @JsonProperty("lastName") public void setLastName(String lastName) { this.lastName = lastName; } /** * * @return * The birthDate */ @JsonProperty("birthDate") public String getBirthDate() { return birthDate; } /** * * @param birthDate * The birthDate */ @JsonProperty("birthDate") public void setBirthDate(String birthDate) { this.birthDate = birthDate; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter public void setAdditionalProperty(String name, Object value) { this.additionalProperties.put(name, value); } @Override public int hashCode() { return new HashCodeBuilder().append(id).append(firstName).append(lastName).append(birthDate).append(additionalProperties).toHashCode(); } @Override public boolean equals(Object other) { if (other == this) { return true; } if ((other instanceof ContactJson) == false) { return false; } ContactJson rhs = ((ContactJson) other); return new EqualsBuilder().append(id, rhs.id).append(firstName, rhs.firstName).append(lastName, rhs.lastName).append(birthDate, rhs.birthDate).append(additionalProperties, rhs.additionalProperties).isEquals(); } } ================================================ FILE: app/src/gen/java/com/example/project/network/json/ContactListJson.java ================================================ package com.example.project.network.json; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Generated; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; /** * Collection of contacts. * */ @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({ "contacts" }) public class ContactListJson { @JsonProperty("contacts") private List contacts = new ArrayList(); @JsonIgnore private Map additionalProperties = new HashMap(); /** * * @return * The contacts */ @JsonProperty("contacts") public List getContacts() { return contacts; } /** * * @param contacts * The contacts */ @JsonProperty("contacts") public void setContacts(List contacts) { this.contacts = contacts; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter public void setAdditionalProperty(String name, Object value) { this.additionalProperties.put(name, value); } @Override public int hashCode() { return new HashCodeBuilder().append(contacts).append(additionalProperties).toHashCode(); } @Override public boolean equals(Object other) { if (other == this) { return true; } if ((other instanceof ContactListJson) == false) { return false; } ContactListJson rhs = ((ContactListJson) other); return new EqualsBuilder().append(contacts, rhs.contacts).append(additionalProperties, rhs.additionalProperties).isEquals(); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/example/project/business/contact/CreateContactFunction.java ================================================ package com.example.project.business.contact; import com.example.project.database.provider.contact.ContactContentValues; import com.example.project.database.contact.ContactDb; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; import java.util.Date; @EBean public class CreateContactFunction { @Bean ContactDb contactDb; public void apply(String firstName, String lastName, Date birthDate) { apply("", firstName, lastName, birthDate); } public void apply(String uid, String firstName, String lastName, Date birthDate) { ContactContentValues contentValues = contactDb.insertDataContainer(); contentValues.putUid(uid); contentValues.putFirstName(firstName); contentValues.putLastName(lastName); contentValues.putBirthdate(birthDate); contactDb.insert(contentValues); } } ================================================ FILE: app/src/main/java/com/example/project/business/contact/DeleteContactFunction.java ================================================ package com.example.project.business.contact; import org.androidannotations.annotations.EBean; @EBean public class DeleteContactFunction { } ================================================ FILE: app/src/main/java/com/example/project/business/contact/QueryContactFunction.java ================================================ package com.example.project.business.contact; import android.support.annotation.Nullable; import com.example.project.database.contact.ContactDb; import com.example.project.database.provider.contact.ContactCursor; import com.example.project.database.provider.contact.ContactModel; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; import java.util.Date; @EBean public class QueryContactFunction { @Bean ContactDb contactDb; public ContactModel apply(long contactId) { ContactCursor contactCursor = contactDb.queryById(contactId); return createContactModel(contactCursor); } public ContactModel applyByUid(String contactUid) { ContactCursor contactCursor = contactDb.queryByUid(contactUid); return createContactModel(contactCursor); } private ContactModel createContactModel(ContactCursor contactCursor) { if(!contactCursor.moveToFirst()) { return null; } final String contactUid = contactCursor.getUid(); final String firstName = contactCursor.getFirstName(); final String lastName = contactCursor.getLastName(); final Date birthDate = contactCursor.getBirthdate(); contactCursor.close(); return new ContactModel() { @Nullable @Override public String getUid() { return contactUid; } @Nullable @Override public String getFirstName() { return firstName; } @Nullable @Override public String getLastName() { return lastName; } @Nullable @Override public Date getBirthdate() { return birthDate; } }; } } ================================================ FILE: app/src/main/java/com/example/project/business/contact/QueryContactListFunction.java ================================================ package com.example.project.business.contact; import com.example.project.database.provider.contact.ContactCursor; import com.example.project.database.contact.ContactDb; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; @EBean public class QueryContactListFunction { @Bean ContactDb contactDb; public ContactCursor apply() { return contactDb.queryAll(); } } ================================================ FILE: app/src/main/java/com/example/project/business/contact/UpdateContactFunction.java ================================================ package com.example.project.business.contact; import org.androidannotations.annotations.EBean; @EBean public class UpdateContactFunction { } ================================================ FILE: app/src/main/java/com/example/project/business/contact_sync/SyncContactsFunction.java ================================================ package com.example.project.business.contact_sync; import com.example.project.business.contact.CreateContactFunction; import com.example.project.business.contact.QueryContactFunction; import com.example.project.database.provider.contact.ContactModel; import com.example.project.network.contact.ContactRestClient; import com.example.project.network.json.ContactJson; import com.example.project.network.json.ContactListJson; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.rest.RestService; import org.apache.http.conn.HttpHostConnectException; import org.joda.time.DateTime; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestClientException; import java.util.Date; @EBean public class SyncContactsFunction { @RestService ContactRestClient contactRestClient; @Bean QueryContactFunction queryContactFunction; @Bean CreateContactFunction createContactFunction; public static class Result { public boolean successful; public String errorReason; public Result(String errorReason) { this.errorReason = errorReason; successful = false; } public Result() { successful = true; } } public Result apply() { try { ResponseEntity contacts = contactRestClient.getContacts(); if (contacts.getStatusCode() == HttpStatus.OK) { syncContactsToDatabase(contacts.getBody()); return new Result(); } else { return new Result("unknown"); } } catch (RestClientException e) { return new Result(e.getMessage()); } } private void syncContactsToDatabase(ContactListJson contacts) { for (ContactJson contact : contacts.getContacts()) { ContactModel contactModel = queryContactFunction.applyByUid(contact.getId()); if (contactModel == null) { String uid = contact.getId(); String firstName = contact.getFirstName(); String lastName = contact.getLastName(); Date birthDate = DateTime.parse(contact.getBirthDate()).toDate(); createContactFunction.apply(uid, firstName, lastName, birthDate); } } } } ================================================ FILE: app/src/main/java/com/example/project/database/ExampleDbProvider.java ================================================ package com.example.project.database; import com.example.project.database.provider.ExampleProvider; import org.androidannotations.annotations.EProvider; @EProvider public class ExampleDbProvider extends ExampleProvider { } ================================================ FILE: app/src/main/java/com/example/project/database/ExampleSQLiteOpenHelperCallbacks.java ================================================ package com.example.project.database; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import com.example.project.BuildConfig; /** * Implement your custom database creation or upgrade code here. */ public class ExampleSQLiteOpenHelperCallbacks { private static final String TAG = ExampleSQLiteOpenHelperCallbacks.class.getSimpleName(); public void onOpen(final Context context, final SQLiteDatabase db) { if (BuildConfig.DEBUG) Log.d(TAG, "onOpen"); // Insert your db open code here. } public void onPreCreate(final Context context, final SQLiteDatabase db) { if (BuildConfig.DEBUG) Log.d(TAG, "onPreCreate"); // Insert your db creation code here. This is called before your tables are created. } public void onPostCreate(final Context context, final SQLiteDatabase db) { if (BuildConfig.DEBUG) Log.d(TAG, "onPostCreate"); // Insert your db creation code here. This is called after your tables are created. } public void onUpgrade(final Context context, final SQLiteDatabase db, final int oldVersion, final int newVersion) { if (BuildConfig.DEBUG) Log.d(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion); // Insert your upgrading code here. } } ================================================ FILE: app/src/main/java/com/example/project/database/contact/AddressDb.java ================================================ package com.example.project.database.contact; import android.content.ContentUris; import android.content.Context; import android.net.Uri; import com.example.project.database.provider.address.AddressColumns; import com.example.project.database.provider.address.AddressContentValues; import com.example.project.database.provider.address.AddressCursor; import com.example.project.database.provider.address.AddressSelection; import com.example.project.database.provider.contact.ContactColumns; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; import org.apache.commons.lang3.ArrayUtils; @EBean public class AddressDb { @RootContext Context context; // one join example private final String[] ALL_JOINED_COLUMNS = (String[]) ArrayUtils.addAll(AddressColumns.ALL_COLUMNS, ContactColumns.ALL_COLUMNS); public long insert(AddressContentValues contentValues) { Uri contentUri = contentValues.insert(context.getContentResolver()); return ContentUris.parseId(contentUri); } public AddressCursor queryById(long addressId) { return new AddressSelection().id(addressId).query(context.getContentResolver(), ALL_JOINED_COLUMNS); } } ================================================ FILE: app/src/main/java/com/example/project/database/contact/ContactDb.java ================================================ package com.example.project.database.contact; import android.content.ContentUris; import android.content.Context; import android.net.Uri; import com.example.project.database.provider.contact.ContactContentValues; import com.example.project.database.provider.contact.ContactCursor; import com.example.project.database.provider.contact.ContactSelection; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; @EBean public class ContactDb { @RootContext Context context; public ContactContentValues insertDataContainer() { return new ContactContentValues(); } public long insert(ContactContentValues contentValues) { Uri contentUri = contentValues.insert(context.getContentResolver()); return ContentUris.parseId(contentUri); } public ContactCursor queryAll() { return new ContactSelection().query(context.getContentResolver()); } public ContactCursor queryById(long contactId) { return new ContactSelection().id(contactId).query(context.getContentResolver()); } public ContactCursor queryByUid(String contactUid) { return new ContactSelection().uid(contactUid).query(context.getContentResolver()); } } ================================================ FILE: app/src/main/java/com/example/project/network/contact/ContactRestClient.java ================================================ package com.example.project.network.contact; import com.example.project.network.json.ContactListJson; import org.androidannotations.annotations.rest.Delete; import org.androidannotations.annotations.rest.Get; import org.androidannotations.annotations.rest.Post; import org.androidannotations.annotations.rest.Put; import org.androidannotations.annotations.rest.Rest; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.RestClientException; @Rest(converters = {MappingJackson2HttpMessageConverter.class}, interceptors = {RootUrlInterceptor.class}) public interface ContactRestClient { @Get("/contacts") ResponseEntity getContacts() throws RestClientException; @Post("/contacts") ResponseEntity createContact() throws RestClientException; @Put("/contacts/{id}") ResponseEntity updateContact(String id) throws RestClientException; @Delete("/contacts/{id}") ResponseEntity deleteContact(String id) throws RestClientException; } ================================================ FILE: app/src/main/java/com/example/project/network/contact/RootUrlInterceptor.java ================================================ package com.example.project.network.contact; import android.content.Context; import com.example.project.R; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import java.io.IOException; import java.net.URI; @EBean public class RootUrlInterceptor implements ClientHttpRequestInterceptor { @RootContext Context context; @Override public ClientHttpResponse intercept(final HttpRequest originalRequest, byte[] body, ClientHttpRequestExecution execution) throws IOException { final URI uriWithRootUrl = prependRootUrl(originalRequest.getURI()); return executeWithInterceptedUri(originalRequest, body, execution, uriWithRootUrl); } private ClientHttpResponse executeWithInterceptedUri(final HttpRequest originalRequest, byte[] body, ClientHttpRequestExecution execution, final URI uriWithRootUrl) throws IOException { HttpRequest interceptedRequest = new HttpRequest() { @Override public HttpHeaders getHeaders() { return originalRequest.getHeaders(); } @Override public HttpMethod getMethod() { return originalRequest.getMethod(); } @Override public URI getURI() { return uriWithRootUrl; } }; return execution.execute(interceptedRequest, body); } private URI prependRootUrl(URI originalUri) { return URI.create("http://" + context.getResources().getString(R.string.const_wiremock_ip) + ":1337" + originalUri.toString()); } } ================================================ FILE: app/src/main/java/com/example/project/views/common/AppIdlingResources.java ================================================ package com.example.project.views.common; import android.support.test.espresso.contrib.CountingIdlingResource; import org.androidannotations.annotations.EBean; @EBean(scope = EBean.Scope.Singleton) public class AppIdlingResources { CountingIdlingResource idlingResource = new CountingIdlingResource("AppIdlingResources"); public CountingIdlingResource getIdlingResource() { return idlingResource; } public void increment() { idlingResource.increment(); } public void decrement() { idlingResource.decrement(); } } ================================================ FILE: app/src/main/java/com/example/project/views/common/cursorloader/CursorAdapterWithCursorLoader.java ================================================ package com.example.project.views.common.cursorloader; import android.database.Cursor; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; import com.example.project.database.provider.contact.ContactCursor; import com.example.project.views.common.mvp.BaseActivityPresenter; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; /** * Simplify handling for basic cursor loader + cursor adapter combination. *

* Always listen for changes on the data source and reload new content. *

* Implement this class, add the Adapter to a AdapterView and call {@link #start()}. */ @EBean public abstract class CursorAdapterWithCursorLoader { /** * Expecting the adapter where the swap cursor method will be called. */ public abstract CursorAdapter getCursorAdapter(); /** * Provide an unique identifier for the cursor loader. */ public abstract int getLoaderId(); /** * Will be called on background when the cursor should loaded */ public abstract Cursor loadCursor(); @RootContext protected BaseActivityPresenter context; public void start() { LoaderManager loaderManager = context.getSupportLoaderManager(); Loader loader = loaderManager.getLoader(getLoaderId()); if (loader != null && !loader.isReset()) { loaderManager.restartLoader(getLoaderId(), null, createLoaderCallback()); } else { loaderManager.initLoader(getLoaderId(), null, createLoaderCallback()); } } private LoaderManager.LoaderCallbacks createLoaderCallback() { return new LoaderManager.LoaderCallbacks() { @Override public Loader onCreateLoader(int id, Bundle args) { return new CursorLoader(context) { private ForceLoadContentObserver observer = new ForceLoadContentObserver(); @Override public Cursor loadInBackground() { Cursor cursor = loadCursor(); cursor.registerContentObserver(observer); return cursor; } }; } @Override public void onLoadFinished(Loader loader, final Cursor data) { getCursorAdapter().swapCursor(data); } @Override public void onLoaderReset(Loader loader) { getCursorAdapter().swapCursor(null); } }; } } ================================================ FILE: app/src/main/java/com/example/project/views/common/mvp/BaseActivityPresenter.java ================================================ package com.example.project.views.common.mvp; import android.support.v7.app.AppCompatActivity; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EActivity; /** * Base presenter for activities. */ @EActivity public abstract class BaseActivityPresenter extends AppCompatActivity implements BasePresenter { /** Guard to avoid multiple calls to {@link BasePresenter#onViewCreated} */ private boolean firstTimeOnAfterViews = true; // wrapper for the life cycles @AfterViews protected void baseOnAfterViews() { if (firstTimeOnAfterViews) { firstTimeOnAfterViews = false; onViewCreated(); } } @Override public void onResume() { super.onResume(); onViewResume(); } @Override public void onPause() { super.onPause(); onViewPause(); } @Override public void onDestroy() { super.onDestroy(); onViewDestroy(); } // don't force child classes to implement the life cycle methods @Override public void onViewCreated() { } @Override public void onViewResume() { } @Override public void onViewPause() { } @Override public void onViewDestroy() { } } ================================================ FILE: app/src/main/java/com/example/project/views/common/mvp/BaseFragmentPresenter.java ================================================ package com.example.project.views.common.mvp; import android.os.Bundle; import android.support.v4.app.Fragment; import org.androidannotations.annotations.EFragment; /** * Base presenter for fragments. */ @EFragment public abstract class BaseFragmentPresenter extends Fragment implements BasePresenter { // wrapper for the life cycles @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); onViewCreated(); } @Override public void onResume() { super.onResume(); onViewResume(); } @Override public void onPause() { super.onPause(); onViewPause(); } @Override public void onDestroy() { super.onDestroy(); onViewDestroy(); } // don't force child classes to implement the life cycle methods @Override public void onViewCreated() { } @Override public void onViewResume() { } @Override public void onViewPause() { } @Override public void onViewDestroy() { } } ================================================ FILE: app/src/main/java/com/example/project/views/common/mvp/BasePresenter.java ================================================ package com.example.project.views.common.mvp; /** * Base presenter for activities and fragments. * * Equalize the lifecycle handling for easy switch between activity and fragment. * The wrapped life cycles avoid the necessary of super method calls and let you easy write unit tests. */ public interface BasePresenter { /** * Called after the view is full created and injected. * * At this time you should start to initialise the view content. This will only be called * once in the life of the view. This gets be called at very end of onCreate. */ void onViewCreated(); /** * Called if the view is shown and the user may interact with it. * * May be called multiple times but only in combination with {@link #onViewPause()}. */ void onViewResume(); /** * Called when the view is going into background and the user can't anymore interact with it. * * This is the place to save persistent content. * * This is the same like onPause. Take also note of {@link android.app.Activity#onPause()}. * May be called multiple times but only in combination with {@link #onViewResume()}. */ void onViewPause(); /** * Called if the view gets destroyed. * * Do final clean up by releasing/stopping not more necessary processes. */ void onViewDestroy(); } ================================================ FILE: app/src/main/java/com/example/project/views/common/mvp/BaseView.java ================================================ package com.example.project.views.common.mvp; public interface BaseView { } ================================================ FILE: app/src/main/java/com/example/project/views/common/testwrapper/ViewFinisher.java ================================================ package com.example.project.views.common.testwrapper; import android.app.Activity; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; @EBean public class ViewFinisher { @RootContext Activity activity; public void finish() { activity.finish(); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_details/DetailActivity.java ================================================ package com.example.project.views.contact_details; import com.example.project.R; import com.example.project.views.common.mvp.BaseActivityPresenter; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.Extra; import org.androidannotations.annotations.FragmentById; @EActivity(R.layout.activity_detail) public class DetailActivity extends BaseActivityPresenter { @FragmentById(R.id.fragment_detail) DetailFragment detailFragment; @Extra protected long contactId; @Override public void onViewCreated() { detailFragment.onShowContact(contactId); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_details/DetailActivityIntent.java ================================================ package com.example.project.views.contact_details; import android.content.Context; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; @EBean public class DetailActivityIntent { @RootContext Context context; public void start(long contactId) { DetailActivity_.intent(context).contactId(contactId).start(); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_details/DetailFragment.java ================================================ package com.example.project.views.contact_details; import com.example.project.R; import com.example.project.views.common.mvp.BaseFragmentPresenter; import org.androidannotations.annotations.EFragment; @EFragment(R.layout.fragment_detail) public class DetailFragment extends BaseFragmentPresenter { public void onShowContact(long contactId) { } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_details/DetailView.java ================================================ package com.example.project.views.contact_details; import com.example.project.views.common.mvp.BaseView; public class DetailView implements BaseView { } ================================================ FILE: app/src/main/java/com/example/project/views/contact_edit/EditActivity.java ================================================ package com.example.project.views.contact_edit; import com.example.project.R; import com.example.project.views.common.mvp.BaseActivityPresenter; import com.example.project.views.common.testwrapper.ViewFinisher; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.Extra; import org.androidannotations.annotations.FragmentById; @EActivity(R.layout.activity_edit) public class EditActivity extends BaseActivityPresenter implements EditConfirmedListener { @FragmentById(R.id.fragment_edit) EditFragment editFragment; @Bean ViewFinisher viewFinisher; @Extra protected long contactId; @Override public void onViewCreated() { editFragment.setEditConfirmedListener(this); editFragment.onShowContact(contactId); } @Override public void onEditConfirmed() { viewFinisher.finish(); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_edit/EditActivityIntent.java ================================================ package com.example.project.views.contact_edit; import android.content.Context; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; @EBean public class EditActivityIntent { @RootContext Context context; public void start(long contactId) { EditActivity_.intent(context).contactId(contactId).start(); } public void start() { EditActivity_.intent(context).start(); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_edit/EditConfirmedListener.java ================================================ package com.example.project.views.contact_edit; public interface EditConfirmedListener { void onEditConfirmed(); } ================================================ FILE: app/src/main/java/com/example/project/views/contact_edit/EditFragment.java ================================================ package com.example.project.views.contact_edit; import com.example.project.R; import com.example.project.business.contact.CreateContactFunction; import com.example.project.business.contact.QueryContactFunction; import com.example.project.database.provider.contact.ContactModel; import com.example.project.views.common.mvp.BaseFragmentPresenter; import org.androidannotations.annotations.Background; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EFragment; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import java.util.Date; @EFragment(R.layout.fragment_edit) public class EditFragment extends BaseFragmentPresenter { @Bean EditView editView; @Bean CreateContactFunction createContactFunction; @Bean QueryContactFunction queryContactFunction; private EditConfirmedListener editConfirmedListener; private long contactId; public void setEditConfirmedListener(EditConfirmedListener editConfirmedListener) { this.editConfirmedListener = editConfirmedListener; } public void onShowContact(long contactId) { this.contactId = contactId; if(contactId != 0) { loadAndShowContactDetails(); } } private void loadAndShowContactDetails() { ContactModel contact = queryContactFunction.apply(contactId); editView.setFirstName(contact.getFirstName()); editView.setLastName(contact.getLastName()); editView.setBirthDate(dateString(contact.getBirthdate())); } @Click(R.id.confirm) public void onClickConfirm() { String firstName = editView.getFirstName(); String lastName = editView.getLastName(); String birthDate = editView.getBirthDate(); createOrUpdateContact(firstName, lastName, date(birthDate)); editConfirmedListener.onEditConfirmed(); } @Background void createOrUpdateContact(String firstName, String lastName, Date birthDate) { createContactFunction.apply(firstName, lastName, birthDate); } private String dateString(Date date) { if (date == null) { return ""; } else { return date.toString(); } } private Date date(String dateString) { if(StringUtils.isNotEmpty(dateString)) { return DateTime.parse(dateString).toDate(); } else { return null; } } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_edit/EditView.java ================================================ package com.example.project.views.contact_edit; import android.widget.EditText; import com.example.project.R; import com.example.project.views.common.mvp.BaseView; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.ViewById; @EBean public class EditView implements BaseView { @ViewById(R.id.first_name) EditText firstName; @ViewById(R.id.last_name) EditText lastName; @ViewById(R.id.birth_date) EditText birthDate; public void setFirstName(String input) { firstName.setText(input); } public String getFirstName() { return firstName.getText().toString(); } public void setLastName(String input) { lastName.setText(input); } public String getLastName() { return lastName.getText().toString(); } public void setBirthDate(String input) { birthDate.setText(input); } public String getBirthDate() { return birthDate.getText().toString(); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_list/ContactAdapter.java ================================================ package com.example.project.views.contact_list; import android.content.Context; import android.database.Cursor; import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.example.project.database.provider.contact.ContactCursor; import org.androidannotations.annotations.EBean; @EBean public class ContactAdapter extends CursorAdapter { public static final int AVOID_AUTO_QUERY_AND_CONTENT_OBSERVERS = 0; public ContactAdapter(Context context) { super(context, null, AVOID_AUTO_QUERY_AND_CONTENT_OBSERVERS); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_2, null); } @Override public void bindView(View view, Context context, Cursor cursor) { ContactCursor contacts = (ContactCursor) cursor; ((TextView) view.findViewById(android.R.id.text1)).setText(contacts.getFirstName() + " " + contacts.getLastName()); if(contacts.getBirthdate() != null) { ((TextView) view.findViewById(android.R.id.text2)).setText(contacts.getBirthdate().toString()); } } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_list/ContactAdapterLoader.java ================================================ package com.example.project.views.contact_list; import android.database.Cursor; import android.support.v4.widget.CursorAdapter; import android.util.Log; import com.example.project.business.contact.QueryContactListFunction; import com.example.project.views.common.cursorloader.CursorAdapterWithCursorLoader; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; @EBean public class ContactAdapterLoader extends CursorAdapterWithCursorLoader { @Bean ContactAdapter contactAdapter; @Bean QueryContactListFunction queryContactListFunction; @Override public CursorAdapter getCursorAdapter() { return contactAdapter; } @Override public int getLoaderId() { return 1; } @Override public Cursor loadCursor() { Log.e("sync", "sync load"); return queryContactListFunction.apply(); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_list/ContactListActivity.java ================================================ package com.example.project.views.contact_list; import android.util.Log; import android.widget.Toast; import com.example.project.R; import com.example.project.business.contact_sync.SyncContactsFunction; import com.example.project.views.common.AppIdlingResources; import com.example.project.views.common.mvp.BaseActivityPresenter; import com.example.project.views.contact_details.DetailActivityIntent; import com.example.project.views.contact_details.DetailFragment; import com.example.project.views.contact_edit.EditActivityIntent; import org.androidannotations.annotations.Background; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.FragmentById; import org.androidannotations.annotations.OptionsItem; import org.androidannotations.annotations.OptionsMenu; import org.androidannotations.annotations.UiThread; @EActivity(R.layout.activity_main) @OptionsMenu(R.menu.menu_main) public class ContactListActivity extends BaseActivityPresenter implements ShowContactListener { @FragmentById(R.id.fragment_list) ContactListFragment contactListFragment; @FragmentById(R.id.fragment_detail) DetailFragment detailFragment; @Bean DetailActivityIntent detailActivityIntent; @Bean EditActivityIntent editActivityIntent; @Bean SyncContactsFunction syncContactsFunction; @Bean AppIdlingResources appIdlingResources; @Override public void onViewCreated() { contactListFragment.setShowContactListener(this); } @OptionsItem(R.id.action_add_contact) public void onCreateContact() { editActivityIntent.start(); } @OptionsItem(R.id.action_sync_contacts) @Background void onSyncContacts() { Log.e("sync", "sync start"); appIdlingResources.increment(); SyncContactsFunction.Result result = syncContactsFunction.apply(); showSyncResult(result); appIdlingResources.decrement(); Log.e("sync", "sync finish"); } @UiThread(propagation = UiThread.Propagation.REUSE) void showSyncResult(SyncContactsFunction.Result result) { if(result.successful) { Log.e("sync", "sync success"); Toast.makeText(this, "Sync done", Toast.LENGTH_SHORT).show(); } else { Log.e("sync", "sync failed"); Toast.makeText(this, "Sync failed: " + result.errorReason, Toast.LENGTH_SHORT).show(); } } @Override public void onShowContact(long contactId) { if(detailFragment == null) { detailActivityIntent.start(contactId); } else { detailFragment.onShowContact(contactId); } } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_list/ContactListActivityIntent.java ================================================ package com.example.project.views.contact_list; import android.content.Context; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.RootContext; @EBean public class ContactListActivityIntent { @RootContext Context context; public void start() { ContactListActivity_.intent(context).start(); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_list/ContactListFragment.java ================================================ package com.example.project.views.contact_list; import com.example.project.R; import com.example.project.database.provider.contact.ContactCursor; import com.example.project.views.common.mvp.BaseFragmentPresenter; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.ItemClick; @EFragment(R.layout.fragment_list) public class ContactListFragment extends BaseFragmentPresenter { @Bean ContactListView view; @Bean ContactAdapterLoader contactsLoader; private ShowContactListener showContactListener; @Override public void onViewCreated() { view.showContacts(contactsLoader.getCursorAdapter()); contactsLoader.start(); } @ItemClick(R.id.listView) public void onContactClick(ContactCursor item) { showContactListener.onShowContact(item.getId()); } public void setShowContactListener(ShowContactListener showContactListener) { this.showContactListener = showContactListener; } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_list/ContactListView.java ================================================ package com.example.project.views.contact_list; import android.widget.ListAdapter; import android.widget.ListView; import com.example.project.R; import com.example.project.views.common.mvp.BaseView; import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.ViewById; @EBean public class ContactListView implements BaseView { @ViewById(R.id.listView) ListView contactList; public void showContacts(ListAdapter listAdapter) { contactList.setAdapter(listAdapter); } } ================================================ FILE: app/src/main/java/com/example/project/views/contact_list/ShowContactListener.java ================================================ package com.example.project.views.contact_list; public interface ShowContactListener { void onShowContact(long contact); } ================================================ FILE: app/src/main/java/com/example/project/views/start/StartActivity.java ================================================ package com.example.project.views.start; import com.example.project.views.common.mvp.BaseActivityPresenter; import com.example.project.views.contact_list.ContactListActivityIntent; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EActivity; @EActivity public class StartActivity extends BaseActivityPresenter { @Bean ContactListActivityIntent contactListActivityIntent; @Override public void onViewResume() { contactListActivityIntent.start(); } } ================================================ FILE: app/src/main/json/database/schema/_config.json ================================================ { "syntaxVersion": 3, "projectPackageId": "com.example.project", "authority": "com.example.project", "providerJavaPackage": "com.example.project.database.provider", "providerClassName": "ExampleProvider", "sqliteOpenHelperClassName": "ExampleSQLiteOpenHelper", "sqliteOpenHelperCallbacksClassName": "ExampleSQLiteOpenHelperCallbacks", "databaseFileName": "example.db", "databaseVersion": 1, "enableForeignKeys": true, "useAnnotations": true } ================================================ FILE: app/src/main/json/database/schema/address.json ================================================ { "fields": [ { "name": "contact_id", "type": "Long", "nullable": false, "foreignKey": { "table": "contact", "onDelete": "CASCADE" } }, { "name": "street", "type": "String", "nullable": true }, { "name": "number", "type": "String", "nullable": true }, { "name": "city", "type": "String", "nullable": true }, { "name": "country", "type": "String", "nullable": true }, { "name": "state", "type": "String", "nullable": true }, { "name": "postalcode", "type": "String", "nullable": true } ] } ================================================ FILE: app/src/main/json/database/schema/contact.json ================================================ { "fields": [ { "name": "uid", "type": "String", "nullable": true }, { "name": "first_name", "type": "String", "nullable": true }, { "name": "last_name", "type": "String", "nullable": true }, { "name": "birthdate", "type": "Date", "nullable": true } ], "constraints": [ { "name": "first_or_last_name_must_be_given", "definition": "CHECK((first_name <> '' AND first_name IS NOT NULL) OR (last_name <> '' AND last_name IS NOT NULL)) ON CONFLICT FAIL" } ] } ================================================ FILE: app/src/main/json/network/schema/contactJson.json ================================================ { "description": "Simple single contact.", "type": "object", "properties": { "id": { "type": "string" }, "firstName": { "type": "string" }, "lastName": { "type": "string" }, "birthDate": { "type": "string" } } } ================================================ FILE: app/src/main/json/network/schema/contactListJson.json ================================================ { "description": "Collection of contacts.", "type": "object", "properties": { "contacts" : { "type" : "array", "items" : { "$ref" : "contactJson.json" } } } } ================================================ FILE: app/src/main/res/layout/activity_detail.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_edit.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: app/src/main/res/layout/fragment_detail.xml ================================================