Initial commit
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
BIN
.idea/caches/build_file_checksums.ser
generated
Normal file
29
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<Objective-C-extensions>
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
||||
</file>
|
||||
<class>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
||||
</class>
|
||||
<extensions>
|
||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
||||
</extensions>
|
||||
</Objective-C-extensions>
|
||||
</code_scheme>
|
||||
</component>
|
||||
22
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
||||
3
.idea/copyright/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,3 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
||||
18
.idea/gradle.xml
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
49
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||
<option name="myNullables">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="4">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ProjectJDKs.UI">
|
||||
<settings>
|
||||
<last-edited>1.8</last-edited>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/FUPlanner.iml" filepath="$PROJECT_DIR$/FUPlanner.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/runConfigurations.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
41
app/build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion '27.0.3'
|
||||
defaultConfig {
|
||||
applicationId "de.sebse.fuplanner"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 27
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation 'com.android.support:recyclerview-v7:27.1.1'
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||
implementation 'com.android.support:design:27.1.1'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
|
||||
implementation 'com.android.volley:volley:1.0.0'
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.google.android.gms:play-services-auth:15.0.0'
|
||||
implementation 'com.android.support:support-v4:27.1.1'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||
implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
|
||||
implementation 'com.android.support:support-v4:27.1.1'
|
||||
}
|
||||
25
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /home/sebastian/Android/Sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.sebse.fuplanner;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumentation test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("de.sebse.fuplanner", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
26
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="de.sebse.fuplanner">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/FUTheme"
|
||||
android:fullBackupContent="@xml/backup_descriptor">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
BIN
app/src/main/ic_launcher-web.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
292
app/src/main/java/de/sebse/fuplanner/MainActivity.java
Normal file
@@ -0,0 +1,292 @@
|
||||
package de.sebse.fuplanner;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import de.sebse.fuplanner.fragments.LoginFragment;
|
||||
import de.sebse.fuplanner.fragments.ModulesFragment;
|
||||
import de.sebse.fuplanner.fragments.StartupFragment;
|
||||
import de.sebse.fuplanner.services.GoogleAuth.ConnectedListener;
|
||||
import de.sebse.fuplanner.services.GoogleAuth.Credentials;
|
||||
import de.sebse.fuplanner.services.GoogleAuth.CredentialsListener;
|
||||
import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth;
|
||||
import de.sebse.fuplanner.services.KVV.KVV;
|
||||
import de.sebse.fuplanner.services.KVV.LoginToken;
|
||||
import de.sebse.fuplanner.services.KVV.Modules;
|
||||
import de.sebse.fuplanner.tools.activity.Logger;
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
public class MainActivity extends AppCompatActivity
|
||||
implements NavigationView.OnNavigationItemSelectedListener,
|
||||
LoginFragment.OnLoginFragmentInteractionListener,
|
||||
StartupFragment.OnStartupFragmentInteractionListener,
|
||||
ModulesFragment.OnModulesFragmentInteractionListener {
|
||||
|
||||
FragmentManager fragmentManager;
|
||||
private GoogleAuth mGoogleAuth;
|
||||
private KVV mKVV;
|
||||
private Logger log = new Logger("MainAct");
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
||||
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
|
||||
drawer.setDrawerListener(toggle);
|
||||
toggle.syncState();
|
||||
|
||||
NavigationView navigationView = findViewById(R.id.nav_view);
|
||||
navigationView.setNavigationItemSelectedListener(this);
|
||||
|
||||
/*try {
|
||||
(new MensaPlan(getApplicationContext())).request(0, new Date());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
this.getKVV().startUpdate();
|
||||
|
||||
fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
fragmentTransaction.replace(R.id.fragcontainer, StartupFragment.newInstance());
|
||||
fragmentTransaction.commit();
|
||||
findViewById(R.id.app_bar_layout).setVisibility(View.GONE);
|
||||
|
||||
|
||||
this.getGoogleAuth().connect(new ConnectedListener() {
|
||||
@Override
|
||||
public void connected() {
|
||||
// getGoogleAuth().setLoginState("seedorf96", "m&gcwBaT@");
|
||||
getGoogleAuth().getLoginState(new CredentialsListener() {
|
||||
@Override
|
||||
public void onCredentials(final Credentials credentials) {
|
||||
if (credentials == null || credentials.getUsername() == null || credentials.getPassword() == null) {
|
||||
MainActivity.this.getKVV().endUpdate();
|
||||
changeLoginState(null);
|
||||
return;
|
||||
}
|
||||
MainActivity.this.getKVV().login(credentials.getUsername(), credentials.getPassword(), new NetworkCallback<LoginToken>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull LoginToken success) {
|
||||
MainActivity.this.getKVV().endUpdate();
|
||||
changeLoginState(credentials);
|
||||
}
|
||||
}, new NetworkErrorCallback() {
|
||||
@Override
|
||||
public void onError(NetworkError error) {
|
||||
MainActivity.this.getKVV().endUpdate();
|
||||
changeLoginState(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
||||
drawer.closeDrawer(GravityCompat.START);
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.main, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId();
|
||||
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (id == R.id.action_settings) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||
// Handle navigation view item clicks here.
|
||||
int id = item.getItemId();
|
||||
|
||||
if (id == R.id.nav_schedule) {
|
||||
|
||||
} else if (id == R.id.nav_share) {
|
||||
|
||||
} else if (id == R.id.nav_logout) {
|
||||
this.getKVV().logout();
|
||||
this.getGoogleAuth().getLoginState(new CredentialsListener() {
|
||||
@Override
|
||||
public void onCredentials(Credentials credentials) {
|
||||
if (credentials != null) {
|
||||
MainActivity.this.getGoogleAuth().deleteLoginState(credentials.getUsername(), credentials.getPassword());
|
||||
}
|
||||
MainActivity.this.changeLoginState(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||
drawer.closeDrawer(GravityCompat.START);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
this.getGoogleAuth().onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* --------------------------------------------*/
|
||||
/* --------------------------------------------*/
|
||||
/* --------------------------------------------*/
|
||||
|
||||
public GoogleAuth getGoogleAuth() {
|
||||
log.d("Holla die Waldfee");
|
||||
if (this.mGoogleAuth == null) {
|
||||
this.mGoogleAuth = new GoogleAuth(this);
|
||||
}
|
||||
return this.mGoogleAuth;
|
||||
}
|
||||
|
||||
public KVV getKVV() {
|
||||
if (this.mKVV == null) {
|
||||
this.mKVV = new KVV(this);
|
||||
}
|
||||
return this.mKVV;
|
||||
}
|
||||
|
||||
private void changeLoginState(Credentials credentials) {
|
||||
log.d("change login state");
|
||||
if (credentials == null) {
|
||||
log.d("null");
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
fragmentTransaction.replace(R.id.fragcontainer, LoginFragment.newInstance());
|
||||
fragmentTransaction.commit();
|
||||
findViewById(R.id.app_bar_layout).setVisibility(View.VISIBLE);
|
||||
|
||||
NavigationView navigationView = findViewById(R.id.nav_view);
|
||||
View header = navigationView.getHeaderView(0);
|
||||
header.findViewById(R.id.imageView).setVisibility(View.GONE);
|
||||
header.findViewById(R.id.login_name).setVisibility(View.GONE);
|
||||
header.findViewById(R.id.login_page).setVisibility(View.VISIBLE);
|
||||
navigationView.getMenu().clear();
|
||||
navigationView.inflateMenu(R.menu.activity_main_drawer);
|
||||
|
||||
} else {
|
||||
log.d(credentials.getUsername());
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
fragmentTransaction.replace(R.id.fragcontainer, ModulesFragment.newInstance());
|
||||
fragmentTransaction.commit();
|
||||
findViewById(R.id.app_bar_layout).setVisibility(View.VISIBLE);
|
||||
|
||||
final NavigationView navigationView = findViewById(R.id.nav_view);
|
||||
View header = navigationView.getHeaderView(0);
|
||||
header.findViewById(R.id.imageView).setVisibility(View.VISIBLE);
|
||||
header.findViewById(R.id.login_name).setVisibility(View.VISIBLE);
|
||||
header.findViewById(R.id.login_page).setVisibility(View.GONE);
|
||||
navigationView.getMenu().clear();
|
||||
navigationView.inflateMenu(R.menu.activity_main_drawer_login);
|
||||
navigationView.setCheckedItem(R.id.nav_modules);
|
||||
getKVV().getModuleList(new NetworkCallback<Modules>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Modules success) {
|
||||
log.d("Modules.get "+success.size());
|
||||
//SubMenu moduleMenu = navigationView.getMenu().findItem(R.id.nav_modules).getSubMenu();
|
||||
int i = 0;
|
||||
for (Modules.Module module: success) {
|
||||
if (module.semester.equals("SS 18")) {
|
||||
MenuItem menuItem = navigationView.getMenu().add(Menu.NONE, Menu.NONE, 101 + i, module.title);
|
||||
final int finalI = i;
|
||||
menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
onModulesFragmentInteraction(finalI);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, new NetworkErrorCallback() {
|
||||
@Override
|
||||
public void onError(NetworkError error) {
|
||||
log.d("Modules.error "+error.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onLoginFragmentInteraction(Credentials credentials) {
|
||||
changeLoginState(credentials);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartupFragmentInteraction(Uri uri) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModulesFragmentInteraction(final int itemPosition) {
|
||||
Log.d("MainAct", "Item clicked "+itemPosition);
|
||||
getKVV().getModuleList(new NetworkCallback<Modules>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Modules success) {
|
||||
Log.d("MainAct", success.get(itemPosition).title);
|
||||
}
|
||||
}, new NetworkErrorCallback() {
|
||||
@Override
|
||||
public void onError(NetworkError error) {
|
||||
// TODO
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package de.sebse.fuplanner.fragments;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
import de.sebse.fuplanner.MainActivity;
|
||||
import de.sebse.fuplanner.R;
|
||||
import de.sebse.fuplanner.services.GoogleAuth.Credentials;
|
||||
import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth;
|
||||
import de.sebse.fuplanner.services.KVV.KVV;
|
||||
import de.sebse.fuplanner.services.KVV.LoginToken;
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
/**
|
||||
* A simple {@link Fragment} subclass.
|
||||
* Activities that contain this fragment must implement the
|
||||
* {@link LoginFragment.OnLoginFragmentInteractionListener} interface
|
||||
* to handle interaction events.
|
||||
* Use the {@link LoginFragment#newInstance} factory method to
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
public class LoginFragment extends Fragment {
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
|
||||
// TODO: Rename and change types of parameters
|
||||
|
||||
private OnLoginFragmentInteractionListener mListener;
|
||||
|
||||
public LoginFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @return A new instance of fragment LoginFragment.
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
public static LoginFragment newInstance() {
|
||||
LoginFragment fragment = new LoginFragment();
|
||||
Bundle args = new Bundle();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
|
||||
View v = inflater.inflate(R.layout.fragment_login, container, false);
|
||||
View btn_login = v.findViewById(R.id.btn_login);
|
||||
if (btn_login != null) {
|
||||
btn_login.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
final ProgressDialog progressDialog = new ProgressDialog(LoginFragment.this.getContext(),
|
||||
R.style.FUTheme_Dialog);
|
||||
progressDialog.setIndeterminate(true);
|
||||
progressDialog.setMessage("Authenticating...");
|
||||
progressDialog.show();
|
||||
|
||||
|
||||
EditText input_usr = ((View) view.getParent()).findViewById(R.id.input_username);
|
||||
EditText input_pwd = ((View) view.getParent()).findViewById(R.id.input_password);
|
||||
if (input_usr != null) {
|
||||
if (input_pwd != null) {
|
||||
if (LoginFragment.this.getActivity() == null) {
|
||||
Log.e("KVVLogin", "Login fragment has no activity!");
|
||||
return;
|
||||
}
|
||||
final String username = input_usr.getText().toString();
|
||||
final String password = input_pwd.getText().toString();
|
||||
final KVV kvv = ((MainActivity) LoginFragment.this.getActivity()).getKVV();
|
||||
final GoogleAuth gauth = ((MainActivity) LoginFragment.this.getActivity()).getGoogleAuth();
|
||||
kvv.login(username, password, new NetworkCallback<LoginToken>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull LoginToken success) {
|
||||
progressDialog.dismiss();
|
||||
Log.d("KVVLogin", success.toString());
|
||||
gauth.setLoginState(username, password);
|
||||
if (LoginFragment.this.mListener != null) {
|
||||
Credentials cred = new Credentials(username, password);
|
||||
LoginFragment.this.mListener.onLoginFragmentInteraction(cred);
|
||||
}
|
||||
}
|
||||
}, new NetworkErrorCallback() {
|
||||
@Override
|
||||
public void onError(NetworkError error) {
|
||||
progressDialog.dismiss();
|
||||
Log.e("KVVLoginError", error.getCode()+"");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnLoginFragmentInteractionListener) {
|
||||
mListener = (OnLoginFragmentInteractionListener) context;
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnLoginFragmentInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface must be implemented by activities that contain this
|
||||
* fragment to allow an interaction in this fragment to be communicated
|
||||
* to the activity and potentially other fragments contained in that
|
||||
* activity.
|
||||
* <p>
|
||||
* See the Android Training lesson <a href=
|
||||
* "http://developer.android.com/training/basics/fragments/communicating.html"
|
||||
* >Communicating with Other Fragments</a> for more information.
|
||||
*/
|
||||
public interface OnLoginFragmentInteractionListener {
|
||||
// TODO: Update argument type and name
|
||||
void onLoginFragmentInteraction(Credentials credentials);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package de.sebse.fuplanner.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import de.sebse.fuplanner.MainActivity;
|
||||
import de.sebse.fuplanner.R;
|
||||
import de.sebse.fuplanner.services.KVV.Modules;
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
* <p/>
|
||||
* Activities containing this fragment MUST implement the {@link OnModulesFragmentInteractionListener}
|
||||
* interface.
|
||||
*/
|
||||
public class ModulesFragment extends Fragment {
|
||||
|
||||
// TODO: Customize parameter argument names
|
||||
//private static final String ARG_COLUMN_COUNT = "column-count";
|
||||
// TODO: Customize parameters
|
||||
private OnModulesFragmentInteractionListener mListener;
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public ModulesFragment() {
|
||||
}
|
||||
|
||||
// TODO: Customize parameter initialization
|
||||
@SuppressWarnings("unused")
|
||||
public static ModulesFragment newInstance() {
|
||||
ModulesFragment fragment = new ModulesFragment();
|
||||
Bundle args = new Bundle();
|
||||
/*args.putInt(ARG_COLUMN_COUNT, columnCount);*/
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
/*if (getArguments() != null) {
|
||||
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Log.d("ModFrag", "onCreateView"+(getActivity() != null));
|
||||
View view = inflater.inflate(R.layout.fragment_modules_list, container, false);
|
||||
|
||||
// Set the adapter
|
||||
if (view instanceof RecyclerView) {
|
||||
Context context = view.getContext();
|
||||
RecyclerView recyclerView = (RecyclerView) view;
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
final ModulesRecyclerViewAdapter adapter = new ModulesRecyclerViewAdapter(mListener);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
|
||||
if (getActivity() != null) {
|
||||
((MainActivity) getActivity()).getKVV().getModuleList(new NetworkCallback<Modules>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Modules success) {
|
||||
adapter.setModules(success);
|
||||
}
|
||||
}, new NetworkErrorCallback() {
|
||||
@Override
|
||||
public void onError(NetworkError error) {
|
||||
Log.e("ModFrag", error.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
Log.d("ModFrag", "onAttach");
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnModulesFragmentInteractionListener) {
|
||||
mListener = (OnModulesFragmentInteractionListener) context;
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnModulesFragmentInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface must be implemented by activities that contain this
|
||||
* fragment to allow an interaction in this fragment to be communicated
|
||||
* to the activity and potentially other fragments contained in that
|
||||
* activity.
|
||||
* <p/>
|
||||
* See the Android Training lesson <a href=
|
||||
* "http://developer.android.com/training/basics/fragments/communicating.html"
|
||||
* >Communicating with Other Fragments</a> for more information.
|
||||
*/
|
||||
public interface OnModulesFragmentInteractionListener {
|
||||
// TODO: Update argument type and name
|
||||
void onModulesFragmentInteraction(int item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package de.sebse.fuplanner.fragments;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import de.sebse.fuplanner.R;
|
||||
import de.sebse.fuplanner.fragments.ModulesFragment.OnModulesFragmentInteractionListener;
|
||||
import de.sebse.fuplanner.services.KVV.Modules;
|
||||
|
||||
/**
|
||||
* {@link RecyclerView.Adapter} that can display a {@link Modules.Module} and makes a call to the
|
||||
* specified {@link OnModulesFragmentInteractionListener}.
|
||||
* TODO: Replace the implementation with code for your data type.
|
||||
*/
|
||||
public class ModulesRecyclerViewAdapter extends RecyclerView.Adapter<ModulesRecyclerViewAdapter.ViewHolder> {
|
||||
|
||||
private Modules mValues;
|
||||
private final OnModulesFragmentInteractionListener mListener;
|
||||
|
||||
public ModulesRecyclerViewAdapter(OnModulesFragmentInteractionListener listener) {
|
||||
mValues = null;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void setModules(Modules modules) {
|
||||
mValues = modules;
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.fragment_modules, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
if (mValues == null)
|
||||
return;
|
||||
holder.mItemPosition = position;
|
||||
holder.mIdView.setText(mValues.get(position).semester);
|
||||
holder.mContentView.setText(mValues.get(position).title);
|
||||
|
||||
holder.mView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (null != mListener) {
|
||||
// Notify the active callbacks interface (the activity, if the
|
||||
// fragment is attached to one) that an item has been selected.
|
||||
mListener.onModulesFragmentInteraction(holder.mItemPosition);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (mValues != null) {
|
||||
Log.d("Recycler", String.valueOf(mValues.size()));
|
||||
return mValues.size();
|
||||
}
|
||||
Log.d("Recycler", "0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public final View mView;
|
||||
public final TextView mIdView;
|
||||
public final TextView mContentView;
|
||||
public int mItemPosition;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
mView = view;
|
||||
mIdView = (TextView) view.findViewById(R.id.id);
|
||||
mContentView = (TextView) view.findViewById(R.id.content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " '" + mContentView.getText() + "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package de.sebse.fuplanner.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import de.sebse.fuplanner.R;
|
||||
|
||||
/**
|
||||
* A simple {@link Fragment} subclass.
|
||||
* Activities that contain this fragment must implement the
|
||||
* {@link StartupFragment.OnStartupFragmentInteractionListener} interface
|
||||
* to handle interaction events.
|
||||
* Use the {@link StartupFragment#newInstance} factory method to
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
public class StartupFragment extends Fragment {
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
|
||||
// TODO: Rename and change types of parameters
|
||||
|
||||
private OnStartupFragmentInteractionListener mListener;
|
||||
|
||||
public StartupFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @return A new instance of fragment StartupFragment.
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
public static StartupFragment newInstance() {
|
||||
StartupFragment fragment = new StartupFragment();
|
||||
Bundle args = new Bundle();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
View v = inflater.inflate(R.layout.fragment_startup, container, false);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnStartupFragmentInteractionListener) {
|
||||
mListener = (OnStartupFragmentInteractionListener) context;
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnStartupFragmentInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface must be implemented by activities that contain this
|
||||
* fragment to allow an interaction in this fragment to be communicated
|
||||
* to the activity and potentially other fragments contained in that
|
||||
* activity.
|
||||
* <p>
|
||||
* See the Android Training lesson <a href=
|
||||
* "http://developer.android.com/training/basics/fragments/communicating.html"
|
||||
* >Communicating with Other Fragments</a> for more information.
|
||||
*/
|
||||
public interface OnStartupFragmentInteractionListener {
|
||||
// TODO: Update argument type and name
|
||||
void onStartupFragmentInteraction(Uri uri);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.sebse.fuplanner.services.GoogleAuth;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 07.11.17.
|
||||
*/
|
||||
|
||||
public interface ConnectedListener {
|
||||
public void connected();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.sebse.fuplanner.services.GoogleAuth;
|
||||
|
||||
/**
|
||||
* Created by Sebastian on 06.11.2017.
|
||||
*/
|
||||
|
||||
public class Credentials {
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public Credentials(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.sebse.fuplanner.services.GoogleAuth;
|
||||
|
||||
/**
|
||||
* Created by Sebastian on 06.11.2017.
|
||||
*/
|
||||
|
||||
public interface CredentialsListener {
|
||||
public void onCredentials(Credentials credentials);
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package de.sebse.fuplanner.services.GoogleAuth;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.auth.api.credentials.Credential;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialRequest;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialRequestResponse;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialsClient;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialsOptions;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
import com.google.android.gms.common.api.ApiException;
|
||||
import com.google.android.gms.common.api.CommonStatusCodes;
|
||||
import com.google.android.gms.common.api.ResolvableApiException;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
/**
|
||||
* Created by Sebastian on 06.11.2017.
|
||||
*/
|
||||
|
||||
public class GoogleAuth {
|
||||
// https://developers.google.com/identity/smartlock-passwords/android/retrieve-credentials
|
||||
|
||||
private static final String TAG = "GoogleAuth";
|
||||
private final FragmentActivity activity;
|
||||
private CredentialsClient mCredentialsClient;
|
||||
private boolean mIsResolving;
|
||||
@Nullable
|
||||
private CredentialsListener mCredentialsListener;
|
||||
|
||||
public GoogleAuth(FragmentActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public void connect(final ConnectedListener listener) {
|
||||
if (this.isUnavailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
listener.connected();
|
||||
return;
|
||||
}
|
||||
this.mCredentialsClient = getClient();
|
||||
listener.connected();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void getLoginState(final CredentialsListener credentialsListener) {
|
||||
if (this.isUnavailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
credentialsListener.onCredentials(null);
|
||||
return;
|
||||
}
|
||||
CredentialRequest request = new CredentialRequest.Builder()
|
||||
.setPasswordLoginSupported(true)
|
||||
.build();
|
||||
|
||||
|
||||
mCredentialsClient.request(request).addOnCompleteListener(new OnCompleteListener<CredentialRequestResponse>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<CredentialRequestResponse> task) {
|
||||
if (task.isSuccessful()) {
|
||||
// Successfully read the credential without any user interaction, this
|
||||
// means there was only a single credential and the user has auto
|
||||
// sign-in enabled.
|
||||
Credential credential = task.getResult().getCredential();
|
||||
credentialsListener.onCredentials(new Credentials(credential.getId(), credential.getPassword()));
|
||||
return;
|
||||
}
|
||||
|
||||
Exception e = task.getException();
|
||||
if (e instanceof ResolvableApiException) {
|
||||
// This is most likely the case where the user has multiple saved
|
||||
// credentials and needs to pick one. This requires showing UI to
|
||||
// resolve the read request.
|
||||
GoogleAuth.this.mCredentialsListener = credentialsListener;
|
||||
ResolvableApiException rae = (ResolvableApiException) e;
|
||||
resolveResult(rae, RequestCode.RC_READ);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e instanceof ApiException) {
|
||||
ApiException ae = (ApiException) e;
|
||||
if (ae.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {
|
||||
// This means only a hint is available, but we are handling that
|
||||
// elsewhere so no need to act here.
|
||||
} else {
|
||||
Log.w(TAG, "Unexpected status code: " + ae.getStatusCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setLoginState(String username, String password) {
|
||||
if (this.isUnavailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
Toast.makeText(activity, "Google auth not available!", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Credential credential = new Credential.Builder(username)
|
||||
.setPassword(password)
|
||||
.build();
|
||||
mCredentialsClient.save(credential).addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
showToast("Credential saved.");
|
||||
return;
|
||||
}
|
||||
|
||||
Exception e = task.getException();
|
||||
if (e instanceof ResolvableApiException) {
|
||||
// The first time a credential is saved, the user is shown UI
|
||||
// to confirm the action. This requires resolution.
|
||||
ResolvableApiException rae = (ResolvableApiException) e;
|
||||
resolveResult(rae, RequestCode.RC_SAVE);
|
||||
} else {
|
||||
// Save failure cannot be resolved.
|
||||
Log.w(TAG, "Save failed.", e);
|
||||
showToast("Credential Save Failed");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteLoginState(String username, String password) {
|
||||
if (this.isUnavailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
return;
|
||||
}
|
||||
Credential credential = new Credential.Builder(username)
|
||||
.setPassword(password)
|
||||
.build();
|
||||
mCredentialsClient.delete(credential).addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
// Credential was deleted successfully
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private boolean isUnavailable() {
|
||||
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this.activity) != ConnectionResult.SUCCESS;
|
||||
}
|
||||
|
||||
private CredentialsClient getClient() {
|
||||
CredentialsOptions options = new CredentialsOptions.Builder()
|
||||
.forceEnableSaveDialog()
|
||||
.build();
|
||||
return com.google.android.gms.auth.api.credentials.Credentials.getClient(this.activity, options);
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data);
|
||||
|
||||
switch (requestCode) {
|
||||
case RequestCode.RC_HINT:
|
||||
// Drop into handling for RC_READ
|
||||
case RequestCode.RC_READ:
|
||||
if (resultCode == RESULT_OK) {
|
||||
boolean isHint = (requestCode == RequestCode.RC_HINT);
|
||||
Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
|
||||
if (mCredentialsListener != null)
|
||||
this.mCredentialsListener.onCredentials(new Credentials(credential.getId(), credential.getPassword()));
|
||||
else
|
||||
Log.d(TAG, "No Credentials Listener");
|
||||
} else {
|
||||
if (mCredentialsListener != null)
|
||||
this.mCredentialsListener.onCredentials(null);
|
||||
else
|
||||
Log.d(TAG, "No Credentials Listener");
|
||||
Log.e(TAG, "Credential Read: NOT OK");
|
||||
showToast("Credential Read Failed");
|
||||
}
|
||||
|
||||
mIsResolving = false;
|
||||
break;
|
||||
case RequestCode.RC_SAVE:
|
||||
if (resultCode == RESULT_OK) {
|
||||
Log.d(TAG, "Credential Save: OK");
|
||||
showToast("Credential Save Success");
|
||||
} else {
|
||||
Log.e(TAG, "Credential Save: NOT OK");
|
||||
showToast("Credential Save Failed");
|
||||
}
|
||||
|
||||
mIsResolving = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void resolveResult(ResolvableApiException rae, int requestCode) {
|
||||
// We don't want to fire multiple resolutions at once since that can result
|
||||
// in stacked dialogs after rotation or another similar event.
|
||||
if (mIsResolving) {
|
||||
Log.w(TAG, "resolveResult: already resolving.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Resolving: " + rae);
|
||||
try {
|
||||
rae.startResolutionForResult(this.activity, requestCode);
|
||||
mIsResolving = true;
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
Log.e(TAG, "STATUS: Failed to send resolution.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Display a short Toast message **/
|
||||
private void showToast(String msg) {
|
||||
Toast.makeText(this.activity, msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.sebse.fuplanner.services.GoogleAuth;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 07.11.17.
|
||||
*/
|
||||
|
||||
public class RequestCode {
|
||||
public static final int RC_SAVE = 1;
|
||||
public static final int RC_HINT = 2;
|
||||
public static final int RC_READ = 3;
|
||||
}
|
||||
77
app/src/main/java/de/sebse/fuplanner/services/KVV/KVV.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package de.sebse.fuplanner.services.KVV;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 29.10.17.
|
||||
*/
|
||||
|
||||
public class KVV {
|
||||
private Context context;
|
||||
private LoginToken lastToken;
|
||||
private boolean isUpdating;
|
||||
private ArrayList<LastTokenCallback> updatingList;
|
||||
private HashMap<String, Object> addons = new HashMap<>();
|
||||
|
||||
public KVV(Context context) {
|
||||
this.context = context;
|
||||
this.isUpdating = false;
|
||||
this.updatingList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void login(@NonNull String username, @NonNull String password, final NetworkCallback<LoginToken> callback, NetworkErrorCallback error) {
|
||||
KVVLogin login = new KVVLogin(this.context);
|
||||
login.login(username, password, new NetworkCallback<LoginToken>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull LoginToken success) {
|
||||
lastToken = success;
|
||||
callback.onResponse(success);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
lastToken = null;
|
||||
addons.clear();
|
||||
}
|
||||
|
||||
public void getModuleList(final NetworkCallback<Modules> callback, final NetworkErrorCallback error) {
|
||||
this.getLastToken(new LastTokenCallback() {
|
||||
@Override
|
||||
public void onReceived(LoginToken token) {
|
||||
KVVModuleList modules = (KVVModuleList) addons.get("modules");
|
||||
if (modules == null) {
|
||||
modules = new KVVModuleList(KVV.this.context, token);
|
||||
addons.put("modules", modules);
|
||||
}
|
||||
modules.getModuleList(callback, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getLastToken(LastTokenCallback lastTokenCallback) {
|
||||
if (this.isUpdating) {
|
||||
this.updatingList.add(lastTokenCallback);
|
||||
} else {
|
||||
lastTokenCallback.onReceived(this.lastToken);
|
||||
}
|
||||
}
|
||||
|
||||
public void startUpdate() {
|
||||
this.isUpdating = true;
|
||||
}
|
||||
|
||||
public void endUpdate() {
|
||||
this.isUpdating = false;
|
||||
for (LastTokenCallback s: this.updatingList) {
|
||||
s.onReceived(this.lastToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
365
app/src/main/java/de/sebse/fuplanner/services/KVV/KVVLogin.java
Normal file
@@ -0,0 +1,365 @@
|
||||
package de.sebse.fuplanner.services.KVV;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
import de.sebse.fuplanner.tools.network.Result;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 24.10.17.
|
||||
*/
|
||||
|
||||
class KVVLogin extends HTTPService {
|
||||
public KVVLogin(Context context) {
|
||||
super(context, false);
|
||||
}
|
||||
|
||||
public void login(final String username, final String password, final NetworkCallback<LoginToken> callback, final NetworkErrorCallback error) {
|
||||
Log.d("KVVMaster0", username+" - "+password);
|
||||
startKVVSession(new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
final String kvvJSESSIONID = success.get("JSESSIONID");
|
||||
getSAMLRequest(kvvJSESSIONID, new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
startIdentSession(success.get("Location"), new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
final String identJSESSIONID = success.get("JSESSIONID");
|
||||
final String ident_idp_authn_lc_key = success.get("_idp_authn_lc_key");
|
||||
final String identROUTEID = success.get("ROUTEID");
|
||||
loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
final String ident_idp_session = success.get("_idp_session");
|
||||
getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
loginKVV(success.get("RelayState"), success.get("SAMLResponse"), kvvJSESSIONID, new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
final LoginToken token = new LoginToken(username, success.get("shibsessionKey"), success.get("shibsessionName"), kvvJSESSIONID);
|
||||
finishKVVlogin(token, new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
Log.d("KVVMaster", "Login worked!");
|
||||
callback.onResponse(token);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
}, error);
|
||||
}
|
||||
|
||||
/*
|
||||
GET https://kvv.imp.fu-berlin.de/portal/login
|
||||
-> JSESSIONID 5c10406f-588c-4c16-96e9-c80d115417de.tomcat1
|
||||
*/
|
||||
private void startKVVSession(final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
get("https://kvv.imp.fu-berlin.de/portal/login", null, new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
String cookies = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies==null) {
|
||||
errorCallback.onError(new NetworkError(100101, -1, "Error on starting KVV session!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object;
|
||||
try {
|
||||
object = getCookie(cookies, new String[]{"JSESSIONID"});
|
||||
} catch (NoSuchFieldException e) {
|
||||
errorCallback.onError(new NetworkError(100102, -1, "Error on starting KVV session!"));
|
||||
return;
|
||||
}
|
||||
callback.onResponse(object);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(100100, error.networkResponse.statusCode, "Error on starting KVV session!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
|
||||
<- JSESSIONID
|
||||
-> (Location-Header) https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||
?SAMLRequest=fZLLb.....Q8yre3X1IHwkJKE0Mnpy/V9TH4A
|
||||
&RelayState=ss:mem:7ea01e29157b8bd906f7002176.....0d1a505f2c8bf
|
||||
*/
|
||||
private void getSAMLRequest(String JSESSIONID, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", JSESSIONID);
|
||||
get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", cookies, new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
String location = response.getHeaders().get("Location");
|
||||
if (location==null) {
|
||||
errorCallback.onError(new NetworkError(100111, -1, "Error on getting SAML request!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object = new HashMap<>();
|
||||
object.put("Location", location);
|
||||
callback.onResponse(object);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(100110, error.networkResponse.statusCode, "Error on getting SAML request!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||
?SAMLRequest=fZLLbsIwEEV/JfI+cWJAUIsgpbAoEi2IpF10UznxUKw6dupxaPn7hkdb2LD29bkzRzNGUeuGZ63fmjV8toA++K61QX58SEnrDLcCFXIjakDuK55njwvOopg3znpbWU2CDBGcV9ZMrcG2BpeD26kKnteLlGy9b5BT+rHbRapuok0bluC0MpEEmm9VWVoNfhshWnpgM7pa5gUJZt0wyogD9h+iJBiv/P6aomQTbtqSdhNtlIYzZg1SOag8zfMlCeazlLyNqpHsy1gO2V1fVsNBMuqJoUyAJaxXDUaiiyG2MDfohfEpYXEyDJM4ZKxgCe/FPI5fSbA6L36vjFTm/bal8hRC/lAUq/C02gs4PK7VBchkfHDNj8Xuwv5trPhVTiY3BeOf4DG96DmVNvypA89nK6tVtQ8yre3X1IHwkJKE0Mnpy/V9TH4A
|
||||
&RelayState=ss:mem:7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||
-> JSESSIONID C4B6A428BA1F50746235D03F5D107A57
|
||||
-> _idp_authn_lc_key 57a6ae26067f374cc3d0ccfc47e27b04b47752d2a3d4eb2782af0d3994535395
|
||||
-> ROUTEID .1
|
||||
*/
|
||||
private void startIdentSession(String url, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
get(url, null, new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
String cookies = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies==null) {
|
||||
errorCallback.onError(new NetworkError(100121, -1, "Error on starting Ident session!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object;
|
||||
try {
|
||||
object = getCookie(cookies, new String[]{"JSESSIONID", "_idp_authn_lc_key", "ROUTEID"});
|
||||
} catch (NoSuchFieldException e) {
|
||||
errorCallback.onError(new NetworkError(100122, -1, "Error on starting Ident session!"));
|
||||
return;
|
||||
}
|
||||
callback.onResponse(object);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(100120, error.networkResponse.statusCode, "Error on starting Ident session!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
POST https://identity.fu-berlin.de/idp-fub/Authn/UserPassword
|
||||
<- j_username seedorf96
|
||||
<- j_password neinhieristpatrick
|
||||
<- (Header-"Content-Type") application/x-www-form-urlencoded
|
||||
<- JSESSIONID
|
||||
<- _idp_authn_lc_key
|
||||
<- ROUTEID
|
||||
-> _idp_session OTMuMTkzLjg1LjMz|LQ==|OGYxOWI4MjA2NTQ4YWUwYzJkOWM4Mjk4YzcwZDMwZmJiZjBmMTdmMzkyZGU2OWIwY2JkNmZlNjlmNTRmNzBlMQ==|wLlzQal7VqyntmG2vLNn06wt8wQ=
|
||||
*/
|
||||
private void loginIdent(final boolean first, String username, String password, String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", JSESSIONID);
|
||||
cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
|
||||
cookies.put("ROUTEID", ROUTEID);
|
||||
HashMap<String, String> body = new HashMap<>();
|
||||
body.put("j_username", username);
|
||||
body.put("j_password", password);
|
||||
post("https://identity.fu-berlin.de/idp-fub/Authn/UserPassword", cookies, body, new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
if (first) {
|
||||
callback.onResponse(new HashMap<String, String>());
|
||||
return;
|
||||
}
|
||||
|
||||
String cookies = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies==null) {
|
||||
errorCallback.onError(new NetworkError(100131, -1, "Error on logging in to Identity Server!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object;
|
||||
try {
|
||||
object = getCookie(cookies, new String[]{"_idp_session"});
|
||||
} catch (NoSuchFieldException e) {
|
||||
errorCallback.onError(new NetworkError(100132, -1, "Error on logging in to Identity Server!"));
|
||||
return;
|
||||
}
|
||||
callback.onResponse(object);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(100130, error.networkResponse.statusCode, "Error on logging in to Identity Server!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||
<- JSESSIONID
|
||||
<- _idp_authn_lc_key
|
||||
<- ROUTEID
|
||||
<- _idp_session
|
||||
-> (BODY) RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||
-> (BODY) SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
|
||||
*/
|
||||
private void getSAMLResponse(String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, String _idp_session, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", JSESSIONID);
|
||||
cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
|
||||
cookies.put("ROUTEID", ROUTEID);
|
||||
cookies.put("_idp_session", _idp_session);
|
||||
get("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO", cookies, new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
HashMap<String, String> object = new HashMap<>();
|
||||
|
||||
Pattern pattern = Pattern.compile("ss:mem:([0-9a-f]+)");
|
||||
Matcher matcher = pattern.matcher(response.getParsed());
|
||||
if (!matcher.find()) {
|
||||
errorCallback.onError(new NetworkError(100142, -1, "Error on getting SAML response!"));
|
||||
return;
|
||||
}
|
||||
object.put("RelayState", "ss:mem:"+matcher.group(1));
|
||||
|
||||
pattern = Pattern.compile("([0-9a-zA-Z+]+==)");
|
||||
matcher = pattern.matcher(response.getParsed());
|
||||
if (!matcher.find()) {
|
||||
errorCallback.onError(new NetworkError(100141, -1, "Error on getting SAML response!"));
|
||||
return;
|
||||
}
|
||||
object.put("SAMLResponse", matcher.group(1));
|
||||
|
||||
callback.onResponse(object);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(100140, error.networkResponse.statusCode, "Error on getting SAML response!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
POST https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST
|
||||
<- RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||
<- SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
|
||||
<- JSESSIONID
|
||||
-> _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
|
||||
_b1912c5a03d733a80bd3fee772bf68d4
|
||||
*/
|
||||
private void loginKVV(String RelayState, String SAMLResponse, String JSESSIONID, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", JSESSIONID);
|
||||
HashMap<String, String> body = new HashMap<>();
|
||||
body.put("RelayState", RelayState);
|
||||
body.put("SAMLResponse", SAMLResponse);
|
||||
post("https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST", cookies, body, new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
String cookies = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies==null) {
|
||||
errorCallback.onError(new NetworkError(100151, -1, "Error on starting KVV session!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object = new HashMap<>();
|
||||
|
||||
|
||||
Pattern pattern = Pattern.compile("(_shibsession_[0-9a-f]+)=([^;]+);");
|
||||
Matcher matcher = pattern.matcher(cookies);
|
||||
if (!matcher.find()) {
|
||||
errorCallback.onError(new NetworkError(100152, -1, "Error on starting Ident session!"));
|
||||
}
|
||||
object.put("shibsessionKey", matcher.group(1));
|
||||
object.put("shibsessionName", matcher.group(2));
|
||||
|
||||
callback.onResponse(object);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(100150, error.networkResponse.statusCode, "Error on starting Ident session!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
|
||||
<- JSESSIONID
|
||||
<- _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
|
||||
_b1912c5a03d733a80bd3fee772bf68d4
|
||||
*/
|
||||
private void finishKVVlogin(LoginToken loginToken, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", loginToken.getCookies(), new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
callback.onResponse(new HashMap<String, String>());
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(100160, error.networkResponse.statusCode, "Cannot finish login process!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private String getCookie(String cookies, String name) throws NoSuchFieldException {
|
||||
Pattern pattern = Pattern.compile(name+"=([^;]+);");
|
||||
Matcher matcher = pattern.matcher(cookies);
|
||||
if (!matcher.find()) {
|
||||
Log.d("GETcookie failed", name);
|
||||
Log.d("GETcookie failed", cookies);
|
||||
throw new NoSuchFieldException();
|
||||
}
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
private HashMap<String, String> getCookie(String cookies, String[] names) throws NoSuchFieldException {
|
||||
HashMap<String, String> result = new HashMap<>();
|
||||
for (String name: names) {
|
||||
result.put(name,this.getCookie(cookies, name));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
package de.sebse.fuplanner.services.KVV;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.regex.MatchResult;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
import de.sebse.fuplanner.tools.network.Result;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 29.10.17.
|
||||
*/
|
||||
|
||||
public class KVVModuleList extends HTTPService {
|
||||
private final LoginToken token;
|
||||
private Modules moduleList;
|
||||
|
||||
public KVVModuleList(Context context, LoginToken token) {
|
||||
super(context);
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public void getModuleList(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (moduleList != null) {
|
||||
callback.onResponse(moduleList);
|
||||
return;
|
||||
}
|
||||
get("https://kvv.imp.fu-berlin.de/portal/site/~" + token.getUsername() + "/tool/9df8c796-7d6b-4416-8ba1-f505ea6b8224/", token.getCookies(), new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
String location = response.getHeaders().get("Location");
|
||||
get("https://kvv.imp.fu-berlin.de/portal/site/~"+token.getUsername()+"/tool/9df8c796-7d6b-4416-8ba1-f505ea6b8224/"+location, token.getCookies(), new Response.Listener<Result>() {
|
||||
@Override
|
||||
public void onResponse(Result response) {
|
||||
String body = response.getParsed();
|
||||
//largeLog("KVVModules", body);
|
||||
Pattern pattern = Pattern.compile("<tbody>(.*)</tbody>", Pattern.DOTALL);
|
||||
Matcher matcher = pattern.matcher(body);
|
||||
if (!matcher.find()) {
|
||||
errorCallback.onError(new NetworkError(101101, -1, "Cannot parse module list!"));
|
||||
return;
|
||||
}
|
||||
//largeLog("KVVGroup", matcher.group(1));
|
||||
Modules modules = new Modules();
|
||||
//<tr.*?>(.|\n)+?</tr>
|
||||
for (MatchResult match: allMatches(Pattern.compile("<tr.*?>.+?</tr>", Pattern.DOTALL), matcher.group(1))) {
|
||||
try {
|
||||
// Instructors
|
||||
HashSet<String> instructs = new HashSet<>();
|
||||
String instructors = regex("<td class=\"instructors\">.+?<div>(.+?)</div>.+?</td>", match.group());
|
||||
for (MatchResult match2: allMatches(Pattern.compile(".*(?=,)"), instructors)) {
|
||||
if (match2.group()!=null && match2.group().length()>0)
|
||||
instructs.add(match2.group());
|
||||
}
|
||||
for (MatchResult match2: allMatches(Pattern.compile(".*(?=\\s+$|$)"), instructors)) {
|
||||
if (match2.group()!=null && match2.group().length()>0)
|
||||
instructs.add(match2.group());
|
||||
}
|
||||
|
||||
// Semester
|
||||
String semester = regex("<div>((Winter|Sommer)semester.*?)</div>", match.group());
|
||||
|
||||
// lvNumber
|
||||
HashSet<String> lvNumbers = new HashSet<>();
|
||||
String numbers = regex("<td class=\"vvid\">.*?<div>(.*?)</div", match.group());
|
||||
for (MatchResult match2: allMatches(Pattern.compile("\\d+"), numbers)) {
|
||||
if (match2.group()!=null && match2.group().length()>0)
|
||||
lvNumbers.add(match2.group());
|
||||
}
|
||||
|
||||
// Title
|
||||
//language=RegExp
|
||||
String title = regex("<span class=\"fs\"></span>(.+?)</a><span>", match.group());
|
||||
|
||||
// Type
|
||||
//language=RegExp
|
||||
String type = regex("<td class=\"typelong\">.*?<div>(.*?)</div>", match.group());
|
||||
|
||||
// Upgrade URI
|
||||
//language=RegExp
|
||||
String upgradeURI = regex("<a href=\"\\./\\?([0-9]*-[0-9]*\\.ILinkListener-tableform-coursetable-body-rows-[0-9]*-cells-[0-9]*-cell-thelink)\"><span class=\"fs\"></span>.+?</a><span>", match.group());
|
||||
|
||||
modules.addModule(semester, lvNumbers, title, instructs, type, upgradeURI);
|
||||
} catch (NoSuchFieldException e) {
|
||||
errorCallback.onError(new NetworkError(101102, -1, "Cannot parse module list!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
KVVModuleList.this.moduleList = modules;
|
||||
callback.onResponse(modules);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(101102, error.networkResponse.statusCode, "Cannot get module list!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
errorCallback.onError(new NetworkError(101100, error.networkResponse.statusCode, "Cannot get module list!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void getModuleDetails(final int index, final NetworkCallback<Modules.UpgradeModule> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (moduleList == null) {
|
||||
this.getModuleList(new NetworkCallback<Modules>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Modules success) {
|
||||
getModuleDetails(index, callback, errorCallback);
|
||||
}
|
||||
}, errorCallback);
|
||||
} else {
|
||||
Modules.Module m = moduleList.get(index);
|
||||
if (m instanceof Modules.SimpleModule) {
|
||||
upgradeModule((Modules.SimpleModule) m, new NetworkCallback<HashMap<String, String>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
||||
moduleList.upgradeItem(index, success.get("moduleID"), success.get("description"));
|
||||
callback.onResponse((Modules.UpgradeModule) moduleList.get(index));
|
||||
}
|
||||
}, errorCallback);
|
||||
} else {
|
||||
callback.onResponse((Modules.UpgradeModule) moduleList.get(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeModule(Modules.SimpleModule module, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> success = new HashMap<>();
|
||||
success.put("moduleID", "cool ID");
|
||||
success.put("desctiption", "cool desctiption");
|
||||
callback.onResponse(success);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private String regex(String regex, String match) throws NoSuchFieldException {
|
||||
return regex(regex, match, 1);
|
||||
}
|
||||
|
||||
private String regex(String regex, String match, int group) throws NoSuchFieldException {
|
||||
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
|
||||
Matcher matcher = pattern.matcher(match);
|
||||
if (!matcher.find()) {
|
||||
throw new NoSuchFieldException();
|
||||
}
|
||||
return matcher.group(group);
|
||||
}
|
||||
|
||||
private static Iterable<MatchResult> allMatches(final Pattern p, final CharSequence input) {
|
||||
return new Iterable<MatchResult>() {
|
||||
@NonNull
|
||||
public Iterator<MatchResult> iterator() {
|
||||
return new Iterator<MatchResult>() {
|
||||
// Use a matcher internally.
|
||||
final Matcher matcher = p.matcher(input);
|
||||
// Keep a match around that supports any interleaving of hasNext/next calls.
|
||||
MatchResult pending;
|
||||
|
||||
public boolean hasNext() {
|
||||
// Lazily fill pending, and avoid calling find() multiple times if the
|
||||
// clients call hasNext() repeatedly before sampling via next().
|
||||
if (pending == null && matcher.find()) {
|
||||
pending = matcher.toMatchResult();
|
||||
}
|
||||
return pending != null;
|
||||
}
|
||||
|
||||
public MatchResult next() {
|
||||
// Fill pending if necessary (as when clients call next() without
|
||||
// checking hasNext()), throw if not possible.
|
||||
if (!hasNext()) { throw new NoSuchElementException(); }
|
||||
// Consume pending so next call to hasNext() does a find().
|
||||
MatchResult next = pending;
|
||||
pending = null;
|
||||
return next;
|
||||
}
|
||||
|
||||
/** Required to satisfy the interface, but unsupported. */
|
||||
public void remove() { throw new UnsupportedOperationException(); }
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.sebse.fuplanner.services.KVV;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 31.01.18.
|
||||
*/
|
||||
|
||||
interface LastTokenCallback {
|
||||
void onReceived(LoginToken token);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package de.sebse.fuplanner.services.KVV;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 29.10.17.
|
||||
*/
|
||||
|
||||
public class LoginToken {
|
||||
private final String username;
|
||||
private final String shibsessionKey;
|
||||
private final String shibsessionName;
|
||||
private String JSESSIONID;
|
||||
|
||||
public LoginToken(String username, String shibsessionKey, String shibsessionName, String JSESSIONID) {
|
||||
this.username = username;
|
||||
this.shibsessionKey = shibsessionKey;
|
||||
this.shibsessionName = shibsessionName;
|
||||
this.JSESSIONID = JSESSIONID;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getShibsessionKey() {
|
||||
return shibsessionKey;
|
||||
}
|
||||
|
||||
public String getShibsessionName() {
|
||||
return shibsessionName;
|
||||
}
|
||||
|
||||
public String getJSESSIONID() {
|
||||
return JSESSIONID;
|
||||
}
|
||||
|
||||
public HashMap<String, String> getCookies() {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", getJSESSIONID());
|
||||
cookies.put(getShibsessionKey(), getShibsessionName());
|
||||
cookies.put("pasystem_timezone_ok", "true");
|
||||
return cookies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
HashMap<String, String> cookies = this.getCookies();
|
||||
for (String header: cookies.keySet()) {
|
||||
result.append(header).append("=").append(cookies.get(header)).append(";");
|
||||
}
|
||||
return result.substring(0, result.length()-1);
|
||||
}
|
||||
}
|
||||
132
app/src/main/java/de/sebse/fuplanner/services/KVV/Modules.java
Normal file
@@ -0,0 +1,132 @@
|
||||
package de.sebse.fuplanner.services.KVV;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 29.10.17.
|
||||
*/
|
||||
|
||||
public class Modules implements Iterable<Modules.Module> {
|
||||
private final ArrayList<Module> list;
|
||||
|
||||
Modules() {
|
||||
this.list = new ArrayList<>();
|
||||
}
|
||||
|
||||
Module addModule(String semester, HashSet<String> lvNumber, String title, HashSet<String> lecturer, String type, String upgradeURI) {
|
||||
Module m = new SimpleModule(semester, lvNumber, title, lecturer, type, upgradeURI);
|
||||
this.list.add(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
UpgradeModule upgradeItem(int index, String moduleID, String description) {
|
||||
Module sm = list.get(index);
|
||||
if (sm instanceof SimpleModule) {
|
||||
UpgradeModule um = new UpgradeModule((SimpleModule) sm, moduleID, description);
|
||||
list.set(index, um);
|
||||
return um;
|
||||
} else {
|
||||
return (UpgradeModule) sm;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Iterator<Module> iterator() {
|
||||
return new Iterator<Module>() {
|
||||
private final Iterator<Module> iter = Modules.this.list.iterator();
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Module next() {
|
||||
return iter.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("no changes allowed");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.list.size();
|
||||
}
|
||||
|
||||
public Module get(int index) {
|
||||
return this.list.get(index);
|
||||
}
|
||||
|
||||
abstract public class Module {
|
||||
public final String semester;
|
||||
public final HashSet<String> lvNumber;
|
||||
public final String title;
|
||||
public final HashSet<String> lecturer;
|
||||
public final String type;
|
||||
|
||||
/*private Module() {
|
||||
this(null, null, null, null, null);
|
||||
throw new AssertionError("Do not use this constructor!");
|
||||
}*/
|
||||
|
||||
private Module(String semester, HashSet<String> lvNumber, String title, HashSet<String> lecturer, String type) {
|
||||
semester = semester.replace("Sommersemester", "SS").replace("Wintersemester", "WS");
|
||||
semester = semester.replaceAll("[0-9]{2}([0-9]{2})", "$1");
|
||||
|
||||
this.semester = semester;
|
||||
this.lvNumber = lvNumber;
|
||||
this.title = title;
|
||||
this.lecturer = lecturer;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Semester: "+semester+
|
||||
"\nlvNumber: "+lvNumber.toString()+
|
||||
"\ntitle: "+title+
|
||||
"\nlecturer: "+lecturer.toString()+
|
||||
"\ntype: "+type;
|
||||
}
|
||||
}
|
||||
|
||||
public class SimpleModule extends Module {
|
||||
public final String upgradeURI;
|
||||
|
||||
private SimpleModule(String semester, HashSet<String> lvNumber, String title, HashSet<String> lecturer, String type, String upgradeURI) {
|
||||
super(semester, lvNumber, title, lecturer, type);
|
||||
this.upgradeURI = upgradeURI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+
|
||||
"\nupgradeURI: "+upgradeURI;
|
||||
}
|
||||
}
|
||||
|
||||
public class UpgradeModule extends Module {
|
||||
public final String moduleID;
|
||||
public final String description;
|
||||
|
||||
private UpgradeModule(SimpleModule module, String moduleID, String description) {
|
||||
super(module.semester, module.lvNumber, module.title, module.lecturer, module.type);
|
||||
this.moduleID = moduleID;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+
|
||||
"\nmoduleID: "+moduleID+
|
||||
"\ndescription: "+description;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
app/src/main/java/de/sebse/fuplanner/services/MensaPlan.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package de.sebse.fuplanner.services;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.volley.AuthFailureError;
|
||||
import com.android.volley.NetworkResponse;
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
import com.android.volley.VolleyLog;
|
||||
import com.android.volley.toolbox.HttpHeaderParser;
|
||||
import com.android.volley.toolbox.StringRequest;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 12.10.17.
|
||||
*/
|
||||
|
||||
public class MensaPlan {
|
||||
|
||||
private final RequestQueue requestQueue;
|
||||
public MensaPlan(Context context) {
|
||||
requestQueue = Volley.newRequestQueue(context);
|
||||
}
|
||||
|
||||
public void request(int MensaID, Date date) throws JSONException {
|
||||
JSONObject post = new JSONObject();
|
||||
post.put("resources_id", 528);
|
||||
post.put("date", "2017-10-13");
|
||||
final String requestBody = post.toString();
|
||||
|
||||
StringRequest request = new StringRequest(Request.Method.POST, "https://www.stw.berlin/xhr/speiseplan-wochentag.html", new Response.Listener<String>() {
|
||||
@Override
|
||||
public void onResponse(String response) {
|
||||
Log.d("MensaPlan DDDD", response);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
Log.d("MensaPlan EEEE", error.getMessage());
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public String getBodyContentType() {
|
||||
return "application/json; charset=utf-8";
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBody() throws AuthFailureError {
|
||||
try {
|
||||
return requestBody == null ? null : requestBody.getBytes("utf-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*@Override
|
||||
protected Response<String> parseNetworkResponse(NetworkResponse response) {
|
||||
String responseString = "";
|
||||
responseString = String.valueOf(response.statusCode);
|
||||
// can get more details such as response.headers
|
||||
|
||||
return Response.success(responseString, HttpHeaderParser.parseCacheHeaders(response));
|
||||
}*/
|
||||
};
|
||||
requestQueue.add(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package de.sebse.fuplanner.tools.activity;
|
||||
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 19.04.18.
|
||||
*/
|
||||
|
||||
public class Logger {
|
||||
private final String tag;
|
||||
|
||||
public Logger(String tag) {
|
||||
super();
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public void d(String text) {
|
||||
Log.d(tag, text);
|
||||
}
|
||||
|
||||
public void d(boolean text) {
|
||||
Log.d(tag, String.valueOf(text));
|
||||
}
|
||||
|
||||
public void d(int text) {
|
||||
Log.d(tag, String.valueOf(text));
|
||||
}
|
||||
|
||||
public void e(String text) {
|
||||
Log.e(tag, text);
|
||||
}
|
||||
|
||||
public void e(boolean text) {
|
||||
Log.e(tag, String.valueOf(text));
|
||||
}
|
||||
|
||||
public void e(int text) {
|
||||
Log.e(tag, String.valueOf(text));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package de.sebse.fuplanner.tools.network;
|
||||
|
||||
import com.android.volley.AuthFailureError;
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.toolbox.HurlStack;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.entity.BasicHttpEntity;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicHttpResponse;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 29.10.17.
|
||||
*/
|
||||
|
||||
public class BetterHurlStack extends HurlStack {
|
||||
private static final String HEADER_CONTENT_TYPE = "Content-Type";
|
||||
|
||||
private final UrlRewriter mUrlRewriter;
|
||||
private final SSLSocketFactory mSslSocketFactory;
|
||||
private boolean followRedirects;
|
||||
|
||||
BetterHurlStack() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
BetterHurlStack(boolean followRedirects) {
|
||||
this(followRedirects, null);
|
||||
}
|
||||
/**
|
||||
* @param urlRewriter Rewriter to use for request URLs
|
||||
*/
|
||||
BetterHurlStack(boolean followRedirects, UrlRewriter urlRewriter) {
|
||||
this(followRedirects, urlRewriter, null);
|
||||
}
|
||||
/**
|
||||
* @param urlRewriter Rewriter to use for request URLs
|
||||
* @param sslSocketFactory SSL factory to use for HTTPS connections
|
||||
*/
|
||||
BetterHurlStack(boolean followRedirects, UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
|
||||
super(urlRewriter, sslSocketFactory);
|
||||
mUrlRewriter = urlRewriter;
|
||||
mSslSocketFactory = sslSocketFactory;
|
||||
this.followRedirects = followRedirects;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
protected HttpURLConnection createConnection(URL url) throws IOException {
|
||||
HttpURLConnection connection = super.createConnection(url);
|
||||
connection.setInstanceFollowRedirects(false);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
|
||||
throws IOException, AuthFailureError {
|
||||
String url = request.getUrl();
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
map.putAll(request.getHeaders());
|
||||
map.putAll(additionalHeaders);
|
||||
if (mUrlRewriter != null) {
|
||||
String rewritten = mUrlRewriter.rewriteUrl(url);
|
||||
if (rewritten == null) {
|
||||
throw new IOException("URL blocked by rewriter: " + url);
|
||||
}
|
||||
url = rewritten;
|
||||
}
|
||||
URL parsedUrl = new URL(url);
|
||||
HttpURLConnection connection = openConnection(parsedUrl, request);
|
||||
for (String headerName : map.keySet()) {
|
||||
connection.addRequestProperty(headerName, map.get(headerName));
|
||||
}
|
||||
setConnectionParametersForRequest(connection, request);
|
||||
// Initialize HttpResponse with data from the HttpURLConnection.
|
||||
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode == -1) {
|
||||
// -1 is returned by getResponseCode() if the response code could not be retrieved.
|
||||
// Signal to the caller that something was wrong with the connection.
|
||||
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
|
||||
}
|
||||
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
|
||||
connection.getResponseCode(), connection.getResponseMessage());
|
||||
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
|
||||
response.setEntity(entityFromConnection(connection));
|
||||
for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
|
||||
if (header.getKey() != null) {
|
||||
Header h;
|
||||
if (header.getKey().equals("Set-Cookie")) {
|
||||
Pattern pattern = Pattern.compile("^([^=]+=[^;]+;)");
|
||||
StringBuilder cookieValue = new StringBuilder();
|
||||
for (String value: header.getValue()) {
|
||||
Matcher matcher = pattern.matcher(value);
|
||||
if (matcher.find()) {
|
||||
cookieValue.append(matcher.group(1));
|
||||
}
|
||||
}
|
||||
h = new BasicHeader(header.getKey(), cookieValue.toString());
|
||||
} else {
|
||||
h = new BasicHeader(header.getKey(), header.getValue().get(0));
|
||||
}
|
||||
response.addHeader(h);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.
|
||||
* @param connection
|
||||
* @return an HttpEntity populated with data from <code>connection</code>.
|
||||
*/
|
||||
private static HttpEntity entityFromConnection(HttpURLConnection connection) {
|
||||
BasicHttpEntity entity = new BasicHttpEntity();
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = connection.getInputStream();
|
||||
} catch (IOException ioe) {
|
||||
inputStream = connection.getErrorStream();
|
||||
}
|
||||
entity.setContent(inputStream);
|
||||
entity.setContentLength(connection.getContentLength());
|
||||
entity.setContentEncoding(connection.getContentEncoding());
|
||||
entity.setContentType(connection.getContentType());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
/* package */ static void setConnectionParametersForRequest(HttpURLConnection connection,
|
||||
Request<?> request) throws IOException, AuthFailureError {
|
||||
switch (request.getMethod()) {
|
||||
case Request.Method.DEPRECATED_GET_OR_POST:
|
||||
// This is the deprecated way that needs to be handled for backwards compatibility.
|
||||
// If the request's post body is null, then the assumption is that the request is
|
||||
// GET. Otherwise, it is assumed that the request is a POST.
|
||||
byte[] postBody = request.getPostBody();
|
||||
if (postBody != null) {
|
||||
// Prepare output. There is no need to set Content-Length explicitly,
|
||||
// since this is handled by HttpURLConnection using the size of the prepared
|
||||
// output stream.
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty(HEADER_CONTENT_TYPE,
|
||||
request.getPostBodyContentType());
|
||||
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
|
||||
out.write(postBody);
|
||||
out.close();
|
||||
}
|
||||
break;
|
||||
case Request.Method.GET:
|
||||
// Not necessary to set the request method because connection defaults to GET but
|
||||
// being explicit here.
|
||||
connection.setRequestMethod("GET");
|
||||
break;
|
||||
case Request.Method.DELETE:
|
||||
connection.setRequestMethod("DELETE");
|
||||
break;
|
||||
case Request.Method.POST:
|
||||
connection.setRequestMethod("POST");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
case Request.Method.PUT:
|
||||
connection.setRequestMethod("PUT");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
case Request.Method.HEAD:
|
||||
connection.setRequestMethod("HEAD");
|
||||
break;
|
||||
case Request.Method.OPTIONS:
|
||||
connection.setRequestMethod("OPTIONS");
|
||||
break;
|
||||
case Request.Method.TRACE:
|
||||
connection.setRequestMethod("TRACE");
|
||||
break;
|
||||
case Request.Method.PATCH:
|
||||
connection.setRequestMethod("PATCH");
|
||||
addBodyIfExists(connection, request);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown method type.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)
|
||||
throws IOException, AuthFailureError {
|
||||
byte[] body = request.getBody();
|
||||
if (body != null) {
|
||||
connection.setDoOutput(true);
|
||||
connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType());
|
||||
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
|
||||
out.write(body);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {
|
||||
HttpURLConnection connection = createConnection(url);
|
||||
int timeoutMs = request.getTimeoutMs();
|
||||
connection.setConnectTimeout(timeoutMs);
|
||||
connection.setReadTimeout(timeoutMs);
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
// use caller-provided custom SslSocketFactory, if any, for HTTPS
|
||||
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
|
||||
((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package de.sebse.fuplanner.tools.network;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.volley.AuthFailureError;
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 24.10.17.
|
||||
*/
|
||||
|
||||
public class HTTPService {
|
||||
protected RequestQueue requestQueue;
|
||||
private boolean followRedirects;
|
||||
|
||||
public HTTPService(Context context) {
|
||||
this(context, false);
|
||||
}
|
||||
|
||||
public HTTPService(Context context, boolean followRedirects) {
|
||||
this.followRedirects = followRedirects;
|
||||
requestQueue = Volley.newRequestQueue(context, new BetterHurlStack(followRedirects));
|
||||
}
|
||||
|
||||
protected void get(String url, @Nullable final HashMap<String, String> cookies, Response.Listener<Result> response, Response.ErrorListener error) {
|
||||
HttpRequest request = new HttpRequest(Request.Method.GET, url, response, error) {
|
||||
@Override
|
||||
public void deliverError(VolleyError error) {
|
||||
if (error == null) {
|
||||
super.deliverError(null);
|
||||
} else {
|
||||
final int status = error.networkResponse.statusCode;
|
||||
if (status == 302 && !followRedirects) {
|
||||
super.deliverResponse(new Result(null, error.networkResponse.headers));
|
||||
} else {
|
||||
super.deliverError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() throws AuthFailureError {
|
||||
Map<String, String> params = super.getHeaders();
|
||||
if (cookies != null) {
|
||||
if (params==null)
|
||||
params = new HashMap<>();
|
||||
else
|
||||
params = new HashMap<>(params);
|
||||
StringBuilder newStr = new StringBuilder();
|
||||
for (String key : cookies.keySet())
|
||||
newStr.append(key).append("=").append(cookies.get(key)).append(";");
|
||||
newStr = new StringBuilder(newStr.substring(0, newStr.length() - 1));
|
||||
params.put("Cookie", newStr.toString());
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
requestQueue.add(request);
|
||||
}
|
||||
|
||||
protected void post(String url, @Nullable final HashMap<String, String> cookies, @Nullable final HashMap<String, String> body, Response.Listener<Result> response, Response.ErrorListener error) {
|
||||
HttpRequest request = new HttpRequest(Request.Method.POST, url, response, error) {
|
||||
@Override
|
||||
public String getBodyContentType() {
|
||||
return "application/x-www-form-urlencoded";
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBody() throws AuthFailureError {
|
||||
if (body==null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(HashMap.Entry<String, String> e: body.entrySet()){
|
||||
if(sb.length() > 0){
|
||||
sb.append('&');
|
||||
}
|
||||
try {
|
||||
Log.e("Superissimo", e.getKey()+"|||"+e.getValue());
|
||||
sb.append(URLEncoder.encode(e.getKey(), "UTF-8")).append('=').append(URLEncoder.encode(e.getValue(), "UTF-8"));
|
||||
} catch (UnsupportedEncodingException ignored) {
|
||||
}
|
||||
}
|
||||
String requestBody = sb.toString();
|
||||
try {
|
||||
return requestBody.getBytes("utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverError(VolleyError error) {
|
||||
final int status = error.networkResponse.statusCode;
|
||||
if (status == 302) {
|
||||
super.deliverResponse(new Result(null, error.networkResponse.headers));
|
||||
} else {
|
||||
super.deliverError(error);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() throws AuthFailureError {
|
||||
Map<String, String> params = super.getHeaders();
|
||||
if (cookies != null) {
|
||||
if (params==null)
|
||||
params = new HashMap<>();
|
||||
else
|
||||
params = new HashMap<>(params);
|
||||
StringBuilder newStr = new StringBuilder();
|
||||
for (String key : cookies.keySet())
|
||||
newStr.append(key).append("=").append(cookies.get(key)).append(";");
|
||||
newStr = new StringBuilder(newStr.substring(0, newStr.length() - 1));
|
||||
params.put("Cookie", newStr.toString());
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
requestQueue.add(request);
|
||||
}
|
||||
|
||||
public static void largeLog(String tag, String content) {
|
||||
if (content==null) {
|
||||
Log.d(tag, "null");
|
||||
} else if (content.length() > 4000) {
|
||||
Log.d(tag, content.substring(0, 4000));
|
||||
largeLog(tag, content.substring(4000));
|
||||
} else {
|
||||
Log.d(tag, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package de.sebse.fuplanner.tools.network;
|
||||
|
||||
import com.android.volley.NetworkResponse;
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.toolbox.HttpHeaderParser;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 24.10.17.
|
||||
*/
|
||||
|
||||
public class HttpRequest extends Request<Result> {
|
||||
private final Response.Listener<Result> mListener;
|
||||
|
||||
public HttpRequest(int method, String url, Response.Listener<Result> listener,
|
||||
Response.ErrorListener errorListener) {
|
||||
super(method, url, errorListener);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response<Result> parseNetworkResponse(NetworkResponse response) {
|
||||
String parsed;
|
||||
try {
|
||||
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
parsed = new String(response.data);
|
||||
}
|
||||
Result result = new Result(parsed, response.headers);
|
||||
|
||||
return Response.success(result, HttpHeaderParser.parseCacheHeaders(response));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deliverResponse(Result response) {
|
||||
mListener.onResponse(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.sebse.fuplanner.tools.network;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public interface NetworkCallback<T> {
|
||||
void onResponse(@NonNull T success);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package de.sebse.fuplanner.tools.network;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 24.10.17.
|
||||
*/
|
||||
|
||||
public class NetworkError {
|
||||
private final int code;
|
||||
private final int httpStatus;
|
||||
private final String message;
|
||||
|
||||
public NetworkError(int code, int httpStatus, String message) {
|
||||
this.code = code;
|
||||
this.httpStatus = httpStatus;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public int getHttpStatus() {
|
||||
return httpStatus;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.valueOf(getCode()) + " - " + getHttpStatus() + " - " + getMessage();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package de.sebse.fuplanner.tools.network;
|
||||
|
||||
public interface NetworkErrorCallback<T> {
|
||||
void onError(NetworkError error);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package de.sebse.fuplanner.tools.network;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 24.10.17.
|
||||
*/
|
||||
public class Result {
|
||||
private final String parsed;
|
||||
private final Map<String, String> headers;
|
||||
|
||||
public Result(String parsed, Map<String, String> headers) {
|
||||
this.parsed = parsed;
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
public String getParsed() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
12
app/src/main/res/drawable-v21/ic_menu_camera.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-v21/ic_menu_gallery.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M22,16V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zm-11,-4l2.03,2.71L16,11l4,5H8l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2H4V6H2z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-v21/ic_menu_manage.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-v21/ic_menu_send.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-v21/ic_menu_share.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable-v21/ic_menu_slideshow.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16,-4H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zm-8,12.5v-9l6,4.5 -6,4.5z" />
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_apps.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_event.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M17,12h-5v5h5v-5zM16,1v2L8,3L8,1L6,1v2L5,3c-1.11,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2h-1L18,1h-2zM19,19L5,19L5,8h14v11z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_exit_to_app.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
||||
74
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
android:height="108dp"
|
||||
android:width="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_local_dining.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8.1,13.34l2.83,-2.83L3.91,3.5c-1.56,1.56 -1.56,4.09 0,5.66l4.19,4.18zM14.88,11.53c1.53,0.71 3.68,0.21 5.27,-1.38 1.91,-1.91 2.28,-4.65 0.81,-6.12 -1.46,-1.46 -4.2,-1.1 -6.12,0.81 -1.59,1.59 -2.09,3.74 -1.38,5.27L3.7,19.87l1.41,1.41L12,14.41l6.88,6.88 1.41,-1.41L13.41,13l1.47,-1.47z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_schedule.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7L11,7v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_settings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/side_nav_bar.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="135"
|
||||
android:centerColor="#4CAF50"
|
||||
android:endColor="#2E7D32"
|
||||
android:startColor="#81C784"
|
||||
android:type="linear" />
|
||||
</shape>
|
||||
25
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:openDrawer="start">
|
||||
|
||||
<include
|
||||
layout="@layout/app_bar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<android.support.design.widget.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true"
|
||||
app:headerLayout="@layout/nav_header_main"
|
||||
app:menu="@menu/activity_main_drawer" />
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
31
app/src/main/res/layout/app_bar_main.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="de.sebse.fuplanner.MainActivity">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/app_bar_layout"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/colorFUPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragcontainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
</FrameLayout>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
59
app/src/main/res/layout/fragment_login.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<ScrollView 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:fitsSystemWindows="true"
|
||||
tools:context="de.sebse.fuplanner.fragments.LoginFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="56dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingRight="24dp">
|
||||
|
||||
<ImageView android:src="@mipmap/ic_launcher"
|
||||
android:layout_width="128dp"
|
||||
android:layout_height="128dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
|
||||
<!-- Email Label -->
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp">
|
||||
<EditText android:id="@+id/input_username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress"
|
||||
android:hint="Username" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<!-- Password Label -->
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp">
|
||||
<EditText android:id="@+id/input_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword"
|
||||
android:hint="Password"/>
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<android.support.v7.widget.AppCompatButton
|
||||
android:id="@+id/btn_login"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:padding="12dp"
|
||||
android:text="Login"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
20
app/src/main/res/layout/fragment_modules.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
</LinearLayout>
|
||||
13
app/src/main/res/layout/fragment_modules_list.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/list"
|
||||
android:name="de.sebse.fuplanner.fragments.ModulesFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:context="de.sebse.fuplanner.fragments.ModulesFragment"
|
||||
tools:listitem="@layout/fragment_modules" />
|
||||
15
app/src/main/res/layout/fragment_startup.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<FrameLayout 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:background="@color/colorFUPrimary"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context="de.sebse.fuplanner.fragments.StartupFragment">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@android:dimen/thumbnail_width"
|
||||
android:layout_height="@android:dimen/thumbnail_height"
|
||||
android:layout_gravity="center"
|
||||
android:src="@mipmap/ic_launcher" />
|
||||
|
||||
</FrameLayout>
|
||||
40
app/src/main/res/layout/nav_header_main.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/nav_header_height"
|
||||
android:background="@drawable/side_nav_bar"
|
||||
android:gravity="bottom"
|
||||
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"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<Button
|
||||
android:id="@+id/login_page"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:text="Login"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@mipmap/ic_launcher"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||
android:text="Android Studio"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
29
app/src/main/res/layout/nav_header_main_login.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/nav_header_height"
|
||||
android:background="@drawable/side_nav_bar"
|
||||
android:gravity="bottom"
|
||||
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"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@mipmap/ic_launcher" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||
android:text="Android Studio"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
||||
|
||||
</LinearLayout>
|
||||
20
app/src/main/res/menu/activity_main_drawer.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<group android:checkableBehavior="single">
|
||||
<item
|
||||
android:id="@+id/nav_dining"
|
||||
android:icon="@drawable/ic_local_dining"
|
||||
android:title="Mensaplan" />
|
||||
</group>
|
||||
|
||||
<item android:title="Optionen">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/nav_share"
|
||||
android:icon="@drawable/ic_menu_share"
|
||||
android:title="Teilen"/>
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
</menu>
|
||||
43
app/src/main/res/menu/activity_main_drawer_login.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<group android:checkableBehavior="single">
|
||||
<item
|
||||
android:id="@+id/nav_schedule"
|
||||
android:icon="@drawable/ic_event"
|
||||
android:title="Stundenplan"
|
||||
android:orderInCategory="10"/>
|
||||
<item
|
||||
android:id="@+id/nav_modules"
|
||||
android:icon="@drawable/ic_apps"
|
||||
android:title="Module"
|
||||
android:orderInCategory="100" />
|
||||
<item
|
||||
android:id="@+id/nav_dining"
|
||||
android:icon="@drawable/ic_local_dining"
|
||||
android:title="Mensaplan"
|
||||
android:orderInCategory="200"/>
|
||||
<item
|
||||
android:id="@+id/nav_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:title="Einstellungen"
|
||||
android:orderInCategory="300"/>
|
||||
</group>
|
||||
|
||||
<item android:title="Optionen"
|
||||
android:orderInCategory="499">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/nav_logout"
|
||||
android:icon="@drawable/ic_exit_to_app"
|
||||
android:title="Logout"
|
||||
android:orderInCategory="500"/>
|
||||
<item
|
||||
android:id="@+id/nav_share"
|
||||
android:icon="@drawable/ic_menu_share"
|
||||
android:title="Teilen"
|
||||
android:orderInCategory="600"/>
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
</menu>
|
||||
9
app/src/main/res/menu/main.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_settings"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
20
app/src/main/res/values-v21/styles.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="FUTheme" parent="Theme.AppCompat.Light.NoActionBar" >
|
||||
<item name="android:colorPrimary">@color/colorFUPrimary</item>
|
||||
<item name="android:colorAccent">@color/colorFUSecondary</item>
|
||||
<item name="android:colorPrimaryDark">@color/colorFUPrimaryDark</item>
|
||||
<item name="android:colorBackground">@color/colorFUGray</item>
|
||||
<item name="android:statusBarColor">?android:attr/colorPrimaryDark</item>
|
||||
<item name="colorPrimary">@color/colorFUPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorFUPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorFUSecondary</item>
|
||||
</style>
|
||||
|
||||
<style name="FUTheme_Dialog" parent="android:Theme.Material.Light.Dialog.NoActionBar" >
|
||||
<item name="android:colorPrimary">@color/colorFUPrimary</item>
|
||||
<item name="android:colorPrimaryDark">@color/colorFUPrimaryDark</item>
|
||||
<item name="android:colorAccent">@color/colorFUSecondary</item>
|
||||
</style>
|
||||
</resources>
|
||||
11
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
<color name="colorFUPrimary">#98cb00</color>
|
||||
<color name="colorFUPrimaryDark">#2f4000</color>
|
||||
<color name="colorFUWhite">#FDFDFD</color>
|
||||
<color name="colorFUGray">#cdcdcd</color>
|
||||
<color name="colorFUSecondary">#003366</color>
|
||||
</resources>
|
||||
9
app/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
<dimen name="nav_header_vertical_spacing">16dp</dimen>
|
||||
<dimen name="nav_header_height">160dp</dimen>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
<dimen name="text_margin">16dp</dimen>
|
||||
</resources>
|
||||
8
app/src/main/res/values/drawables.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item name="ic_menu_camera" type="drawable">@android:drawable/ic_menu_camera</item>
|
||||
<item name="ic_menu_gallery" type="drawable">@android:drawable/ic_menu_gallery</item>
|
||||
<item name="ic_menu_slideshow" type="drawable">@android:drawable/ic_menu_slideshow</item>
|
||||
<item name="ic_menu_manage" type="drawable">@android:drawable/ic_menu_manage</item>
|
||||
<item name="ic_menu_share" type="drawable">@android:drawable/ic_menu_share</item>
|
||||
<item name="ic_menu_send" type="drawable">@android:drawable/ic_menu_send</item>
|
||||
</resources>
|
||||
11
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<resources>
|
||||
<string name="app_name">FU Planner</string>
|
||||
|
||||
<string name="navigation_drawer_open">Open navigation drawer</string>
|
||||
<string name="navigation_drawer_close">Close navigation drawer</string>
|
||||
|
||||
<string name="action_settings">Settings</string>
|
||||
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
||||
27
app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||
|
||||
<style name="FUTheme" parent="Theme.AppCompat.Light.NoActionBar" >
|
||||
<item name="android:colorBackground">@color/colorFUGray</item>
|
||||
<item name="colorPrimary">@color/colorFUPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorFUPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorFUSecondary</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
4
app/src/main/res/xml/backup_descriptor.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<full-backup-content>
|
||||
<!-- Exclude specific shared preferences that contain GCM registration Id -->
|
||||
</full-backup-content>
|
||||
17
app/src/test/java/de/sebse/fuplanner/ExampleUnitTest.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package de.sebse.fuplanner;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
25
build.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
180
docs/GoogleAuth-old.java
Normal file
@@ -0,0 +1,180 @@
|
||||
package de.sebse.fuplanner.services.GoogleAuth;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.auth.api.Auth;
|
||||
import com.google.android.gms.auth.api.credentials.Credential;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialRequest;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialRequestResult;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialsClient;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
/**
|
||||
* Created by Sebastian on 06.11.2017.
|
||||
*/
|
||||
|
||||
public class GoogleAuth {
|
||||
// https://developers.google.com/identity/smartlock-passwords/android/retrieve-credentials
|
||||
|
||||
private static final String TAG = "GoogleAuth";
|
||||
private final FragmentActivity activity;
|
||||
private GoogleApiClient mCredentialsClient;
|
||||
|
||||
public GoogleAuth(FragmentActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public void connect(final ConnectedListener listener) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
listener.connected();
|
||||
return;
|
||||
}
|
||||
this.mCredentialsClient = getClient(new GoogleApiClient.ConnectionCallbacks() {
|
||||
@Override
|
||||
public void onConnected(@Nullable Bundle bundle) {
|
||||
listener.connected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int i) {
|
||||
}
|
||||
}, new GoogleApiClient.OnConnectionFailedListener() {
|
||||
@Override
|
||||
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void getLoginState(final CredentialsListener credentialsListener) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
credentialsListener.onCredentials(null);
|
||||
return;
|
||||
}
|
||||
CredentialRequest mCredentialRequest = new CredentialRequest.Builder()
|
||||
.setPasswordLoginSupported(true)
|
||||
.build();
|
||||
|
||||
Auth.CredentialsApi.request(this.mCredentialsClient, mCredentialRequest).setResultCallback(
|
||||
new ResultCallback<CredentialRequestResult>() {
|
||||
@Override
|
||||
public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {
|
||||
if (credentialRequestResult.getStatus().isSuccess()) {
|
||||
// See "Handle successful credential requests"
|
||||
Credential credential = credentialRequestResult.getCredential();
|
||||
credentialsListener.onCredentials(new Credentials(credential.getId(), credential.getPassword()));
|
||||
} else {
|
||||
// See "Handle unsuccessful and incomplete credential requests"
|
||||
credentialsListener.onCredentials(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void setLoginState(String username, String password) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
Toast.makeText(activity, "Google auth not available!", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Credential credential = new Credential.Builder(username)
|
||||
.setPassword(password)
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
|
||||
Auth.CredentialsApi.save(mCredentialsClient, credential).setResultCallback(
|
||||
new ResultCallback<Status>() {
|
||||
@Override
|
||||
public void onResult(@NonNull Status status) {
|
||||
if (status.isSuccess()) {
|
||||
Log.d(TAG, "SAVE: OK");
|
||||
Toast.makeText(activity, "Credentials saved", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Log.d(TAG, String.valueOf(status.hasResolution()));
|
||||
Log.d(TAG, String.valueOf(status.getStatus()));
|
||||
if (status.hasResolution()) {
|
||||
// Try to resolve the save request. This will prompt the user if
|
||||
// the credential is new.
|
||||
try {
|
||||
status.startResolutionForResult(activity, RequestCode.RC_SAVE);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
// Could not resolve the request
|
||||
Log.e(TAG, "STATUS: Failed to send resolution.", e);
|
||||
Toast.makeText(activity, "Save failed", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
// Request has no resolution
|
||||
Toast.makeText(activity, "Save failed", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void deleteLoginState(String username, String password) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
return;
|
||||
}
|
||||
Credential credential = new Credential.Builder(username)
|
||||
.setPassword(password)
|
||||
.build();
|
||||
Auth.CredentialsApi.delete(mCredentialsClient, credential).setResultCallback(
|
||||
new ResultCallback<Status>() {
|
||||
@Override
|
||||
public void onResult(Status status) {
|
||||
if (status.isSuccess()) {
|
||||
// Credential was deleted successfully
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private boolean isAvailable() {
|
||||
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this.activity) == ConnectionResult.SUCCESS;
|
||||
}
|
||||
|
||||
private GoogleApiClient getClient(@NonNull GoogleApiClient.ConnectionCallbacks connectionCallbacks, @NonNull GoogleApiClient.OnConnectionFailedListener failedListener) {
|
||||
return new GoogleApiClient.Builder(this.activity)
|
||||
.addConnectionCallbacks(connectionCallbacks)
|
||||
.enableAutoManage(this.activity, failedListener)
|
||||
.addApi(Auth.CREDENTIALS_API)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == RequestCode.RC_SAVE) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
Log.d(TAG, "SAVE: OK");
|
||||
Toast.makeText(activity, "Credentials saved", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Log.e(TAG, "SAVE: Canceled by user");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
301
docs/GoogleAuth.java
Normal file
@@ -0,0 +1,301 @@
|
||||
package de.sebse.fuplanner.services.GoogleAuth;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.gms.auth.api.Auth;
|
||||
import com.google.android.gms.auth.api.credentials.Credential;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialRequest;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialRequestResponse;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialRequestResult;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialsClient;
|
||||
import com.google.android.gms.auth.api.credentials.CredentialsOptions;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
import com.google.android.gms.common.api.ApiException;
|
||||
import com.google.android.gms.common.api.CommonStatusCodes;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.ResolvableApiException;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
/**
|
||||
* Created by Sebastian on 06.11.2017.
|
||||
*/
|
||||
|
||||
public class GoogleAuth {
|
||||
// https://developers.google.com/identity/smartlock-passwords/android/retrieve-credentials
|
||||
|
||||
private static final String TAG = "GoogleAuth";
|
||||
private final FragmentActivity activity;
|
||||
private CredentialsClient mCredentialsClient;
|
||||
private boolean mIsResolving;
|
||||
|
||||
public GoogleAuth(FragmentActivity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public void connect(final ConnectedListener listener) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
listener.connected();
|
||||
return;
|
||||
}
|
||||
this.mCredentialsClient = getClient(new GoogleApiClient.ConnectionCallbacks() {
|
||||
@Override
|
||||
public void onConnected(@Nullable Bundle bundle) {
|
||||
listener.connected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int i) {
|
||||
}
|
||||
}, new GoogleApiClient.OnConnectionFailedListener() {
|
||||
@Override
|
||||
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void getLoginState(final CredentialsListener credentialsListener) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
credentialsListener.onCredentials(null);
|
||||
return;
|
||||
}
|
||||
CredentialRequest request = new CredentialRequest.Builder()
|
||||
.setPasswordLoginSupported(true)
|
||||
.build();
|
||||
|
||||
|
||||
mCredentialsClient.request(request).addOnCompleteListener(
|
||||
new OnCompleteListener<CredentialRequestResponse>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<CredentialRequestResponse> task) {
|
||||
|
||||
if (task.isSuccessful()) {
|
||||
// Successfully read the credential without any user interaction, this
|
||||
// means there was only a single credential and the user has auto
|
||||
// sign-in enabled.
|
||||
Credential credential = task.getResult().getCredential();
|
||||
credentialsListener.onCredentials(new Credentials(credential.getId(), credential.getPassword()));
|
||||
return;
|
||||
}
|
||||
|
||||
Exception e = task.getException();
|
||||
if (e instanceof ResolvableApiException) {
|
||||
// This is most likely the case where the user has multiple saved
|
||||
// credentials and needs to pick one. This requires showing UI to
|
||||
// resolve the read request.
|
||||
ResolvableApiException rae = (ResolvableApiException) e;
|
||||
resolveResult(rae, RequestCode.RC_READ);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e instanceof ApiException) {
|
||||
ApiException ae = (ApiException) e;
|
||||
if (ae.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {
|
||||
// This means only a hint is available, but we are handling that
|
||||
// elsewhere so no need to act here.
|
||||
} else {
|
||||
Log.w(TAG, "Unexpected status code: " + ae.getStatusCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*Auth.CredentialsApi.request(this.mCredentialsClient, mCredentialRequest).setResultCallback(
|
||||
new ResultCallback<CredentialRequestResult>() {
|
||||
@Override
|
||||
public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {
|
||||
if (credentialRequestResult.getStatus().isSuccess()) {
|
||||
// See "Handle successful credential requests"
|
||||
Credential credential = credentialRequestResult.getCredential();
|
||||
credentialsListener.onCredentials(new Credentials(credential.getId(), credential.getPassword()));
|
||||
} else {
|
||||
// See "Handle unsuccessful and incomplete credential requests"
|
||||
credentialsListener.onCredentials(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
);*/
|
||||
}
|
||||
|
||||
public void setLoginState(String username, String password) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
Toast.makeText(activity, "Google auth not available!", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Credential credential = new Credential.Builder(username)
|
||||
.setPassword(password)
|
||||
.build();
|
||||
mCredentialsClient.save(credential).addOnCompleteListener(new OnCompleteListener<Void>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Void> task) {
|
||||
if (task.isSuccessful()) {
|
||||
showToast("Credential saved.");
|
||||
return;
|
||||
}
|
||||
|
||||
Exception e = task.getException();
|
||||
if (e instanceof ResolvableApiException) {
|
||||
// The first time a credential is saved, the user is shown UI
|
||||
// to confirm the action. This requires resolution.
|
||||
ResolvableApiException rae = (ResolvableApiException) e;
|
||||
resolveResult(rae, RequestCode.RC_SAVE);
|
||||
} else {
|
||||
// Save failure cannot be resolved.
|
||||
Log.w(TAG, "Save failed.", e);
|
||||
showToast("Credential Save Failed");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
/*Auth.CredentialsApi.save(mCredentialsClient, credential).setResultCallback(
|
||||
new ResultCallback<Status>() {
|
||||
@Override
|
||||
public void onResult(@NonNull Status status) {
|
||||
if (status.isSuccess()) {
|
||||
Log.d(TAG, "SAVE: OK");
|
||||
Toast.makeText(activity, "Credentials saved", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Log.d(TAG, String.valueOf(status.hasResolution()));
|
||||
Log.d(TAG, String.valueOf(status.getStatus()));
|
||||
if (status.hasResolution()) {
|
||||
// Try to resolve the save request. This will prompt the user if
|
||||
// the credential is new.
|
||||
try {
|
||||
status.startResolutionForResult(activity, RC_SAVE);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
// Could not resolve the request
|
||||
Log.e(TAG, "STATUS: Failed to send resolution.", e);
|
||||
Toast.makeText(activity, "Save failed", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
// Request has no resolution
|
||||
Toast.makeText(activity, "Save failed", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);*/
|
||||
}
|
||||
|
||||
public void deleteLoginState(String username, String password) {
|
||||
if (!this.isAvailable()) {
|
||||
Log.d(TAG, "STATUS: Google auth not available!");
|
||||
return;
|
||||
}
|
||||
Credential credential = new Credential.Builder(username)
|
||||
.setPassword(password)
|
||||
.build();
|
||||
Auth.CredentialsApi.delete(mCredentialsClient, credential).setResultCallback(
|
||||
new ResultCallback<Status>() {
|
||||
@Override
|
||||
public void onResult(Status status) {
|
||||
if (status.isSuccess()) {
|
||||
// Credential was deleted successfully
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private boolean isAvailable() {
|
||||
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this.activity) == ConnectionResult.SUCCESS;
|
||||
}
|
||||
|
||||
private CredentialsClient getClient(@NonNull GoogleApiClient.ConnectionCallbacks connectionCallbacks, @NonNull GoogleApiClient.OnConnectionFailedListener failedListener) {
|
||||
CredentialsOptions options = new CredentialsOptions.Builder()
|
||||
.forceEnableSaveDialog()
|
||||
.build();
|
||||
return com.google.android.gms.auth.api.credentials.Credentials.getClient(this.activity, options);
|
||||
|
||||
|
||||
/*return new GoogleApiClient.Builder(this.activity)
|
||||
.addConnectionCallbacks(connectionCallbacks)
|
||||
.enableAutoManage(this.activity, failedListener)
|
||||
.addApi(Auth.CREDENTIALS_API)
|
||||
.build();*/
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Log.d(TAG, "onActivityResult:" + requestCode + ":" + resultCode + ":" + data);
|
||||
|
||||
switch (requestCode) {
|
||||
case RequestCode.RC_HINT:
|
||||
// Drop into handling for RC_READ
|
||||
case RequestCode.RC_READ:
|
||||
if (resultCode == RESULT_OK) {
|
||||
boolean isHint = (requestCode == RequestCode.RC_HINT);
|
||||
Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
|
||||
|
||||
processRetrievedCredential(credential, isHint);
|
||||
} else {
|
||||
Log.e(TAG, "Credential Read: NOT OK");
|
||||
showToast("Credential Read Failed");
|
||||
}
|
||||
|
||||
mIsResolving = false;
|
||||
break;
|
||||
case RequestCode.RC_SAVE:
|
||||
if (resultCode == RESULT_OK) {
|
||||
Log.d(TAG, "Credential Save: OK");
|
||||
showToast("Credential Save Success");
|
||||
} else {
|
||||
Log.e(TAG, "Credential Save: NOT OK");
|
||||
showToast("Credential Save Failed");
|
||||
}
|
||||
|
||||
mIsResolving = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void resolveResult(ResolvableApiException rae, int requestCode) {
|
||||
// We don't want to fire multiple resolutions at once since that can result
|
||||
// in stacked dialogs after rotation or another similar event.
|
||||
if (mIsResolving) {
|
||||
Log.w(TAG, "resolveResult: already resolving.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Resolving: " + rae);
|
||||
try {
|
||||
rae.startResolutionForResult(this.activity, requestCode);
|
||||
mIsResolving = true;
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
Log.e(TAG, "STATUS: Failed to send resolution.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Display a short Toast message **/
|
||||
private void showToast(String msg) {
|
||||
Toast.makeText(this.activity, msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
77
docs/kvvlogin.txt
Normal file
@@ -0,0 +1,77 @@
|
||||
-----------------------------------------------------------------------------
|
||||
KVV-Login
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
GET https://kvv.imp.fu-berlin.de/portal/login
|
||||
-> JSESSIONID 5c10406f-588c-4c16-96e9-c80d115417de.tomcat1
|
||||
|
||||
|
||||
GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
|
||||
<- JSESSIONID
|
||||
-> (Location-Header) https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||
?SAMLRequest=fZLLb.....Q8yre3X1IHwkJKE0Mnpy/V9TH4A
|
||||
&RelayState=ss:mem:7ea01e29157b8bd906f7002176.....0d1a505f2c8bf
|
||||
|
||||
|
||||
GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||
?SAMLRequest=fZLLbsIwEEV/JfI+cWJAUIsgpbAoEi2IpF10UznxUKw6dupxaPn7hkdb2LD29bkzRzNGUeuGZ63fmjV8toA++K61QX58SEnrDLcCFXIjakDuK55njwvOopg3znpbWU2CDBGcV9ZMrcG2BpeD26kKnteLlGy9b5BT+rHbRapuok0bluC0MpEEmm9VWVoNfhshWnpgM7pa5gUJZt0wyogD9h+iJBiv/P6aomQTbtqSdhNtlIYzZg1SOag8zfMlCeazlLyNqpHsy1gO2V1fVsNBMuqJoUyAJaxXDUaiiyG2MDfohfEpYXEyDJM4ZKxgCe/FPI5fSbA6L36vjFTm/bal8hRC/lAUq/C02gs4PK7VBchkfHDNj8Xuwv5trPhVTiY3BeOf4DG96DmVNvypA89nK6tVtQ8yre3X1IHwkJKE0Mnpy/V9TH4A
|
||||
&RelayState=ss:mem:7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||
-> JSESSIONID C4B6A428BA1F50746235D03F5D107A57
|
||||
-> _idp_authn_lc_key 57a6ae26067f374cc3d0ccfc47e27b04b47752d2a3d4eb2782af0d3994535395
|
||||
-> ROUTEID .1
|
||||
|
||||
|
||||
POST https://identity.fu-berlin.de/idp-fub/Authn/UserPassword
|
||||
------ 2x
|
||||
<- j_username seedorf96
|
||||
<- j_password neinhieristpatrick
|
||||
<- (Header-"Content-Type") application/x-www-form-urlencoded
|
||||
<- JSESSIONID
|
||||
<- _idp_authn_lc_key
|
||||
<- ROUTEID
|
||||
-> _idp_session OTMuMTkzLjg1LjMz|LQ==|OGYxOWI4MjA2NTQ4YWUwYzJkOWM4Mjk4YzcwZDMwZmJiZjBmMTdmMzkyZGU2OWIwY2JkNmZlNjlmNTRmNzBlMQ==|wLlzQal7VqyntmG2vLNn06wt8wQ=
|
||||
|
||||
|
||||
GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||
<- JSESSIONID
|
||||
<- _idp_authn_lc_key
|
||||
<- ROUTEID
|
||||
<- _idp_session
|
||||
-> (BODY) RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||
-> (BODY) SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
|
||||
|
||||
|
||||
POST https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST
|
||||
<- RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||
<- SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
|
||||
<- JSESSIONID
|
||||
-> _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
|
||||
_b1912c5a03d733a80bd3fee772bf68d4
|
||||
|
||||
|
||||
GET https://kvv.imp.fu-berlin.de/
|
||||
<- JSESSIONID
|
||||
<- _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
KVV-Login (Relogin)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
GET https://kvv.imp.fu-berlin.de/portal/login
|
||||
<- JSESSIONID
|
||||
<- _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
|
||||
<- pasystem_timezone_ok true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<tbody>(.|\n)*</tbody>
|
||||
1482
docs/module_details.txt
Normal file
17
gradle.properties
Normal file
@@ -0,0 +1,17 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Thu Apr 19 17:52:36 CEST 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
||||
160
gradlew
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||