├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── android │ │ └── room │ │ └── database │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── android │ │ │ └── room │ │ │ └── database │ │ │ ├── LoginActivity.java │ │ │ ├── db │ │ │ ├── AppDatabase.java │ │ │ ├── dao │ │ │ │ └── UserDao.java │ │ │ └── entity │ │ │ │ └── User.java │ │ │ └── service │ │ │ ├── UserService.java │ │ │ └── serviceImpl │ │ │ └── UserServiceImpl.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_login.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── android │ └── room │ └── database │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Saving Data Using the Room Persistence Library 2 | Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite. 3 | 4 | There are 3 major components in Room: 5 | 1. Database 6 | 2. Entity 7 | 3. Dao 8 | 9 | # In existing project - 10 | Very basic usages and setup of room data base has been shown via user example. 11 | 12 | Basic crucks- 13 | 14 | *. Setup of data base 15 | 16 | AppDatabase - create db 17 | ``` 18 | @Database(entities = {User.class}, version = 1) 19 | public abstract class AppDatabase extends RoomDatabase { 20 | 21 | appDatabase = Room.databaseBuilder(context.getApplicationContext(), 22 | AppDatabase.class, "database-name").build(); 23 | ``` 24 | 25 | *. UserDao - interface to provide access on db- 26 | ``` 27 | @Dao 28 | public interface UserDao { 29 | @Query("SELECT * FROM user") 30 | List getAll(); 31 | ``` 32 | //init service 33 | 34 | *. Initilize service where you want to use room db- 35 | ``` 36 | private UserServiceImpl userService; 37 | userService = new UserServiceImpl(LoginActivity.this); 38 | ``` 39 | 40 | *. From do in background save objects in db 41 | 42 | User user = new User(); 43 | user.setUid(new Random().nextInt()); 44 | user.setEmail(mEmail); 45 | user.setPassword(mPassword); 46 | user.setFirstName("First Name"); 47 | user.setLastName("Last Name"); 48 | userService.insertAll(user); 49 | users = userService.getAll(); 50 | 51 | *. Simple method to get db in background thread and showing data on UI- 52 | ``` 53 | private void getUsersFromDB() { 54 | new AsyncTask() { 55 | @Override 56 | protected Void doInBackground(Void... params) { 57 | users = userService.getAll(); 58 | return null; 59 | } 60 | @Override 61 | protected void onPostExecute(Void agentsCount) { 62 | usersTextView.setText("Users \n\n " + users); 63 | } 64 | }.execute(); 65 | ``` 66 | 67 | 68 | # https://developer.android.com/images/training/data-storage/room_architecture.png 69 | 70 | 71 | # Screen shots 72 | 73 | ![device-2018-01-25-202154](https://user-images.githubusercontent.com/28217318/35485232-a43a6d02-0482-11e8-84f8-8dbc2773d90b.png) 74 | 75 | ![device-2018-01-25-202231](https://user-images.githubusercontent.com/28217318/35485233-a4647a48-0482-11e8-8742-8e0167137e5f.png) 76 | 77 | ![device-2018-01-25-202311](https://user-images.githubusercontent.com/28217318/35485234-a48ee472-0482-11e8-9a20-4209dec75dcb.png) 78 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "com.android.room.database" 7 | minSdkVersion 14 8 | targetSdkVersion 27 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:27.0.2' 24 | implementation 'com.android.support:design:27.0.2' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 28 | 29 | /*android room from developers android*/ 30 | 31 | // ViewModel and LiveData 32 | implementation "android.arch.lifecycle:extensions:1.1.0" 33 | // alternatively, just ViewModel 34 | implementation "android.arch.lifecycle:viewmodel:1.1.0" 35 | // alternatively, just LiveData 36 | implementation "android.arch.lifecycle:livedata:1.1.0" 37 | 38 | annotationProcessor "android.arch.lifecycle:compiler:1.1.0" 39 | 40 | // Room (use 1.1.0-alpha1 for latest alpha) 41 | implementation "android.arch.persistence.room:runtime:1.0.0" 42 | annotationProcessor "android.arch.persistence.room:compiler:1.0.0" 43 | 44 | // Paging 45 | implementation "android.arch.paging:runtime:1.0.0-alpha5" 46 | 47 | // Test helpers for LiveData 48 | testImplementation "android.arch.core:core-testing:1.1.0" 49 | 50 | // Test helpers for Room 51 | testImplementation "android.arch.persistence.room:testing:1.0.0" 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/android/room/database/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.android.room.database; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.android.room.database", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/room/database/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.android.room.database; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.annotation.TargetApi; 6 | import android.content.pm.PackageManager; 7 | import android.support.annotation.NonNull; 8 | import android.support.design.widget.Snackbar; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.app.LoaderManager.LoaderCallbacks; 11 | 12 | import android.content.CursorLoader; 13 | import android.content.Loader; 14 | import android.database.Cursor; 15 | import android.net.Uri; 16 | import android.os.AsyncTask; 17 | 18 | import android.os.Build; 19 | import android.os.Bundle; 20 | import android.provider.ContactsContract; 21 | import android.text.TextUtils; 22 | import android.util.Log; 23 | import android.view.KeyEvent; 24 | import android.view.View; 25 | import android.view.View.OnClickListener; 26 | import android.view.inputmethod.EditorInfo; 27 | import android.widget.AbsSeekBar; 28 | import android.widget.ArrayAdapter; 29 | import android.widget.AutoCompleteTextView; 30 | import android.widget.Button; 31 | import android.widget.EditText; 32 | import android.widget.TextView; 33 | import android.widget.Toast; 34 | 35 | import com.android.room.database.db.AppDatabase; 36 | import com.android.room.database.db.entity.User; 37 | import com.android.room.database.service.UserService; 38 | import com.android.room.database.service.serviceImpl.UserServiceImpl; 39 | 40 | import org.w3c.dom.Text; 41 | 42 | import java.util.ArrayList; 43 | import java.util.List; 44 | import java.util.Random; 45 | 46 | import static android.Manifest.permission.READ_CONTACTS; 47 | 48 | /** 49 | * A login screen that offers login via email/password. 50 | */ 51 | public class LoginActivity extends AppCompatActivity implements LoaderCallbacks { 52 | 53 | /** 54 | * Id to identity READ_CONTACTS permission request. 55 | */ 56 | private static final int REQUEST_READ_CONTACTS = 0; 57 | 58 | /** 59 | * A dummy authentication store containing known user names and passwords. 60 | * TODO: remove after connecting to a real authentication system. 61 | */ 62 | private static final String[] DUMMY_CREDENTIALS = new String[]{ 63 | "foo@example.com:hello", "bar@example.com:world" 64 | }; 65 | private static final String TAG = LoginActivity.class.getSimpleName(); 66 | /** 67 | * Keep track of the login task to ensure we can cancel it if requested. 68 | */ 69 | private UserLoginTask mAuthTask = null; 70 | 71 | // UI references. 72 | private AutoCompleteTextView mEmailView; 73 | private EditText mPasswordView; 74 | private View mProgressView; 75 | private View mLoginFormView; 76 | 77 | 78 | private UserServiceImpl userService; 79 | 80 | private List users = new ArrayList<>(); 81 | 82 | private TextView usersTextView; 83 | 84 | @Override 85 | protected void onCreate(Bundle savedInstanceState) { 86 | super.onCreate(savedInstanceState); 87 | setContentView(R.layout.activity_login); 88 | 89 | //init service 90 | userService = new UserServiceImpl(LoginActivity.this); 91 | usersTextView = findViewById(R.id.usersTextView); 92 | 93 | getUsersFromDB(); 94 | 95 | 96 | // Set up the login form. 97 | mEmailView = (AutoCompleteTextView) findViewById(R.id.email); 98 | populateAutoComplete(); 99 | 100 | mPasswordView = (EditText) findViewById(R.id.password); 101 | mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() { 102 | @Override 103 | public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { 104 | if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) { 105 | attemptLogin(); 106 | return true; 107 | } 108 | return false; 109 | } 110 | }); 111 | 112 | Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); 113 | mEmailSignInButton.setOnClickListener(new OnClickListener() { 114 | @Override 115 | public void onClick(View view) { 116 | attemptLogin(); 117 | } 118 | }); 119 | 120 | mLoginFormView = findViewById(R.id.login_form); 121 | mProgressView = findViewById(R.id.login_progress); 122 | } 123 | 124 | private void populateAutoComplete() { 125 | if (!mayRequestContacts()) { 126 | return; 127 | } 128 | 129 | getLoaderManager().initLoader(0, null, this); 130 | } 131 | 132 | private boolean mayRequestContacts() { 133 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 134 | return true; 135 | } 136 | if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) { 137 | return true; 138 | } 139 | if (shouldShowRequestPermissionRationale(READ_CONTACTS)) { 140 | Snackbar.make(mEmailView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE) 141 | .setAction(android.R.string.ok, new View.OnClickListener() { 142 | @Override 143 | @TargetApi(Build.VERSION_CODES.M) 144 | public void onClick(View v) { 145 | requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS); 146 | } 147 | }); 148 | } else { 149 | requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS); 150 | } 151 | return false; 152 | } 153 | 154 | /** 155 | * Callback received when a permissions request has been completed. 156 | */ 157 | @Override 158 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 159 | @NonNull int[] grantResults) { 160 | if (requestCode == REQUEST_READ_CONTACTS) { 161 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 162 | populateAutoComplete(); 163 | } 164 | } 165 | } 166 | 167 | 168 | /** 169 | * Attempts to sign in or register the account specified by the login form. 170 | * If there are form errors (invalid email, missing fields, etc.), the 171 | * errors are presented and no actual login attempt is made. 172 | */ 173 | private void attemptLogin() { 174 | if (mAuthTask != null) { 175 | return; 176 | } 177 | 178 | // Reset errors. 179 | mEmailView.setError(null); 180 | mPasswordView.setError(null); 181 | 182 | // Store values at the time of the login attempt. 183 | String email = mEmailView.getText().toString(); 184 | String password = mPasswordView.getText().toString(); 185 | 186 | boolean cancel = false; 187 | View focusView = null; 188 | 189 | // Check for a valid password, if the user entered one. 190 | if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) { 191 | mPasswordView.setError(getString(R.string.error_invalid_password)); 192 | focusView = mPasswordView; 193 | cancel = true; 194 | } 195 | 196 | // Check for a valid email address. 197 | if (TextUtils.isEmpty(email)) { 198 | mEmailView.setError(getString(R.string.error_field_required)); 199 | focusView = mEmailView; 200 | cancel = true; 201 | } else if (!isEmailValid(email)) { 202 | mEmailView.setError(getString(R.string.error_invalid_email)); 203 | focusView = mEmailView; 204 | cancel = true; 205 | } 206 | 207 | if (cancel) { 208 | // There was an error; don't attempt login and focus the first 209 | // form field with an error. 210 | focusView.requestFocus(); 211 | } else { 212 | // Show a progress spinner, and kick off a background task to 213 | // perform the user login attempt. 214 | showProgress(true); 215 | mAuthTask = new UserLoginTask(email, password); 216 | mAuthTask.execute((Void) null); 217 | } 218 | } 219 | 220 | private boolean isEmailValid(String email) { 221 | //TODO: Replace this with your own logic 222 | return email.contains("@"); 223 | } 224 | 225 | private boolean isPasswordValid(String password) { 226 | //TODO: Replace this with your own logic 227 | return password.length() > 4; 228 | } 229 | 230 | /** 231 | * Shows the progress UI and hides the login form. 232 | */ 233 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) 234 | private void showProgress(final boolean show) { 235 | // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow 236 | // for very easy animations. If available, use these APIs to fade-in 237 | // the progress spinner. 238 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { 239 | int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime); 240 | 241 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 242 | mLoginFormView.animate().setDuration(shortAnimTime).alpha( 243 | show ? 0 : 1).setListener(new AnimatorListenerAdapter() { 244 | @Override 245 | public void onAnimationEnd(Animator animation) { 246 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 247 | } 248 | }); 249 | 250 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 251 | mProgressView.animate().setDuration(shortAnimTime).alpha( 252 | show ? 1 : 0).setListener(new AnimatorListenerAdapter() { 253 | @Override 254 | public void onAnimationEnd(Animator animation) { 255 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 256 | } 257 | }); 258 | } else { 259 | // The ViewPropertyAnimator APIs are not available, so simply show 260 | // and hide the relevant UI components. 261 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 262 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 263 | } 264 | } 265 | 266 | @Override 267 | public Loader onCreateLoader(int i, Bundle bundle) { 268 | return new CursorLoader(this, 269 | // Retrieve data rows for the device user's 'profile' contact. 270 | Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI, 271 | ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION, 272 | 273 | // Select only email addresses. 274 | ContactsContract.Contacts.Data.MIMETYPE + 275 | " = ?", new String[]{ContactsContract.CommonDataKinds.Email 276 | .CONTENT_ITEM_TYPE}, 277 | 278 | // Show primary email addresses first. Note that there won't be 279 | // a primary email address if the user hasn't specified one. 280 | ContactsContract.Contacts.Data.IS_PRIMARY + " DESC"); 281 | } 282 | 283 | @Override 284 | public void onLoadFinished(Loader cursorLoader, Cursor cursor) { 285 | List emails = new ArrayList<>(); 286 | cursor.moveToFirst(); 287 | while (!cursor.isAfterLast()) { 288 | emails.add(cursor.getString(ProfileQuery.ADDRESS)); 289 | cursor.moveToNext(); 290 | } 291 | 292 | addEmailsToAutoComplete(emails); 293 | } 294 | 295 | @Override 296 | public void onLoaderReset(Loader cursorLoader) { 297 | 298 | } 299 | 300 | private void addEmailsToAutoComplete(List emailAddressCollection) { 301 | //Create adapter to tell the AutoCompleteTextView what to show in its dropdown list. 302 | ArrayAdapter adapter = 303 | new ArrayAdapter<>(LoginActivity.this, 304 | android.R.layout.simple_dropdown_item_1line, emailAddressCollection); 305 | 306 | mEmailView.setAdapter(adapter); 307 | } 308 | 309 | 310 | private interface ProfileQuery { 311 | String[] PROJECTION = { 312 | ContactsContract.CommonDataKinds.Email.ADDRESS, 313 | ContactsContract.CommonDataKinds.Email.IS_PRIMARY, 314 | }; 315 | 316 | int ADDRESS = 0; 317 | int IS_PRIMARY = 1; 318 | } 319 | 320 | /** 321 | * Represents an asynchronous login/registration task used to authenticate 322 | * the user. 323 | */ 324 | public class UserLoginTask extends AsyncTask { 325 | 326 | private final String mEmail; 327 | private final String mPassword; 328 | 329 | UserLoginTask(String email, String password) { 330 | mEmail = email; 331 | mPassword = password; 332 | } 333 | 334 | @Override 335 | protected Boolean doInBackground(Void... params) { 336 | // TODO: attempt authentication against a network service. 337 | 338 | try { 339 | // Simulate network access. 340 | // creating object manually this can be done using dependency injection 341 | Log.i(TAG, "user from db...all users - " + userService.getAll().size()); 342 | 343 | User user = new User(); 344 | user.setUid(new Random().nextInt()); 345 | user.setEmail(mEmail); 346 | user.setPassword(mPassword); 347 | user.setFirstName("First Name"); 348 | user.setLastName("Last Name"); 349 | 350 | userService.insertAll(user); 351 | users = userService.getAll(); 352 | 353 | Log.i(TAG, "user inserted in db..." + user); 354 | Log.i(TAG, "user from db...all users - " + userService.getAll().size()); 355 | 356 | Thread.sleep(2000); 357 | } catch (InterruptedException e) { 358 | return false; 359 | } 360 | 361 | for (String credential : DUMMY_CREDENTIALS) { 362 | String[] pieces = credential.split(":"); 363 | if (pieces[0].equals(mEmail)) { 364 | // Account exists, return true if the password matches. 365 | return pieces[1].equals(mPassword); 366 | } 367 | } 368 | 369 | // TODO: register the new account here. 370 | return true; 371 | } 372 | 373 | @Override 374 | protected void onPostExecute(final Boolean success) { 375 | mAuthTask = null; 376 | showProgress(false); 377 | 378 | if (success) { 379 | Toast.makeText(LoginActivity.this, "User created...", Toast.LENGTH_LONG).show(); 380 | usersTextView.setText("Users \n\n " + users); 381 | } else { 382 | mPasswordView.setError(getString(R.string.error_incorrect_password)); 383 | mPasswordView.requestFocus(); 384 | } 385 | } 386 | 387 | @Override 388 | protected void onCancelled() { 389 | mAuthTask = null; 390 | showProgress(false); 391 | } 392 | } 393 | 394 | private void getUsersFromDB() { 395 | new AsyncTask() { 396 | @Override 397 | protected Void doInBackground(Void... params) { 398 | users = userService.getAll(); 399 | return null; 400 | } 401 | 402 | @Override 403 | protected void onPostExecute(Void agentsCount) { 404 | usersTextView.setText("Users \n\n " + users); 405 | } 406 | }.execute(); 407 | } 408 | } 409 | 410 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/room/database/db/AppDatabase.java: -------------------------------------------------------------------------------- 1 | package com.android.room.database.db; 2 | 3 | import android.arch.persistence.room.Database; 4 | import android.arch.persistence.room.Room; 5 | import android.arch.persistence.room.RoomDatabase; 6 | import android.content.Context; 7 | 8 | import com.android.room.database.db.dao.UserDao; 9 | import com.android.room.database.db.entity.User; 10 | 11 | @Database(entities = {User.class}, version = 1) 12 | public abstract class AppDatabase extends RoomDatabase { 13 | private static AppDatabase appDatabase = null; 14 | 15 | /** 16 | * from developers android, made my own singleton 17 | * 18 | * @param context 19 | * @return 20 | */ 21 | public static AppDatabase getInstance(Context context) { 22 | if (appDatabase == null) { 23 | appDatabase = Room.databaseBuilder(context.getApplicationContext(), 24 | AppDatabase.class, "database-name").build(); 25 | } 26 | return appDatabase; 27 | } 28 | 29 | public abstract UserDao userDao(); 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/room/database/db/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.android.room.database.db.dao; 2 | 3 | import android.arch.persistence.room.Dao; 4 | import android.arch.persistence.room.Delete; 5 | import android.arch.persistence.room.Insert; 6 | import android.arch.persistence.room.Query; 7 | 8 | import com.android.room.database.db.entity.User; 9 | 10 | import java.util.List; 11 | 12 | @Dao 13 | public interface UserDao { 14 | @Query("SELECT * FROM user") 15 | List getAll(); 16 | 17 | @Query("SELECT * FROM user WHERE uid IN (:userIds)") 18 | List loadAllByIds(int[] userIds); 19 | 20 | @Query("SELECT * FROM user WHERE first_name LIKE :first AND " 21 | + "last_name LIKE :last LIMIT 1") 22 | User findByName(String first, String last); 23 | 24 | @Insert 25 | void insertAll(User... users); 26 | 27 | @Delete 28 | void delete(User user); 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/room/database/db/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.android.room.database.db.entity; 2 | 3 | import android.arch.persistence.room.ColumnInfo; 4 | import android.arch.persistence.room.Entity; 5 | import android.arch.persistence.room.PrimaryKey; 6 | 7 | @Entity 8 | public class User { 9 | @PrimaryKey 10 | private int uid; 11 | 12 | @ColumnInfo(name = "first_name") 13 | private String firstName; 14 | 15 | @ColumnInfo(name = "last_name") 16 | private String lastName; 17 | 18 | @ColumnInfo(name = "email") 19 | private String email; 20 | 21 | @ColumnInfo(name = "password") 22 | private String password; 23 | 24 | public int getUid() { 25 | return uid; 26 | } 27 | 28 | public void setUid(int uid) { 29 | this.uid = uid; 30 | } 31 | 32 | public String getFirstName() { 33 | return firstName; 34 | } 35 | 36 | public void setFirstName(String firstName) { 37 | this.firstName = firstName; 38 | } 39 | 40 | public String getLastName() { 41 | return lastName; 42 | } 43 | 44 | public void setLastName(String lastName) { 45 | this.lastName = lastName; 46 | } 47 | 48 | public String getEmail() { 49 | return email; 50 | } 51 | 52 | public void setEmail(String email) { 53 | this.email = email; 54 | } 55 | 56 | public String getPassword() { 57 | return password; 58 | } 59 | 60 | public void setPassword(String password) { 61 | this.password = password; 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return "\nUser{" + 67 | "uid=" + uid + 68 | ", firstName='" + firstName + '\'' + 69 | ", lastName='" + lastName + '\'' + 70 | ", email='" + email + '\'' + 71 | ", password='" + password + '\'' + 72 | '}' + "\n\n"; 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/android/room/database/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.android.room.database.service; 2 | 3 | import android.arch.persistence.room.Insert; 4 | 5 | import com.android.room.database.db.entity.User; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Created by dinakar.maurya on 25-01-2018. 11 | */ 12 | 13 | /** 14 | * writing my own service interface 15 | */ 16 | public interface UserService { 17 | 18 | List getAll(); 19 | 20 | void insertAll(User... users); 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/android/room/database/service/serviceImpl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.android.room.database.service.serviceImpl; 2 | 3 | import android.content.Context; 4 | 5 | import com.android.room.database.db.AppDatabase; 6 | import com.android.room.database.db.dao.UserDao; 7 | import com.android.room.database.db.entity.User; 8 | import com.android.room.database.service.UserService; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by dinakar.maurya on 25-01-2018. 14 | */ 15 | 16 | /** 17 | * writing my own impls 18 | */ 19 | public class UserServiceImpl implements UserService { 20 | 21 | private UserDao userDao; 22 | 23 | public UserServiceImpl(Context context) { 24 | userDao = AppDatabase.getInstance(context).userDao(); 25 | } 26 | 27 | @Override 28 | public List getAll() { 29 | return userDao.getAll(); 30 | } 31 | 32 | @Override 33 | public void insertAll(User... users) { 34 | userDao.insertAll(users); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 21 | 22 | 26 | 27 | 32 | 33 | 36 | 37 | 46 | 47 | 48 | 49 | 52 | 53 | 64 | 65 | 66 | 67 |