v0.8.0: added an update notification service

This commit is contained in:
Evan Debenham 2019-11-22 15:05:47 -05:00
parent 2e533b74db
commit 2138ad24ec
24 changed files with 606 additions and 13 deletions

View File

@ -28,6 +28,7 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONTokener; import org.json.JSONTokener;
import java.io.BufferedInputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
@ -35,7 +36,6 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.PushbackInputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -46,6 +46,8 @@ public class Bundle {
private static final String CLASS_NAME = "__className"; private static final String CLASS_NAME = "__className";
public static final String DEFAULT_KEY = "key";
private static HashMap<String,String> aliases = new HashMap<>(); private static HashMap<String,String> aliases = new HashMap<>();
private JSONObject data; private JSONObject data;
@ -224,6 +226,25 @@ public class Bundle {
} }
} }
public Bundle[] getBundleArray(){
return getBundleArray( DEFAULT_KEY );
}
public Bundle[] getBundleArray( String key ){
try {
JSONArray array = data.getJSONArray( key );
int length = array.length();
Bundle[] result = new Bundle[length];
for (int i=0; i < length; i++) {
result[i] = new Bundle( array.getJSONObject( i ) );
}
return result;
} catch (JSONException e) {
Game.reportException(e);
return null;
}
}
public Collection<Bundlable> getCollection( String key ) { public Collection<Bundlable> getCollection( String key ) {
ArrayList<Bundlable> list = new ArrayList<>(); ArrayList<Bundlable> list = new ArrayList<>();
@ -410,22 +431,32 @@ public class Bundle {
public static Bundle read( InputStream stream ) throws IOException { public static Bundle read( InputStream stream ) throws IOException {
try { try {
BufferedReader reader; if (!stream.markSupported()){
stream = new BufferedInputStream( stream, 2 );
}
//determines if we're reading a regular, or compressed file //determines if we're reading a regular, or compressed file
PushbackInputStream pb = new PushbackInputStream( stream, 2 ); stream.mark( 2 );
byte[] header = new byte[2]; byte[] header = new byte[2];
pb.unread(header, 0, pb.read(header)); stream.read( header );
//GZIP header is 0x1f8b stream.reset();
if( header[ 0 ] == (byte) 0x1f && header[ 1 ] == (byte) 0x8b )
reader = new BufferedReader( new InputStreamReader( new GZIPInputStream( pb, GZIP_BUFFER ) ) );
else
reader = new BufferedReader( new InputStreamReader( pb ) );
JSONObject json = (JSONObject)new JSONTokener( reader.readLine() ).nextValue(); //GZIP header is 0x1f8b
if( header[ 0 ] == (byte) 0x1f && header[ 1 ] == (byte) 0x8b ) {
stream = new GZIPInputStream( stream, GZIP_BUFFER );
}
//cannot just tokenize the stream directly as that constructor doesn't exist on Android
BufferedReader reader = new BufferedReader( new InputStreamReader( stream ));
Object json = new JSONTokener( reader.readLine() ).nextValue();
reader.close(); reader.close();
return new Bundle( json ); //if the data is an array, put it in a fresh object with the default key
if (json instanceof JSONArray){
json = new JSONObject().put( DEFAULT_KEY, json );
}
return new Bundle( (JSONObject) json );
} catch (Exception e) { } catch (Exception e) {
Game.reportException(e); Game.reportException(e);
throw new IOException(); throw new IOException();

View File

@ -29,6 +29,8 @@ public abstract class PlatformSupport {
public abstract void updateSystemUI(); public abstract void updateSystemUI();
public abstract boolean connectedToUnmeteredNetwork();
//FIXME this is currently used because no platform-agnostic text input has been implemented. //FIXME this is currently used because no platform-agnostic text input has been implemented.
//should look into doing that using either plain openGL or Libgdx's libraries //should look into doing that using either plain openGL or Libgdx's libraries
public abstract void promptTextInput( String title, String hintText, int maxLen, boolean multiLine, public abstract void promptTextInput( String title, String hintText, int maxLen, boolean multiLine,

View File

@ -25,6 +25,9 @@ android {
debug { debug {
applicationIdSuffix ".indev" applicationIdSuffix ".indev"
versionNameSuffix '-INDEV' versionNameSuffix '-INDEV'
dependencies {
debugImplementation project(':services:updates:debugUpdates')
}
} }
release { release {
@ -35,6 +38,10 @@ android {
shrinkResources true shrinkResources true
minifyEnabled true minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
dependencies {
releaseImplementation project(':services:updates:githubUpdates')
}
} }
} }

View File

@ -6,6 +6,8 @@
<uses-feature android:glEsVersion="0x00020000"/> <uses-feature android:glEsVersion="0x00020000"/>
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Note that the game doesn't truly support small screen resolutions, <!-- Note that the game doesn't truly support small screen resolutions,
it instead forces downscaling to work on these displays.--> it instead forces downscaling to work on these displays.-->

View File

@ -32,6 +32,8 @@ import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings; import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.UpdateImpl;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
import com.watabou.noosa.Game; import com.watabou.noosa.Game;
import com.watabou.utils.FileUtils; import com.watabou.utils.FileUtils;
@ -59,6 +61,10 @@ public class AndroidGame extends AndroidApplication {
Game.versionCode = 0; Game.versionCode = 0;
} }
if (UpdateImpl.supportsUpdates()){
Updates.service = UpdateImpl.getUpdateService();
}
FileUtils.setDefaultFileProperties( Files.FileType.Local, "" ); FileUtils.setDefaultFileProperties( Files.FileType.Local, "" );
// grab preferences directly using our instance first // grab preferences directly using our instance first

View File

@ -22,7 +22,10 @@
package com.shatteredpixel.shatteredpixeldungeon.android; package com.shatteredpixel.shatteredpixeldungeon.android;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build; import android.os.Build;
import android.view.View; import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
@ -140,6 +143,23 @@ public class AndroidPlatformSupport extends PlatformSupport {
} }
@Override
@SuppressWarnings("deprecation")
public boolean connectedToUnmeteredNetwork() {
//Returns true if using unmetered connection, use shortcut method if available
ConnectivityManager cm = (ConnectivityManager) AndroidGame.instance.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
return !cm.isActiveNetworkMetered();
} else {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting() &&
(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI
|| activeNetwork.getType() == ConnectivityManager.TYPE_WIMAX
|| activeNetwork.getType() == ConnectivityManager.TYPE_BLUETOOTH
|| activeNetwork.getType() == ConnectivityManager.TYPE_ETHERNET);
}
}
@Override @Override
public void promptTextInput(final String title, final String hintText, final int maxLen, final boolean multiLine, final String posTxt, final String negTxt, final TextCallback callback) { public void promptTextInput(final String title, final String hintText, final int maxLen, final boolean multiLine, final String posTxt, final String negTxt, final TextCallback callback) {
Game.runOnRenderThread( new Callback() { Game.runOnRenderThread( new Callback() {

View File

@ -5,4 +5,6 @@ sourceCompatibility = targetCompatibility = appJavaCompatibility
dependencies { dependencies {
api project(':SPD-classes') api project(':SPD-classes')
//TODO might be nice to remove this, should decide
implementation project(':services')
} }

View File

@ -34,6 +34,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.LanguageButton; import com.shatteredpixel.shatteredpixeldungeon.ui.LanguageButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.PrefsButton; import com.shatteredpixel.shatteredpixeldungeon.ui.PrefsButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.UpdateNotification;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndStartGame; import com.shatteredpixel.shatteredpixeldungeon.windows.WndStartGame;
import com.watabou.glwrap.Blending; import com.watabou.glwrap.Blending;
@ -225,6 +226,10 @@ public class TitleScene extends PixelScene {
btnExit.setPos( w - btnExit.width(), 0 ); btnExit.setPos( w - btnExit.width(), 0 );
add( btnExit ); add( btnExit );
UpdateNotification updInfo = new UpdateNotification();
updInfo.setRect(4, h-BTN_HEIGHT, updInfo.reqWidth() + 6, BTN_HEIGHT-4);
add(updInfo);
fadeIn(); fadeIn();
} }

View File

@ -0,0 +1,69 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
public class Updates {
public static UpdateService service;
public static boolean supportsUpdates(){
return service != null;
}
private static boolean updateChecked = false;
public static void checkForUpdate(){
if (!supportsUpdates() || updateChecked) return;
service.checkForUpdate(new UpdateService.UpdateResultCallback() {
@Override
public void onUpdateAvailable(AvailableUpdateData update) {
updateChecked = true;
updateData = update;
}
@Override
public void onNoUpdateFound() {
updateChecked = true;
}
@Override
public void onConnectionFailed() {
updateChecked = false;
}
});
}
public static void launchUpdate( AvailableUpdateData data ){
service.initializeUpdate( data );
}
private static AvailableUpdateData updateData = null;
public static boolean updateAvailable(){
return updateData != null;
}
public static AvailableUpdateData updateData(){
return updateData;
}
}

View File

@ -0,0 +1,79 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.ui;
import com.shatteredpixel.shatteredpixeldungeon.Chrome;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.AvailableUpdateData;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
import com.watabou.noosa.Game;
public class UpdateNotification extends StyledButton {
private static AvailableUpdateData update;
public UpdateNotification(){
super( Chrome.Type.GREY_BUTTON_TR, Messages.get(UpdateNotification.class, "title") );
textColor( Window.SHPX_COLOR );
visible = false;
Updates.checkForUpdate();
}
@Override
public void update() {
super.update();
if (Updates.updateAvailable()){
bg.alpha((float) (0.7f + Math.sin(Game.timeTotal*2)*0.3f));
text.alpha((float) (0.7f + Math.sin(Game.timeTotal*2)*0.3f));
visible = true;
} else {
visible = false;
}
}
@Override
protected void onClick() {
update = Updates.updateData();
ShatteredPixelDungeon.scene().addToFront( new WndUpdate() );
}
public static class WndUpdate extends WndOptions {
public WndUpdate(){
super(
update.versionName == null ? Messages.get(WndUpdate.class,"title") : Messages.get(WndUpdate.class,"versioned_title", update.versionName),
update.desc == null ? Messages.get(WndUpdate.class,"desc") : update.desc,
Messages.get(WndUpdate.class,"button"));
}
@Override
protected void onSelect(int index) {
if (index == 0) {
Updates.launchUpdate(update);
}
}
}
}

View File

@ -1,3 +1,9 @@
ui.quickslotbutton.select_item=Quickslot an item ui.quickslotbutton.select_item=Quickslot an item
ui.toolbar.examine_prompt=Press again to search\nPress a tile to examine ui.toolbar.examine_prompt=Press again to search\nPress a tile to examine
ui.updatenotification.title=Update
ui.updatenotification$wndupdate.title=An Update is Available!
ui.updatenotification$wndupdate.versioned_title=Update Available: %s
ui.updatenotification$wndupdate.desc=Shattered Pixel Dungeon is regularly updated with overhauls to existing game content, or entirely new content!\n\nGame balance is also frequently improved in game updates, so that specific items/heroes/enemies aren't too strong or too weak.\n\nUpdates also include fixes for bugs and other various stability improvements.
ui.updatenotification$wndupdate.button=Go To Update Page

View File

@ -20,6 +20,10 @@ task debug(dependsOn: classes, type: JavaExec) {
systemProperty 'Specification-Title', appName systemProperty 'Specification-Title', appName
systemProperty 'Specification-Version', appVersionName + "-INDEV" systemProperty 'Specification-Version', appVersionName + "-INDEV"
systemProperty 'Implementation-Version', appVersionCode systemProperty 'Implementation-Version', appVersionCode
dependencies {
debugImplementation project(':services:updates:debugUpdates')
}
} }
//need a separate task to compile dependencies first, seeing as we're setting them up in an odd way //need a separate task to compile dependencies first, seeing as we're setting them up in an odd way
@ -38,6 +42,10 @@ task release(dependsOn: compileForRelease, type: Jar) {
attributes 'Specification-Version': appVersionName attributes 'Specification-Version': appVersionName
attributes 'Implementation-Version': appVersionCode attributes 'Implementation-Version': appVersionCode
} }
dependencies {
releaseImplementation project(':services:updates:githubUpdates')
}
} }
dependencies { dependencies {
@ -47,4 +55,8 @@ dependencies {
implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion" implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
//Need these at compile time to prevent errors there.
// The actual dependency used at runtime will vary based on source set.
compileOnly project(':services:updates:debugUpdates')
} }

View File

@ -29,6 +29,8 @@ import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Preferences;
import com.badlogic.gdx.utils.SharedLibraryLoader; import com.badlogic.gdx.utils.SharedLibraryLoader;
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings; import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.UpdateImpl;
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
import com.watabou.noosa.Game; import com.watabou.noosa.Game;
import com.watabou.utils.FileUtils; import com.watabou.utils.FileUtils;
import com.watabou.utils.Point; import com.watabou.utils.Point;
@ -80,6 +82,10 @@ public class DesktopLauncher {
Game.versionCode = Integer.parseInt(System.getProperty("Implementation-Version")); Game.versionCode = Integer.parseInt(System.getProperty("Implementation-Version"));
} }
if (UpdateImpl.supportsUpdates()){
Updates.service = UpdateImpl.getUpdateService();
}
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setTitle( title ); config.setTitle( title );

View File

@ -58,6 +58,11 @@ public class DesktopPlatformSupport extends PlatformSupport {
} ); } );
} }
@Override
public boolean connectedToUnmeteredNetwork() {
return true; //no easy way to check this in desktop, just assume user doesn't care
}
@Override @Override
public void promptTextInput(String title, String hintText, int maxLen, boolean multiLine, String posTxt, String negTxt, TextCallback callback) { public void promptTextInput(String title, String hintText, int maxLen, boolean multiLine, String posTxt, String negTxt, TextCallback callback) {

4
services/build.gradle Normal file
View File

@ -0,0 +1,4 @@
apply plugin: 'java-library'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
sourceCompatibility = targetCompatibility = appJavaCompatibility

View File

@ -0,0 +1,33 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
public class AvailableUpdateData {
public String versionName;
public int versionCode;
public String desc;
public String URL;
}

View File

@ -0,0 +1,36 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
public abstract class UpdateService {
public static abstract class UpdateResultCallback {
public abstract void onUpdateAvailable( AvailableUpdateData update );
public abstract void onNoUpdateFound();
public abstract void onConnectionFailed();
}
public abstract void checkForUpdate( UpdateResultCallback callback );
public abstract void initializeUpdate( AvailableUpdateData update );
}

View File

@ -0,0 +1,9 @@
apply plugin: 'java-library'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
sourceCompatibility = targetCompatibility = appJavaCompatibility
dependencies {
implementation project(':SPD-classes')
api project(':services')
}

View File

@ -0,0 +1,55 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
import com.watabou.noosa.Game;
import com.watabou.utils.DeviceCompat;
public class DebugUpdates extends UpdateService {
private static AvailableUpdateData debugUpdateInfo;
@Override
public void checkForUpdate(UpdateResultCallback callback) {
//turn on to test update UI
if (false){
debugUpdateInfo = new AvailableUpdateData();
debugUpdateInfo.versionCode = Game.versionCode+1;
debugUpdateInfo.URL = "http://www.google.com";
callback.onUpdateAvailable(debugUpdateInfo);
} else {
debugUpdateInfo = null;
callback.onNoUpdateFound();
}
}
@Override
public void initializeUpdate(AvailableUpdateData update) {
DeviceCompat.openURI( update.URL );
}
}

View File

@ -0,0 +1,36 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
public class UpdateImpl {
private static UpdateService updateChecker = new DebugUpdates();
public static UpdateService getUpdateService(){
return updateChecker;
}
public static boolean supportsUpdates(){
return true;
}
}

View File

@ -0,0 +1,9 @@
apply plugin: 'java-library'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
sourceCompatibility = targetCompatibility = appJavaCompatibility
dependencies {
implementation project(':SPD-classes')
api project(':services')
}

View File

@ -0,0 +1,122 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net;
import com.watabou.noosa.Game;
import com.watabou.utils.Bundle;
import com.watabou.utils.DeviceCompat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLProtocolException;
public class GitHubUpdates extends UpdateService {
private static Pattern descPattern = Pattern.compile("(.*?)(\r\n|\n|\r)(\r\n|\n|\r)---", Pattern.DOTALL + Pattern.MULTILINE);
private static Pattern versionCodePattern = Pattern.compile("internal version number: ([0-9]*)", Pattern.CASE_INSENSITIVE);
@Override
public void checkForUpdate(UpdateResultCallback callback) {
if (!Game.platform.connectedToUnmeteredNetwork()){
callback.onConnectionFailed();
}
Net.HttpRequest httpGet = new Net.HttpRequest(Net.HttpMethods.GET);
httpGet.setUrl("https://api.github.com/repos/00-Evan/shattered-pixel-dungeon/releases");
httpGet.setHeader("Accept", "application/vnd.github.v3+json");
Gdx.net.sendHttpRequest(httpGet, new Net.HttpResponseListener() {
@Override
public void handleHttpResponse(Net.HttpResponse httpResponse) {
try {
Bundle latestRelease = null;
int latestVersionCode = Game.versionCode;
boolean includePrereleases = Game.version.toLowerCase().contains("beta");
for (Bundle b : Bundle.read( httpResponse.getResultAsStream() ).getBundleArray()){
Matcher m = versionCodePattern.matcher(b.getString("body"));
if (m.find()){
int releaseVersion = Integer.parseInt(m.group(1));
if (releaseVersion > latestVersionCode
&& (includePrereleases || !b.getBoolean("prerelease"))){
latestRelease = b;
latestVersionCode = releaseVersion;
}
}
}
if (latestRelease == null){
callback.onNoUpdateFound();
} else {
AvailableUpdateData update = new AvailableUpdateData();
update.versionName = latestRelease.getString("name");
update.versionCode = latestVersionCode;
Matcher m = descPattern.matcher(latestRelease.getString("body"));
m.find();
update.desc = m.group(1);
update.URL = latestRelease.getString("html_url");
callback.onUpdateAvailable(update);
}
} catch (Exception e) {
Game.reportException( e );
callback.onConnectionFailed();
}
}
@Override
public void failed(Throwable t) {
//Failure in SSL handshake, possibly because GitHub requires TLS 1.2+.
// Often happens for old OS versions with outdated security protocols.
// Future update attempts won't work anyway, so just pretend nothing was found.
if (t instanceof SSLProtocolException){
callback.onNoUpdateFound();
} else {
Game.reportException(t);
callback.onConnectionFailed();
}
}
@Override
public void cancelled() {
callback.onConnectionFailed();
}
});
}
@Override
public void initializeUpdate(AvailableUpdateData update) {
DeviceCompat.openURI( update.URL );
}
}

View File

@ -0,0 +1,36 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2019 Evan Debenham
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
public class UpdateImpl {
private static UpdateService updateChecker = new GitHubUpdates();
public static UpdateService getUpdateService(){
return updateChecker;
}
public static boolean supportsUpdates(){
return true;
}
}

View File

@ -1 +1,2 @@
include ':core', ':SPD-classes', ':android', ':desktop' include ':core', ':SPD-classes', ':android', ':desktop', ':services',
':services:updates:debugUpdates', ':services:updates:githubUpdates'