Updates... Fixes...

This commit is contained in:
Gabriel Tofvesson 2016-06-24 00:19:22 +02:00
parent 2cab203cf7
commit b9740896da
17 changed files with 197 additions and 128 deletions

View File

@ -64,14 +64,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
@ -80,6 +72,14 @@
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
@ -120,5 +120,6 @@
<orderEntry type="library" exported="" name="support-v4-24.0.0" level="project" />
<orderEntry type="library" exported="" name="support-vector-drawable-24.0.0" level="project" />
<orderEntry type="library" exported="" name="animated-vector-drawable-24.0.0" level="project" />
<orderEntry type="module" module-name="libcacher" exported="" />
</component>
</module>

View File

@ -33,4 +33,5 @@ dependencies {
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:design:24.0.0'
compile 'org.jsoup:jsoup:1.9.2'
compile project(path: ':libcacher')
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.gabriel.projectmonster">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.INTERNET"/>
@ -29,10 +28,10 @@
</intent-filter>
</receiver>
<service android:name="com.gabriel.projectmonster.DSync"/>
<service android:name="com.gabriel.projectmonster.network.DSync"/>
<activity
android:name=".MainActivity"
android:name=".activity.MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
@ -42,12 +41,12 @@
</intent-filter>
</activity>
<activity
android:name=".PostActivity"
android:name=".activity.PostActivity"
android:label="@string/title_activity_post"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.gabriel.projectmonster.MainActivity" />
android:value="com.gabriel.projectmonster.activity.MainActivity" />
</activity>
</application>

View File

@ -4,13 +4,13 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootReceiver extends BroadcastReceiver {
public BootReceiver(){ super(); }
import com.gabriel.projectmonster.network.DSync;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED) || intent.getAction().equalsIgnoreCase(Intent.ACTION_PACKAGE_REPLACED)
|| intent.getAction().equalsIgnoreCase(Intent.ACTION_PACKAGE_ADDED))
if(intent.getAction().equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED) || intent.getAction().equalsIgnoreCase(Intent.ACTION_PACKAGE_REPLACED) || intent.getAction()
.equalsIgnoreCase(Intent.ACTION_PACKAGE_ADDED))
context.startService(new Intent(context, DSync.class));
}
}

View File

@ -1,51 +0,0 @@
package com.gabriel.projectmonster;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
public class DSync extends Service {
public int cacheTimeoutSeconds = 3600;
public static final String url = "www.luckyprison.com/";
public static final String store = "store.luckyprison.com";
public static final String[] pages = {"?page=%p", "forums/", "members/"}; //Simple reference to pages on site
public static final String[] memberType = {"", "positive_ratings", "points", "staff"};
public static final String CACHE_FRONT_PAGE_NOID = "front_page_";
// Helpful classes
class DBinder extends Binder { DSync getDataSyncService(){ return DSync.this; } }
private static boolean running = false;
DBinder d = new DBinder();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
running = true;
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
running = false;
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return d;
}
public static boolean isRunning(){ return running; }
//TODO: Not this
public String loadFrontPage() throws IOException { return null; }
}

View File

@ -1,7 +0,0 @@
package com.gabriel.projectmonster;
import org.jsoup.nodes.Document;
public interface INetworkCallback {
public void onDataReceived(Document data);
}

View File

@ -1,4 +1,4 @@
package com.gabriel.projectmonster;
package com.gabriel.projectmonster.activity;
import android.content.ComponentName;
import android.content.Context;
@ -6,10 +6,10 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
@ -19,9 +19,9 @@ import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import org.jsoup.Jsoup;
import java.io.IOException;
import com.gabriel.projectmonster.R;
import com.gabriel.projectmonster.network.DSync;
import com.gabriel.projectmonster.network.NetworkConnection;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@ -34,24 +34,18 @@ public class MainActivity extends AppCompatActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NetworkConnection.getDataAsync("https://luckyprison.com/", d -> ((TextView) MainActivity.this.findViewById(R.id.text)).setText(d.getElementsByTag("html").get(0).toString()), true);
NetworkConnection.getDataAsync("https://luckyprison.com/", d -> ((TextView) MainActivity.this.findViewById(R.id.text)).setText(d.getElementsByTag("html").get(0).toString()), Looper.getMainLooper());
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
fab.setOnClickListener(view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show());
DrawerLayout drawer = (DrawerLayout) 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);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);

