login function added, include library Jsoup
This commit is contained in:
parent
b4f565e41f
commit
8f2305303c
@ -22,6 +22,9 @@ dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.android.support:appcompat-v7:26.1.0'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
|
||||
implementation 'com.android.support:design:26.1.0'
|
||||
// jsoup HTML parser library @ https://jsoup.org/
|
||||
compile 'org.jsoup:jsoup:1.11.3'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
|
@ -2,6 +2,11 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="tech.goda.studyck">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@ -16,6 +21,9 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:label="@string/title_activity_login"></activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
219
app/src/main/java/tech/goda/studyck/KeyStoreHelper.java
Normal file
219
app/src/main/java/tech/goda/studyck/KeyStoreHelper.java
Normal file
@ -0,0 +1,219 @@
|
||||
package tech.goda.studyck;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.security.KeyPairGeneratorSpec;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyProperties;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
/**
|
||||
* Created by Jerry on 2018/7/8.
|
||||
*/
|
||||
|
||||
public class KeyStoreHelper {
|
||||
private static final String TAG = "KEYSTORE";
|
||||
|
||||
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
|
||||
private static final String AES_MODE = "AES/GCM/NoPadding";
|
||||
private static final String RSA_MODE = "RSA/ECB/PKCS1Padding";
|
||||
|
||||
private static final String KEYSTORE_ALIAS = "KEYSTORE_DEMO";
|
||||
|
||||
|
||||
private KeyStore keyStore;
|
||||
private SharedPreferencesHelper prefsHelper;
|
||||
|
||||
public KeyStoreHelper(Context context, SharedPreferencesHelper sharedPreferencesHelper) {
|
||||
try {
|
||||
prefsHelper = sharedPreferencesHelper;
|
||||
keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER);
|
||||
keyStore.load(null);
|
||||
|
||||
if (!keyStore.containsAlias(KEYSTORE_ALIAS)) {
|
||||
prefsHelper.setIV("");
|
||||
genKeyStoreKey(context);
|
||||
genAESKey();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void genKeyStoreKey(Context context) throws Exception {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
generateRSAKey_AboveApi23();
|
||||
} else {
|
||||
generateRSAKey_BelowApi23(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void generateRSAKey_AboveApi23() throws Exception {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator
|
||||
.getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEYSTORE_PROVIDER);
|
||||
|
||||
|
||||
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec
|
||||
.Builder(KEYSTORE_ALIAS, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
|
||||
.build();
|
||||
|
||||
keyPairGenerator.initialize(keyGenParameterSpec);
|
||||
keyPairGenerator.generateKeyPair();
|
||||
|
||||
}
|
||||
|
||||
private void generateRSAKey_BelowApi23(Context context) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
|
||||
Calendar start = Calendar.getInstance();
|
||||
Calendar end = Calendar.getInstance();
|
||||
end.add(Calendar.YEAR, 30);
|
||||
|
||||
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
|
||||
.setAlias(KEYSTORE_ALIAS)
|
||||
.setSubject(new X500Principal("CN=" + KEYSTORE_ALIAS))
|
||||
.setSerialNumber(BigInteger.TEN)
|
||||
.setStartDate(start.getTime())
|
||||
.setEndDate(end.getTime())
|
||||
.build();
|
||||
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator
|
||||
.getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEYSTORE_PROVIDER);
|
||||
|
||||
keyPairGenerator.initialize(spec);
|
||||
keyPairGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
public String encrypt(String plainText) {
|
||||
try {
|
||||
return encryptAES(plainText);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, Log.getStackTraceString(e));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
public String decrypt(String encryptedText) {
|
||||
try {
|
||||
return decryptAES(encryptedText);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, Log.getStackTraceString(e));
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private String encryptRSA(byte[] plainText) throws Exception {
|
||||
PublicKey publicKey = keyStore.getCertificate(KEYSTORE_ALIAS).getPublicKey();
|
||||
|
||||
Cipher cipher = Cipher.getInstance(RSA_MODE);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
|
||||
byte[] encryptedByte = cipher.doFinal(plainText);
|
||||
return Base64.encodeToString(encryptedByte, Base64.DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
private byte[] decryptRSA(String encryptedText) throws Exception {
|
||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEYSTORE_ALIAS, null);
|
||||
|
||||
Cipher cipher = Cipher.getInstance(RSA_MODE);
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
|
||||
byte[] encryptedBytes = Base64.decode(encryptedText, Base64.DEFAULT);
|
||||
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
|
||||
|
||||
return decryptedBytes;
|
||||
}
|
||||
|
||||
private void genAESKey() throws Exception {
|
||||
// Generate AES-Key
|
||||
byte[] aesKey = new byte[16];
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
secureRandom.nextBytes(aesKey);
|
||||
|
||||
|
||||
// Generate 12 bytes iv then save to SharedPrefs
|
||||
byte[] generated = secureRandom.generateSeed(12);
|
||||
String iv = Base64.encodeToString(generated, Base64.DEFAULT);
|
||||
prefsHelper.setIV(iv);
|
||||
|
||||
|
||||
// Encrypt AES-Key with RSA Public Key then save to SharedPrefs
|
||||
String encryptAESKey = encryptRSA(aesKey);
|
||||
prefsHelper.setAESKey(encryptAESKey);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* AES Encryption
|
||||
* @param plainText: A string which needs to be encrypted.
|
||||
* @return A base64's string after encrypting.
|
||||
*/
|
||||
private String encryptAES(String plainText) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(AES_MODE);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, getAESKey(), new IvParameterSpec(getIV()));
|
||||
|
||||
// 加密過後的byte
|
||||
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
|
||||
|
||||
// 將byte轉為base64的string編碼
|
||||
return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
private String decryptAES(String encryptedText) throws Exception {
|
||||
// 將加密過後的Base64編碼格式 解碼成 byte
|
||||
byte[] decodedBytes = Base64.decode(encryptedText.getBytes(), Base64.DEFAULT);
|
||||
|
||||
// 將解碼過後的byte 使用AES解密
|
||||
Cipher cipher = Cipher.getInstance(AES_MODE);
|
||||
cipher.init(Cipher.DECRYPT_MODE, getAESKey(), new IvParameterSpec(getIV()));
|
||||
|
||||
return new String(cipher.doFinal(decodedBytes));
|
||||
}
|
||||
|
||||
|
||||
private byte[] getIV() {
|
||||
String prefIV = prefsHelper.getIV();
|
||||
return Base64.decode(prefIV, Base64.DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private SecretKeySpec getAESKey() throws Exception {
|
||||
String encryptedKey = prefsHelper.getAESKey();
|
||||
byte[] aesKey = decryptRSA(encryptedKey);
|
||||
|
||||
return new SecretKeySpec(aesKey, AES_MODE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
314
app/src/main/java/tech/goda/studyck/LoginActivity.java
Normal file
314
app/src/main/java/tech/goda/studyck/LoginActivity.java
Normal file
@ -0,0 +1,314 @@
|
||||
package tech.goda.studyck;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
|
||||
import android.content.CursorLoader;
|
||||
import android.content.Loader;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static android.Manifest.permission.READ_CONTACTS;
|
||||
import static tech.goda.studyck.Network.LOGIN_URI;
|
||||
|
||||
/**
|
||||
* A login screen that offers login via email/password.
|
||||
*/
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
/**
|
||||
* Id to identity READ_CONTACTS permission request.
|
||||
*/
|
||||
private static final int REQUEST_READ_CONTACTS = 0;
|
||||
|
||||
/**
|
||||
* A dummy authentication store containing known user names and passwords.
|
||||
* TODO: remove after connecting to a real authentication system.
|
||||
*/
|
||||
private static final String[] DUMMY_CREDENTIALS = new String[]{
|
||||
"foo@example.com:hello", "bar@example.com:world"
|
||||
};
|
||||
/**
|
||||
* Keep track of the login task to ensure we can cancel it if requested.
|
||||
*/
|
||||
private UserLoginTask mAuthTask = null;
|
||||
|
||||
// UI references.
|
||||
private AutoCompleteTextView mEmailView;
|
||||
private EditText mPasswordView;
|
||||
private View mProgressView;
|
||||
private View mLoginFormView;
|
||||
private String response = null;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_login);
|
||||
// Set up the login form.
|
||||
|
||||
|
||||
|
||||
|
||||
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
|
||||
|
||||
mPasswordView = (EditText) findViewById(R.id.password);
|
||||
mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
|
||||
if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
|
||||
attemptLogin();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Intent intent = this.getIntent();
|
||||
|
||||
try{
|
||||
mEmailView.setText(intent.getExtras().getString("account"));
|
||||
mPasswordView.setText(intent.getExtras().getString("password"));
|
||||
} catch(NullPointerException e){
|
||||
Log.e("Login", Log.getStackTraceString(e));
|
||||
}
|
||||
|
||||
Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
|
||||
mEmailSignInButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
attemptLogin();
|
||||
}
|
||||
});
|
||||
|
||||
mLoginFormView = findViewById(R.id.login_form);
|
||||
mProgressView = findViewById(R.id.login_progress);
|
||||
}
|
||||
|
||||
private boolean mayRequestContacts() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
return true;
|
||||
}
|
||||
if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
}
|
||||
if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
|
||||
Snackbar.make(mEmailView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(android.R.string.ok, new View.OnClickListener() {
|
||||
@Override
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public void onClick(View v) {
|
||||
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback received when a permissions request has been completed.
|
||||
*/
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
if (requestCode == REQUEST_READ_CONTACTS) {
|
||||
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to sign in or register the account specified by the login form.
|
||||
* If there are form errors (invalid email, missing fields, etc.), the
|
||||
* errors are presented and no actual login attempt is made.
|
||||
*/
|
||||
private void attemptLogin() {
|
||||
if (mAuthTask != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset errors.
|
||||
mEmailView.setError(null);
|
||||
mPasswordView.setError(null);
|
||||
|
||||
// Store values at the time of the login attempt.
|
||||
String email = mEmailView.getText().toString();
|
||||
String password = mPasswordView.getText().toString();
|
||||
|
||||
boolean cancel = false;
|
||||
View focusView = null;
|
||||
|
||||
// Check for a valid password, if the user entered one.
|
||||
if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
|
||||
mPasswordView.setError(getString(R.string.error_invalid_password));
|
||||
focusView = mPasswordView;
|
||||
cancel = true;
|
||||
}
|
||||
|
||||
// Check for a valid email address.
|
||||
if (TextUtils.isEmpty(email)) {
|
||||
mEmailView.setError(getString(R.string.error_field_required));
|
||||
focusView = mEmailView;
|
||||
cancel = true;
|
||||
} else if (!isEmailValid(email)) {
|
||||
mEmailView.setError(getString(R.string.error_invalid_email));
|
||||
focusView = mEmailView;
|
||||
cancel = true;
|
||||
}
|
||||
|
||||
if (cancel) {
|
||||
// There was an error; don't attempt login and focus the first
|
||||
// form field with an error.
|
||||
focusView.requestFocus();
|
||||
} else {
|
||||
// Show a progress spinner, and kick off a background task to
|
||||
// perform the user login attempt.
|
||||
showProgress(true);
|
||||
mAuthTask = new UserLoginTask(email, password);
|
||||
mAuthTask.execute((Void) null);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmailValid(String email) {
|
||||
//TODO: Replace this with your own logic
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isPasswordValid(String password) {
|
||||
//TODO: Replace this with your own logic
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the progress UI and hides the login form.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
|
||||
private void showProgress(final boolean show) {
|
||||
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
|
||||
// for very easy animations. If available, use these APIs to fade-in
|
||||
// the progress spinner.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
||||
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
|
||||
|
||||
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
||||
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
|
||||
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||
mProgressView.animate().setDuration(shortAnimTime).alpha(
|
||||
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// The ViewPropertyAnimator APIs are not available, so simply show
|
||||
// and hide the relevant UI components.
|
||||
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents an asynchronous login/registration task used to authenticate
|
||||
* the user.
|
||||
*/
|
||||
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private final String mEmail;
|
||||
private final String mPassword;
|
||||
|
||||
UserLoginTask(String email, String password) {
|
||||
mEmail = email;
|
||||
mPassword = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
// TODO: attempt authentication against a network service.
|
||||
|
||||
// Simulate network access.
|
||||
Map<String, String> param = new HashMap<>();
|
||||
param.put("f_uid", mEmail);
|
||||
param.put("f_pwd", mPassword);
|
||||
response = Network.requestPost(LOGIN_URI, param);
|
||||
//Thread.sleep(2000);
|
||||
Log.e("Login", response);
|
||||
return !response.contains("錯誤");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean success) {
|
||||
mAuthTask = null;
|
||||
showProgress(false);
|
||||
|
||||
if (success) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("response", response);
|
||||
intent.putExtra("account", mEmail);
|
||||
intent.putExtra("password", mPassword);
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
} else {
|
||||
mPasswordView.setError(getString(R.string.error_incorrect_password));
|
||||
mPasswordView.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
mAuthTask = null;
|
||||
showProgress(false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
|
||||
//Toast.makeText(getApplicationContext(), "請登入SAD", Toast.LENGTH_SHORT).show();
|
||||
finishAffinity();
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,305 @@
|
||||
package tech.goda.studyck;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.Layout;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private static final int PICK_FILE_REQUEST = 0;
|
||||
private static final int LOGIN = 1;
|
||||
TextView messageText;
|
||||
Button uploadButton, choose;
|
||||
EditText editFileName;
|
||||
int serverResponseCode = 0;
|
||||
|
||||
String uploadServerUri = null;
|
||||
InputStream in;
|
||||
String fileName;
|
||||
String loginResponse;
|
||||
/********** File Path *************/
|
||||
String uploadFilePath = Environment.getExternalStorageDirectory().getPath() + "/test.png";
|
||||
Button button3;
|
||||
|
||||
KeyStoreHelper keyStoreHelper;
|
||||
SharedPreferencesHelper preferencesHelper;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
Log.e("Directory", uploadFilePath);
|
||||
uploadButton = findViewById(R.id.uploadButton);
|
||||
choose = findViewById(R.id.choose);
|
||||
messageText = findViewById(R.id.messageText);
|
||||
editFileName = findViewById(R.id.fileName);
|
||||
button3 = findViewById(R.id.button3);
|
||||
|
||||
CookieManager manager = new CookieManager();
|
||||
CookieHandler.setDefault(manager);
|
||||
|
||||
preferencesHelper = new SharedPreferencesHelper(getApplicationContext());
|
||||
keyStoreHelper = new KeyStoreHelper(getApplicationContext(), preferencesHelper);
|
||||
|
||||
messageText.setText("Uploading file path : " + uploadFilePath);
|
||||
|
||||
|
||||
//uploadServerUri = "http://study.ck.tp.edu.tw/login_chk.asp";
|
||||
uploadServerUri = "http://192.168.173.104/WebPageTest/upload-big5.php";
|
||||
|
||||
uploadButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
messageText.setText("uploading started.....");
|
||||
}
|
||||
});
|
||||
|
||||
Network.uploadFile(uploadServerUri, in, editFileName.getText().toString());
|
||||
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
|
||||
button3.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final Map<String, String> params = new HashMap<>();
|
||||
|
||||
params.put("f_mnuid", "");
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
Network.requestPost("http://study.ck.tp.edu.tw", params);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
|
||||
choose.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showFileChooser();
|
||||
}
|
||||
});
|
||||
|
||||
String encryptedText = preferencesHelper.getInput();
|
||||
final String mEmail = preferencesHelper.getString(SharedPreferencesHelper.PREF_AC);
|
||||
final String mPassword = keyStoreHelper.decrypt(encryptedText);
|
||||
if(mEmail.equals("") || mPassword.equals("")){
|
||||
callLogin(mEmail, mPassword);
|
||||
}
|
||||
else{
|
||||
final Map<String, String> param = new HashMap<>();
|
||||
param.put("f_uid", mEmail);
|
||||
param.put("f_pwd", mPassword);
|
||||
Toast.makeText(getApplicationContext(), "自動登入中...", Toast.LENGTH_SHORT).show();
|
||||
|
||||
View layout = findViewById(android.R.id.content);
|
||||
layout.setVisibility(View.GONE);
|
||||
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
loginResponse = Network.requestPost(Network.LOGIN_URI, param);
|
||||
//Thread.sleep(2000);
|
||||
Log.e("Login", loginResponse);
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(!loginResponse.contains("錯誤")){
|
||||
LoginSuccess(mEmail, mPassword);
|
||||
}
|
||||
else{
|
||||
Toast.makeText(getApplicationContext(), "Login Failed", Toast.LENGTH_SHORT).show();
|
||||
callLogin(mEmail, mPassword);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
||||
//return !response.contains("錯誤");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void callLogin(String account, String password) {
|
||||
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
|
||||
intent.putExtra("account", account);
|
||||
intent.putExtra("password", password);
|
||||
startActivityForResult(intent, LOGIN);
|
||||
}
|
||||
|
||||
|
||||
private void LoginSuccess(String account, String password) {
|
||||
View layout = findViewById(android.R.id.content);
|
||||
Toast.makeText(getApplicationContext(), "登入成功!!", Toast.LENGTH_SHORT).show();
|
||||
Document doc = Jsoup.parse(loginResponse);
|
||||
String name = doc.select("form > font").first().text();
|
||||
messageText.setText(name);
|
||||
|
||||
// Save Login Information
|
||||
String encryptedPassword = keyStoreHelper.encrypt(password);
|
||||
preferencesHelper.setInput(encryptedPassword);
|
||||
preferencesHelper.putString(SharedPreferencesHelper.PREF_AC, account);
|
||||
|
||||
layout.setVisibility(View.VISIBLE);
|
||||
|
||||
}
|
||||
|
||||
private void showFileChooser() {
|
||||
Intent intent = new Intent();
|
||||
//sets the select file to all types of files
|
||||
intent.setType("*/*");
|
||||
//allows to select data and return it
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
//starts new activity to select file and return data
|
||||
startActivityForResult(Intent.createChooser(intent,"Choose File to Upload.."), PICK_FILE_REQUEST);
|
||||
}
|
||||
|
||||
private boolean isVirtualFile(Uri uri) {
|
||||
if (!DocumentsContract.isDocumentUri(this, uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Cursor cursor = getContentResolver().query(
|
||||
uri,
|
||||
new String[] { DocumentsContract.Document.COLUMN_FLAGS },
|
||||
null, null, null);
|
||||
|
||||
int flags = 0;
|
||||
if (cursor.moveToFirst()) {
|
||||
flags = cursor.getInt(0);
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
|
||||
}
|
||||
|
||||
private InputStream getInputStreamForVirtualFile(Uri uri, String mimeTypeFilter)
|
||||
throws IOException {
|
||||
|
||||
ContentResolver resolver = getContentResolver();
|
||||
|
||||
String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter);
|
||||
|
||||
if (openableMimeTypes == null ||
|
||||
openableMimeTypes.length < 1) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
return resolver
|
||||
.openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
|
||||
.createInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
switch (requestCode){
|
||||
case PICK_FILE_REQUEST:
|
||||
if(resultCode == RESULT_OK) {
|
||||
if (data == null) {
|
||||
//no data present
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Uri selectedFileUri = data.getData();
|
||||
fileName = DocumentFile.fromSingleUri(this, selectedFileUri).getName();
|
||||
editFileName.setText(fileName);
|
||||
messageText.setText("Upload File:" + fileName + "(Change file name below)");
|
||||
Log.e("GetPathDocumentName", fileName);
|
||||
|
||||
try {
|
||||
if (isVirtualFile(selectedFileUri)) {
|
||||
Log.e("GetPath", "This is virtual file");
|
||||
in = getInputStreamForVirtualFile(selectedFileUri, "*/*");
|
||||
|
||||
} else {
|
||||
in = getContentResolver().openInputStream(selectedFileUri);
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.e("GetPathError", e.toString());
|
||||
}
|
||||
}
|
||||
/*if(uploadFilePath != null && !uploadFilePath.equals("")){
|
||||
messageText.setText(uploadFilePath);
|
||||
}else{
|
||||
Toast.makeText(this,"Cannot upload file to server",Toast.LENGTH_SHORT).show();
|
||||
}*/
|
||||
break;
|
||||
case LOGIN:
|
||||
if(resultCode == RESULT_OK){
|
||||
Bundle bundle = data.getExtras();
|
||||
String account = bundle.getString("account");
|
||||
String password = bundle.getString("password");
|
||||
loginResponse = bundle.getString("response");
|
||||
//messageText.setText(loginResponse);
|
||||
LoginSuccess(account, password);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
381
app/src/main/java/tech/goda/studyck/Network.java
Normal file
381
app/src/main/java/tech/goda/studyck/Network.java
Normal file
@ -0,0 +1,381 @@
|
||||
package tech.goda.studyck;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Jerry on 2018/7/7.
|
||||
*/
|
||||
|
||||
public class Network {
|
||||
public static final String LOGIN_URI = "http://study.ck.tp.edu.tw/login_chk.asp";
|
||||
|
||||
public static String uploadFile(String sourceFileUri, InputStream in, String uploadFileName) {
|
||||
|
||||
|
||||
//String fileName = sourceFileUri;
|
||||
HttpURLConnection conn = null;
|
||||
//CookieManager cookieManager = null;
|
||||
DataOutputStream dos = null;
|
||||
String lineEnd = "\r\n";
|
||||
String twoHyphens = "--";
|
||||
String boundary = "*****";
|
||||
int bytesRead, bytesAvailable, bufferSize;
|
||||
byte[] buffer;
|
||||
int maxBufferSize = 1 * 1024 * 1024;
|
||||
|
||||
//File sourceFile = new File(sourceFileUri);
|
||||
String response = null;
|
||||
if(in == null){
|
||||
/*runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(MainActivity.this, "Please Choose File First.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});*/
|
||||
return null;
|
||||
}
|
||||
else{
|
||||
try {
|
||||
|
||||
// open a URL connection to the Servlet
|
||||
//FileInputStream fileInputStream = new FileInputStream(sourceFile);
|
||||
URL url = new URL(sourceFileUri);
|
||||
|
||||
// Open a HTTP connection to the URL
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setDoInput(true); // Allow Inputs
|
||||
conn.setDoOutput(true); // Allow Outputs
|
||||
conn.setUseCaches(false); // Don't use a Cached Copy
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||
|
||||
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
|
||||
conn.setRequestProperty("f_file", uploadFileName);
|
||||
|
||||
dos = new DataOutputStream(conn.getOutputStream());
|
||||
|
||||
dos.writeBytes(twoHyphens + boundary + lineEnd);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"f_hwintro\""+ lineEnd + lineEnd);
|
||||
dos.writeBytes("" + lineEnd);
|
||||
dos.writeBytes(twoHyphens + boundary + lineEnd);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"f_file\";filename=\"");
|
||||
dos.write(uploadFileName.getBytes());
|
||||
dos.writeBytes("\"" + lineEnd);
|
||||
|
||||
dos.writeBytes(lineEnd);
|
||||
|
||||
// create a buffer of maximum size
|
||||
bytesAvailable = in.available();
|
||||
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
buffer = new byte[bufferSize];
|
||||
|
||||
// read file and write it into form...
|
||||
bytesRead = in.read(buffer, 0, bufferSize);
|
||||
while (bytesRead > 0) {
|
||||
|
||||
dos.write(buffer, 0, bufferSize);
|
||||
bytesAvailable = in.available();
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
bytesRead = in.read(buffer, 0, bufferSize);
|
||||
|
||||
}
|
||||
|
||||
// send multipart form data necessary after file data...
|
||||
dos.writeBytes(lineEnd);
|
||||
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
|
||||
|
||||
// Responses from the server (code and message)
|
||||
int serverResponseCode = conn.getResponseCode();
|
||||
String serverResponseMessage = conn.getResponseMessage();
|
||||
try{
|
||||
BufferedReader br;
|
||||
if (200 <= serverResponseCode && serverResponseCode <= 299) {
|
||||
br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "big5"));
|
||||
} else {
|
||||
br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "big5"));
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String output;
|
||||
while ((output = br.readLine()) != null) {
|
||||
sb.append(output);
|
||||
}
|
||||
|
||||
response = sb.toString();
|
||||
Log.e("Response", response);
|
||||
} catch(java.io.IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.e("uploadFile", "HTTP Response is : "
|
||||
+ serverResponseMessage + ": " + serverResponseCode);
|
||||
|
||||
if(serverResponseCode == 200){
|
||||
|
||||
/*runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
|
||||
String msg = "File Upload Completed.";
|
||||
|
||||
messageText.setText(msg);
|
||||
//Toast.makeText(MainActivity.this, "File Upload Completed.",
|
||||
//Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
//close the streams //
|
||||
in.close();
|
||||
dos.flush();
|
||||
dos.close();
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
Log.e("Upload file to server", "error: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("Upload", "Exception : "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
/*if (!sourceFile.isFile()) {
|
||||
|
||||
Log.e("uploadFile", "Source File not exist :"
|
||||
+uploadFilePath);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
try {
|
||||
|
||||
// open a URL connection to the Servlet
|
||||
FileInputStream fileInputStream = new FileInputStream(sourceFile);
|
||||
URL url = new URL(uploadServerUri);
|
||||
|
||||
// Open a HTTP connection to the URL
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setDoInput(true); // Allow Inputs
|
||||
conn.setDoOutput(true); // Allow Outputs
|
||||
conn.setUseCaches(false); // Don't use a Cached Copy
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
|
||||
conn.setRequestProperty("f_file", fileName);
|
||||
|
||||
dos = new DataOutputStream(conn.getOutputStream());
|
||||
|
||||
dos.writeBytes(twoHyphens + boundary + lineEnd);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"f_hwintro\""+ lineEnd + lineEnd);
|
||||
dos.writeBytes("" + lineEnd);
|
||||
dos.writeBytes(twoHyphens + boundary + lineEnd);
|
||||
dos.writeBytes("Content-Disposition: form-data; name=\"f_file\";filename=\""
|
||||
+ fileName + "\"" + lineEnd);
|
||||
|
||||
dos.writeBytes(lineEnd);
|
||||
|
||||
// create a buffer of maximum size
|
||||
bytesAvailable = fileInputStream.available();
|
||||
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
buffer = new byte[bufferSize];
|
||||
|
||||
// read file and write it into form...
|
||||
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
|
||||
while (bytesRead > 0) {
|
||||
|
||||
dos.write(buffer, 0, bufferSize);
|
||||
bytesAvailable = fileInputStream.available();
|
||||
bufferSize = Math.min(bytesAvailable, maxBufferSize);
|
||||
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
|
||||
|
||||
}
|
||||
|
||||
// send multipart form data necesssary after file data...
|
||||
dos.writeBytes(lineEnd);
|
||||
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
|
||||
|
||||
|
||||
|
||||
// Responses from the server (code and message)
|
||||
serverResponseCode = conn.getResponseCode();
|
||||
String serverResponseMessage = conn.getResponseMessage();
|
||||
try{
|
||||
BufferedReader br = null;
|
||||
if (200 <= serverResponseCode && serverResponseCode <= 299) {
|
||||
br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
} else {
|
||||
br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String output;
|
||||
while ((output = br.readLine()) != null) {
|
||||
sb.append(output);
|
||||
}
|
||||
|
||||
Log.e("Response", sb.toString());
|
||||
} catch(java.io.IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.e("uploadFile", "HTTP Response is : "
|
||||
+ serverResponseMessage + ": " + serverResponseCode);
|
||||
|
||||
if(serverResponseCode == 200){
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
|
||||
String msg = "File Upload Completed.";
|
||||
|
||||
messageText.setText(msg);
|
||||
Toast.makeText(MainActivity.this, "File Upload Complete.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//close the streams //
|
||||
fileInputStream.close();
|
||||
dos.flush();
|
||||
dos.close();
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
|
||||
|
||||
|
||||
Log.e("Upload file to server", "error: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
|
||||
e.printStackTrace();
|
||||
|
||||
|
||||
Log.e("Upload", "Exception : "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
return serverResponseCode;
|
||||
|
||||
} // End else block
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String requestPost(String uri, Map<String, String> params){
|
||||
HttpURLConnection conn;
|
||||
DataOutputStream dos;
|
||||
String response = null;
|
||||
try {
|
||||
// open a URL connection to the Servlet
|
||||
URL url = new URL(uri);
|
||||
// Open a HTTP connection to the URL
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setDoInput(true); // Allow Inputs
|
||||
conn.setDoOutput(true); // Allow Outputs
|
||||
conn.setUseCaches(false); // Don't use a Cached Copy
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Connection", "Keep-Alive");
|
||||
dos = new DataOutputStream(conn.getOutputStream());
|
||||
|
||||
Set keySet = params.keySet();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object objKey : keySet) {
|
||||
//有了鍵就可以通過map集合的get方法獲取其對應的値
|
||||
|
||||
String key = objKey.toString();
|
||||
String value = params.get(key);
|
||||
|
||||
sb.append(key).append("=").append(value).append("&");
|
||||
|
||||
Log.e("Params", "key: " + key + ", value: " + value);
|
||||
}
|
||||
if(params.size() != 0){
|
||||
sb.deleteCharAt(sb.length()-1);
|
||||
}
|
||||
|
||||
Log.e("StringBuilder", sb.toString());
|
||||
dos.writeBytes(sb.toString());
|
||||
|
||||
|
||||
// Responses from the server (code and message)
|
||||
int serverResponseCode = conn.getResponseCode();
|
||||
String serverResponseMessage = conn.getResponseMessage();
|
||||
try{
|
||||
BufferedReader br;
|
||||
if (200 <= serverResponseCode && serverResponseCode <= 299) {
|
||||
br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "big5"));
|
||||
} else {
|
||||
br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "UTF-8"));
|
||||
}
|
||||
sb = new StringBuilder();
|
||||
String output;
|
||||
while ((output = br.readLine()) != null) {
|
||||
sb.append(output);
|
||||
}
|
||||
response = sb.toString();
|
||||
Log.e("Response", response);
|
||||
} catch(java.io.IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.e("uploadFile", "HTTP Response is : "
|
||||
+ serverResponseMessage + ": " + serverResponseCode);
|
||||
|
||||
if(serverResponseCode == 200){
|
||||
|
||||
/*runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
|
||||
String msg = "File Upload Completed.";
|
||||
|
||||
messageText.setText(msg);
|
||||
//Toast.makeText(MainActivity.this, "File Upload Completed.",
|
||||
//Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
dos.flush();
|
||||
dos.close();
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
Log.e("Upload file to server", "error: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("Upload", "Exception : "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package tech.goda.studyck;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
/**
|
||||
* Created by Jerry on 2018/7/8.
|
||||
*/
|
||||
|
||||
|
||||
public class SharedPreferencesHelper {
|
||||
|
||||
private static final String SHARED_PREF_NAME = "KEYSTORE_SETTING";
|
||||
|
||||
private static final String PREF_KEY_AES = "PREF_KEY_AES";
|
||||
private static final String PREF_KEY_IV = "PREF_KEY_IV";
|
||||
private static final String PREF_KEY_INPUT = "PREF_KEY_INPUT";
|
||||
public static final String PREF_AC = "PREF_AC";
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
|
||||
|
||||
SharedPreferencesHelper(Context context){
|
||||
sharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
|
||||
String getString(String key) {
|
||||
return sharedPreferences.getString(key, "");
|
||||
}
|
||||
|
||||
void putString(String key, String value) {
|
||||
sharedPreferences.edit()
|
||||
.putString(key, value)
|
||||
.apply();
|
||||
}
|
||||
|
||||
private boolean getBoolean(String key) {
|
||||
return sharedPreferences.getBoolean(key, false);
|
||||
}
|
||||
|
||||
private void putBoolean(String key, boolean value) {
|
||||
sharedPreferences.edit()
|
||||
.putBoolean(key, value)
|
||||
.apply();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void setIV(String value) {
|
||||
putString(PREF_KEY_IV, value);
|
||||
}
|
||||
|
||||
String getIV() {
|
||||
return getString(PREF_KEY_IV);
|
||||
}
|
||||
|
||||
void setAESKey(String value) {
|
||||
putString(PREF_KEY_AES, value);
|
||||
}
|
||||
|
||||
String getAESKey() {
|
||||
return getString(PREF_KEY_AES);
|
||||
}
|
||||
|
||||
public void setInput(String value) {
|
||||
putString(PREF_KEY_INPUT, value);
|
||||
}
|
||||
|
||||
String getInput() {
|
||||
return getString(PREF_KEY_INPUT);
|
||||
}
|
||||
|
||||
}
|
77
app/src/main/res/layout/activity_login.xml
Normal file
77
app/src/main/res/layout/activity_login.xml
Normal file
@ -0,0 +1,77 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
tools:context="tech.goda.studyck.LoginActivity">
|
||||
|
||||
<!-- Login progress -->
|
||||
<ProgressBar
|
||||
android:id="@+id/login_progress"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/login_form"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/email_login_form"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/prompt_email"
|
||||
android:inputType="textEmailAddress"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true" />
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/prompt_password"
|
||||
android:imeActionId="6"
|
||||
android:imeActionLabel="@string/action_sign_in_short"
|
||||
android:imeOptions="actionUnspecified"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true" />
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/email_sign_in_button"
|
||||
style="?android:textAppearanceSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/action_sign_in"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/mainActivity"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
@ -7,12 +8,83 @@
|
||||
tools:context="tech.goda.studyck.MainActivity">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/messageText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="Hello World!"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.29000002" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/uploadButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Upload"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/messageText"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/choose"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Choose"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="@+id/messageText"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/fileName"
|
||||
android:layout_width="218dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ems="10"
|
||||
android:inputType="textPersonName"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/messageText"
|
||||
app:layout_constraintVertical_bias="0.13" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Request Test"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/fileName"
|
||||
app:layout_constraintVertical_bias="0.268" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:id="@+id/guideline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.5" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
@ -1,3 +1,17 @@
|
||||
<resources>
|
||||
<string name="app_name">StudyCK</string>
|
||||
<string name="title_activity_login">Sign in</string>
|
||||
|
||||
<!-- Strings related to login -->
|
||||
<string name="prompt_email">Account</string>
|
||||
<string name="prompt_password">Password</string>
|
||||
<string name="action_sign_in">Sign</string>
|
||||
<string name="action_sign_in_short">Sign in</string>
|
||||
<string name="error_invalid_email">This email address is invalid</string>
|
||||
<string name="error_invalid_password">This password is too short</string>
|
||||
<string name="error_incorrect_password">Account or password is incorrect</string>
|
||||
<string name="error_field_required">This field is required</string>
|
||||
<string name="permission_rationale">"Contacts permissions are needed for providing email
|
||||
completions."
|
||||
</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user