Skip to content

[Obsolete] Add Android Export feature #545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions android-resources/config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="io.cordova.hellocordova" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

io.cordova.hellocordova ???

Would there be a problem installing two of these? Maybe the id would need to have the program hash in it to disambiguate? But I'm not sure, because I'm not sure what this is used for.

<name>CodeWorld App</name>
<description>
CodeWorld App
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be more descriptive, right? Maybe "This application is exported from CodeWorld." or something?

</description>
<author href="https://code.world">
CodeWorld
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe set this to "CodeWorld User" so it doesn't seem like we're claiming authorship of student programs?

</author>
<content src="index.html" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of all these allow-intent elements?

<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<platform name="android">
<allow-intent href="market:*" />
<icon density="mdpi" src="res/icon/android/mipmap-mdpi/codeworld.png" />
<icon density="hdpi" src="res/icon/android/mipmap-hdpi/codeworld.png" />
<icon density="xhdpi" src="res/icon/android/mipmap-xhdpi/codeworld.png" />
<icon density="xxhdpi" src="res/icon/android/mipmap-xxhdpi/codeworld.png" />
<icon density="xxxhdpi" src="res/icon/android/mipmap-xxxhdpi/codeworld.png" />
</platform>
<plugin name="cordova-plugin-whitelist" spec="^1.3.2" />
</widget>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
105 changes: 105 additions & 0 deletions android-resources/www/css/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
* {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a source header, which you can copy from other css files in the project (e.g., in web/css).

-webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
}

body {
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
background-color:#E4E4E4;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a gray background color or gradient anywhere in the app. Does any of this matter?

background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
background-image:-webkit-gradient(
linear,
left top,
left bottom,
color-stop(0, #A7A7A7),
color-stop(0.51, #E4E4E4)
);
background-attachment:fixed;
font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The text in exported apps appears to be a serif font, so I'll assume this doesn't matter either?

font-size:12px;
height:100%;
margin:0px;
padding:0px;
text-transform:uppercase;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, this doesn't seem to matter.

width:100%;
}

/* Portrait layout (default) */
.app {
position:absolute; /* position in the center of the screen */
left:50%;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this? What text box is it talking about?

top:30%;
height:50px; /* text area height */
width:225px; /* text area width */
text-align:center;
}

canvas {
position: relative;
left: -50%;
top: -50%;
}

.app-inner {
position: relative;
left: -50%;
top: -50%;
}

/* Landscape layout (with min-width) */
@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
.app {
background-position:left center;
padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
/* offset horizontal: half of image width and text area width */
}
}

h1 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This h1, .event, and .event.* also seem to refer to things that don't exist.

font-size:24px;
font-weight:normal;
margin:0px;
overflow:visible;
padding:0px;
text-align:center;
}

.event {
border-radius:4px;
-webkit-border-radius:4px;
color:#FFFFFF;
font-size:12px;
margin:0px 30px;
padding:2px 0px;
}

.event.listening {
background-color:#333333;
display:block;
}

.event.received {
background-color:#4B946A;
display:none;
}

@keyframes fade {
from { opacity: 1.0; }
50% { opacity: 0.4; }
to { opacity: 1.0; }
}

@-webkit-keyframes fade {
from { opacity: 1.0; }
50% { opacity: 0.4; }
to { opacity: 1.0; }
}

.blink {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blink? What's blinking?

animation:fade 3000ms infinite;
-webkit-animation:fade 3000ms infinite;
}
99 changes: 99 additions & 0 deletions android-resources/www/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=default,Array.prototype.find,Number.isFinite,Number.isInteger,console,console.log,document.head,performance.now"></script>
<head>
<title>CodeWorld</title>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the title matter? If so, it should probably be set to the app name. If it doesn't, take it out?

<style type="text/css">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed a lot of JavaScript and CSS is copied and pasted from other files. Is that because you can't package those other files into the Android apk? That would be a shame. If possible, let's try to use the same code rather than copy.

* { margin: 0; overflow: hidden }
#screen {
cursor: default;
width: 100vw;
height: 100vw;
max-height: 100vh;
max-width: 100vh;
}
</style>
</head>
<body style="text-align: center">
<canvas id="screen"></canvas>
</body>
<script type="text/javascript">
function addMessage(err, str) {
if (window.parent && window.parent.addToMessage) {
var message = window.parent.addToMessage(str);

if (err) {
var message = window.parent.document.getElementById('message');
message.classList.add('error');
}
} else {
console.log(str);
}
}

function showCanvas() {
if (!window.parent) {
return;
}

var runner = window.parent.document.getElementById('runner');
if (!runner) {
return;
}

runner.style.display = '';
runner.focus();
runner.contentWindow.focus();
}

function start() {
h$base_writeStdout = function(fd, fdo, buf, buf_offset, n, c) {
addMessage(false, h$decodeUtf8(buf, n, buf_offset));
c(n);
};
h$base_writeStderr = function(fd, fdo, buf, buf_offset, n, c) {
addMessage(false, h$decodeUtf8(buf, n, buf_offset));
c(n);
};
h$log = function() {
var s = '';
for(var i=0;i<arguments.length;i++) { s = s + arguments[i]; }
addMessage(false, s+'\n');
};
h$errorMsg = function(str) {
for(var i=1;i<arguments.length;i++) {
str = str.replace(/%s/, arguments[i]);
}
addMessage(true, '\n' + str);
};
h$base_stdout_fd.write = h$base_writeStdout;
h$base_stderr_fd.write = h$base_writeStderr;

h$run(h$mainZCZCMainzimain);
}