View File

@ -1,4 +1,4 @@
package com.gabriel.projectmonster;
package com.gabriel.projectmonster.activity;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
@ -7,6 +7,9 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import com.gabriel.projectmonster.R;
import com.gabriel.projectmonster.network.DSync;
public class PostActivity extends AppCompatActivity {
DSync d;

View File

@ -0,0 +1,69 @@
package com.gabriel.projectmonster.network;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.Nullable;
import com.tofvesson.Cacher;
import org.jsoup.Jsoup;
import java.io.IOException;
public class DSync extends Service {
// Helpful classes
public class DBinder extends Binder { public DSync getDataSyncService(){ return DSync.this; } }
// Public values
public static int cacheTimeoutSeconds = 3600;
public static final String url = "www.luckyprison.com/";
public static final String store = "store.luckyprison.com";
public static final String[] pages = {"?page=%p", "forums/", "members/"}; //Simple reference to pages on site
public static final String pageID = "%p";
public static final String[] memberType = {"", "positive_ratings", "points", "staff"};
public static final String CACHE_FRONT_PAGE_NOID = "front_page_";
private Cacher cache;
// Defines if service is running
private static boolean running = false;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
running = true;
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
running = false;
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new DBinder();
}
public static boolean isRunning(){ return running; }
//TODO: Add code to load front page
public void loadFrontPage(INetworkCallback onLoad, Looper whereToExecute) throws IOException {
if(cache.containsKey(CACHE_FRONT_PAGE_NOID+"COUNT"))
if((System.currentTimeMillis()/1000-cache.load(CACHE_FRONT_PAGE_NOID+0).unixTimeCached)<cacheTimeoutSeconds) onLoad.onDataReceived(Jsoup.parse(cache.load(CACHE_FRONT_PAGE_NOID+0).data));
else cache.remove(CACHE_FRONT_PAGE_NOID+0);
else{
NetworkConnection.getDataAsync(url+pages[0].replace(pageID, "0"), d ->
{
String s;
cache.store(CACHE_FRONT_PAGE_NOID+0, d.toString());
cache.store(CACHE_FRONT_PAGE_NOID, (s = (s = d.getElementsByClass("pageNavHeader").get(0).toString()).substring(s.indexOf(">")+1, s.substring(s.indexOf(">")).indexOf("<")+s.indexOf(">")))
.substring(s.lastIndexOf(" ")+1, s.length()) );
onLoad.onDataReceived(d);
}, whereToExecute);
}
}
public void loadFrontPage(INetworkCallback onLoad){ try { loadFrontPage(onLoad, Looper.getMainLooper()); } catch (IOException e) { e.printStackTrace(); } }
}

View File

@ -0,0 +1,7 @@
package com.gabriel.projectmonster.network;
import org.jsoup.nodes.Document;
public interface INetworkCallback {
void onDataReceived(Document data);
}

View File

