- rosto-motor.js: emocoes como posicao de palpebra (cima, inclinacao, baixo) com transicao suave; respiracao, sacadas e piscada que achata o olho - rostos novos Carinha Viva, Bloco, Matriz (LEDs) e Lente (iris/pupila); os classicos continuam; emoji/figurinha nos olhos seguem no SVG - formato do olho (padrao, redondo, pilula, quadrado, largo) para Viva, Bloco e Matriz; salvo na aparencia e enviado como ordem "formato X" - toque na tela do S10: cutucar = susto e risada, deslizar = carinho, tocar dormindo acorda - painel: tela Rosto (celular em destaque, cartoes de rosto, formatos, cores, testar emocoes so na previa ou no celular, lista do que ja esta pronto); Ao vivo leva a ela; paleta ganha rostos e formatos - corrige /comando rosto que nao salvava a aparencia Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
3.5 KiB
Python
68 lines
3.5 KiB
Python
"""Build Windows/Linux usando JDK e Android SDK existentes; sem Gradle."""
|
|
import argparse
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
import zipfile
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
DEFAULT_TOOLS = os.environ.get('CARINHA_TOOLS', 'C:/Users/JullioPC/Documents/Open/orange-pi-zero3/android/tools')
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--tools', default=DEFAULT_TOOLS)
|
|
args = parser.parse_args()
|
|
tools = Path(args.tools)
|
|
suffix = '.exe' if os.name == 'nt' else ''
|
|
java = tools / 'jdk/bin' / ('java' + suffix)
|
|
javac = tools / 'jdk/bin' / ('javac' + suffix)
|
|
bt = tools / 'android-sdk/build-tools/34.0.0'
|
|
android = tools / 'android-sdk/platforms/android-34/android.jar'
|
|
for path in (java, javac, android, bt / ('aapt2' + suffix), HERE / 'keystore.jks'):
|
|
if not path.exists():
|
|
raise SystemExit('Arquivo necessário não encontrado: ' + str(path))
|
|
work = HERE.parents[2] / 'work'
|
|
work.mkdir(parents=True, exist_ok=True)
|
|
|
|
def run(*command):
|
|
subprocess.run([str(x) for x in command], check=True)
|
|
|
|
for name in ('carinha.html', 'camera.html', 'rosto-motor.js'):
|
|
shutil.copy2(HERE.parent / name, HERE / 'app/assets' / name)
|
|
with tempfile.TemporaryDirectory(prefix='carinha-build-', dir=work) as folder:
|
|
tmp = Path(folder)
|
|
for name in ('compiled', 'classes', 'gen'):
|
|
(tmp / name).mkdir()
|
|
print('Recursos e manifesto', flush=True)
|
|
run(bt / ('aapt2' + suffix), 'compile', '--dir', HERE / 'app/res', '-o', tmp / 'compiled/res.zip')
|
|
run(bt / ('aapt2' + suffix), 'link', '-o', tmp / 'base.apk', '-I', android,
|
|
'--manifest', HERE / 'app/AndroidManifest.xml', '-A', HERE / 'app/assets',
|
|
'--java', tmp / 'gen', '--min-sdk-version', '21', '--target-sdk-version', '34', tmp / 'compiled/res.zip')
|
|
sources = list((HERE / 'app/java').rglob('*.java')) + list((tmp / 'gen').rglob('*.java'))
|
|
print('Java e DEX', flush=True)
|
|
run(javac, '--release', '8', '-nowarn', '-classpath', android, '-d', tmp / 'classes', *sources)
|
|
classes = list((tmp / 'classes').rglob('*.class'))
|
|
run(java, '-cp', bt / 'lib/d8.jar', 'com.android.tools.r8.D8', '--lib', android,
|
|
'--min-api', '21', '--output', tmp, *classes)
|
|
with zipfile.ZipFile(tmp / 'base.apk', 'a', zipfile.ZIP_DEFLATED) as z:
|
|
z.write(tmp / 'classes.dex', 'classes.dex')
|
|
for native in (HERE / 'app/native/arm64-v8a').glob('*.so'):
|
|
z.write(native, 'lib/arm64-v8a/' + native.name)
|
|
run(bt / ('zipalign' + suffix), '-f', '-p', '4', tmp / 'base.apk', tmp / 'aligned.apk')
|
|
print('Assinatura persistente', flush=True)
|
|
run(java, '-jar', bt / 'lib/apksigner.jar', 'sign', '--ks', HERE / 'keystore.jks',
|
|
'--ks-pass', 'pass:android', '--key-pass', 'pass:android', '--ks-key-alias', 'carinha',
|
|
'--out', HERE / 'carinha-rosto.apk', tmp / 'aligned.apk')
|
|
run(java, '-jar', bt / 'lib/apksigner.jar', 'verify', HERE / 'carinha-rosto.apk')
|
|
with zipfile.ZipFile(HERE / 'carinha-rosto.apk') as z:
|
|
required = {'AndroidManifest.xml', 'classes.dex', 'resources.arsc', 'assets/carinha.html', 'assets/camera.html', 'assets/transmissao.html', 'assets/qualidade-auto.js'}
|
|
assert required.issubset(z.namelist()), 'APK incompleto'
|
|
print('APK pronto: ' + str(HERE / 'carinha-rosto.apk'))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|