Login speed improved and network usage reduced

This commit is contained in:
Caesar2011
2018-07-15 20:11:04 +02:00
parent f052e18d63
commit 792807154e
8 changed files with 184 additions and 50 deletions

View File

@@ -2,33 +2,33 @@ package de.sebse.fuplanner;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Pair;
import android.view.View;
import android.support.design.widget.NavigationView; import android.support.design.widget.NavigationView;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat; import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Pair;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import java.util.Calendar; import java.util.Calendar;
import java.util.Iterator; import java.util.Iterator;
import de.sebse.fuplanner.fragments.LoginFragment; import de.sebse.fuplanner.fragments.LoginFragment;
import de.sebse.fuplanner.fragments.ScheduleFragment;
import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment;
import de.sebse.fuplanner.fragments.ModulesFragment; import de.sebse.fuplanner.fragments.ModulesFragment;
import de.sebse.fuplanner.fragments.ScheduleFragment;
import de.sebse.fuplanner.fragments.StartupFragment; import de.sebse.fuplanner.fragments.StartupFragment;
import de.sebse.fuplanner.services.GoogleAuth.Credentials; import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment;
import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth; import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth;
import de.sebse.fuplanner.services.KVV.KVV; import de.sebse.fuplanner.services.KVV.KVV;
import de.sebse.fuplanner.services.KVV.types.LoginToken;
import de.sebse.fuplanner.services.KVV.types.Modules; import de.sebse.fuplanner.services.KVV.types.Modules;
import de.sebse.fuplanner.tools.Conversion; import de.sebse.fuplanner.tools.Conversion;
import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.logging.Logger;
@@ -79,16 +79,16 @@ public class MainActivity extends AppCompatActivity
this.getGoogleAuth().connect(() -> { this.getGoogleAuth().connect(() -> {
getGoogleAuth().getLoginState(credentials -> { getGoogleAuth().getLoginState(credentials -> {
if (credentials == null || credentials.getUsername() == null || credentials.getPassword() == null) { if (credentials == null || credentials.getUsername() == null || credentials.getPassword() == null) {
MainActivity.this.getKVV().endUpdate(); this.getKVV().endUpdate();
toLogoutState(); toLogoutState();
return; return;
} }
MainActivity.this.getKVV().login(credentials.getUsername(), credentials.getPassword(), success -> { this.getKVV().login(credentials.getUsername(), credentials.getPassword(), success -> {
MainActivity.this.getKVV().endUpdate(); this.getKVV().endUpdate();
toLoginState(credentials); toLoginState(success);
}, error -> { }, error -> {
log.e(error); log.e(error);
MainActivity.this.getKVV().endUpdate(); this.getKVV().endUpdate();
toLogoutState(); toLogoutState();
}); });
}); });
@@ -204,11 +204,11 @@ public class MainActivity extends AppCompatActivity
return this.mKVV; return this.mKVV;
} }
private void toLoginState(Credentials credentials) { private void toLoginState(LoginToken loginToken) {
if (credentials == null) { if (loginToken == null) {
toLogoutState(); toLogoutState();
} else { } else {
toLoginState(credentials.getUsername()); toLoginState(loginToken.getFullname(), loginToken.getEmail());
} }
} }
@@ -222,6 +222,7 @@ public class MainActivity extends AppCompatActivity
View header = mNavigationView.getHeaderView(0); View header = mNavigationView.getHeaderView(0);
header.findViewById(R.id.imageView).setVisibility(View.GONE); header.findViewById(R.id.imageView).setVisibility(View.GONE);
header.findViewById(R.id.login_name).setVisibility(View.GONE); header.findViewById(R.id.login_name).setVisibility(View.GONE);
header.findViewById(R.id.login_mail).setVisibility(View.GONE);
header.findViewById(R.id.btn_login_page).setVisibility(View.VISIBLE); header.findViewById(R.id.btn_login_page).setVisibility(View.VISIBLE);
header.findViewById(R.id.btn_login_page).setOnClickListener(v -> { header.findViewById(R.id.btn_login_page).setOnClickListener(v -> {
DrawerLayout drawer = findViewById(R.id.drawer_layout); DrawerLayout drawer = findViewById(R.id.drawer_layout);
@@ -233,7 +234,7 @@ public class MainActivity extends AppCompatActivity
mNavigationView.inflateMenu(R.menu.activity_main_drawer); mNavigationView.inflateMenu(R.menu.activity_main_drawer);
} }
private void toLoginState(String username) { private void toLoginState(String fullname, String email) {
setTitle(R.string.courses); setTitle(R.string.courses);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragcontainer, ModulesFragment.newInstance()); fragmentTransaction.replace(R.id.fragcontainer, ModulesFragment.newInstance());
@@ -243,7 +244,9 @@ public class MainActivity extends AppCompatActivity
View header = mNavigationView.getHeaderView(0); View header = mNavigationView.getHeaderView(0);
header.findViewById(R.id.imageView).setVisibility(View.VISIBLE); header.findViewById(R.id.imageView).setVisibility(View.VISIBLE);
header.findViewById(R.id.login_name).setVisibility(View.VISIBLE); header.findViewById(R.id.login_name).setVisibility(View.VISIBLE);
((TextView) header.findViewById(R.id.login_name)).setText(username); header.findViewById(R.id.login_mail).setVisibility(View.VISIBLE);
((TextView) header.findViewById(R.id.login_name)).setText(fullname);
((TextView) header.findViewById(R.id.login_mail)).setText(email);
header.findViewById(R.id.btn_login_page).setVisibility(View.GONE); header.findViewById(R.id.btn_login_page).setVisibility(View.GONE);
mNavigationView.getMenu().clear(); mNavigationView.getMenu().clear();
mNavigationView.inflateMenu(R.menu.activity_main_drawer_login); mNavigationView.inflateMenu(R.menu.activity_main_drawer_login);
@@ -275,8 +278,8 @@ public class MainActivity extends AppCompatActivity
@Override @Override
public void onLoginFragmentInteraction(String username) { public void onLoginFragmentInteraction(LoginToken loginToken) {
toLoginState(username); toLoginState(loginToken.getFullname(), loginToken.getEmail());
} }
@Override @Override

View File

@@ -17,6 +17,7 @@ import de.sebse.fuplanner.MainActivity;
import de.sebse.fuplanner.R; import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth; import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth;
import de.sebse.fuplanner.services.KVV.KVV; import de.sebse.fuplanner.services.KVV.KVV;
import de.sebse.fuplanner.services.KVV.types.LoginToken;
import de.sebse.fuplanner.services.KVV.types.Modules; import de.sebse.fuplanner.services.KVV.types.Modules;
import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.logging.Logger;
@@ -66,8 +67,8 @@ public class LoginFragment extends Fragment {
if (modules != null) { if (modules != null) {
Button offline_btn = v.findViewById(R.id.btn_offline); Button offline_btn = v.findViewById(R.id.btn_offline);
offline_btn.setVisibility(View.VISIBLE); offline_btn.setVisibility(View.VISIBLE);
offline_btn.setText(v.getResources().getString(R.string.enter_offline_mode, modules.getUsername())); offline_btn.setText(v.getResources().getString(R.string.enter_offline_mode, modules.getToken().getUsername()));
offline_btn.setOnClickListener(v1 -> mListener.onLoginFragmentInteraction(modules.getUsername())); offline_btn.setOnClickListener(v1 -> mListener.onLoginFragmentInteraction(modules.getToken()));
} }
} }
} catch (IOException e) { } catch (IOException e) {
@@ -100,7 +101,7 @@ public class LoginFragment extends Fragment {
progressDialog.dismiss(); progressDialog.dismiss();
gauth.setLoginState(username, password); gauth.setLoginState(username, password);
if (mListener != null) if (mListener != null)
mListener.onLoginFragmentInteraction(username); mListener.onLoginFragmentInteraction(success);
}, error -> { }, error -> {
progressDialog.dismiss(); progressDialog.dismiss();
log.e("Error on KVV login!", error); log.e("Error on KVV login!", error);
@@ -142,6 +143,6 @@ public class LoginFragment extends Fragment {
* >Communicating with Other Fragments</a> for more information. * >Communicating with Other Fragments</a> for more information.
*/ */
public interface OnLoginFragmentInteractionListener { public interface OnLoginFragmentInteractionListener {
void onLoginFragmentInteraction(String username); void onLoginFragmentInteraction(LoginToken loginToken);
} }
} }

View File

@@ -10,7 +10,6 @@ import java.util.HashMap;
import de.sebse.fuplanner.services.KVV.types.LoginToken; import de.sebse.fuplanner.services.KVV.types.LoginToken;
import de.sebse.fuplanner.services.KVV.types.Modules; import de.sebse.fuplanner.services.KVV.types.Modules;
import de.sebse.fuplanner.tools.logging.Logger;
import de.sebse.fuplanner.tools.network.NetworkCallback; import de.sebse.fuplanner.tools.network.NetworkCallback;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback; import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
@@ -24,10 +23,8 @@ public class KVV {
private boolean isUpdating; private boolean isUpdating;
private ArrayList<LastTokenCallback> updatingList; private ArrayList<LastTokenCallback> updatingList;
private HashMap<String, Object> addons = new HashMap<>(); private HashMap<String, Object> addons = new HashMap<>();
private Logger log = new Logger(this);
public KVV(Context context) { public KVV(Context context) {
log.d("new kvv");
this.context = context; this.context = context;
this.isUpdating = false; this.isUpdating = false;
this.updatingList = new ArrayList<>(); this.updatingList = new ArrayList<>();
@@ -37,12 +34,20 @@ public class KVV {
KVVLogin login = new KVVLogin(this.context); KVVLogin login = new KVVLogin(this.context);
login.login(username, password, success -> { login.login(username, password, success -> {
lastToken = success; lastToken = success;
try {
login.saveOffline(this.context);
} catch (IOException e) {
e.printStackTrace();
}
callback.onResponse(success); callback.onResponse(success);
}, error); }, error);
} }
public void logout() { public void logout() {
if (lastToken != null) {
lastToken.delete(this.context);
lastToken = null; lastToken = null;
}
KVVModuleList modules = (KVVModuleList) addons.get("modules"); KVVModuleList modules = (KVVModuleList) addons.get("modules");
if (modules != null) { if (modules != null) {
modules.deleteModulesOffline(this.context); modules.deleteModulesOffline(this.context);

View File

@@ -1,8 +1,11 @@
package de.sebse.fuplanner.services.KVV; package de.sebse.fuplanner.services.KVV;
import android.content.Context; import android.content.Context;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -18,23 +21,71 @@ import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
*/ */
class KVVLogin extends HTTPService { class KVVLogin extends HTTPService {
public KVVLogin(Context context) { private LoginToken loginToken;
KVVLogin(Context context) {
super(context, false); super(context, false);
try {
this.loginToken = LoginToken.load(context);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} }
public void login(final String username, final String password, final NetworkCallback<LoginToken> callback, final NetworkErrorCallback error) { public void login(String username, String password, NetworkCallback<LoginToken> callback, NetworkErrorCallback errorCallback) {
if (this.loginToken != null) {
if (this.loginToken.getUsername().equals(username)) {
log.d("Old login found!");
testLogin(this.loginToken, success -> callback.onResponse(this.loginToken), error -> {
this.loginToken = null;
log.d("Old login invalid! Re-login...");
login(username, password, callback, errorCallback);
});
} else {
this.loginToken = null;
log.d("Login name no no match! Re-login...");
login(username, password, callback, errorCallback);
}
} else {
log.d("No login found! Loggin in!");
doLogin(username, password, token -> {
this.loginToken = token;
log.d("Logged in successfully! Testing...");
testLogin(this.loginToken, success -> callback.onResponse(this.loginToken), errorCallback);
}, errorCallback);
}
}
public void deleteOffline(Context context) {
if (this.loginToken != null)
this.loginToken.delete(context);
}
public void saveOffline(Context context) throws IOException {
if (this.loginToken != null)
this.loginToken.save(context);
}
private void doLogin(String username, String password, NetworkCallback<LoginToken> callback, NetworkErrorCallback error) {
startKVVSession(success -> { startKVVSession(success -> {
final String kvvJSESSIONID = success.get("JSESSIONID"); String kvvJSESSIONID = success.get("JSESSIONID");
getSAMLRequest(kvvJSESSIONID, success1 -> startIdentSession(success1.get("Location"), success11 -> { getSAMLRequest(kvvJSESSIONID, success1 -> startIdentSession(success1.get("Location"), success11 -> {
final String identJSESSIONID = success11.get("JSESSIONID"); String identJSESSIONID = success11.get("JSESSIONID");
final String ident_idp_authn_lc_key = success11.get("_idp_authn_lc_key"); String ident_idp_authn_lc_key = success11.get("_idp_authn_lc_key");
final String identROUTEID = success11.get("ROUTEID"); String identROUTEID = success11.get("ROUTEID");
loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success111 -> loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success11112 -> { loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success111 -> loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success11112 -> {
final String ident_idp_session = success11112.get("_idp_session"); String ident_idp_session = success11112.get("_idp_session");
getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, success1111 -> loginKVV(success1111.get("RelayState"), success1111.get("SAMLResponse"), kvvJSESSIONID, success111112 -> { getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, success1111 -> loginKVV(success1111.get("RelayState"), success1111.get("SAMLResponse"), kvvJSESSIONID, success111112 -> {
final LoginToken token = new LoginToken(username, success111112.get("shibsessionKey"), success111112.get("shibsessionName"), kvvJSESSIONID); LoginToken token = new LoginToken(username, success111112.get("shibsessionKey"), success111112.get("shibsessionName"), kvvJSESSIONID);
finishKVVlogin(token, success11111 -> { finishKVVlogin(token, success11111 -> {
Log.d("KVVMaster", "Login worked!"); log.d("Login worked!");
callback.onResponse(token); callback.onResponse(token);
}, error); }, error);
}, error), error); }, error), error);
@@ -43,6 +94,22 @@ class KVVLogin extends HTTPService {
}, error); }, error);
} }
private void testLogin(LoginToken loginToken, NetworkCallback<LoginToken> callback, NetworkErrorCallback errorCallback) {
get(String.format("https://kvv.imp.fu-berlin.de/direct/profile/%s.json", loginToken.getUsername()), loginToken.getCookies(), response -> {
String body = response.getParsed();
try {
JSONObject json = new JSONObject(body);
String displayName = json.getString("displayName");
String email = json.getString("email");
loginToken.setAdditionals(displayName, email);
callback.onResponse(loginToken);
} catch (JSONException e) {
errorCallback.onError(new NetworkError(100201, 403, "Cannot parse announcements!"));
return;
}
}, error -> errorCallback.onError(new NetworkError(100200, error.networkResponse.statusCode, "Testing login failed!")));
}
/* /*
GET https://kvv.imp.fu-berlin.de/portal/login GET https://kvv.imp.fu-berlin.de/portal/login
-> JSESSIONID 5c10406f-588c-4c16-96e9-c80d115417de.tomcat1 -> JSESSIONID 5c10406f-588c-4c16-96e9-c80d115417de.tomcat1
@@ -253,8 +320,8 @@ class KVVLogin extends HTTPService {
Pattern pattern = Pattern.compile(name+"=([^;]+);"); Pattern pattern = Pattern.compile(name+"=([^;]+);");
Matcher matcher = pattern.matcher(cookies); Matcher matcher = pattern.matcher(cookies);
if (!matcher.find()) { if (!matcher.find()) {
Log.d("GETcookie failed", name); log.d("GETcookie failed", name);
Log.d("GETcookie failed", cookies); log.d("GETcookie failed", cookies);
throw new NoSuchFieldException(); throw new NoSuchFieldException();
} }
return matcher.group(1); return matcher.group(1);

View File

@@ -46,7 +46,7 @@ public class KVVModuleList extends HTTPService {
this.token = token; this.token = token;
try { try {
Modules modules = Modules.load(context); Modules modules = Modules.load(context);
if (token == null || modules.getUsername().equals(token.getUsername())) if (token == null || token.isSameUser(modules.getToken()))
this.moduleList = modules; this.moduleList = modules;
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@@ -84,7 +84,7 @@ public class KVVModuleList extends HTTPService {
errorCallback.onError(new NetworkError(101101, 403, "No module list retrieved!")); errorCallback.onError(new NetworkError(101101, 403, "No module list retrieved!"));
return; return;
} }
Modules modules = new Modules(token.getUsername()); Modules modules = new Modules(token);
try { try {
JSONObject json = new JSONObject(body); JSONObject json = new JSONObject(body);
JSONArray sites = json.getJSONArray("site_collection"); JSONArray sites = json.getJSONArray("site_collection");

View File

@@ -1,16 +1,27 @@
package de.sebse.fuplanner.services.KVV.types; package de.sebse.fuplanner.services.KVV.types;
import android.content.Context;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
/** /**
* Created by sebastian on 29.10.17. * Created by sebastian on 29.10.17.
*/ */
public class LoginToken { public class LoginToken implements Serializable {
private static final String FILE_NAME = "LoginTokenSaving";
private final String username; private final String username;
private final String shibsessionKey; private final String shibsessionKey;
private final String shibsessionName; private final String shibsessionName;
private String JSESSIONID; private String JSESSIONID;
private String fullname;
private String email;
public LoginToken(String username, String shibsessionKey, String shibsessionName, String JSESSIONID) { public LoginToken(String username, String shibsessionKey, String shibsessionName, String JSESSIONID) {
this.username = username; this.username = username;
@@ -19,22 +30,56 @@ public class LoginToken {
this.JSESSIONID = JSESSIONID; this.JSESSIONID = JSESSIONID;
} }
public static LoginToken load(Context context) throws IOException, ClassNotFoundException {
FileInputStream fis = context.openFileInput(FILE_NAME);
ObjectInputStream is = new ObjectInputStream(fis);
LoginToken loginToken = (LoginToken) is.readObject();
is.close();
fis.close();
return loginToken;
}
public void save(Context context) throws IOException {
FileOutputStream fos = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.close();
fos.close();
}
public void delete(Context context) {
context.deleteFile(FILE_NAME);
}
public void setAdditionals(String fullname, String email) {
this.fullname = fullname;
this.email = email;
}
public String getUsername() { public String getUsername() {
return username; return username;
} }
public String getShibsessionKey() { private String getShibsessionKey() {
return shibsessionKey; return shibsessionKey;
} }
public String getShibsessionName() { private String getShibsessionName() {
return shibsessionName; return shibsessionName;
} }
public String getJSESSIONID() { private String getJSESSIONID() {
return JSESSIONID; return JSESSIONID;
} }
public String getFullname() {
return fullname;
}
public String getEmail() {
return email;
}
public HashMap<String, String> getCookies() { public HashMap<String, String> getCookies() {
HashMap<String, String> cookies = new HashMap<>(); HashMap<String, String> cookies = new HashMap<>();
cookies.put("JSESSIONID", getJSESSIONID()); cookies.put("JSESSIONID", getJSESSIONID());
@@ -43,6 +88,10 @@ public class LoginToken {
return cookies; return cookies;
} }
public boolean isSameUser(LoginToken token) {
return token != null && this.getUsername().equals(token.getUsername());
}
@Override @Override
public String toString() { public String toString() {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();

View File

@@ -27,12 +27,12 @@ import de.sebse.fuplanner.tools.SortedModuleList;
public class Modules implements Iterable<Modules.Module>, Serializable { public class Modules implements Iterable<Modules.Module>, Serializable {
private final SortedModuleList list; private final SortedModuleList list;
private String latestSemester = null; private String latestSemester = null;
private String username; private LoginToken token;
//private transient Logger log = new Logger(this); //private transient Logger log = new Logger(this);
private static final String FILE_NAME = "ModuleListSaving"; private static final String FILE_NAME = "ModuleListSaving";
public Modules(String username) { public Modules(LoginToken loginToken) {
this.username = username; this.token = loginToken;
this.list = new SortedModuleList(); this.list = new SortedModuleList();
} }
@@ -177,8 +177,8 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
context.deleteFile(FILE_NAME); context.deleteFile(FILE_NAME);
} }
public String getUsername() { public LoginToken getToken() {
return username; return token;
} }
public class Module implements Serializable { public class Module implements Serializable {

View File

@@ -39,4 +39,13 @@
tools:text="Android Studio" tools:text="Android Studio"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:visibility="gone" /> android:visibility="gone" />
<TextView
android:id="@+id/login_mail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
tools:text="Android Studio"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:visibility="gone" />
</LinearLayout> </LinearLayout>