@ -1,6 +1,5 @@
package com.gabriel.projectmonster;
package com.gabriel.projectmonster.network;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
@ -13,39 +12,36 @@ import java.io.IOException;
public class NetworkConnection {
private static volatile boolean callbackInMain = true;
private static volatile Document data;
private static volatile String page = "";
private static volatile INetworkCallback callback = null;
private static Thread t;
private static final Runnable grabData = new Runnable(){
static volatile Looper whereToRun;
static volatile Document data;
static volatile String page = "";
static volatile INetworkCallback callback = null;
static Thread t;
static final Runnable grabData = new Runnable(){
@Override
public void run() {
// Local variables to make thread functionally compatible with static methods
boolean call = callbackInMain;
Looper runIn = whereToRun;
final INetworkCallback c = callback;
try { data = Jsoup.connect(page).userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36").get(); }
try { data = Jsoup.connect(page).get(); }
catch (IOException e) { e.printStackTrace(); }
final Document dat = data;
Runnable r = c!=null ? () -> c.onDataReceived(dat) : null;
if(c != null)
if (call) new Handler(Looper.getMainLooper()).post(r);
else r.run();
if(c != null) new Handler(runIn).post(r);
}
};
public static Document getData(String page){
public static Document getData(String page){
NetworkConnection.callback = null;
NetworkConnection.page = page;
(t = new Thread(grabData)).start();
try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); }
return data;
}
public static void getDataAsync(@NonNull String page, @Nullable INetworkCallback callback, boolean callbackInMainThread){
callbackInMain = callbackInMainThread;
public static void getDataAsync(@NonNull String page, @Nullable INetworkCallback callback, @NonNull Looper runIn){
runIn = whereToRun;
NetworkConnection.page = page;
NetworkConnection.callback = callback;
(t = new Thread(grabData)).start();
NetworkConnection.callback = null;
}
}

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.gabriel.projectmonster.PostActivity">
tools:context="com.gabriel.projectmonster.activity.PostActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.gabriel.projectmonster.MainActivity">
tools:context="com.gabriel.projectmonster.activity.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"

View File

@ -9,7 +9,7 @@
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.gabriel.projectmonster.MainActivity"
tools:context="com.gabriel.projectmonster.activity.MainActivity"
tools:showIn="@layout/app_bar_main">
<TextView

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.gabriel.projectmonster.PostActivity"
tools:context="com.gabriel.projectmonster.activity.PostActivity"
tools:showIn="@layout/activity_post">
<TextView

View File

@ -1,7 +1,7 @@
<menu 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"
tools:context="com.gabriel.projectmonster.PostActivity">
tools:context="com.gabriel.projectmonster.activity.PostActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"

View File

@ -5,15 +5,12 @@ import com.sun.istack.internal.Nullable;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -21,13 +18,15 @@ import java.util.Map;
@SuppressWarnings("ALL")
public class Cacher implements Closeable{
private class CacheDataHolder{ int unixTimeCached = 0; String data = ""; public CacheDataHolder(String s, int i){ unixTimeCached=i; data=s; } }
public class CacheDataHolder{ public int unixTimeCached = 0; public String data = ""; public CacheDataHolder(String s, int i){ unixTimeCached=i; data=s; } }
private PrintStream cache;
private BufferedReader cacheIn;
private FileReader cacheFileReader;
private File cacheFile;
private Map<String, CacheDataHolder> cachedValues = new HashMap<>();
boolean verbose;
Thread purger;
PrintStream cache;
BufferedReader cacheIn;
FileReader cacheFileReader;
File cacheFile;
Map<String, CacheDataHolder> cachedValues = new HashMap<>();
public Cacher(File file, String s) throws FileNotFoundException, UnsupportedEncodingException {
if(!(cacheFile = file).isFile()) try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); }
@ -102,6 +101,8 @@ public class Cacher implements Closeable{
return false;
}
public boolean containsKey(String k){ return cachedValues.containsKey(k) || cacheContainsKey(k); }
public void store(String k, String v, int cacheTime){
if(cachedValues.containsKey(k = k.replace("[", "[lb").replace(" ", "[sp"))) cachedValues.replace(k, new CacheDataHolder(v.replace("[", "[lb").replace(" ", "[sp"), cacheTime));
else cachedValues.put(k, new CacheDataHolder(v.replace("[", "[lb").replace(" ", "[sp"), cacheTime));
@ -118,13 +119,24 @@ public class Cacher implements Closeable{
return null;
}
public void remove(String k){
if(cachedValues.containsKey(k)) cachedValues.remove(k);
if(cacheContainsKey(k)){
for(String s : loadKeysFromCache())
if(!cachedValues.containsKey(k))
cachedValues.put(k, loadFromCache(k));
cachedValues.remove(k);
try { overwriteCache(); } catch (IOException e) { e.printStackTrace(); }
}
}
@Nullable
private CacheDataHolder loadFromCache(String k){
k = k.replace("[", "[lb").replace(" ", "[sp");
String s = "";
try {
while((s = cacheIn.readLine())!=null) if(s.substring(0, s.indexOf(" ")).equals(k)) //value 123
return new CacheDataHolder(s.substring(s.indexOf(" ")+1, s.substring(s.indexOf(" ")+1).indexOf(" ")+s.indexOf(" ")).replace(" ", "[sp").replace("[", "[lb"),
return new CacheDataHolder(s.substring(s.indexOf(" ")+1, s.substring(s.indexOf(" ")+1).indexOf(" ")+s.indexOf(" ")).replace("[sp", " ").replace("[lb", "["),
Integer.parseInt(s.substring(s.substring(s.indexOf(" ")+1).indexOf(" ")+1+s.indexOf(" "))));
} catch (IOException e) {
e.printStackTrace();
@ -136,15 +148,22 @@ public class Cacher implements Closeable{
String s = "";
List<String> keys = new ArrayList<>();
try { resetReader(); while((s = cacheIn.readLine())!=null) keys.add(s.substring(s.indexOf(" "))); } catch (IOException e) { e.printStackTrace(); }
return keys;
}
public void flush() throws IOException {
public void flush() {
List<String> fileKeys = loadKeysFromCache();
for(String k : fileKeys)
if(cachedValues.containsKey(k)) cachedValues.replace(k, loadFromCache(k));
else cachedValues.put(k, loadFromCache(k));
try{
overwriteCache();
}catch(IOException e){
e.printStackTrace();
}
}
private void overwriteCache() throws IOException {
cacheFile.delete();
cacheFile.createNewFile();
cache = new PrintStream(cacheFile);
@ -184,16 +203,54 @@ public class Cacher implements Closeable{
return true;
}
private int allOccurrencesOf(String s, String sequence){
private int allOccurrencesOf(String s, String regex){
int i = 0;
//Assign string to the substring *after* first instance of sequence by incrementing counter, dividing counter variable by itself (i/i = 1)
//and multiplying by length of sequence to exclude it from new string
while(s.indexOf(sequence)!=0) s = s.substring(s.indexOf(sequence)+(((++i)/i)*sequence.length()));
while(s.indexOf(regex)!=0) s = s.substring(s.indexOf(regex)+(((++i)/i)*regex.length()));
return i;
}
public void purge(int timeout) {
for (String k : cachedValues.keySet())
if (timeout < (System.currentTimeMillis() / 1000) - cachedValues.get(k).unixTimeCached)
cachedValues.remove(k);
for (String k : loadKeysFromCache())
if (timeout < (System.currentTimeMillis() / 1000) - loadFromCache(k).unixTimeCached)
remove(k);
}
/**
* Starts a thread that will automatically purge old/unusable resources
* @param maxTime The maximum time in seconds between the current time and the time when resource was cached before the resource is purged
* @param timedelay Time interval between purges (choose a relatively high number to minimize high proceeor loads)
* @param verbose Whether or not to output debug to System.out
*/
public void startAutoPurge(final int maxTime, final int timedelay, final boolean verbose){
purger = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
if (verbose) System.out.println("Purging cache...");
purge(maxTime);
try {
Thread.sleep(timedelay * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
purger.start();
}
@Override
public void close() throws IOException {
this.flush();
closeNoFlush();
}
public void closeNoFlush() throws IOException {
cache.close();
cacheIn.close();
}