login function added, include library Jsoup

This commit is contained in:
Jerry Wu 2018-07-11 00:02:12 +08:00
parent b4f565e41f
commit 8f2305303c
10 changed files with 1457 additions and 1 deletions

View File

@ -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'

View File

@ -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>

View 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);
}
}

View 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);
}
}

View File

@ -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;
}
}
}

View 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;
}
}

View File

@ -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);
}
}

View 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>

View File

@ -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>

View File

@ -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>