APK purge (#20446)
* purge begins * release files * remove those * no more android * only qt * text and spinner * neos update script * update sounds * update cpu usage * all done Co-authored-by: Comma Device <device@comma.ai>pull/20470/head
parent
49748d5dc1
commit
e76c80ffa1
30 changed files with 81 additions and 1059 deletions
@ -1,3 +0,0 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:34f8beca20214315be942f67aa3a6f2743174430da06b15706fbca610a9150b5 |
||||
size 13715186 |
@ -1,105 +0,0 @@ |
||||
import os |
||||
import subprocess |
||||
import glob |
||||
import hashlib |
||||
import shutil |
||||
from common.basedir import BASEDIR |
||||
from selfdrive.swaglog import cloudlog |
||||
|
||||
android_packages = ("ai.comma.plus.offroad",) |
||||
|
||||
def get_installed_apks(): |
||||
dat = subprocess.check_output(["pm", "list", "packages", "-f"], encoding='utf8').strip().split("\n") |
||||
ret = {} |
||||
for x in dat: |
||||
if x.startswith("package:"): |
||||
v, k = x.split("package:")[1].split("=") |
||||
ret[k] = v |
||||
return ret |
||||
|
||||
def install_apk(path): |
||||
# can only install from world readable path |
||||
install_path = "/sdcard/%s" % os.path.basename(path) |
||||
shutil.copyfile(path, install_path) |
||||
|
||||
ret = subprocess.call(["pm", "install", "-r", install_path]) |
||||
os.remove(install_path) |
||||
return ret == 0 |
||||
|
||||
def start_offroad(): |
||||
set_package_permissions() |
||||
system("am start -n ai.comma.plus.offroad/.MainActivity") |
||||
|
||||
def set_package_permissions(): |
||||
try: |
||||
output = subprocess.check_output(['dumpsys', 'package', 'ai.comma.plus.offroad'], encoding="utf-8") |
||||
given_permissions = output.split("runtime permissions")[1] |
||||
except Exception: |
||||
given_permissions = "" |
||||
|
||||
wanted_permissions = ["ACCESS_FINE_LOCATION", "READ_PHONE_STATE", "READ_EXTERNAL_STORAGE"] |
||||
for permission in wanted_permissions: |
||||
if permission not in given_permissions: |
||||
pm_grant("ai.comma.plus.offroad", "android.permission."+permission) |
||||
|
||||
appops_set("ai.comma.plus.offroad", "SU", "allow") |
||||
appops_set("ai.comma.plus.offroad", "WIFI_SCAN", "allow") |
||||
|
||||
def appops_set(package, op, mode): |
||||
system(f"LD_LIBRARY_PATH= appops set {package} {op} {mode}") |
||||
|
||||
def pm_grant(package, permission): |
||||
system(f"pm grant {package} {permission}") |
||||
|
||||
def system(cmd): |
||||
try: |
||||
cloudlog.info("running %s" % cmd) |
||||
subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) |
||||
except subprocess.CalledProcessError as e: |
||||
cloudlog.event("running failed", |
||||
cmd=e.cmd, |
||||
output=e.output[-1024:], |
||||
returncode=e.returncode) |
||||
|
||||
# *** external functions *** |
||||
|
||||
def update_apks(): |
||||
# install apks |
||||
installed = get_installed_apks() |
||||
|
||||
install_apks = glob.glob(os.path.join(BASEDIR, "apk/*.apk")) |
||||
for apk in install_apks: |
||||
app = os.path.basename(apk)[:-4] |
||||
if app not in installed: |
||||
installed[app] = None |
||||
|
||||
cloudlog.info("installed apks %s" % (str(installed), )) |
||||
|
||||
for app in installed.keys(): |
||||
apk_path = os.path.join(BASEDIR, "apk/"+app+".apk") |
||||
if not os.path.exists(apk_path): |
||||
continue |
||||
|
||||
h1 = hashlib.sha1(open(apk_path, 'rb').read()).hexdigest() |
||||
h2 = None |
||||
if installed[app] is not None: |
||||
h2 = hashlib.sha1(open(installed[app], 'rb').read()).hexdigest() |
||||
cloudlog.info("comparing version of %s %s vs %s" % (app, h1, h2)) |
||||
|
||||
if h2 is None or h1 != h2: |
||||
cloudlog.info("installing %s" % app) |
||||
|
||||
success = install_apk(apk_path) |
||||
if not success: |
||||
cloudlog.info("needing to uninstall %s" % app) |
||||
system("pm uninstall %s" % app) |
||||
success = install_apk(apk_path) |
||||
|
||||
assert success |
||||
|
||||
def pm_apply_packages(cmd): |
||||
for p in android_packages: |
||||
system("pm %s %s" % (cmd, p)) |
||||
|
||||
if __name__ == "__main__": |
||||
update_apks() |
@ -0,0 +1,4 @@ |
||||
#!/usr/bin/bash |
||||
|
||||
ROOT=$PWD/../../.. |
||||
$ROOT/installer/updater/updater "file://$ROOT/installer/updater/update.json" |
@ -1,125 +0,0 @@ |
||||
#include <math.h> |
||||
#include <stdlib.h> |
||||
#include <atomic> |
||||
#include "common/swaglog.h" |
||||
#include "common/timing.h" |
||||
|
||||
#include "android/sl_sound.hpp" |
||||
|
||||
#define LogOnError(func, msg) \ |
||||
if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); } |
||||
|
||||
#define ReturnOnError(func, msg) \ |
||||
if ((func) != SL_RESULT_SUCCESS) { LOGW(msg); return false; } |
||||
|
||||
struct SLSound::Player { |
||||
SLObjectItf player; |
||||
SLPlayItf playItf; |
||||
std::atomic<int> repeat; |
||||
}; |
||||
|
||||
SLSound::SLSound() { |
||||
if (!init()){ |
||||
throw std::runtime_error("Failed to initialize sound"); |
||||
} |
||||
} |
||||
|
||||
bool SLSound::init() { |
||||
SLEngineOption engineOptions[] = {{SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE}}; |
||||
const SLInterfaceID ids[1] = {SL_IID_VOLUME}; |
||||
const SLboolean req[1] = {SL_BOOLEAN_FALSE}; |
||||
SLEngineItf engineInterface = NULL; |
||||
ReturnOnError(slCreateEngine(&engine_, 1, engineOptions, 0, NULL, NULL), "Failed to create OpenSL engine"); |
||||
ReturnOnError((*engine_)->Realize(engine_, SL_BOOLEAN_FALSE), "Failed to realize OpenSL engine"); |
||||
ReturnOnError((*engine_)->GetInterface(engine_, SL_IID_ENGINE, &engineInterface), "Failed to get OpenSL engine interface"); |
||||
ReturnOnError((*engineInterface)->CreateOutputMix(engineInterface, &outputMix_, 1, ids, req), "Failed to create output mix"); |
||||
ReturnOnError((*outputMix_)->Realize(outputMix_, SL_BOOLEAN_FALSE), "Failed to realize output mix"); |
||||
|
||||
for (auto &kv : sound_map) { |
||||
SLDataLocator_URI locUri = {SL_DATALOCATOR_URI, (SLchar *)kv.second.first}; |
||||
SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; |
||||
SLDataSource audioSrc = {&locUri, &formatMime}; |
||||
SLDataLocator_OutputMix outMix = {SL_DATALOCATOR_OUTPUTMIX, outputMix_}; |
||||
SLDataSink audioSnk = {&outMix, NULL}; |
||||
|
||||
SLObjectItf player = NULL; |
||||
SLPlayItf playItf = NULL; |
||||
ReturnOnError((*engineInterface)->CreateAudioPlayer(engineInterface, &player, &audioSrc, &audioSnk, 0, NULL, NULL), "Failed to create audio player"); |
||||
ReturnOnError((*player)->Realize(player, SL_BOOLEAN_FALSE), "Failed to realize audio player"); |
||||
ReturnOnError((*player)->GetInterface(player, SL_IID_PLAY, &playItf), "Failed to get player interface"); |
||||
ReturnOnError((*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED), "Failed to initialize playstate to SL_PLAYSTATE_PAUSED"); |
||||
|
||||
player_[kv.first] = new SLSound::Player{player, playItf}; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event) { |
||||
SLSound::Player *s = reinterpret_cast<SLSound::Player *>(context); |
||||
if (event == SL_PLAYEVENT_HEADATEND && s->repeat != 0) { |
||||
if (s->repeat > 0) --s->repeat; |
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); |
||||
(*playItf)->SetMarkerPosition(playItf, 0); |
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); |
||||
} |
||||
} |
||||
|
||||
bool SLSound::play(AudibleAlert alert) { |
||||
if (currentSound_ != AudibleAlert::NONE) { |
||||
stop(); |
||||
} |
||||
|
||||
auto player = player_.at(alert); |
||||
SLPlayItf playItf = player->playItf; |
||||
|
||||
int loops = sound_map[alert].second; |
||||
player->repeat = loops > 0 ? loops - 1 : loops; |
||||
if (player->repeat != 0) { |
||||
ReturnOnError((*playItf)->RegisterCallback(playItf, slplay_callback, player), "Failed to register callback"); |
||||
ReturnOnError((*playItf)->SetCallbackEventsMask(playItf, SL_PLAYEVENT_HEADATEND), "Failed to set callback event mask"); |
||||
} |
||||
|
||||
// Reset the audio player
|
||||
ReturnOnError((*playItf)->ClearMarkerPosition(playItf), "Failed to clear marker position"); |
||||
uint32_t states[] = {SL_PLAYSTATE_PAUSED, SL_PLAYSTATE_STOPPED, SL_PLAYSTATE_PLAYING}; |
||||
for (auto state : states) { |
||||
ReturnOnError((*playItf)->SetPlayState(playItf, state), "Failed to set SL_PLAYSTATE_PLAYING"); |
||||
} |
||||
currentSound_ = alert; |
||||
return true; |
||||
} |
||||
|
||||
void SLSound::stop() { |
||||
if (currentSound_ != AudibleAlert::NONE) { |
||||
auto player = player_.at(currentSound_); |
||||
player->repeat = 0; |
||||
LogOnError((*(player->playItf))->SetPlayState(player->playItf, SL_PLAYSTATE_PAUSED), "Failed to set SL_PLAYSTATE_PAUSED"); |
||||
currentSound_ = AudibleAlert::NONE; |
||||
} |
||||
} |
||||
|
||||
void SLSound::setVolume(int volume) { |
||||
if (last_volume_ == volume) return; |
||||
|
||||
double current_time = nanos_since_boot(); |
||||
if ((current_time - last_set_volume_time_) > (5 * (1e+9))) { // 5s timeout on updating the volume
|
||||
char volume_change_cmd[64]; |
||||
snprintf(volume_change_cmd, sizeof(volume_change_cmd), "service call audio 3 i32 3 i32 %d i32 1 &", volume); |
||||
system(volume_change_cmd); |
||||
last_volume_ = volume; |
||||
last_set_volume_time_ = current_time; |
||||
} |
||||
} |
||||
|
||||
SLSound::~SLSound() { |
||||
for (auto &kv : player_) { |
||||
(*(kv.second->player))->Destroy(kv.second->player); |
||||
delete kv.second; |
||||
} |
||||
if (outputMix_) { |
||||
(*outputMix_)->Destroy(outputMix_); |
||||
} |
||||
if (engine_) { |
||||
(*engine_)->Destroy(engine_); |
||||
} |
||||
} |
@ -1,26 +0,0 @@ |
||||
#pragma once |
||||
#include <SLES/OpenSLES.h> |
||||
#include <SLES/OpenSLES_Android.h> |
||||
|
||||
#include "sound.hpp" |
||||
|
||||
|
||||
class SLSound : public Sound { |
||||
public: |
||||
SLSound(); |
||||
~SLSound(); |
||||
bool play(AudibleAlert alert); |
||||
void stop(); |
||||
void setVolume(int volume); |
||||
|
||||
private: |
||||
bool init(); |
||||
SLObjectItf engine_ = nullptr; |
||||
SLObjectItf outputMix_ = nullptr; |
||||
int last_volume_ = 0; |
||||
double last_set_volume_time_ = 0.; |
||||
AudibleAlert currentSound_ = AudibleAlert::NONE; |
||||
struct Player; |
||||
std::map<AudibleAlert, Player *> player_; |
||||
friend void SLAPIENTRY slplay_callback(SLPlayItf playItf, void *context, SLuint32 event); |
||||
}; |
@ -1,77 +0,0 @@ |
||||
CC = clang
|
||||
CXX = clang++
|
||||
|
||||
ROOT_DIR = ../../..
|
||||
PHONELIBS = $(ROOT_DIR)/phonelibs
|
||||
COMMON = $(ROOT)/selfdrive/common
|
||||
|
||||
WARN_FLAGS = -Werror=implicit-function-declaration \
|
||||
-Werror=incompatible-pointer-types \
|
||||
-Werror=int-conversion \
|
||||
-Werror=return-type \
|
||||
-Werror=format-extra-args
|
||||
|
||||
CFLAGS = -std=gnu11 -fPIC -O2 $(WARN_FLAGS)
|
||||
CXXFLAGS = -std=c++1z -fPIC -O2 $(WARN_FLAGS)
|
||||
|
||||
NANOVG_FLAGS = -I$(PHONELIBS)/nanovg
|
||||
|
||||
OPENGL_LIBS = -lGLESv3
|
||||
|
||||
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
|
||||
|
||||
OBJS = spinner.o \
|
||||
$(COMMON)/framebuffer.o \
|
||||
$(COMMON)/util.o \
|
||||
$(PHONELIBS)/nanovg/nanovg.o \
|
||||
$(COMMON)/spinner.o \
|
||||
opensans_semibold.o \
|
||||
img_spinner_track.o \
|
||||
img_spinner_comma.o
|
||||
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
.PHONY: all |
||||
all: spinner |
||||
|
||||
spinner: $(OBJS) |
||||
@echo "[ LINK ] $@"
|
||||
$(CXX) -fPIC -o '$@' $^ \
|
||||
-s \
|
||||
$(FRAMEBUFFER_LIBS) \
|
||||
-L/system/vendor/lib64 \
|
||||
$(OPENGL_LIBS) \
|
||||
-lm -llog
|
||||
|
||||
$(COMMON)/framebuffer.o: $(COMMON)/framebuffer.cc |
||||
@echo "[ CXX ] $@"
|
||||
$(CXX) $(CXXFLAGS) -MMD \
|
||||
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||
-I$(PHONELIBS)/android_system_core/include \
|
||||
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
opensans_semibold.o: $(ROOT_DIR)/selfdrive/assets/fonts/opensans_semibold.ttf |
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
img_spinner_track.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_track.png |
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
img_spinner_comma.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_comma.png |
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
%.o: %.c |
||||
@echo "[ CC ] $@"
|
||||
$(CC) $(CFLAGS) -MMD \
|
||||
-I../.. \
|
||||
$(NANOVG_FLAGS) \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
.PHONY: clean |
||||
clean: |
||||
rm -f spinner $(OBJS) $(DEPS)
|
||||
|
||||
-include $(DEPS) |
Binary file not shown.
@ -1,182 +0,0 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <stdbool.h> |
||||
#include <math.h> |
||||
#include <unistd.h> |
||||
#include <assert.h> |
||||
#include <ctype.h> |
||||
|
||||
#include <GLES3/gl3.h> |
||||
#include <EGL/egl.h> |
||||
#include <EGL/eglext.h> |
||||
|
||||
#include "nanovg.h" |
||||
#define NANOVG_GLES3_IMPLEMENTATION |
||||
#include "nanovg_gl.h" |
||||
#include "nanovg_gl_utils.h" |
||||
|
||||
#include "framebuffer.h" |
||||
#include "spinner.h" |
||||
|
||||
#define SPINTEXT_LENGTH 128 |
||||
|
||||
// external resources linked in
|
||||
extern const unsigned char _binary_opensans_semibold_ttf_start[]; |
||||
extern const unsigned char _binary_opensans_semibold_ttf_end[]; |
||||
|
||||
extern const unsigned char _binary_img_spinner_track_png_start[]; |
||||
extern const unsigned char _binary_img_spinner_track_png_end[]; |
||||
|
||||
extern const unsigned char _binary_img_spinner_comma_png_start[]; |
||||
extern const unsigned char _binary_img_spinner_comma_png_end[]; |
||||
|
||||
bool stdin_input_available() { |
||||
struct timeval timeout; |
||||
timeout.tv_sec = 0; |
||||
timeout.tv_usec = 0; |
||||
|
||||
fd_set fds; |
||||
FD_ZERO(&fds); |
||||
FD_SET(STDIN_FILENO, &fds); |
||||
select(STDIN_FILENO+1, &fds, NULL, NULL, &timeout); |
||||
return (FD_ISSET(0, &fds)); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
|
||||
bool draw_progress = false; |
||||
float progress_val = 0.0; |
||||
|
||||
char spintext[SPINTEXT_LENGTH]; |
||||
spintext[0] = 0; |
||||
|
||||
const char* spintext_arg = NULL; |
||||
if (argc >= 2) { |
||||
strncpy(spintext, argv[1], SPINTEXT_LENGTH); |
||||
} |
||||
|
||||
// spinner
|
||||
int fb_w, fb_h; |
||||
FramebufferState *fb = framebuffer_init("spinner", 0x00001000, false, |
||||
&fb_w, &fb_h); |
||||
assert(fb); |
||||
framebuffer_set_power(fb, HWC_POWER_MODE_NORMAL); |
||||
|
||||
NVGcontext *vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES); |
||||
assert(vg); |
||||
|
||||
int font = nvgCreateFontMem(vg, "Bold", (unsigned char*)_binary_opensans_semibold_ttf_start, _binary_opensans_semibold_ttf_end-_binary_opensans_semibold_ttf_start, 0); |
||||
assert(font >= 0); |
||||
|
||||
int spinner_img = nvgCreateImageMem(vg, 0, (unsigned char*)_binary_img_spinner_track_png_start, _binary_img_spinner_track_png_end - _binary_img_spinner_track_png_start); |
||||
assert(spinner_img >= 0); |
||||
int spinner_img_s = 360; |
||||
int spinner_img_x = ((fb_w/2)-(spinner_img_s/2)); |
||||
int spinner_img_y = 260; |
||||
int spinner_img_xc = (fb_w/2); |
||||
int spinner_img_yc = (fb_h/2)-100; |
||||
int spinner_comma_img = nvgCreateImageMem(vg, 0, (unsigned char*)_binary_img_spinner_comma_png_start, _binary_img_spinner_comma_png_end - _binary_img_spinner_comma_png_start); |
||||
assert(spinner_comma_img >= 0); |
||||
|
||||
for (int cnt = 0; ; cnt++) { |
||||
// Check stdin for new text
|
||||
if (stdin_input_available()){ |
||||
fgets(spintext, SPINTEXT_LENGTH, stdin); |
||||
spintext[strcspn(spintext, "\n")] = 0; |
||||
|
||||
// Check if number (update progress bar)
|
||||
size_t len = strlen(spintext); |
||||
bool is_number = len > 0; |
||||
for (int i = 0; i < len; i++){ |
||||
if (!isdigit(spintext[i])){ |
||||
is_number = false; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (is_number) { |
||||
progress_val = (float)(atoi(spintext)) / 100.0; |
||||
progress_val = fmin(1.0, progress_val); |
||||
progress_val = fmax(0.0, progress_val); |
||||
} |
||||
|
||||
draw_progress = is_number; |
||||
} |
||||
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0); |
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
||||
glEnable(GL_BLEND); |
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||
nvgBeginFrame(vg, fb_w, fb_h, 1.0f); |
||||
|
||||
// background
|
||||
nvgBeginPath(vg); |
||||
NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h, |
||||
nvgRGBA(0, 0, 0, 175), nvgRGBA(0, 0, 0, 255)); |
||||
nvgFillPaint(vg, bg); |
||||
nvgRect(vg, 0, 0, fb_w, fb_h); |
||||
nvgFill(vg); |
||||
|
||||
// spin track
|
||||
nvgSave(vg); |
||||
nvgTranslate(vg, spinner_img_xc, spinner_img_yc); |
||||
nvgRotate(vg, (3.75*M_PI * cnt/120.0)); |
||||
nvgTranslate(vg, -spinner_img_xc, -spinner_img_yc); |
||||
NVGpaint spinner_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y, |
||||
spinner_img_s, spinner_img_s, 0, spinner_img, 0.6f); |
||||
nvgBeginPath(vg); |
||||
nvgFillPaint(vg, spinner_imgPaint); |
||||
nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s); |
||||
nvgFill(vg); |
||||
nvgRestore(vg); |
||||
|
||||
// comma
|
||||
NVGpaint comma_imgPaint = nvgImagePattern(vg, spinner_img_x, spinner_img_y, |
||||
spinner_img_s, spinner_img_s, 0, spinner_comma_img, 1.0f); |
||||
nvgBeginPath(vg); |
||||
nvgFillPaint(vg, comma_imgPaint); |
||||
nvgRect(vg, spinner_img_x, spinner_img_y, spinner_img_s, spinner_img_s); |
||||
nvgFill(vg); |
||||
|
||||
if (draw_progress){ |
||||
// draw progress bar
|
||||
int progress_width = 1000; |
||||
int progress_x = fb_w/2-progress_width/2; |
||||
int progress_y = 775; |
||||
int progress_height = 25; |
||||
|
||||
NVGpaint paint = nvgBoxGradient( |
||||
vg, progress_x + 1, progress_y + 1, |
||||
progress_width - 2, progress_height, 3, 4, nvgRGB(27, 27, 27), nvgRGB(27, 27, 27)); |
||||
nvgBeginPath(vg); |
||||
nvgRoundedRect(vg, progress_x, progress_y, progress_width, progress_height, 12); |
||||
nvgFillPaint(vg, paint); |
||||
nvgFill(vg); |
||||
|
||||
int bar_pos = ((progress_width - 2) * progress_val); |
||||
|
||||
paint = nvgBoxGradient( |
||||
vg, progress_x, progress_y, |
||||
bar_pos+1.5f, progress_height-1, 3, 4, |
||||
nvgRGB(245, 245, 245), nvgRGB(105, 105, 105)); |
||||
|
||||
nvgBeginPath(vg); |
||||
nvgRoundedRect( |
||||
vg, progress_x+1, progress_y+1, |
||||
bar_pos, progress_height-2, 12); |
||||
nvgFillPaint(vg, paint); |
||||
nvgFill(vg); |
||||
} else { |
||||
// message
|
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_TOP); |
||||
nvgFontSize(vg, 96.0f); |
||||
nvgText(vg, fb_w/2, (fb_h*2/3)+24, spintext, NULL); |
||||
} |
||||
|
||||
nvgEndFrame(vg); |
||||
framebuffer_swap(fb); |
||||
assert(glGetError() == GL_NO_ERROR); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -1,64 +0,0 @@ |
||||
CC = clang
|
||||
CXX = clang++
|
||||
|
||||
PHONELIBS = ../../../../phonelibs
|
||||
COMMON = ../../../common
|
||||
|
||||
WARN_FLAGS = -Werror=implicit-function-declaration \
|
||||
-Werror=incompatible-pointer-types \
|
||||
-Werror=int-conversion \
|
||||
-Werror=return-type \
|
||||
-Werror=format-extra-args
|
||||
|
||||
CFLAGS = -std=gnu11 -fPIC -O2 $(WARN_FLAGS)
|
||||
CXXFLAGS = -std=c++1z -fPIC -O2 $(WARN_FLAGS)
|
||||
|
||||
NANOVG_FLAGS = -I$(PHONELIBS)/nanovg
|
||||
|
||||
OPENGL_LIBS = -lGLESv3
|
||||
|
||||
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
|
||||
|
||||
OBJS = text.o \
|
||||
$(COMMON)/framebuffer.o \
|
||||
$(COMMON)/util.o \
|
||||
$(COMMON)/touch.o \
|
||||
$(PHONELIBS)/nanovg/nanovg.o \
|
||||
opensans_regular.o \
|
||||
|
||||
DEPS := $(OBJS:.o=.d)
|
||||
|
||||
.PHONY: all |
||||
all: text |
||||
|
||||
text: $(OBJS) |
||||
@echo "[ LINK ] $@"
|
||||
$(CXX) -fPIC -o '$@' $^ \
|
||||
-s \
|
||||
$(FRAMEBUFFER_LIBS) \
|
||||
-L/system/vendor/lib64 \
|
||||
$(OPENGL_LIBS) \
|
||||
-lm -llog
|
||||
|
||||
opensans_regular.o: ../../../assets/fonts/opensans_regular.ttf |
||||
@echo "[ bin2o ] $@"
|
||||
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
|
||||
|
||||
%.o: %.cc |
||||
mkdir -p $(@D)
|
||||
@echo "[ CXX ] $@"
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) \
|
||||
-I../../../selfdrive \
|
||||
-I../../../ \
|
||||
-I$(PHONELIBS)/android_frameworks_native/include \
|
||||
-I$(PHONELIBS)/android_system_core/include \
|
||||
-I$(PHONELIBS)/android_hardware_libhardware/include \
|
||||
$(NANOVG_FLAGS) \
|
||||
-c -o '$@' '$<'
|
||||
|
||||
|
||||
.PHONY: clean |
||||
clean: |
||||
rm -f text $(OBJS) $(DEPS)
|
||||
|
||||
-include $(DEPS) |
Binary file not shown.
@ -1,133 +0,0 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <stdbool.h> |
||||
#include <math.h> |
||||
#include <unistd.h> |
||||
#include <assert.h> |
||||
#include <memory> |
||||
#include <GLES3/gl3.h> |
||||
#include <EGL/egl.h> |
||||
#include <EGL/eglext.h> |
||||
|
||||
#include "nanovg.h" |
||||
#define NANOVG_GLES3_IMPLEMENTATION |
||||
#include "nanovg_gl.h" |
||||
#include "nanovg_gl_utils.h" |
||||
|
||||
#include "common/framebuffer.h" |
||||
#include "common/touch.h" |
||||
|
||||
|
||||
#define COLOR_WHITE nvgRGBA(255, 255, 255, 255) |
||||
#define MAX_TEXT_SIZE 2048 |
||||
|
||||
extern const uint8_t bin_opensans_regular[] asm("_binary_opensans_regular_ttf_start"); |
||||
extern const uint8_t *bin_opensans_regular_end asm("_binary_opensans_regular_ttf_end"); |
||||
|
||||
|
||||
int main(int argc, char** argv) { |
||||
int err; |
||||
|
||||
// spinner
|
||||
int fb_w, fb_h; |
||||
std::unique_ptr<FrameBuffer> fb = std::make_unique<FrameBuffer>("text", 0x00001000, false, |
||||
&fb_w, &fb_h); |
||||
assert(fb); |
||||
|
||||
NVGcontext *vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES); |
||||
assert(vg); |
||||
|
||||
int font = nvgCreateFontMem(vg, "regular", (unsigned char*)bin_opensans_regular, (bin_opensans_regular_end - bin_opensans_regular), 0); |
||||
assert(font >= 0); |
||||
|
||||
// Awake
|
||||
fb->set_power(HWC_POWER_MODE_NORMAL); |
||||
set_brightness(255); |
||||
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0); |
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
||||
glEnable(GL_BLEND); |
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||
nvgBeginFrame(vg, fb_w, fb_h, 1.0f); |
||||
|
||||
// background
|
||||
nvgBeginPath(vg); |
||||
NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h, |
||||
nvgRGBA(0, 0, 0, 175), nvgRGBA(0, 0, 0, 255)); |
||||
nvgFillPaint(vg, bg); |
||||
nvgRect(vg, 0, 0, fb_w, fb_h); |
||||
nvgFill(vg); |
||||
|
||||
|
||||
// Text
|
||||
nvgFillColor(vg, COLOR_WHITE); |
||||
nvgFontSize(vg, 75.0f); |
||||
|
||||
if (argc >= 2) { |
||||
float x = 150; |
||||
float y = 150; |
||||
|
||||
// Copy text
|
||||
char * text = (char *)malloc(MAX_TEXT_SIZE); |
||||
strncpy(text, argv[1], MAX_TEXT_SIZE); |
||||
|
||||
float lineh; |
||||
nvgTextMetrics(vg, NULL, NULL, &lineh); |
||||
|
||||
// nvgTextBox strips leading whitespace. We have to reimplement
|
||||
char * next = strtok(text, "\n"); |
||||
while (next != NULL){ |
||||
nvgText(vg, x, y, next, NULL); |
||||
y += lineh; |
||||
next = strtok(NULL, "\n"); |
||||
} |
||||
} |
||||
|
||||
// Button
|
||||
int b_x = 1500; |
||||
int b_y = 800; |
||||
int b_w = 300; |
||||
int b_h = 150; |
||||
|
||||
nvgBeginPath(vg); |
||||
nvgFillColor(vg, nvgRGBA(8, 8, 8, 255)); |
||||
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); |
||||
nvgFill(vg); |
||||
|
||||
nvgFillColor(vg, nvgRGBA(255, 255, 255, 255)); |
||||
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); |
||||
nvgText(vg, b_x+b_w/2, b_y+b_h/2, "Exit", NULL); |
||||
|
||||
nvgBeginPath(vg); |
||||
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 50)); |
||||
nvgStrokeWidth(vg, 5); |
||||
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20); |
||||
nvgStroke(vg); |
||||
|
||||
// Draw to screen
|
||||
nvgEndFrame(vg); |
||||
fb->swap(); |
||||
assert(glGetError() == GL_NO_ERROR); |
||||
|
||||
|
||||
// Wait for button
|
||||
TouchState touch; |
||||
touch_init(&touch); |
||||
|
||||
while (true){ |
||||
int touch_x = -1, touch_y = -1; |
||||
int res = touch_poll(&touch, &touch_x, &touch_y, 0); |
||||
if (res){ |
||||
|
||||
if (touch_x > b_x && touch_x < b_x + b_w){ |
||||
if (touch_y > b_y && touch_y < b_y + b_h){ |
||||
return 1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
usleep(1000000 / 60); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -1,191 +0,0 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <math.h> |
||||
#include <sys/resource.h> |
||||
|
||||
#include <algorithm> |
||||
|
||||
#include "common/framebuffer.h" |
||||
#include "common/util.h" |
||||
#include "common/params.h" |
||||
#include "common/swaglog.h" |
||||
#include "common/touch.h" |
||||
#include "common/watchdog.h" |
||||
|
||||
#include "ui.hpp" |
||||
#include "paint.hpp" |
||||
#include "android/sl_sound.hpp" |
||||
|
||||
ExitHandler do_exit; |
||||
static void ui_set_brightness(UIState *s, int brightness) { |
||||
static int last_brightness = -1; |
||||
if (last_brightness != brightness && (s->awake || brightness == 0)) { |
||||
if (set_brightness(brightness)) { |
||||
last_brightness = brightness; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void handle_display_state(UIState *s, FrameBuffer *fb, bool user_input) { |
||||
static int awake_timeout = 0; |
||||
|
||||
constexpr float accel_samples = 5*UI_FREQ; |
||||
static float accel_prev = 0., gyro_prev = 0.; |
||||
|
||||
bool should_wake = s->scene.started || s->scene.ignition || user_input; |
||||
if (!should_wake) { |
||||
// tap detection while display is off
|
||||
bool accel_trigger = abs(s->scene.accel_sensor - accel_prev) > 0.2; |
||||
bool gyro_trigger = abs(s->scene.gyro_sensor - gyro_prev) > 0.15; |
||||
should_wake = accel_trigger && gyro_trigger; |
||||
gyro_prev = s->scene.gyro_sensor; |
||||
accel_prev = (accel_prev * (accel_samples - 1) + s->scene.accel_sensor) / accel_samples; |
||||
} |
||||
|
||||
// determine desired state
|
||||
if (should_wake) { |
||||
awake_timeout = 30*UI_FREQ; |
||||
} else if (awake_timeout > 0){ |
||||
--awake_timeout; |
||||
should_wake = true; |
||||
} |
||||
|
||||
// handle state transition
|
||||
if (s->awake != should_wake) { |
||||
s->awake = should_wake; |
||||
int display_mode = s->awake ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF; |
||||
LOGW("setting display mode %d", display_mode); |
||||
fb->set_power(display_mode); |
||||
|
||||
if (s->awake) { |
||||
system("service call window 18 i32 1"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void handle_vision_touch(UIState *s, int touch_x, int touch_y) { |
||||
if (s->scene.started && (touch_x >= s->viz_rect.x - bdr_s) |
||||
&& (s->active_app != cereal::UiLayoutState::App::SETTINGS)) { |
||||
if (!s->scene.driver_view) { |
||||
s->sidebar_collapsed = !s->sidebar_collapsed; |
||||
} else { |
||||
Params().write_db_value("IsDriverViewEnabled", "0", 1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void handle_sidebar_touch(UIState *s, int touch_x, int touch_y) { |
||||
if (!s->sidebar_collapsed && touch_x <= sbr_w) { |
||||
if (settings_btn.ptInRect(touch_x, touch_y)) { |
||||
s->active_app = cereal::UiLayoutState::App::SETTINGS; |
||||
} else if (home_btn.ptInRect(touch_x, touch_y)) { |
||||
if (s->scene.started) { |
||||
s->active_app = cereal::UiLayoutState::App::NONE; |
||||
s->sidebar_collapsed = true; |
||||
} else { |
||||
s->active_app = cereal::UiLayoutState::App::HOME; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void update_offroad_layout_state(UIState *s, PubMaster *pm) { |
||||
static int timeout = 0; |
||||
static bool prev_collapsed = false; |
||||
static cereal::UiLayoutState::App prev_app = cereal::UiLayoutState::App::NONE; |
||||
if (timeout > 0) { |
||||
timeout--; |
||||
} |
||||
if (prev_collapsed != s->sidebar_collapsed || prev_app != s->active_app || timeout == 0) { |
||||
MessageBuilder msg; |
||||
auto layout = msg.initEvent().initUiLayoutState(); |
||||
layout.setActiveApp(s->active_app); |
||||
layout.setSidebarCollapsed(s->sidebar_collapsed); |
||||
pm->send("offroadLayout", msg); |
||||
LOGD("setting active app to %d with sidebar %d", (int)s->active_app, s->sidebar_collapsed); |
||||
prev_collapsed = s->sidebar_collapsed; |
||||
prev_app = s->active_app; |
||||
timeout = 2 * UI_FREQ; |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char* argv[]) { |
||||
setpriority(PRIO_PROCESS, 0, -14); |
||||
|
||||
SLSound sound; |
||||
UIState uistate = {}; |
||||
UIState *s = &uistate; |
||||
FrameBuffer fb = FrameBuffer("ui", 0, true, &s->fb_w, &s->fb_h); |
||||
|
||||
ui_init(s); |
||||
s->sound = &sound; |
||||
|
||||
TouchState touch = {0}; |
||||
touch_init(&touch); |
||||
handle_display_state(s, &fb, true); |
||||
|
||||
PubMaster *pm = new PubMaster({"offroadLayout"}); |
||||
|
||||
// light sensor scaling and volume params
|
||||
float brightness_b = 0, brightness_m = 0; |
||||
int result = read_param(&brightness_b, "BRIGHTNESS_B", true); |
||||
result += read_param(&brightness_m, "BRIGHTNESS_M", true); |
||||
if (result != 0) { |
||||
brightness_b = 10.0; |
||||
brightness_m = 2.6; |
||||
write_param_float(brightness_b, "BRIGHTNESS_B", true); |
||||
write_param_float(brightness_m, "BRIGHTNESS_M", true); |
||||
} |
||||
float smooth_brightness = brightness_b; |
||||
|
||||
const int MIN_VOLUME = 12; |
||||
const int MAX_VOLUME = 15; |
||||
s->sound->setVolume(MIN_VOLUME); |
||||
|
||||
while (!do_exit) { |
||||
watchdog_kick(); |
||||
if (!s->scene.started) { |
||||
util::sleep_for(50); |
||||
} |
||||
double u1 = millis_since_boot(); |
||||
|
||||
ui_update(s); |
||||
|
||||
// poll for touch events
|
||||
int touch_x = -1, touch_y = -1; |
||||
int touched = touch_poll(&touch, &touch_x, &touch_y, 0); |
||||
if (touched == 1) { |
||||
handle_sidebar_touch(s, touch_x, touch_y); |
||||
handle_vision_touch(s, touch_x, touch_y); |
||||
} |
||||
|
||||
// Don't waste resources on drawing in case screen is off
|
||||
handle_display_state(s, &fb, touched == 1); |
||||
if (!s->awake) { |
||||
continue; |
||||
} |
||||
|
||||
// up one notch every 5 m/s
|
||||
s->sound->setVolume(fmin(MAX_VOLUME, MIN_VOLUME + s->scene.car_state.getVEgo() / 5)); |
||||
|
||||
// set brightness
|
||||
float clipped_brightness = fmin(512, (s->scene.light_sensor*brightness_m) + brightness_b); |
||||
smooth_brightness = fmin(255, clipped_brightness * 0.01 + smooth_brightness * 0.99); |
||||
ui_set_brightness(s, (int)smooth_brightness); |
||||
|
||||
update_offroad_layout_state(s, pm); |
||||
|
||||
ui_draw(s); |
||||
double u2 = millis_since_boot(); |
||||
if (!s->scene.driver_view && (u2-u1 > 66)) { |
||||
// warn on sub 15fps
|
||||
LOGW("slow frame(%llu) time: %.2f", (s->sm)->frame, u2-u1); |
||||
} |
||||
fb.swap(); |
||||
} |
||||
|
||||
handle_display_state(s, &fb, true); |
||||
delete s->sm; |
||||
delete pm; |
||||
return 0; |
||||
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue