Compare commits
10 commits
5d054e293d
...
aa1419e8bf
Author | SHA1 | Date | |
---|---|---|---|
aa1419e8bf | |||
deeff3bd2d | |||
3f60dc1850 | |||
911170325e | |||
f817f61876 | |||
a40f5f9eb6 | |||
8a945ef3a3 | |||
3a2f4c028a | |||
09444ce35a | |||
f694b3a607 |
8 changed files with 245 additions and 10 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -6,3 +6,7 @@
|
||||||
/app/bin
|
/app/bin
|
||||||
/app/bin/*
|
/app/bin/*
|
||||||
/app/app.apk
|
/app/app.apk
|
||||||
|
/app/android-sdk
|
||||||
|
/app/android-sdk/
|
||||||
|
/app/android-sdk/*
|
||||||
|
app/ToyKey.keystore
|
||||||
|
|
92
README.md
92
README.md
|
@ -1,3 +1,93 @@
|
||||||
# Android App
|
# Android App (build via docker/podman)
|
||||||
|
|
||||||
|
The goal of this repo, is to create a container that can serve to produce an "empty android Application" (i.e `app.apk` file).
|
||||||
|
As such the philosophy is to keep the process "simple" as to now make the understanding too difficult.
|
||||||
|
|
||||||
|
## usage
|
||||||
|
|
||||||
|
0. clone this repo
|
||||||
|
1. run
|
||||||
|
|
||||||
|
```
|
||||||
|
./build-android-app.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. follow the configuration
|
||||||
|
3. upon success the apk file created is in app/result/app.apk and can be installed via `adb`
|
||||||
|
```
|
||||||
|
adb install -r app/result/app.apk
|
||||||
|
```
|
||||||
|
|
||||||
|
## basic ideas
|
||||||
|
|
||||||
|
* work within container (debian based image)
|
||||||
|
* use Makefile as a build tool
|
||||||
|
|
||||||
|
## benefits of this (compared to AndroidStudio)
|
||||||
|
|
||||||
|
* no need to install rather bloated hell of software (i.e AndroidStudio) and all
|
||||||
|
* less hidding of internals (i.e Makefile allows to see how app.apk is made)
|
||||||
|
* small app.apk file
|
||||||
|
* oftentimes faster compile time (as compared with AndroidStudio Gradle builds)
|
||||||
|
* quick "webview" which can serve as starting point for people that can to PWA and websites
|
||||||
|
* Assisted initial configuration provides access to configure almost all types of [Android app permissions](app/.Makefile.scripts/make--app-config.sh#L127)
|
||||||
|
* no need to have Kotlin, Gradle setup
|
||||||
|
/
|
||||||
|
## basic info
|
||||||
|
|
||||||
|
This repo should allow to generate an empty "android app". by simply cloning this repo and
|
||||||
|
```
|
||||||
|
./build-android-app.sh
|
||||||
|
```
|
||||||
|
It does so via:
|
||||||
|
|
||||||
|
1. building a container (in any of the runtime/daemons it finds: i.e. docker,podman,etc..)
|
||||||
|
2. running this container having the `./app` folder being mounted within as `/app`
|
||||||
|
3. executing the [`app/Makefile`](app/Makefile) which will then:
|
||||||
|
4. either work with the configuration stored in an `app/app-config.sh` in case such file exists or
|
||||||
|
5. if not go through a `whiptail` text menu wizzard to configure a new empty app. (Makefile recipe: `./app-config.sh`)
|
||||||
|
6. it will then download the required android sdk files as necessary (Makefile recipe: `./android-sdk/installed`)
|
||||||
|
7. go through the further steps to setup the blank app.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## files and purpose
|
||||||
|
|
||||||
|
Upon `clone` of this repo the `app` folder is setup with these files:
|
||||||
|
```
|
||||||
|
# The (GNU) Makefile which...
|
||||||
|
app/Makefile
|
||||||
|
# ... has recipes that call scripts in folder....
|
||||||
|
app/.Makefile.scripts
|
||||||
|
# .. which creates an `app-config.sh`, a file to keep
|
||||||
|
# the configuration (app name,lable,api-levels,permissions etc)...
|
||||||
|
app/.Makefile.scripts/make--app-config.sh
|
||||||
|
# .. which creates an `AndroidManifest.xml`
|
||||||
|
app/.Makefile.scripts/make--AndroidManifest.xml
|
||||||
|
# .. which creates an `AppActivity.java` file (which just setup a Webview and loads `assets/index.html`)
|
||||||
|
app/.Makefile.scripts/make--AppActivity.java.sh
|
||||||
|
# .. which installs the necessary Android SDK in the correct versions
|
||||||
|
app/.Makefile.scripts/make--android-sdk.sh
|
||||||
|
app/assets
|
||||||
|
# the index.html file
|
||||||
|
app/assets/index.html
|
||||||
|
app/res
|
||||||
|
app/res/drawable
|
||||||
|
# the icon of the app
|
||||||
|
app/res/drawable/appicon.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
Upon further `./build-android-app.sh` execution more folders will appear
|
||||||
|
```
|
||||||
|
# a folder in which the Android-sdk stuff (installed via sdkmanager) is stored
|
||||||
|
android-sdk
|
||||||
|
# folders used during build...
|
||||||
|
# ... for temporary files
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
result/
|
||||||
|
# app configuration resulting from text whiptail menu
|
||||||
|
app-config.sh
|
||||||
|
# the Manifest file as resulted from data from app-config.sh
|
||||||
|
AndroidManifest.xml
|
||||||
|
```
|
||||||
|
|
|
@ -213,7 +213,7 @@ APP_PERMISSIONS="${APP_PERMISSIONS:-"$(whiptail --nocancel --notags --checklist
|
||||||
'android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE' 'BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE' 0 \
|
'android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE' 'BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE' 0 \
|
||||||
'android.permission.BIND_SCREENING_SERVICE' 'BIND_SCREENING_SERVICE - Must be required by a CallScreeningService, to ensure that only the system can bind to it.' 0 \
|
'android.permission.BIND_SCREENING_SERVICE' 'BIND_SCREENING_SERVICE - Must be required by a CallScreeningService, to ensure that only the system can bind to it.' 0 \
|
||||||
'android.permission.BIND_TELECOM_CONNECTION_SERVICE' 'BIND_TELECOM_CONNECTION_SERVICE - Must be required by a ConnectionService, to ensure that only the system can bind to it.' 0 \
|
'android.permission.BIND_TELECOM_CONNECTION_SERVICE' 'BIND_TELECOM_CONNECTION_SERVICE - Must be required by a ConnectionService, to ensure that only the system can bind to it.' 0 \
|
||||||
'android.permission.BIND_TEXT_SERVICE' 'BIND_TEXT_SERVICE - Must be required by a TextService (e.g. SpellCheckerService) to ensure that only the system can bind to it.' 0 \
|
'android.permission.BIND_TEXT_SERVICE' 'BIND_TEXT_SERVICE - Must be required by a TextService (e.g.SpellCheckerService) to ensure that only the system can bind to it.' 0 \
|
||||||
'android.permission.BIND_TRUST_AGENT' 'BIND_TRUST_AGENT' 0 \
|
'android.permission.BIND_TRUST_AGENT' 'BIND_TRUST_AGENT' 0 \
|
||||||
'android.permission.BIND_TV_INPUT' 'BIND_TV_INPUT - Must be required by a TvInputService to ensure that only the system can bind to it.' 0 \
|
'android.permission.BIND_TV_INPUT' 'BIND_TV_INPUT - Must be required by a TvInputService to ensure that only the system can bind to it.' 0 \
|
||||||
'android.permission.BIND_TV_INTERACTIVE_APP' 'BIND_TV_INTERACTIVE_APP - Must be required by a TvInteractiveAppService to ensure that only the system can bind to it.' 0 \
|
'android.permission.BIND_TV_INTERACTIVE_APP' 'BIND_TV_INTERACTIVE_APP - Must be required by a TvInteractiveAppService to ensure that only the system can bind to it.' 0 \
|
||||||
|
@ -411,7 +411,7 @@ APP_PERMISSIONS="${APP_PERMISSIONS:-"$(whiptail --nocancel --notags --checklist
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK' 'MANAGE_DEVICE_POLICY_MOBILE_NETWORK - Allows an application to set policy related to mobile networks.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK' 'MANAGE_DEVICE_POLICY_MOBILE_NETWORK - Allows an application to set policy related to mobile networks.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS' 'MANAGE_DEVICE_POLICY_MODIFY_USERS - Allows an application to manage policy preventing users from modifying users.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS' 'MANAGE_DEVICE_POLICY_MODIFY_USERS - Allows an application to manage policy preventing users from modifying users.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_MTE' 'MANAGE_DEVICE_POLICY_MTE - Allows an application to manage policy related to the Memory Tagging Extension (MTE).' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_MTE' 'MANAGE_DEVICE_POLICY_MTE - Allows an application to manage policy related to the Memory Tagging Extension (MTE).' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION' 'MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION - Allows an application to set policy related to nearby communications (e.g. Beam and nearby streaming).' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION' 'MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION - Allows an application to set policy related to nearby communications (e.g.Beam and nearby streaming).' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_NETWORK_LOGGING' 'MANAGE_DEVICE_POLICY_NETWORK_LOGGING - Allows an application to set policy related to network logging.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_NETWORK_LOGGING' 'MANAGE_DEVICE_POLICY_NETWORK_LOGGING - Allows an application to set policy related to network logging.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY' 'MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY - Allows an application to manage the identity of the managing organization.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY' 'MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY - Allows an application to manage the identity of the managing organization.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_OVERRIDE_APN' 'MANAGE_DEVICE_POLICY_OVERRIDE_APN - Allows an application to set policy related to override APNs.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_OVERRIDE_APN' 'MANAGE_DEVICE_POLICY_OVERRIDE_APN - Allows an application to set policy related to override APNs.' 0 \
|
||||||
|
@ -420,7 +420,7 @@ APP_PERMISSIONS="${APP_PERMISSIONS:-"$(whiptail --nocancel --notags --checklist
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_PRINTING' 'MANAGE_DEVICE_POLICY_PRINTING - Allows an application to set policy related to printing.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_PRINTING' 'MANAGE_DEVICE_POLICY_PRINTING - Allows an application to set policy related to printing.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_PRIVATE_DNS' 'MANAGE_DEVICE_POLICY_PRIVATE_DNS - Allows an application to set policy related to private DNS.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_PRIVATE_DNS' 'MANAGE_DEVICE_POLICY_PRIVATE_DNS - Allows an application to set policy related to private DNS.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_PROFILES' 'MANAGE_DEVICE_POLICY_PROFILES - Allows an application to set policy related to profiles.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_PROFILES' 'MANAGE_DEVICE_POLICY_PROFILES - Allows an application to set policy related to profiles.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION' 'MANAGE_DEVICE_POLICY_PROFILE_INTERACTION - Allows an application to set policy related to interacting with profiles (e.g. Disallowing cross-profile copy and paste).' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION' 'MANAGE_DEVICE_POLICY_PROFILE_INTERACTION - Allows an application to set policy related to interacting with profiles (e.g.Disallowing cross-profile copy and paste).' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_PROXY' 'MANAGE_DEVICE_POLICY_PROXY - Allows an application to set a network-independent global HTTP proxy.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_PROXY' 'MANAGE_DEVICE_POLICY_PROXY - Allows an application to set a network-independent global HTTP proxy.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES' 'MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES - Allows an application query system updates.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES' 'MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES - Allows an application query system updates.' 0 \
|
||||||
'android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD' 'MANAGE_DEVICE_POLICY_RESET_PASSWORD - Allows an application to force set a new device unlock password or a managed profile challenge on current user.' 0 \
|
'android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD' 'MANAGE_DEVICE_POLICY_RESET_PASSWORD - Allows an application to force set a new device unlock password or a managed profile challenge on current user.' 0 \
|
||||||
|
@ -633,7 +633,7 @@ APP_PERMISSIONS="${APP_PERMISSIONS:-"$(whiptail --nocancel --notags --checklist
|
||||||
'android.permission.TETHER_PRIVILEGED' 'TETHER_PRIVILEGED' 0 \
|
'android.permission.TETHER_PRIVILEGED' 'TETHER_PRIVILEGED' 0 \
|
||||||
'android.permission.TRANSMIT_IR' 'TRANSMIT_IR - Allows using the devices IR transmitter, if available.' 0 \
|
'android.permission.TRANSMIT_IR' 'TRANSMIT_IR - Allows using the devices IR transmitter, if available.' 0 \
|
||||||
'android.permission.TRUST_LISTENER' 'TRUST_LISTENER' 0 \
|
'android.permission.TRUST_LISTENER' 'TRUST_LISTENER' 0 \
|
||||||
'android.permission.TURN_SCREEN_ON' 'TURN_SCREEN_ON - Allows an app to turn on the screen on, e.g. with PowerManager.ACQUIRE_CAUSES_WAKEUP.' 0 \
|
'android.permission.TURN_SCREEN_ON' 'TURN_SCREEN_ON - Allows an app to turn on the screen on, e.g.with PowerManager.ACQUIRE_CAUSES_WAKEUP.' 0 \
|
||||||
'android.permission.TV_INPUT_HARDWARE' 'TV_INPUT_HARDWARE' 0 \
|
'android.permission.TV_INPUT_HARDWARE' 'TV_INPUT_HARDWARE' 0 \
|
||||||
'android.permission.TV_VIRTUAL_REMOTE_CONTROLLER' 'TV_VIRTUAL_REMOTE_CONTROLLER' 0 \
|
'android.permission.TV_VIRTUAL_REMOTE_CONTROLLER' 'TV_VIRTUAL_REMOTE_CONTROLLER' 0 \
|
||||||
'android.permission.UNINSTALL_SHORTCUT' 'UNINSTALL_SHORTCUT - ' 0 \
|
'android.permission.UNINSTALL_SHORTCUT' 'UNINSTALL_SHORTCUT - ' 0 \
|
||||||
|
|
22
app/AndroidManifest.xml
Normal file
22
app/AndroidManifest.xml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="app.persistence"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0">
|
||||||
|
<uses-sdk android:minSdkVersion="30"
|
||||||
|
android:targetSdkVersion="33"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS"/>
|
||||||
|
<application android:label="persistence" android:icon="@drawable/appicon">
|
||||||
|
<activity android:name="app.persistence.AppActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||||
|
android:label="persistence">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
7
app/app-config.sh
Normal file
7
app/app-config.sh
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
APP_NAME='persistence'
|
||||||
|
APP_PACKAGE='app.persistence'
|
||||||
|
APP_VERSION_SDK_TARGET='33'
|
||||||
|
APP_VERSION_SDK_MIN='30'
|
||||||
|
APP_PERMISSIONS='<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS"/>'
|
|
@ -4,7 +4,114 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta content="width=device-width,initial-scale=1.0" name="viewport">
|
<meta content="width=device-width,initial-scale=1.0" name="viewport">
|
||||||
</head>
|
</head>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function sleepit(ms) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(1);
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function divMessage(html){
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML=html;
|
||||||
|
document.body.appendChild(div);
|
||||||
|
div.scrollIntoView({ behavior: 'smooth'});
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function webviewprogram(){
|
||||||
|
var port;
|
||||||
|
var resolves = [];
|
||||||
|
function setupMessage(){
|
||||||
|
divMessage("starting SetupMessage()");
|
||||||
|
try{
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
window.addEventListener('message',(e)=>{
|
||||||
|
if(e.data=="init-from-java" && ! port){
|
||||||
|
divMessage('INIT');
|
||||||
|
port = e.ports[0];
|
||||||
|
port.onmessage = function (ee) {
|
||||||
|
divMessage('AAport.onmessage='+ee.data);
|
||||||
|
var response = JSON.parse(ee.data);
|
||||||
|
divMessage('response.resolveIndex'+response.resolveIndex);//AAport.onmessage='+ee.data);
|
||||||
|
var localresolve = resolves[response.resolveIndex];
|
||||||
|
divMessage(typeof localresolve)
|
||||||
|
|
||||||
|
localresolve(response);
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
divMessage('message='+e.data);
|
||||||
|
},true);
|
||||||
|
});
|
||||||
|
} catch(error){
|
||||||
|
divMessage('setuperror');
|
||||||
|
divMessage('setuperror='+error.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function doTest(){
|
||||||
|
divMessage('doTest');
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
divMessage('resolves.length'+resolves.length);
|
||||||
|
resolves.push(resolve);
|
||||||
|
divMessage('after push resolves.length'+resolves.length);
|
||||||
|
port.postMessage('{"function":"test","resolveIndex":"'+(resolves.length-1)+'"}');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// function doLs(path){
|
||||||
|
// divMessage('doLs');
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
// divMessage('resolves.length'+resolves.length);
|
||||||
|
// resolves.push(resolve);
|
||||||
|
// divMessage('after push resolves.length'+resolves.length);
|
||||||
|
// port.postMessage('{"function":"ls","path":"'+path+'","resolveIndex":"'+(resolves.length-1)+'"}');
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// function doCat(file){
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
// resolves.push(resolve);
|
||||||
|
// port.postMessage('{"function":"cat","resolveIndex":"'+resolves.length+'"}');
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
function doLoadedWait(){
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
window.addEventListener('load',()=>{
|
||||||
|
resolve();
|
||||||
|
},false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.addEventListener('load',()=>{
|
||||||
|
divMessage('JAVASCRIPT WORKS');
|
||||||
|
},false);
|
||||||
|
await doLoadedWait();
|
||||||
|
// await sleepit(2000);
|
||||||
|
// divMessage('awaited 2000');
|
||||||
|
// await sleepit(2000);
|
||||||
|
// divMessage('awaited again 2000');
|
||||||
|
// divMessage("before.setup 1");
|
||||||
|
divMessage('before.setup');
|
||||||
|
await setupMessage();
|
||||||
|
divMessage('setup');
|
||||||
|
async function mapDoTest(){
|
||||||
|
divMessage("doTest ");
|
||||||
|
var reply = await doTest();
|
||||||
|
divMessage("reply was",JSON.stringify(reply));
|
||||||
|
// divMessage("reply.result.length"+reply.result.length);
|
||||||
|
// reply.result.forEach((info)=>{
|
||||||
|
// divMessage(JSON.stringify(info));
|
||||||
|
// // divMessage(info.info);//reply.result.length"+reply.result.length);
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
await mapDoTest();
|
||||||
|
divMessage("done");
|
||||||
|
// for(let file of DCIM.result){
|
||||||
|
// divMessage("filename");
|
||||||
|
// });
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
<body>
|
<body>
|
||||||
<h1> SUPER</h1>
|
<input type=text />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -6,4 +6,7 @@
|
||||||
<path
|
<path
|
||||||
android:pathData="M95 50A45 45 0 0 1 5 50A45 45 0 0 1 95 50Z"
|
android:pathData="M95 50A45 45 0 0 1 5 50A45 45 0 0 1 95 50Z"
|
||||||
android:fillColor="#FF0000" />
|
android:fillColor="#FF0000" />
|
||||||
|
<path
|
||||||
|
android:pathData="M75 50A25 25 0 0 1 25 50A25 25 0 0 1 75 50Z"
|
||||||
|
android:fillColor="#FFFF00" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -36,8 +36,10 @@ DOCKERFILEEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
diff Dockerfile <(DockerfileContent) 2>/dev/null > /dev/null || {
|
diff Dockerfile <(DockerfileContent) 2>/dev/null > /dev/null || {
|
||||||
|
test -f Dockerfile && {
|
||||||
read -p 'reset/start Dockerfile[Y/n]' YES
|
read -p 'reset/start Dockerfile[Y/n]' YES
|
||||||
test "$YES" = "n" && { echo "aborting..." >&2; exit 1; }
|
test "$YES" = "n" && { echo "aborting..." >&2; exit 1; }
|
||||||
|
}
|
||||||
DockerfileContent > Dockerfile
|
DockerfileContent > Dockerfile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue