LoginActivity.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. package ru.ktk45.www.feature;
  2. import android.animation.Animator;
  3. import android.animation.AnimatorListenerAdapter;
  4. import android.annotation.TargetApi;
  5. import android.content.Intent;
  6. import android.content.pm.PackageManager;
  7. import android.os.StrictMode;
  8. import android.support.annotation.NonNull;
  9. import android.support.design.widget.Snackbar;
  10. import android.support.v7.app.AppCompatActivity;
  11. import android.app.LoaderManager.LoaderCallbacks;
  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. import android.os.Build;
  18. import android.os.Bundle;
  19. import android.provider.ContactsContract;
  20. import android.text.TextUtils;
  21. import android.util.Log;
  22. import android.view.KeyEvent;
  23. import android.view.View;
  24. import android.view.View.OnClickListener;
  25. import android.view.inputmethod.EditorInfo;
  26. import android.widget.ArrayAdapter;
  27. import android.widget.AutoCompleteTextView;
  28. import android.widget.Button;
  29. import android.widget.EditText;
  30. import android.widget.TextView;
  31. import android.widget.Toast;
  32. import org.json.JSONException;
  33. import org.json.JSONObject;
  34. import java.io.IOException;
  35. import java.util.ArrayList;
  36. import java.util.List;
  37. import static android.Manifest.permission.READ_CONTACTS;
  38. /**
  39. * A login screen that offers login via email/password.
  40. */
  41. public class LoginActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
  42. /**
  43. * Id to identity READ_CONTACTS permission request.
  44. */
  45. private static final int REQUEST_READ_CONTACTS = 0;
  46. /**
  47. * A dummy authentication store containing known user names and passwords.
  48. * TODO: remove after connecting to a real authentication system.
  49. */
  50. private static final String[] DUMMY_CREDENTIALS = new String[]{
  51. "foo@example.com:hello", "bar@example.com:world"
  52. };
  53. /**
  54. * Keep track of the login task to ensure we can cancel it if requested.
  55. */
  56. private UserLoginTask mAuthTask = null;
  57. // UI references.
  58. private AutoCompleteTextView mEmailView;
  59. private EditText mPasswordView;
  60. private View mProgressView;
  61. private View mLoginFormView;
  62. @Override
  63. protected void onCreate(Bundle savedInstanceState) {
  64. super.onCreate(savedInstanceState);
  65. setContentView(R.layout.activity_login);
  66. // StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
  67. // StrictMode.setThreadPolicy(policy);
  68. // Set up the login form.
  69. mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
  70. populateAutoComplete();
  71. mPasswordView = (EditText) findViewById(R.id.password);
  72. mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
  73. @Override
  74. public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
  75. if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
  76. attemptLogin();
  77. return true;
  78. }
  79. return false;
  80. }
  81. });
  82. Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
  83. mEmailSignInButton.setOnClickListener(new OnClickListener() {
  84. @Override
  85. public void onClick(View view) {
  86. attemptLogin();
  87. }
  88. });
  89. mLoginFormView = findViewById(R.id.login_form);
  90. mProgressView = findViewById(R.id.login_progress);
  91. Intent intent = new Intent(LoginActivity.this, MainActivity.class);
  92. startActivity(intent);
  93. }
  94. private void populateAutoComplete() {
  95. if (!mayRequestContacts()) {
  96. return;
  97. }
  98. getLoaderManager().initLoader(0, null, this);
  99. }
  100. private boolean mayRequestContacts() {
  101. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
  102. return true;
  103. }
  104. if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
  105. return true;
  106. }
  107. if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
  108. Snackbar.make(mEmailView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
  109. .setAction(android.R.string.ok, new View.OnClickListener() {
  110. @Override
  111. @TargetApi(Build.VERSION_CODES.M)
  112. public void onClick(View v) {
  113. requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
  114. }
  115. });
  116. } else {
  117. requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
  118. }
  119. return false;
  120. }
  121. /**
  122. * Callback received when a permissions request has been completed.
  123. */
  124. @Override
  125. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
  126. @NonNull int[] grantResults) {
  127. if (requestCode == REQUEST_READ_CONTACTS) {
  128. if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  129. populateAutoComplete();
  130. }
  131. }
  132. }
  133. /**
  134. * Attempts to sign in or register the account specified by the login form.
  135. * If there are form errors (invalid email, missing fields, etc.), the
  136. * errors are presented and no actual login attempt is made.
  137. */
  138. private void attemptLogin() {
  139. if (mAuthTask != null) {
  140. return;
  141. }
  142. // Reset errors.
  143. mEmailView.setError(null);
  144. mPasswordView.setError(null);
  145. // Store values at the time of the login attempt.
  146. String email = mEmailView.getText().toString();
  147. String password = mPasswordView.getText().toString();
  148. boolean cancel = false;
  149. View focusView = null;
  150. // Check for a valid password, if the user entered one.
  151. if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
  152. mPasswordView.setError(getString(R.string.error_invalid_password));
  153. focusView = mPasswordView;
  154. cancel = true;
  155. }
  156. // Check for a valid email address.
  157. if (TextUtils.isEmpty(email)) {
  158. mEmailView.setError(getString(R.string.error_field_required));
  159. focusView = mEmailView;
  160. cancel = true;
  161. } else if (!isEmailValid(email)) {
  162. mEmailView.setError(getString(R.string.error_invalid_login));
  163. focusView = mEmailView;
  164. cancel = true;
  165. }
  166. if (cancel) {
  167. // There was an error; don't attempt login and focus the first
  168. // form field with an error.
  169. focusView.requestFocus();
  170. } else {
  171. // Show a progress spinner, and kick off a background task to
  172. // perform the user login attempt.
  173. showProgress(true);
  174. mAuthTask = new UserLoginTask(email, password);
  175. mAuthTask.execute((Void) null);
  176. }
  177. }
  178. private boolean isEmailValid(String email) {
  179. char[] test = email.toCharArray();
  180. for (int i = 0; i < test.length; i++) {
  181. if (test[i] < 48 || test[i] > 57) {
  182. return false;
  183. }
  184. }
  185. return true;
  186. }
  187. private boolean isPasswordValid(String password) {
  188. //TODO: Replace this with your own logic
  189. return password.length() > 4;
  190. }
  191. /**
  192. * Shows the progress UI and hides the login form.
  193. */
  194. @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
  195. private void showProgress(final boolean show) {
  196. // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
  197. // for very easy animations. If available, use these APIs to fade-in
  198. // the progress spinner.
  199. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
  200. int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
  201. mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
  202. mLoginFormView.animate().setDuration(shortAnimTime).alpha(
  203. show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
  204. @Override
  205. public void onAnimationEnd(Animator animation) {
  206. mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
  207. }
  208. });
  209. mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
  210. mProgressView.animate().setDuration(shortAnimTime).alpha(
  211. show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
  212. @Override
  213. public void onAnimationEnd(Animator animation) {
  214. mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
  215. }
  216. });
  217. } else {
  218. // The ViewPropertyAnimator APIs are not available, so simply show
  219. // and hide the relevant UI components.
  220. mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
  221. mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
  222. }
  223. }
  224. @Override
  225. public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
  226. return new CursorLoader(this,
  227. // Retrieve data rows for the device user's 'profile' contact.
  228. Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
  229. ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,
  230. // Select only email addresses.
  231. ContactsContract.Contacts.Data.MIMETYPE +
  232. " = ?", new String[]{ContactsContract.CommonDataKinds.Email
  233. .CONTENT_ITEM_TYPE},
  234. // Show primary email addresses first. Note that there won't be
  235. // a primary email address if the user hasn't specified one.
  236. ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
  237. }
  238. @Override
  239. public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
  240. List<String> emails = new ArrayList<>();
  241. cursor.moveToFirst();
  242. while (!cursor.isAfterLast()) {
  243. emails.add(cursor.getString(ProfileQuery.ADDRESS));
  244. cursor.moveToNext();
  245. }
  246. addEmailsToAutoComplete(emails);
  247. }
  248. @Override
  249. public void onLoaderReset(Loader<Cursor> cursorLoader) {
  250. }
  251. private void addEmailsToAutoComplete(List<String> emailAddressCollection) {
  252. //Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
  253. ArrayAdapter<String> adapter =
  254. new ArrayAdapter<>(LoginActivity.this,
  255. android.R.layout.simple_dropdown_item_1line, emailAddressCollection);
  256. mEmailView.setAdapter(adapter);
  257. }
  258. private interface ProfileQuery {
  259. String[] PROJECTION = {
  260. ContactsContract.CommonDataKinds.Email.ADDRESS,
  261. ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
  262. };
  263. int ADDRESS = 0;
  264. int IS_PRIMARY = 1;
  265. }
  266. /**
  267. * Represents an asynchronous login/registration task used to authenticate
  268. * the user.
  269. */
  270. public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
  271. private final String mEmail;
  272. private final String mPassword;
  273. UserLoginTask(String email, String password) {
  274. mEmail = email;
  275. mPassword = password;
  276. }
  277. @Override
  278. protected Boolean doInBackground(Void... params) {
  279. // TODO: attempt authentication against a network service.
  280. try {
  281. Link h = new Link();
  282. h.SetParameter("f0", mEmail);
  283. h.SetParameter("f1", mPassword);
  284. JSONObject obj = h.POST("/Authorization/Login");
  285. String res = obj.getString("Error");
  286. if (res.equals("null")) {
  287. Intent intent = new Intent(LoginActivity.this, MainActivity.class);
  288. startActivity(intent);
  289. } else {
  290. Toast.makeText(LoginActivity.this, obj.getString("Note"), Toast.LENGTH_LONG);
  291. }
  292. } catch (JSONException e) {
  293. e.printStackTrace();
  294. }
  295. // TODO: register the new account here.
  296. return true;
  297. }
  298. @Override
  299. protected void onPostExecute(final Boolean success) {
  300. mAuthTask = null;
  301. showProgress(false);
  302. if (success) {
  303. // finish();
  304. } else {
  305. mPasswordView.setError(getString(R.string.error_incorrect_password));
  306. mPasswordView.requestFocus();
  307. }
  308. }
  309. @Override
  310. protected void onCancelled() {
  311. mAuthTask = null;
  312. showProgress(false);
  313. }
  314. }
  315. }