function reportRuntimeError(err, str) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dead code. There are no calls to reportRuntimeError any longer.

if (window.parent.addToMessage) {
var message = window.parent.addToMessage('\n' + str);

if (err) {
var message = window.parent.document.getElementById('message');
message.classList.add('error');
}
} else {
console.log(str);
}
}

var loadScript = document.createElement('script');
loadScript.setAttribute('type', 'text/javascript');
loadScript.setAttribute('src', 'js/runjs.js');
loadScript.onload = function() {
start();
};
document.head.appendChild(loadScript);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just write this instead of this whole block:

<script type="text/javascript" src="js/runjs.js" onload="start()"></script>

</script>

</html>


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray blank lines at the end.

9 changes: 9 additions & 0 deletions base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ export PATH=$BUILD/bin:$PATH
export LANG=${LANG:-C.UTF-8}
export PREFIX=$BUILD

export ANDROID_HOME=$BUILD/Android/Sdk
export PATH=$BUILD/Android/Sdk/tools:$PATH
export PATH=$BUILD/Android/Sdk/platform-tools:$PATH
export PATH=$BUILD/Android/Sdk/tools/bin:$PATH
export PATH=$BUILD/Android/Sdk/tools/lib:$PATH
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does lib really need to be in the path? That's weird.


export PATH=$BUILD/Cordova/node_modules/cordova/bin:$PATH

function run {
OLD_PWD=$PWD
cd $1
Expand All @@ -38,3 +46,4 @@ function run {
function cabal_install {
cabal install --force-reinstalls --global --prefix=$BUILD $@
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray blank line.

4 changes: 4 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ cwd=$(pwd)

source base.sh

# Create Cordova template
run ./android-template cordova build android

run . cabal update

# Install the codeworld-base and codeworld-api packages
Expand Down Expand Up @@ -53,3 +56,4 @@ run . cabal_install ./codeworld-server \

# Build the JavaScript client code for FunBlocks, the block-based UI.
run . cabal_install --ghcjs ./funblocks-client

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray blank line

3 changes: 3 additions & 0 deletions codeworld-server/codeworld-server.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Executable codeworld-server
base64-bytestring,
bytestring,
codeworld-compiler,
containers,
cryptonite,
data-default,
directory,
Expand All @@ -35,6 +36,8 @@ Executable codeworld-server
regex-tdfa,
snap-core,
snap-server,
strict,
tagsoup,
temporary,
text,
unix
Expand Down
83 changes: 83 additions & 0 deletions codeworld-server/src/AndroidExport.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{-# LANGUAGE OverloadedStrings #-}

{-
Copyright 2017 The CodeWorld Authors. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-}

module AndroidExport where

import Data.Maybe
import qualified Data.Map as M
import System.Process
import System.Directory
import System.FilePath
import qualified System.IO.Strict as ST
import Text.HTML.TagSoup

import Util

buildAndroid :: BuildMode -> ProgramId -> AppProps -> IO ()
buildAndroid mode programId appProps = do
let appName = fromJust $ M.lookup "appName" appProps
initCordovaProject mode programId
copySource mode programId
setAppName mode programId appName
buildApk mode programId
return ()

initCordovaProject :: BuildMode -> ProgramId -> IO ()
initCordovaProject mode programId = do
let rootDir = androidRootDir mode
checkIfRootExists <- doesDirectoryExist rootDir
if not checkIfRootExists
then do
createDirectory $ androidRootDir mode
else return ()
let buildDir = androidBuildDir mode programId
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to build in a temp dir. Otherwise you'll risk kicking off simultaneous builds pointed at the same directory, and this can confuse things and cause weird bug reports. It has happened before.

checkIfBuildExists <- doesDirectoryExist buildDir
if not checkIfBuildExists
then do
checkIfParentExists <- doesDirectoryExist $ androidRootDir mode </> sourceParent programId
if not checkIfParentExists
then do
createDirectory $ androidRootDir mode </> sourceParent programId
copyDirIfExists "android-template" (androidRootDir mode </> sourceBase programId)
else return ()
else return ()

copySource :: BuildMode -> ProgramId -> IO ()
copySource mode programId =
copyFile
(buildRootDir mode </> targetFile programId)
(androidBuildDir mode programId </> "www" </> "js" </> "runjs.js")

setAppName :: BuildMode -> ProgramId -> String -> IO ()
setAppName mode programId appName = do
let configFileName = androidBuildDir mode programId </> "config.xml"
configContents <- ST.readFile configFileName
let tagSoup = parseTags configContents
let newNameTag = [TagOpen "name" [], TagText appName]
writeFile configFileName (renderTags $ newSoup tagSoup newNameTag)
where newSoup soup insertTag = takeWhile nameId soup
++ insertTag
++ drop 2 (dropWhile nameId soup)
nameId = (~/= ("<name>"::String))

buildApk :: BuildMode -> ProgramId -> IO ()
buildApk mode programId = do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to set a time limit, and kill the process if it exceeds the time limit. There's a utility for that at https://github.com/google/codeworld/blob/master/codeworld-compiler/src/Compile.hs#L203, but unfortunately it was moved from codeworld-server to codeworld-compiler, as part of another Summer of Haskell project. For now, feel free to copy it back into codeworld-server/src/Util.hs

currwd <- getCurrentDirectory
setCurrentDirectory $ androidBuildDir mode programId
readProcess "cordova" ["build", "android"] ""
setCurrentDirectory currwd
Loading