diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 2664cc4a3..66d3b53ce 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,8 +1,11 @@ - + android:installLocation="auto" + android:targetSandboxVersion="2" + xmlns:dist="http://schemas.android.com/apk/distribution"> + + diff --git a/build.gradle b/build.gradle index e7356127d..c78d1e9fc 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ allprojects { appName = 'Shattered Pixel Dungeon' appPackageName = 'com.shatteredpixel.shatteredpixeldungeon' - appVersionCode = 422 + appVersionCode = 434 appVersionName = '0.8.1a' appJavaCompatibility = JavaVersion.VERSION_1_8 diff --git a/core/src/main/assets/messages/scenes/scenes.properties b/core/src/main/assets/messages/scenes/scenes.properties index 049b50b85..93e6aa7d2 100644 --- a/core/src/main/assets/messages/scenes/scenes.properties +++ b/core/src/main/assets/messages/scenes/scenes.properties @@ -42,6 +42,7 @@ scenes.interlevelscene$mode.resurrect=Resurrecting... scenes.interlevelscene$mode.return=Returning... scenes.interlevelscene$mode.fall=Falling... scenes.interlevelscene$mode.reset=Resetting... +scenes.interlevelscene.install=Install the Game scenes.interlevelscene.file_not_found=Save file not found. If this error persists after restarting, it may mean this save game is corrupted. Sorry about that. scenes.interlevelscene.io_error=Cannot read save file. If this error persists after restarting, it may mean this save game is corrupted. Sorry about that. @@ -78,6 +79,7 @@ scenes.titlescene.badges=Badges scenes.titlescene.news=News scenes.titlescene.changes=Changes scenes.titlescene.update=Update +scenes.titlescene.install=Install scenes.titlescene.settings=Settings scenes.titlescene.about=About scenes.titlescene.support=Support the Game diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index d514ee89d..5e6c0bcec 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -14,6 +14,7 @@ windows.wnddocument.missing=page missing windows.wnderror.title=ERROR windows.wndgame.settings=Settings +windows.wndgame.install=Install the Game windows.wndgame.challenges=Challenges windows.wndgame.rankings=Rankings windows.wndgame.start=Start New Game diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java index 081dc64ac..62da8f124 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/InterlevelScene.java @@ -22,6 +22,7 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes; import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Chrome; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.GamesInProgress; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; @@ -33,8 +34,12 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.Level; import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm; import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.special.SpecialRoom; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates; import com.shatteredpixel.shatteredpixeldungeon.ui.GameLog; +import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; +import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; +import com.shatteredpixel.shatteredpixeldungeon.ui.Window; import com.shatteredpixel.shatteredpixeldungeon.windows.WndError; import com.shatteredpixel.shatteredpixeldungeon.windows.WndStory; import com.watabou.gltextures.TextureCache; @@ -138,8 +143,11 @@ public class InterlevelScene extends PixelScene { else if (loadingDepth <= 25) loadingAsset = Assets.Interfaces.LOADING_HALLS; else loadingAsset = Assets.Interfaces.SHADOW; + //slow down transition when displaying an install prompt + if (Updates.isInstallable()){ + fadeTime += 0.5f; //adds 1 second total //speed up transition when debugging - if (DeviceCompat.isDebug()){ + } else if (DeviceCompat.isDebug()){ fadeTime /= 2; } @@ -189,6 +197,30 @@ public class InterlevelScene extends PixelScene { ); align(message); add( message ); + + if (Updates.isInstallable()){ + StyledButton install = new StyledButton(Chrome.Type.GREY_BUTTON_TR, Messages.get(this, "install")){ + @Override + public void update() { + super.update(); + float p = timeLeft / fadeTime; + if (phase == Phase.FADE_IN) alpha(1 - p); + else if (phase == Phase.FADE_OUT) alpha(p); + else alpha(1); + } + + @Override + protected void onClick() { + super.onClick(); + Updates.launchInstall(); + } + }; + install.icon(Icons.get(Icons.CHANGES)); + install.textColor(Window.SHPX_COLOR); + install.setSize(install.reqWidth()+5, 20); + install.setPos((Camera.main.width - install.width())/2, (Camera.main.height - message.bottom())/3 + message.bottom()); + add(install); + } phase = Phase.FADE_IN; timeLeft = fadeTime; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java index 3863c0d28..abe5aa739 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java @@ -260,18 +260,23 @@ public class TitleScene extends PixelScene { public void update() { super.update(); - if (Updates.updateAvailable()){ - if (!updateShown){ - updateShown = true; - text(Messages.get(TitleScene.class, "update")); - } + if (!updateShown && (Updates.updateAvailable() || Updates.isInstallable())){ + updateShown = true; + if (Updates.isInstallable()) text(Messages.get(TitleScene.class, "install")); + else text(Messages.get(TitleScene.class, "update")); + } + + if (updateShown){ textColor(ColorMath.interpolate( 0xFFFFFF, Window.SHPX_COLOR, 0.5f + (float)Math.sin(Game.timeTotal*5)/2f)); } } @Override protected void onClick() { - if (Updates.updateAvailable()){ + if (Updates.isInstallable()){ + Updates.launchInstall(); + + } else if (Updates.updateAvailable()){ AvailableUpdateData update = Updates.updateData(); ShatteredPixelDungeon.scene().addToFront( new WndOptions( @@ -290,6 +295,7 @@ public class TitleScene extends PixelScene { } } }); + } else { ChangesScene.changesSelected = 0; ShatteredPixelDungeon.switchNoFade( ChangesScene.class ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/Updates.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/Updates.java index 8fbc85f58..5913ed90c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/Updates.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/Updates.java @@ -36,8 +36,12 @@ public class Updates { private static Date lastCheck = null; private static final long CHECK_DELAY = 1000*60*60; //1 hour + public static boolean isUpdateable(){ + return supportsUpdates() && service.isUpdateable(); + } + public static void checkForUpdate(){ - if (!supportsUpdates()) return; + if (!isUpdateable()) return; if (lastCheck != null && (new Date().getTime() - lastCheck.getTime()) < CHECK_DELAY) return; service.checkForUpdate(!SPDSettings.WiFi(), new UpdateService.UpdateResultCallback() { @@ -78,4 +82,14 @@ public class Updates { lastCheck = null; } + public static boolean isInstallable(){ + return supportsUpdates() && service.isInstallable(); + } + + public static void launchInstall(){ + if (supportsUpdates()){ + service.initializeInstall(); + } + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGame.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGame.java index 825d81c90..408211cb1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGame.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndGame.java @@ -30,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.HeroSelectScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.InterlevelScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.RankingsScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.TitleScene; +import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; @@ -59,6 +60,18 @@ public class WndGame extends Window { }); curBtn.icon(Icons.get(Icons.PREFS)); + //install prompt + if (Updates.isInstallable()){ + addButton( curBtn = new RedButton( Messages.get(this, "install") ) { + @Override + protected void onClick() { + Updates.launchInstall(); + } + } ); + curBtn.textColor(Window.SHPX_COLOR); + curBtn.icon(Icons.get(Icons.CHANGES)); + } + // Challenges window if (Dungeon.challenges > 0) { addButton( curBtn = new RedButton( Messages.get(this, "challenges") ) { diff --git a/services/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/UpdateService.java b/services/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/UpdateService.java index d6afd7a97..ff3d030b9 100644 --- a/services/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/UpdateService.java +++ b/services/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/UpdateService.java @@ -29,8 +29,16 @@ public abstract class UpdateService { public abstract void onConnectionFailed(); } + //whether the app is updateable via an ingame prompt (e.g. not a demo or an android instant app) + public abstract boolean isUpdateable(); + public abstract void checkForUpdate( boolean useMetered, UpdateResultCallback callback ); public abstract void initializeUpdate( AvailableUpdateData update ); + //whether the app installable via an ingame prompt (e.g. a demo, or an android instant app) + public abstract boolean isInstallable(); + + public abstract void initializeInstall(); + } diff --git a/services/updates/debugUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/DebugUpdates.java b/services/updates/debugUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/DebugUpdates.java index 2937453ae..301d53ef6 100644 --- a/services/updates/debugUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/DebugUpdates.java +++ b/services/updates/debugUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/DebugUpdates.java @@ -29,6 +29,11 @@ public class DebugUpdates extends UpdateService { private static AvailableUpdateData debugUpdateInfo; + @Override + public boolean isUpdateable() { + return false; //turn on to debug update prompts + } + @Override public void checkForUpdate(boolean useMetered, UpdateResultCallback callback) { @@ -37,18 +42,11 @@ public class DebugUpdates extends UpdateService { return; } - //turn on to test update UI - if (false){ - debugUpdateInfo = new AvailableUpdateData(); - debugUpdateInfo.versionCode = Game.versionCode+1; - debugUpdateInfo.URL = "http://www.google.com"; + debugUpdateInfo = new AvailableUpdateData(); + debugUpdateInfo.versionCode = Game.versionCode+1; + debugUpdateInfo.URL = "http://www.google.com"; - callback.onUpdateAvailable(debugUpdateInfo); - } else { - debugUpdateInfo = null; - - callback.onNoUpdateFound(); - } + callback.onUpdateAvailable(debugUpdateInfo); } @@ -57,4 +55,14 @@ public class DebugUpdates extends UpdateService { DeviceCompat.openURI( update.URL ); } + @Override + public boolean isInstallable() { + return false; //turn on to test install prompts + } + + @Override + public void initializeInstall() { + //does nothing + } + } diff --git a/services/updates/githubUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/GitHubUpdates.java b/services/updates/githubUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/GitHubUpdates.java index dfc5dedde..613e50709 100644 --- a/services/updates/githubUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/GitHubUpdates.java +++ b/services/updates/githubUpdates/src/main/java/com/shatteredpixel/shatteredpixeldungeon/services/updates/GitHubUpdates.java @@ -38,6 +38,11 @@ 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 boolean isUpdateable() { + return true; + } + @Override public void checkForUpdate(boolean useMetered, UpdateResultCallback callback) { @@ -120,4 +125,14 @@ public class GitHubUpdates extends UpdateService { DeviceCompat.openURI( update.URL ); } + @Override + public boolean isInstallable() { + return false; + } + + @Override + public void initializeInstall() { + //does nothing, always installed + } + }