├── Android.mk ├── README.md ├── device_defines.mk ├── kernel_cmdline ├── Android.mk └── kernel_cmdline.c ├── kernel_permissive_patcher ├── kernel_permissive.sh └── updater-script ├── kernel_permissive_selinuxaudit ├── kernel_selinuxaudit.sh └── updater-script ├── kernel_safetynet_verified ├── kernel_safetynet.sh └── updater-script ├── lib ├── Android.mk ├── animation.c ├── animation.h ├── atomics.h ├── button.c ├── button.h ├── colors.c ├── colors.h ├── containers.c ├── containers.h ├── framebuffer.c ├── framebuffer.h ├── framebuffer_generic.c ├── framebuffer_png.c ├── framebuffer_qcom_overlay.c ├── framebuffer_truetype.c ├── fstab.c ├── fstab.h ├── inject.c ├── inject.h ├── input.c ├── input.h ├── input_priv.h ├── input_type_a.c ├── input_type_b.c ├── keyboard.c ├── keyboard.h ├── listview.c ├── listview.h ├── log.h ├── mrom_data.c ├── mrom_data.h ├── notification_card.c ├── notification_card.h ├── progressdots.c ├── progressdots.h ├── tabview.c ├── tabview.h ├── touch_tracker.c ├── touch_tracker.h ├── util.c ├── util.h ├── velocity_tracker.c ├── workers.c └── workers.h ├── logo.png ├── release ├── kernel_permissive_patcher.zip ├── kernel_safetynet_verified.zip └── kernel_selinuxaudit_patcher.zip └── version.h /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | multirom_local_path := $(LOCAL_PATH) 3 | 4 | # Kernel CmdLine 5 | include $(multirom_local_path)/kernel_cmdline/Android.mk 6 | 7 | # libmultirom 8 | include $(multirom_local_path)/lib/Android.mk 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kernel Permissive Patcher for Android 2 | * [See the project on XDA](http://forum.xda-developers.com/-/-/-t3506338) 3 | 4 | ## Downloads 5 | * Kernel Permissive Patcher: [kernel_permissive_patcher.zip](release/kernel_permissive_patcher.zip) 6 | * Kernel Selinux Verbose Audit: [kernel_selinuxaudit_patcher.zip](release/kernel_selinuxaudit_patcher.zip) 7 | 8 | ## How the project works and what it does 9 | * Appends the permissive command to the kernel 10 | installed on the device without other changes 11 | 12 | * Detects the bootimage partition, detection 13 | based on the same logic from Chainfire 14 | 15 | * Reads the kernel header and contents with 16 | libbootimg used for our MultiROM projects 17 | 18 | * Appends if necessary the new permissive element 19 | and write the kernel back to the partition 20 | 21 | * Also compatible with the Sony ELF boot partitions 22 | by using my MultiROM version of the libbootimg 23 | -------------------------------------------------------------------------------- /device_defines.mk: -------------------------------------------------------------------------------- 1 | # Defines from device files 2 | # Init default define values 3 | MULTIROM_DEFAULT_ROTATION := 0 4 | 5 | # This value is used to have different folders on USB drives 6 | # for different devices. Grouper didn't have that, hence the hack 7 | LOCAL_CFLAGS += -DTARGET_DEVICE="\"$(TARGET_DEVICE)\"" 8 | ifeq ($(TARGET_DEVICE),grouper) 9 | LOCAL_CFLAGS += -DMR_MOVE_USB_DIR 10 | endif 11 | 12 | ifneq ($(TW_DEFAULT_ROTATION),) 13 | MULTIROM_DEFAULT_ROTATION := $(TW_DEFAULT_ROTATION) 14 | endif 15 | LOCAL_CFLAGS += -DMULTIROM_DEFAULT_ROTATION=$(MULTIROM_DEFAULT_ROTATION) 16 | 17 | # TWRP framebuffer flags 18 | ifeq ($(RECOVERY_GRAPHICS_USE_LINELENGTH), true) 19 | LOCAL_CFLAGS += -DRECOVERY_GRAPHICS_USE_LINELENGTH 20 | endif 21 | 22 | ifeq ($(MR_PIXEL_FORMAT),) 23 | MR_PIXEL_FORMAT := $(TARGET_RECOVERY_PIXEL_FORMAT) 24 | endif 25 | 26 | ifeq ($(MR_PIXEL_FORMAT),"RGBX_8888") 27 | LOCAL_CFLAGS += -DRECOVERY_RGBX 28 | else ifeq ($(MR_PIXEL_FORMAT),"RGBA_8888") 29 | LOCAL_CFLAGS += -DRECOVERY_RGBA 30 | else ifeq ($(MR_PIXEL_FORMAT),"BGRA_8888") 31 | LOCAL_CFLAGS += -DRECOVERY_BGRA 32 | else ifeq ($(MR_PIXEL_FORMAT),"RGB_565") 33 | LOCAL_CFLAGS += -DRECOVERY_RGB_565 34 | else ifeq ($(MR_PIXEL_FORMAT),"ABGR_8888") 35 | LOCAL_CFLAGS += -DRECOVERY_ABGR 36 | else 37 | $(info TARGET_RECOVERY_PIXEL_FORMAT or MR_PIXEL_FORMAT not set or have invalid value) 38 | endif 39 | 40 | ifeq ($(MR_DPI),) 41 | $(info MR_DPI not defined in device files) 42 | else ifeq ($(MR_DPI),hdpi) 43 | ifeq ($(MR_DPI_MUL),) 44 | MR_DPI_MUL := 1 45 | endif 46 | else ifeq ($(MR_DPI),xhdpi) 47 | ifeq ($(MR_DPI_MUL),) 48 | MR_DPI_MUL := 1.5 49 | endif 50 | else ifeq ($(MR_DPI),xxhdpi) 51 | ifeq ($(MR_DPI_MUL),) 52 | MR_DPI_MUL := 2.0 53 | endif 54 | endif 55 | 56 | ifeq ($(MR_DPI_FONT),) 57 | MR_DPI_FONT := 96 58 | endif 59 | 60 | LOCAL_CFLAGS += -DMR_DPI_FONT=$(MR_DPI_FONT) 61 | 62 | ifneq ($(MR_DPI_MUL),) 63 | LOCAL_CFLAGS += -DDPI_MUL=$(MR_DPI_MUL) 64 | else 65 | $(info MR_DPI_MUL not defined!) 66 | endif 67 | 68 | ifeq ($(MR_DISABLE_ALPHA),true) 69 | LOCAL_CFLAGS += -DMR_DISABLE_ALPHA 70 | endif 71 | 72 | ifneq ($(TW_BRIGHTNESS_PATH),) 73 | LOCAL_CFLAGS += -DTW_BRIGHTNESS_PATH=\"$(TW_BRIGHTNESS_PATH)\" 74 | endif 75 | 76 | ifneq ($(TW_SECONDARY_BRIGHTNESS_PATH),) 77 | LOCAL_CFLAGS += -DTW_SECONDARY_BRIGHTNESS_PATH=\"$(TW_SECONDARY_BRIGHTNESS_PATH)\" 78 | endif 79 | 80 | ifeq ($(TW_SCREEN_BLANK_ON_BOOT), true) 81 | LOCAL_CFLAGS += -DTW_SCREEN_BLANK_ON_BOOT 82 | endif 83 | 84 | ifneq ($(MR_DEFAULT_BRIGHTNESS),) 85 | LOCAL_CFLAGS += -DMULTIROM_DEFAULT_BRIGHTNESS=\"$(MR_DEFAULT_BRIGHTNESS)\" 86 | else 87 | LOCAL_CFLAGS += -DMULTIROM_DEFAULT_BRIGHTNESS=40 88 | endif 89 | 90 | ifneq ($(MR_INPUT_ROTATION),) 91 | LOCAL_CFLAGS += -DMR_INPUT_ROTATION=$(MR_INPUT_ROTATION) 92 | endif 93 | 94 | ifneq ($(MR_KEXEC_MEM_MIN),) 95 | LOCAL_CFLAGS += -DMR_KEXEC_MEM_MIN=\"$(MR_KEXEC_MEM_MIN)\" 96 | else 97 | $(info MR_KEXEC_MEM_MIN was not defined in device files!) 98 | endif 99 | 100 | ifeq ($(MR_KEXEC_DTB),true) 101 | LOCAL_CFLAGS += -DMR_KEXEC_DTB 102 | endif 103 | 104 | ifeq ($(MR_CONTINUOUS_FB_UPDATE),true) 105 | LOCAL_CFLAGS += -DMR_CONTINUOUS_FB_UPDATE 106 | endif 107 | 108 | LOCAL_CFLAGS += -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION) 109 | 110 | ifeq ($(MR_USE_MROM_FSTAB),true) 111 | LOCAL_CFLAGS += -DMR_USE_MROM_FSTAB 112 | endif 113 | 114 | ifeq ($(MR_ENCRYPTION),true) 115 | LOCAL_CFLAGS += -DMR_ENCRYPTION 116 | endif 117 | 118 | ifneq ($(MR_RD_ADDR),) 119 | LOCAL_CFLAGS += -DMR_RD_ADDR=$(MR_RD_ADDR) 120 | endif 121 | 122 | ifeq ($(MR_ALLOW_NKK71_NOKEXEC_WORKAROUND),true) 123 | LOCAL_CFLAGS += -DMR_ALLOW_NKK71_NOKEXEC_WORKAROUND 124 | endif 125 | -------------------------------------------------------------------------------- /kernel_cmdline/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_C_INCLUDES += \ 5 | $(multirom_local_path) \ 6 | $(multirom_local_path)/lib \ 7 | system/extras/libbootimg/include \ 8 | 9 | LOCAL_SRC_FILES:= \ 10 | kernel_cmdline.c \ 11 | 12 | LOCAL_MODULE := kernel_cmdline 13 | LOCAL_MODULE_TAGS := eng 14 | 15 | LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES 16 | LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities 17 | 18 | LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) 19 | LOCAL_STATIC_LIBRARIES := libcutils libc libmultirom_static libbootimg 20 | 21 | LOCAL_FORCE_STATIC_EXECUTABLE := true 22 | LOCAL_PACK_MODULE_RELOCATIONS := false 23 | 24 | include $(BUILD_EXECUTABLE) 25 | -------------------------------------------------------------------------------- /kernel_cmdline/kernel_cmdline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "../lib/log.h" 24 | #include "../lib/util.h" 25 | 26 | #include 27 | 28 | #define KERNEL_TMP "/tmp/kernel.new.tmp" 29 | 30 | int kernel_cmdline(const char *kernel_path, const char *cmd_append, char debug) 31 | { 32 | int res = -1; 33 | struct bootimg img; 34 | int cmd_append_size; 35 | int cmdline_size; 36 | char* cmdline_write; 37 | char* cmdline_write_tmp; 38 | 39 | if (libbootimg_init_load(&img, kernel_path, LIBBOOTIMG_LOAD_ALL) < 0) 40 | { 41 | ERROR("Could not open boot image (%s)!\n", kernel_path); 42 | return -1; 43 | } 44 | 45 | if (debug) 46 | { 47 | printf("kernel_cmdline: Original \"%s\"\n", img.hdr.cmdline); 48 | } 49 | 50 | if (strstr((char*)img.hdr.cmdline, cmd_append) == NULL) 51 | { 52 | cmd_append_size = strlen(cmd_append); 53 | cmdline_size = strlen((char*)img.hdr.cmdline); 54 | cmdline_write = memchr(img.hdr.cmdline, 0x00, BOOT_ARGS_SIZE); 55 | cmdline_write_tmp = memchr(img.hdr.cmdline, 0x0A, BOOT_ARGS_SIZE); 56 | 57 | if (cmdline_write_tmp != NULL && cmdline_write_tmp < cmdline_write) 58 | { 59 | cmdline_write = cmdline_write_tmp; 60 | } 61 | 62 | if (cmdline_write != (char*)img.hdr.cmdline) 63 | { 64 | *cmdline_write = ' '; 65 | ++cmdline_write; 66 | if (img.is_elf) 67 | { 68 | img.hdr_info->cmdline_size += 1; 69 | } 70 | } 71 | 72 | strcpy(cmdline_write, cmd_append); 73 | cmdline_write[cmd_append_size] = 0x00; 74 | if (img.is_elf) 75 | { 76 | img.hdr_info->cmdline_size += cmd_append_size; 77 | } 78 | 79 | if (debug) 80 | { 81 | printf("kernel_cmdline: Patched \"%s\"\n", img.hdr.cmdline); 82 | } 83 | 84 | if (libbootimg_write_img(&img, KERNEL_TMP) >= 0) 85 | { 86 | INFO("Writing boot.img updated with kernel\n"); 87 | if (copy_file(KERNEL_TMP, kernel_path) < 0) 88 | ERROR("Failed to copy %s to %s!\n", KERNEL_TMP, kernel_path); 89 | else 90 | res = 0; 91 | remove(KERNEL_TMP); 92 | } 93 | else 94 | { 95 | ERROR("Failed to libbootimg_write_img to %s!\n", KERNEL_TMP); 96 | } 97 | } 98 | else if (debug) 99 | { 100 | printf("kernel_cmdline: cmdline already patched\n"); 101 | } 102 | 103 | exit: 104 | libbootimg_destroy(&img); 105 | return res; 106 | } 107 | 108 | int main(int argc, char *argv[]) 109 | { 110 | int i, res; 111 | static char *const cmd[] = { "/init", NULL }; 112 | char *inject_path = NULL; 113 | char *cmd_append = NULL; 114 | char debug = 0; 115 | 116 | for (i = 1; i < argc; ++i) 117 | { 118 | if (strstartswith(argv[i], "--inject=")) 119 | { 120 | inject_path = argv[i] + strlen("--inject="); 121 | } 122 | else if (strstartswith(argv[i], "--cmd_append=")) 123 | { 124 | cmd_append = argv[i] + strlen("--cmd_append="); 125 | } 126 | else if (strstartswith(argv[i], "--debug")) 127 | { 128 | debug = 1; 129 | } 130 | } 131 | 132 | if (!inject_path || !cmd_append) 133 | { 134 | printf("kernel_cmdline usage:\n"); 135 | printf(" --inject=[path to bootimage to patch] needed\n"); 136 | printf(" --cmd_append=[cmdline string to append] needed\n"); 137 | printf(" --debug optional\n"); 138 | fflush(stdout); 139 | return 1; 140 | } 141 | 142 | mrom_set_log_tag("kernel_cmdline"); 143 | return kernel_cmdline(inject_path, cmd_append, debug); 144 | } 145 | -------------------------------------------------------------------------------- /kernel_permissive_patcher/kernel_permissive.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | 3 | # find_boot_image logic by Chainfire 4 | for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT Kernel kernel KERNEL boot BOOT lnx LNX; do 5 | BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION); 6 | if [ ! -z "$BOOTIMAGE" ]; then 7 | break; 8 | fi; 9 | done; 10 | 11 | # Bootimage not found 12 | if [ -z "$BOOTIMAGE" ]; then 13 | return -1; 14 | fi; 15 | 16 | # Inject the permissive cmdline 17 | chmod 755 /tmp/kernel_cmdline; 18 | /tmp/kernel_cmdline --inject="$BOOTIMAGE" --cmd_append="androidboot.selinux=permissive"; 19 | return $?; 20 | 21 | -------------------------------------------------------------------------------- /kernel_permissive_patcher/updater-script: -------------------------------------------------------------------------------- 1 | ui_print(" "); 2 | ui_print(" "); 3 | ui_print(" ================================"); 4 | ui_print(" | Universal Permissive Patcher |"); 5 | ui_print(" | Adrian DC - 2016 |"); 6 | ui_print(" ================================"); 7 | ui_print(" "); 8 | 9 | show_progress(1.000000, 0); 10 | ui_print(" - Extracting the script files..."); 11 | package_extract_dir("scripts", "/tmp/"); 12 | set_perm(0, 0, 0777, "/tmp/kernel_cmdline"); 13 | set_perm(0, 0, 0777, "/tmp/kernel_permissive.sh"); 14 | 15 | set_progress(0.330000); 16 | ui_print(" - Patching the kernel permissive..."); 17 | assert(run_program("/tmp/kernel_permissive.sh") == 0); 18 | 19 | set_progress(0.660000); 20 | ui_print(" - Cleaning temporary files..."); 21 | delete("/tmp/kernel_cmdline"); 22 | delete("/tmp/kernel_permissive.sh"); 23 | 24 | unmount("/system"); 25 | set_progress(1.000000); 26 | ui_print(" "); 27 | ui_print(" Patch completed!"); 28 | ui_print(" "); 29 | 30 | -------------------------------------------------------------------------------- /kernel_permissive_selinuxaudit/kernel_selinuxaudit.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | 3 | # find_boot_image logic by Chainfire 4 | for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT Kernel kernel KERNEL boot BOOT lnx LNX; do 5 | BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION); 6 | if [ ! -z "${BOOTIMAGE}" ]; then 7 | break; 8 | fi; 9 | done; 10 | 11 | # Bootimage not found 12 | if [ -z "${BOOTIMAGE}" ]; then 13 | return -1; 14 | fi; 15 | 16 | # Inject the permissive cmdline 17 | chmod 755 /tmp/kernel_cmdline; 18 | /tmp/kernel_cmdline --inject="${BOOTIMAGE}" --cmd_append='audit=1'; 19 | return 0; 20 | 21 | -------------------------------------------------------------------------------- /kernel_permissive_selinuxaudit/updater-script: -------------------------------------------------------------------------------- 1 | ui_print(" "); 2 | ui_print(" "); 3 | ui_print(" ==================================="); 4 | ui_print(" | Universal Selinux Audit Patcher |"); 5 | ui_print(" | Adrian DC - 2017 |"); 6 | ui_print(" ==================================="); 7 | ui_print(" "); 8 | 9 | show_progress(1.000000, 0); 10 | ui_print(" - Extracting the script files..."); 11 | package_extract_dir("scripts", "/tmp/"); 12 | set_perm(0, 0, 0777, "/tmp/kernel_cmdline"); 13 | set_perm(0, 0, 0777, "/tmp/kernel_selinuxaudit.sh"); 14 | 15 | set_progress(0.330000); 16 | ui_print(" - Patching the kernel selinux audit..."); 17 | assert(run_program("/tmp/kernel_selinuxaudit.sh") == 0); 18 | 19 | set_progress(0.660000); 20 | ui_print(" - Cleaning temporary files..."); 21 | delete("/tmp/kernel_cmdline"); 22 | delete("/tmp/kernel_selinuxaudit.sh"); 23 | 24 | unmount("/system"); 25 | set_progress(1.000000); 26 | ui_print(" "); 27 | ui_print(" Patch completed!"); 28 | ui_print(" "); 29 | 30 | -------------------------------------------------------------------------------- /kernel_safetynet_verified/kernel_safetynet.sh: -------------------------------------------------------------------------------- 1 | #!/sbin/sh 2 | 3 | # find_boot_image logic by Chainfire 4 | for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT Kernel kernel KERNEL boot BOOT lnx LNX; do 5 | BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION); 6 | if [ ! -z "$BOOTIMAGE" ]; then 7 | break; 8 | fi; 9 | done; 10 | 11 | # Bootimage not found 12 | if [ -z "$BOOTIMAGE" ]; then 13 | return -1; 14 | fi; 15 | 16 | # Inject the SafetyNet verified cmdline 17 | chmod 755 /tmp/kernel_cmdline; 18 | /tmp/kernel_cmdline --inject="$BOOTIMAGE" --cmd_append="androidboot.verifiedbootstate=green"; 19 | return $?; 20 | 21 | -------------------------------------------------------------------------------- /kernel_safetynet_verified/updater-script: -------------------------------------------------------------------------------- 1 | ui_print(" "); 2 | ui_print(" "); 3 | ui_print(" =============================="); 4 | ui_print(" | SafetyNet Verified Patcher |"); 5 | ui_print(" | Adrian DC - 2019 |"); 6 | ui_print(" =============================="); 7 | ui_print(" "); 8 | 9 | show_progress(1.000000, 0); 10 | ui_print(" - Extracting the script files..."); 11 | package_extract_dir("scripts", "/tmp/"); 12 | set_perm(0, 0, 0777, "/tmp/kernel_cmdline"); 13 | set_perm(0, 0, 0777, "/tmp/kernel_safetynet.sh"); 14 | 15 | set_progress(0.330000); 16 | ui_print(" - Patching the kernel SafetyNet..."); 17 | assert(run_program("/tmp/kernel_safetynet.sh") == 0); 18 | 19 | set_progress(0.660000); 20 | ui_print(" - Cleaning temporary files..."); 21 | delete("/tmp/kernel_cmdline"); 22 | delete("/tmp/kernel_safetynet.sh"); 23 | 24 | unmount("/system"); 25 | set_progress(1.000000); 26 | ui_print(" "); 27 | ui_print(" Patch completed!"); 28 | ui_print(" "); 29 | 30 | -------------------------------------------------------------------------------- /lib/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | 3 | common_SRC_FILES := \ 4 | animation.c \ 5 | button.c \ 6 | colors.c \ 7 | containers.c \ 8 | framebuffer.c \ 9 | framebuffer_generic.c \ 10 | framebuffer_png.c \ 11 | framebuffer_truetype.c \ 12 | fstab.c \ 13 | inject.c \ 14 | input.c \ 15 | listview.c \ 16 | keyboard.c \ 17 | mrom_data.c \ 18 | notification_card.c \ 19 | progressdots.c \ 20 | tabview.c \ 21 | touch_tracker.c \ 22 | util.c \ 23 | workers.c \ 24 | 25 | common_C_INCLUDES := $(multirom_local_path)/lib \ 26 | external/libpng \ 27 | external/zlib \ 28 | external/freetype/include \ 29 | system/extras/libbootimg/include \ 30 | 31 | # With these, GCC optimizes aggressively enough so full-screen alpha blending 32 | # is quick enough to be done in an animation 33 | common_C_FLAGS := -O3 -funsafe-math-optimizations 34 | 35 | ifeq ($(MR_INPUT_TYPE),) 36 | MR_INPUT_TYPE := type_b 37 | endif 38 | common_SRC_FILES += input_$(MR_INPUT_TYPE).c 39 | 40 | ifeq ($(MR_USE_QCOM_OVERLAY),true) 41 | common_C_FLAGS += -DMR_USE_QCOM_OVERLAY 42 | common_SRC_FILES += framebuffer_qcom_overlay.c 43 | ifneq ($(MR_QCOM_OVERLAY_HEADER),) 44 | common_C_FLAGS += -DMR_QCOM_OVERLAY_HEADER=\"../../../../$(MR_QCOM_OVERLAY_HEADER)\" 45 | else 46 | $(error MR_USE_QCOM_OVERLAY is true but MR_QCOM_OVERLAY_HEADER was not specified!) 47 | endif 48 | ifneq ($(MR_QCOM_OVERLAY_CUSTOM_PIXEL_FORMAT),) 49 | common_C_FLAGS += -DMR_QCOM_OVERLAY_CUSTOM_PIXEL_FORMAT=$(MR_QCOM_OVERLAY_CUSTOM_PIXEL_FORMAT) 50 | endif 51 | ifeq ($(MR_QCOM_OVERLAY_USE_VSYNC),true) 52 | common_C_FLAGS += -DMR_QCOM_OVERLAY_USE_VSYNC 53 | endif 54 | endif 55 | 56 | 57 | 58 | include $(CLEAR_VARS) 59 | 60 | LOCAL_MODULE := libmultirom_static 61 | LOCAL_MODULE_TAGS := eng 62 | LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) 63 | LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) 64 | LOCAL_CFLAGS += $(common_C_FLAGS) 65 | LOCAL_C_INCLUDES += $(common_C_INCLUDES) 66 | LOCAL_SRC_FILES := $(common_SRC_FILES) 67 | 68 | include $(multirom_local_path)/device_defines.mk 69 | 70 | include $(BUILD_STATIC_LIBRARY) 71 | 72 | 73 | 74 | include $(CLEAR_VARS) 75 | 76 | LOCAL_MODULE := libmultirom 77 | LOCAL_MODULE_TAGS := eng 78 | LOCAL_SHARED_LIBRARIES := libcutils libc libm libpng libz libft2 79 | LOCAL_STATIC_LIBRARIES := libbootimg 80 | LOCAL_CFLAGS += $(common_C_FLAGS) 81 | LOCAL_SRC_FILES := $(common_SRC_FILES) 82 | LOCAL_C_INCLUDES += $(common_C_INCLUDES) 83 | 84 | include $(multirom_local_path)/device_defines.mk 85 | 86 | include $(BUILD_SHARED_LIBRARY) 87 | 88 | 89 | 90 | # We need static libtruetype but it isn't in standard android makefile :( 91 | LOCAL_PATH := external/freetype/ 92 | include $(CLEAR_VARS) 93 | 94 | # compile in ARM mode, since the glyph loader/renderer is a hotspot 95 | # when loading complex pages in the browser 96 | # 97 | LOCAL_ARM_MODE := arm 98 | 99 | LOCAL_SRC_FILES := \ 100 | src/base/ftbbox.c \ 101 | src/base/ftbitmap.c \ 102 | src/base/ftfstype.c \ 103 | src/base/ftglyph.c \ 104 | src/base/ftlcdfil.c \ 105 | src/base/ftstroke.c \ 106 | src/base/fttype1.c \ 107 | src/base/ftbase.c \ 108 | src/base/ftsystem.c \ 109 | src/base/ftinit.c \ 110 | src/base/ftgasp.c \ 111 | src/raster/raster.c \ 112 | src/sfnt/sfnt.c \ 113 | src/smooth/smooth.c \ 114 | src/autofit/autofit.c \ 115 | src/truetype/truetype.c \ 116 | src/cff/cff.c \ 117 | src/psnames/psnames.c \ 118 | src/pshinter/pshinter.c 119 | 120 | ifeq ($(shell if [ -e "$(ANDROID_BUILD_TOP)/external/freetype/src/gzip/ftgzip.c" ]; then echo "hasgzip"; fi),hasgzip) 121 | LOCAL_SRC_FILES += src/gzip/ftgzip.c 122 | endif 123 | 124 | ifeq ($(shell if [ -e "$(ANDROID_BUILD_TOP)/external/freetype/src/base/ftxf86.c" ]; then echo "found"; fi),found) 125 | LOCAL_SRC_FILES += src/base/ftxf86.c 126 | else 127 | LOCAL_SRC_FILES += \ 128 | src/base/ftfntfmt.c \ 129 | src/base/ftmm.c 130 | endif 131 | 132 | LOCAL_C_INCLUDES += \ 133 | $(LOCAL_PATH)/builds \ 134 | $(LOCAL_PATH)/include \ 135 | external/libpng \ 136 | external/zlib 137 | 138 | LOCAL_CFLAGS += -W -Wall 139 | LOCAL_CFLAGS += -fPIC -DPIC 140 | LOCAL_CFLAGS += "-DDARWIN_NO_CARBON" 141 | LOCAL_CFLAGS += "-DFT2_BUILD_LIBRARY" 142 | 143 | LOCAL_STATIC_LIBRARIES += libpng libz 144 | 145 | # the following is for testing only, and should not be used in final builds 146 | # of the product 147 | #LOCAL_CFLAGS += "-DTT_CONFIG_OPTION_BYTECODE_INTERPRETER" 148 | 149 | LOCAL_CFLAGS += -O2 150 | 151 | LOCAL_MODULE:= libft2_mrom_static 152 | include $(BUILD_STATIC_LIBRARY) 153 | -------------------------------------------------------------------------------- /lib/animation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "log.h" 24 | #include "workers.h" 25 | #include "animation.h" 26 | #include "util.h" 27 | #include "framebuffer.h" 28 | #include "containers.h" 29 | 30 | struct anim_list_it 31 | { 32 | int anim_type; 33 | anim_header *anim; 34 | 35 | struct anim_list_it *prev; 36 | struct anim_list_it *next; 37 | }; 38 | 39 | struct anim_list 40 | { 41 | struct anim_list_it *first; 42 | struct anim_list_it *last; 43 | 44 | struct anim_list_it **inactive_ctx; 45 | 46 | int running; 47 | float duration_coef; 48 | volatile int in_update_loop; 49 | pthread_mutex_t mutex; 50 | }; 51 | 52 | static struct anim_list_it EMPTY_CONTEXT; 53 | 54 | static struct anim_list anim_list = { 55 | .first = NULL, 56 | .last = NULL, 57 | .inactive_ctx = NULL, 58 | .running = 0, 59 | .duration_coef = 1.f, 60 | .in_update_loop = 0, 61 | .mutex = PTHREAD_MUTEX_INITIALIZER, 62 | }; 63 | 64 | static void anim_list_append(struct anim_list_it *it) 65 | { 66 | pthread_mutex_lock(&anim_list.mutex); 67 | if(!anim_list.first) 68 | { 69 | anim_list.first = anim_list.last = it; 70 | pthread_mutex_unlock(&anim_list.mutex); 71 | return; 72 | } 73 | 74 | it->prev = anim_list.last; 75 | anim_list.last->next = it; 76 | anim_list.last = it; 77 | pthread_mutex_unlock(&anim_list.mutex); 78 | } 79 | 80 | // anim_list.mutex must be locked 81 | static void anim_list_rm(struct anim_list_it *it) 82 | { 83 | if(it->prev) 84 | it->prev->next = it->next; 85 | else 86 | anim_list.first = it->next; 87 | 88 | if(it->next) 89 | it->next->prev = it->prev; 90 | else 91 | anim_list.last = it->prev; 92 | } 93 | 94 | // anim_list.mutex must be locked 95 | static void anim_list_clear(void) 96 | { 97 | struct anim_list_it *it, *next; 98 | for(next = anim_list.first; next; ) 99 | { 100 | it = next; 101 | next = next->next; 102 | 103 | free(it->anim); 104 | free(it); 105 | } 106 | anim_list.first = anim_list.last = NULL; 107 | } 108 | 109 | #define OVERSHOOT_TENSION 2.f 110 | static float anim_interpolate(int type, float input) 111 | { 112 | switch(type) 113 | { 114 | default: 115 | case INTERPOLATOR_LINEAR: 116 | return input; 117 | case INTERPOLATOR_DECELERATE: 118 | return (1.f - (1.f - input) * (1.f - input)); 119 | case INTERPOLATOR_ACCELERATE: 120 | return input * input; 121 | case INTERPOLATOR_OVERSHOOT: 122 | input -= 1.f; 123 | return (input * input * ((OVERSHOOT_TENSION+1.f) * input + OVERSHOOT_TENSION) + 1.f); 124 | case INTERPOLATOR_ACCEL_DECEL: 125 | return (float)(cos((input + 1) * M_PI) / 2.0f) + 0.5f; 126 | } 127 | } 128 | 129 | static inline void anim_int_step(int *prop, int *start, int *last, int *target, float interpolated) 130 | { 131 | if(*target != -1) 132 | { 133 | const int diff = *prop - *last; 134 | *start += diff; 135 | *prop = *start + (int)((*target) * interpolated); 136 | *last = *prop; 137 | } 138 | } 139 | 140 | static inline int item_anim_is_on_screen(item_anim *anim) 141 | { 142 | fb_item_header *it = anim->item; 143 | return it->x + it->w > 0 && it->x < (int)fb_width && 144 | it->y + it->h > 0 && it->y < (int)fb_height; 145 | } 146 | 147 | static void item_anim_step(item_anim *anim, float interpolated, int *need_draw) 148 | { 149 | int outside = !item_anim_is_on_screen(anim); 150 | 151 | fb_item_header *fb_it = anim->item; 152 | anim_int_step(&fb_it->x, &anim->start[0], &anim->last[0], &anim->targetX, interpolated); 153 | anim_int_step(&fb_it->y, &anim->start[1], &anim->last[1], &anim->targetY, interpolated); 154 | anim_int_step(&fb_it->w, &anim->start[2], &anim->last[2], &anim->targetW, interpolated); 155 | anim_int_step(&fb_it->h, &anim->start[3], &anim->last[3], &anim->targetH, interpolated); 156 | 157 | if(!(*need_draw) && (!outside || item_anim_is_on_screen(anim))) 158 | *need_draw = 1; 159 | } 160 | 161 | static void item_anim_on_start(item_anim *anim) 162 | { 163 | fb_item_header *fb_it = anim->item; 164 | anim->start[0] = anim->last[0] = fb_it->x; 165 | anim->start[1] = anim->last[1] = fb_it->y; 166 | anim->start[2] = anim->last[2] = fb_it->w; 167 | anim->start[3] = anim->last[3] = fb_it->h; 168 | 169 | if(anim->targetX != -1) 170 | anim->targetX -= fb_it->x; 171 | if(anim->targetY != -1) 172 | anim->targetY -= fb_it->y; 173 | if(anim->targetW != -1) 174 | anim->targetW -= fb_it->w; 175 | if(anim->targetH != -1) 176 | anim->targetH -= fb_it->h; 177 | } 178 | 179 | static void item_anim_on_finished(item_anim *anim) 180 | { 181 | if(anim->destroy_item_when_finished) 182 | fb_remove_item(anim->item); 183 | } 184 | 185 | static void call_anim_step(call_anim *anim, float interpolated) 186 | { 187 | if(anim->callback) 188 | anim->callback(anim->data, interpolated); 189 | } 190 | 191 | static int anim_update(uint32_t diff, void *data) 192 | { 193 | struct anim_list *list = data; 194 | struct anim_list_it *it; 195 | anim_header *anim; 196 | float normalized, interpolated; 197 | int need_draw = 0; 198 | 199 | pthread_mutex_lock(&list->mutex); 200 | list->in_update_loop = 1; 201 | 202 | for(it = list->first; it; ) 203 | { 204 | anim = it->anim; 205 | 206 | // Handle offset 207 | if(anim->start_offset) 208 | { 209 | if(anim->start_offset > diff) 210 | anim->start_offset -= diff; 211 | else 212 | anim->start_offset = 0; 213 | it = it->next; 214 | continue; 215 | } 216 | 217 | // calculate interpolation 218 | anim->elapsed += diff; 219 | if(anim->elapsed >= anim->duration) 220 | normalized = 1.f; 221 | else 222 | normalized = ((float)anim->elapsed)/anim->duration; 223 | 224 | interpolated = anim_interpolate(anim->interpolator, normalized); 225 | 226 | // Handle animation step 227 | switch(it->anim_type) 228 | { 229 | case ANIM_TYPE_ITEM: 230 | item_anim_step((item_anim*)anim, interpolated, &need_draw); 231 | break; 232 | case ANIM_TYPE_CALLBACK: 233 | call_anim_step((call_anim*)anim, interpolated); 234 | break; 235 | } 236 | 237 | if(anim->on_step_call) 238 | { 239 | pthread_mutex_unlock(&list->mutex); 240 | anim->on_step_call(anim->on_step_data, interpolated); 241 | pthread_mutex_lock(&list->mutex); 242 | } 243 | 244 | // remove complete animations 245 | if(anim->elapsed >= anim->duration) 246 | { 247 | if(anim->on_finished_call) 248 | { 249 | pthread_mutex_unlock(&list->mutex); 250 | anim->on_finished_call(anim->on_finished_data); 251 | pthread_mutex_lock(&list->mutex); 252 | } 253 | 254 | switch(it->anim_type) 255 | { 256 | case ANIM_TYPE_ITEM: 257 | pthread_mutex_unlock(&list->mutex); 258 | item_anim_on_finished((item_anim*)anim); 259 | pthread_mutex_lock(&list->mutex); 260 | break; 261 | } 262 | 263 | struct anim_list_it *to_remove = it; 264 | it = it->next; 265 | anim_list_rm(to_remove); 266 | free(to_remove->anim); 267 | free(to_remove); 268 | } 269 | else 270 | it = it->next; 271 | } 272 | 273 | if(need_draw) 274 | fb_request_draw(); 275 | 276 | list->in_update_loop = 0; 277 | pthread_mutex_unlock(&list->mutex); 278 | 279 | return 0; 280 | } 281 | 282 | static uint32_t anim_generate_id(void) 283 | { 284 | static uint32_t id = 0; 285 | uint32_t res = id++; 286 | if(res == ANIM_INVALID_ID) 287 | res = id++; 288 | return res; 289 | } 290 | 291 | void anim_init(float duration_coef) 292 | { 293 | if(anim_list.running) 294 | return; 295 | 296 | anim_list.running = 1; 297 | anim_list.duration_coef = duration_coef; 298 | workers_add(&anim_update, &anim_list); 299 | } 300 | 301 | void anim_stop(int wait_for_finished) 302 | { 303 | if(!anim_list.running) 304 | return; 305 | 306 | anim_list.running = 0; 307 | while(wait_for_finished) 308 | { 309 | pthread_mutex_lock(&anim_list.mutex); 310 | if(!anim_list.first) 311 | { 312 | pthread_mutex_unlock(&anim_list.mutex); 313 | break; 314 | } 315 | pthread_mutex_unlock(&anim_list.mutex); 316 | usleep(10000); 317 | } 318 | 319 | workers_remove(&anim_update, &anim_list); 320 | 321 | pthread_mutex_lock(&anim_list.mutex); 322 | anim_list_clear(); 323 | pthread_mutex_unlock(&anim_list.mutex); 324 | } 325 | 326 | void anim_cancel(uint32_t id, int only_not_started) 327 | { 328 | if(!anim_list.running) 329 | return; 330 | 331 | struct anim_list_it *it; 332 | 333 | pthread_mutex_lock(&anim_list.mutex); 334 | for(it = anim_list.first; it; ) 335 | { 336 | if(it->anim->id == id && (!only_not_started || it->anim->start_offset == 0)) 337 | { 338 | anim_list_rm(it); 339 | free(it->anim); 340 | free(it); 341 | break; 342 | } 343 | else 344 | it = it->next; 345 | } 346 | pthread_mutex_unlock(&anim_list.mutex); 347 | } 348 | 349 | void anim_cancel_for(void *fb_item, int only_not_started) 350 | { 351 | if(!anim_list.running) 352 | return; 353 | 354 | if(anim_list.in_update_loop && pthread_equal(pthread_self(), workers_get_thread_id())) 355 | return; 356 | 357 | struct anim_list_it *it, *to_remove; 358 | anim_header *anim; 359 | 360 | pthread_mutex_lock(&anim_list.mutex); 361 | for(it = anim_list.first; it; ) 362 | { 363 | anim = it->anim; 364 | 365 | if(!anim->cancel_check || (only_not_started && anim->start_offset == 0)) 366 | { 367 | it = it->next; 368 | continue; 369 | } 370 | 371 | if(anim->cancel_check(anim->cancel_check_data, fb_item)) 372 | { 373 | to_remove = it; 374 | it = it->next; 375 | anim_list_rm(to_remove); 376 | free(to_remove->anim); 377 | free(to_remove); 378 | } 379 | else 380 | it = it->next; 381 | } 382 | pthread_mutex_unlock(&anim_list.mutex); 383 | } 384 | 385 | void anim_push_context(void) 386 | { 387 | pthread_mutex_lock(&anim_list.mutex); 388 | if(anim_list.first) 389 | { 390 | list_add(&anim_list.inactive_ctx, anim_list.first); 391 | anim_list.first = anim_list.last = NULL; 392 | } 393 | else 394 | { 395 | list_add(&anim_list.inactive_ctx, &EMPTY_CONTEXT); 396 | } 397 | pthread_mutex_unlock(&anim_list.mutex); 398 | } 399 | 400 | void anim_pop_context(void) 401 | { 402 | pthread_mutex_lock(&anim_list.mutex); 403 | if(!anim_list.inactive_ctx) 404 | { 405 | pthread_mutex_unlock(&anim_list.mutex); 406 | return; 407 | } 408 | 409 | if(anim_list.first) 410 | anim_list_clear(); 411 | 412 | const int idx = list_item_count(anim_list.inactive_ctx)-1; 413 | struct anim_list_it *last_active_ctx = anim_list.inactive_ctx[idx]; 414 | if(last_active_ctx != &EMPTY_CONTEXT) 415 | { 416 | anim_list.first = last_active_ctx; 417 | while(last_active_ctx->next) 418 | last_active_ctx = last_active_ctx->next; 419 | anim_list.last = last_active_ctx; 420 | } 421 | list_rm_at(&anim_list.inactive_ctx, idx, NULL); 422 | pthread_mutex_unlock(&anim_list.mutex); 423 | } 424 | 425 | int anim_item_cancel_check(void *item_my, void *item_destroyed) 426 | { 427 | return item_my == item_destroyed; 428 | } 429 | 430 | item_anim *item_anim_create(void *fb_item, int duration, int interpolator) 431 | { 432 | item_anim *anim = mzalloc(sizeof(item_anim)); 433 | anim->id = anim_generate_id(); 434 | anim->item = fb_item; 435 | anim->duration = duration * anim_list.duration_coef; 436 | anim->interpolator = interpolator; 437 | anim->cancel_check_data = fb_item; 438 | anim->cancel_check = anim_item_cancel_check; 439 | anim->targetX = -1; 440 | anim->targetY = -1; 441 | anim->targetW = -1; 442 | anim->targetH = -1; 443 | return anim; 444 | } 445 | 446 | void item_anim_add(item_anim *anim) 447 | { 448 | if(!anim_list.running) 449 | { 450 | free(anim); 451 | return; 452 | } 453 | 454 | item_anim_on_start(anim); 455 | 456 | struct anim_list_it *it = mzalloc(sizeof(struct anim_list_it)); 457 | it->anim_type = ANIM_TYPE_ITEM; 458 | it->anim = (anim_header*)anim; 459 | anim_list_append(it); 460 | } 461 | 462 | void item_anim_add_after(item_anim *anim) 463 | { 464 | struct anim_list_it *it; 465 | pthread_mutex_lock(&anim_list.mutex); 466 | for(it = anim_list.first; it; it = it->next) 467 | { 468 | if(it->anim_type == ANIM_TYPE_ITEM && ((item_anim*)it->anim)->item == anim->item) 469 | { 470 | const int u = it->anim->start_offset + it->anim->duration - it->anim->elapsed; 471 | anim->start_offset = imax(anim->start_offset, u); 472 | } 473 | } 474 | pthread_mutex_unlock(&anim_list.mutex); 475 | 476 | item_anim_add(anim); 477 | } 478 | 479 | call_anim *call_anim_create(void *data, call_anim_callback callback, int duration, int interpolator) 480 | { 481 | call_anim *anim = mzalloc(sizeof(call_anim)); 482 | anim->id = anim_generate_id(); 483 | anim->data = data; 484 | anim->callback = callback; 485 | anim->duration = duration * anim_list.duration_coef; 486 | anim->interpolator = interpolator; 487 | return anim; 488 | } 489 | 490 | void call_anim_add(call_anim *anim) 491 | { 492 | if(!anim_list.running) 493 | { 494 | free(anim); 495 | return; 496 | } 497 | 498 | struct anim_list_it *it = mzalloc(sizeof(struct anim_list_it)); 499 | it->anim_type = ANIM_TYPE_CALLBACK; 500 | it->anim = (anim_header*)anim; 501 | anim_list_append(it); 502 | } 503 | -------------------------------------------------------------------------------- /lib/animation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef ANIMATION_H 19 | #define ANIMATION_H 20 | 21 | enum 22 | { 23 | ANIM_TYPE_ITEM, 24 | ANIM_TYPE_CALLBACK, 25 | }; 26 | 27 | enum 28 | { 29 | INTERPOLATOR_LINEAR, 30 | INTERPOLATOR_DECELERATE, 31 | INTERPOLATOR_ACCELERATE, 32 | INTERPOLATOR_OVERSHOOT, 33 | INTERPOLATOR_ACCEL_DECEL, 34 | }; 35 | 36 | typedef void (*animation_callback)(void*); // data 37 | typedef void (*animation_callback_step)(void*, float); // data, interpolated 38 | typedef int (*animation_cancel_check)(void*, void*); // data, item 39 | 40 | #define ANIM_INVALID_ID UINT32_MAX 41 | 42 | #define ANIM_HEADER \ 43 | uint32_t id; \ 44 | uint32_t start_offset; \ 45 | uint32_t duration; \ 46 | uint32_t elapsed; \ 47 | int interpolator; \ 48 | void *on_finished_data; \ 49 | animation_callback on_finished_call; \ 50 | void *on_step_data; \ 51 | animation_callback_step on_step_call; \ 52 | void *cancel_check_data; \ 53 | animation_cancel_check cancel_check; 54 | 55 | typedef struct 56 | { 57 | ANIM_HEADER 58 | } anim_header; 59 | 60 | typedef struct 61 | { 62 | ANIM_HEADER 63 | void *item; 64 | 65 | int destroy_item_when_finished; 66 | 67 | int start[4]; 68 | int last[4]; 69 | 70 | int targetX, targetY; 71 | int targetW, targetH; 72 | } item_anim; 73 | 74 | typedef void (*call_anim_callback)(void*, float); // data, interpolated 75 | typedef struct 76 | { 77 | ANIM_HEADER 78 | 79 | call_anim_callback callback; 80 | void *data; 81 | } call_anim; 82 | 83 | void anim_init(float duration_coef); 84 | void anim_stop(int wait_for_finished); 85 | void anim_cancel(uint32_t id, int only_not_started); 86 | void anim_cancel_for(void *fb_item, int only_not_started); 87 | void anim_push_context(void); 88 | void anim_pop_context(void); 89 | int anim_item_cancel_check(void *item_my, void *item_destroyed); 90 | 91 | item_anim *item_anim_create(void *fb_item, int duration, int interpolator); 92 | void item_anim_add(item_anim *anim); 93 | void item_anim_add_after(item_anim *anim); 94 | 95 | call_anim *call_anim_create(void *data, call_anim_callback callback, int duration, int interpolator); 96 | void call_anim_add(call_anim *anim); 97 | 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /lib/atomics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef ATOMICS_H 19 | #define ATOMICS_H 20 | 21 | #if (PLATFORM_SDK_VERSION >= 21) 22 | #include 23 | #else 24 | #include 25 | typedef struct { volatile int __val; } atomic_int; 26 | #define ATOMIC_VAR_INIT(value) { .__val = value } 27 | #define atomic_compare_exchange_strong(valptr, oldval, newval) (!__atomic_cmpxchg((oldval)->__val, newval, &((valptr)->__val))) 28 | #endif 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /lib/button.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | 20 | #include "button.h" 21 | #include "input.h" 22 | #include "util.h" 23 | #include "colors.h" 24 | #include "log.h" 25 | #include "containers.h" 26 | 27 | void button_init_ui(button *b, const char *text, int size) 28 | { 29 | b->touch_id = -1; 30 | 31 | if(text != NULL) 32 | { 33 | b->c[CLR_NORMAL][0] = C_HIGHLIGHT_BG; 34 | b->c[CLR_NORMAL][1] = C_HIGHLIGHT_TEXT; 35 | b->c[CLR_HOVER][0] = C_HIGHLIGHT_HOVER; 36 | b->c[CLR_HOVER][1] = C_HIGHLIGHT_TEXT; 37 | b->c[CLR_DIS][0] = GRAY; 38 | b->c[CLR_DIS][1] = WHITE; 39 | b->c[CLR_CHECK][0] = C_HIGHLIGHT_BG; 40 | b->c[CLR_CHECK][1] = C_HIGHLIGHT_TEXT; 41 | 42 | b->rect = fb_add_rect_lvl(b->level_off + LEVEL_RECT, b->x, b->y, b->w, b->h, b->c[CLR_NORMAL][0]); 43 | 44 | fb_text_proto *p = fb_text_create(0, 0, b->c[CLR_NORMAL][1], size, text); 45 | p->level = b->level_off + LEVEL_TEXT; 46 | p->style = STYLE_MEDIUM; 47 | b->text = fb_text_finalize(p); 48 | center_text(b->text, b->x, b->y, b->w, b->h); 49 | } 50 | else 51 | { 52 | b->text = NULL; 53 | b->rect = NULL; 54 | } 55 | 56 | add_touch_handler(&button_touch_handler, b); 57 | } 58 | 59 | void button_destroy(button *b) 60 | { 61 | rm_touch_handler(&button_touch_handler, b); 62 | keyaction_remove(&button_keyaction_call, b); 63 | 64 | if(b->text) 65 | { 66 | fb_rm_rect(b->rect); 67 | fb_rm_text(b->text); 68 | } 69 | 70 | free(b); 71 | } 72 | 73 | void button_move(button *b, int x, int y) 74 | { 75 | b->x = x; 76 | b->y = y; 77 | 78 | if(b->text) 79 | { 80 | b->rect->x = x; 81 | b->rect->y = y; 82 | 83 | center_text(b->text, b->x, b->y, b->w, b->h); 84 | } 85 | } 86 | 87 | void button_set_hover(button *b, int hover) 88 | { 89 | if((hover == 1) == ((b->flags & BTN_HOVER) != 0)) 90 | return; 91 | 92 | if(hover) 93 | b->flags |= BTN_HOVER; 94 | else 95 | b->flags &= ~(BTN_HOVER); 96 | 97 | if(b->text) 98 | { 99 | button_update_colors(b); 100 | fb_request_draw(); 101 | } 102 | } 103 | 104 | void button_enable(button *b, int enable) 105 | { 106 | if(enable) 107 | b->flags &= ~(BTN_DISABLED); 108 | else 109 | { 110 | b->flags |= BTN_DISABLED; 111 | b->flags &= ~(BTN_HOVER); 112 | } 113 | 114 | if(b->text) 115 | { 116 | button_update_colors(b); 117 | fb_request_draw(); 118 | } 119 | } 120 | 121 | int button_touch_handler(touch_event *ev, void *data) 122 | { 123 | button *b = (button*)data; 124 | 125 | if(b->flags & BTN_DISABLED) 126 | return -1; 127 | 128 | if(b->touch_id == -1 && (ev->changed & TCHNG_ADDED) && !ev->consumed) 129 | { 130 | if(!in_rect(ev->x, ev->y, b->x, b->y, b->w, b->h)) 131 | return -1; 132 | 133 | b->touch_id = ev->id; 134 | } 135 | 136 | if(b->touch_id != ev->id) 137 | return -1; 138 | 139 | if(ev->changed & TCHNG_POS) 140 | button_set_hover(b, in_rect(ev->x, ev->y, b->x, b->y, b->w, b->h)); 141 | 142 | if(ev->changed & TCHNG_REMOVED) 143 | { 144 | if((b->flags & BTN_HOVER) && b->clicked) 145 | (*b->clicked)(b->clicked_data); 146 | button_set_hover(b, 0); 147 | b->touch_id = -1; 148 | } 149 | 150 | return 0; 151 | } 152 | 153 | void button_set_color(button *b, int idx, int text, uint32_t color) 154 | { 155 | b->c[idx][text] = color; 156 | button_update_colors(b); 157 | } 158 | 159 | void button_update_colors(button *b) 160 | { 161 | int state = CLR_NORMAL; 162 | if(b->flags & BTN_DISABLED) 163 | state = CLR_DIS; 164 | else if(b->flags & BTN_HOVER) 165 | state = CLR_HOVER; 166 | else if(b->flags & BTN_CHECKED) 167 | state = CLR_CHECK; 168 | 169 | if(b->text) 170 | { 171 | b->rect->color = b->c[state][0]; 172 | fb_text_set_color(b->text, b->c[state][1]); 173 | } 174 | } 175 | 176 | void button_set_checked(button *b, int checked) 177 | { 178 | if((checked == 1) == ((b->flags & BTN_CHECKED) != 0)) 179 | return; 180 | 181 | if(checked) 182 | b->flags |= BTN_CHECKED; 183 | else 184 | b->flags &= ~(BTN_CHECKED); 185 | 186 | button_update_colors(b); 187 | fb_request_draw(); 188 | } 189 | 190 | int button_keyaction_call(void *data, int act) 191 | { 192 | button *b = data; 193 | switch(act) 194 | { 195 | case KEYACT_UP: 196 | case KEYACT_DOWN: 197 | case KEYACT_CLEAR: 198 | { 199 | if(act != KEYACT_CLEAR && b->keyact_frame == NULL) 200 | { 201 | fb_add_rect_notfilled(b->level_off + LEVEL_RECT, b->x, b->y, b->w, b->h, C_KEYACT_FRAME, KEYACT_FRAME_W, &b->keyact_frame); 202 | fb_request_draw(); 203 | return 0; 204 | } 205 | else 206 | { 207 | list_clear(&b->keyact_frame, &fb_remove_item); 208 | fb_request_draw(); 209 | return (act == KEYACT_CLEAR) ? 0 : 1; 210 | } 211 | } 212 | case KEYACT_CONFIRM: 213 | { 214 | if(b->clicked && !(b->flags & BTN_DISABLED)) 215 | (*b->clicked)(b->clicked_data); 216 | return 0; 217 | } 218 | default: 219 | return 0; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /lib/button.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef BUTTON_H 19 | #define BUTTON_H 20 | 21 | #include "framebuffer.h" 22 | #include "input.h" 23 | 24 | enum 25 | { 26 | BTN_HOVER = 0x01, 27 | BTN_DISABLED = 0x02, 28 | BTN_CHECKED = 0x04, 29 | }; 30 | 31 | enum 32 | { 33 | CLR_NORMAL = 0, 34 | CLR_HOVER, 35 | CLR_DIS, 36 | CLR_CHECK, 37 | 38 | CLR_MAX 39 | }; 40 | 41 | typedef struct 42 | { 43 | FB_ITEM_HEAD 44 | 45 | fb_img *text; 46 | fb_rect *rect; 47 | fb_rect **keyact_frame; 48 | int level_off; 49 | 50 | uint32_t c[CLR_MAX][2]; 51 | 52 | int flags; 53 | int touch_id; 54 | 55 | void *clicked_data; 56 | void (*clicked)(void*); // clicked_data 57 | } button; 58 | 59 | void button_init_ui(button *b, const char *text, int size); 60 | void button_destroy(button *b); 61 | void button_move(button *b, int x, int y); 62 | void button_set_hover(button *b, int hover); 63 | void button_enable(button *b, int enable); 64 | void button_set_checked(button *b, int checked); 65 | void button_set_color(button *b, int idx, int text, uint32_t color); 66 | void button_update_colors(button *b); 67 | int button_touch_handler(touch_event *ev, void *data); 68 | int button_keyaction_call(void *data, int act); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /lib/colors.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include "colors.h" 19 | #include "util.h" 20 | 21 | static const struct mrom_color_theme color_themes[] = { 22 | // 0 - red/white, default 23 | { 24 | .background = 0xFFDCDCDC, 25 | .highlight_bg = 0xFFF72F2F, 26 | .highlight_hover = 0xFFF85555, 27 | .highlight_text = 0xFFFFFFFF, 28 | .text = 0xFF000000, 29 | .text_secondary = 0xFF4D4D4D, 30 | .ncard_bg = 0xFF37474F, 31 | .ncard_text = 0xFFFFFFFF, 32 | .ncard_text_secondary = 0xFFE6E6E6, 33 | .ncard_shadow = 0x54000000, 34 | .rom_highlight = 0xFFFFFFFF, 35 | .rom_highlight_shadow = 0x54000000, 36 | .keyaction_frame = 0xFF0000FF, 37 | .btn_fake_shadow = 0xFFA1A1A1, 38 | }, 39 | // 1 - orange/white 40 | { 41 | .background = 0xFFDCDCDC, 42 | .highlight_bg = 0xFFFF5722, 43 | .highlight_hover = 0xFFFF8A65, 44 | .highlight_text = 0xFFFFFFFF, 45 | .text = 0xFF000000, 46 | .text_secondary = 0xFF4D4D4D, 47 | .ncard_bg = 0xFF37474F, 48 | .ncard_text = 0xFFFFFFFF, 49 | .ncard_text_secondary = 0xFFE6E6E6, 50 | .ncard_shadow = 0x54000000, 51 | .rom_highlight = 0xFFFFFFFF, 52 | .rom_highlight_shadow = 0x54000000, 53 | .keyaction_frame = 0xFFFF0000, 54 | .btn_fake_shadow = 0xFFA1A1A1, 55 | }, 56 | // 2 - blue/white 57 | { 58 | .background = 0xFFDCDCDC, 59 | .highlight_bg = 0xFF5677FC, 60 | .highlight_hover = 0xFF91A7FF, 61 | .highlight_text = 0xFFFFFFFF, 62 | .text = 0xFF000000, 63 | .text_secondary = 0xFF4D4D4D, 64 | .ncard_bg = 0xFF37474F, 65 | .ncard_text = 0xFFFFFFFF, 66 | .ncard_text_secondary = 0xFFE6E6E6, 67 | .ncard_shadow = 0x54000000, 68 | .rom_highlight = 0xFFFFFFFF, 69 | .rom_highlight_shadow = 0x54000000, 70 | .keyaction_frame = 0xFFFF0000, 71 | .btn_fake_shadow = 0xFFA1A1A1, 72 | }, 73 | // 3 - purple/white 74 | { 75 | .background = 0xFFDCDCDC, 76 | .highlight_bg = 0xFF673AB7, 77 | .highlight_hover = 0xFF9575CD, 78 | .highlight_text = 0xFFFFFFFF, 79 | .text = 0xFF000000, 80 | .text_secondary = 0xFF4D4D4D, 81 | .ncard_bg = 0xFF37474F, 82 | .ncard_text = 0xFFFFFFFF, 83 | .ncard_text_secondary = 0xFFE6E6E6, 84 | .ncard_shadow = 0x54000000, 85 | .rom_highlight = 0xFFFFFFFF, 86 | .rom_highlight_shadow = 0x54000000, 87 | .keyaction_frame = 0xFFFF0000, 88 | .btn_fake_shadow = 0xFFA1A1A1, 89 | }, 90 | // 4 - green/white 91 | { 92 | .background = 0xFFDCDCDC, 93 | .highlight_bg = 0xFF259B24, 94 | .highlight_hover = 0xFF72D572, 95 | .highlight_text = 0xFFFFFFFF, 96 | .text = 0xFF000000, 97 | .text_secondary = 0xFF4D4D4D, 98 | .ncard_bg = 0xFF37474F, 99 | .ncard_text = 0xFFFFFFFF, 100 | .ncard_text_secondary = 0xFFE6E6E6, 101 | .ncard_shadow = 0x54000000, 102 | .rom_highlight = 0xFFFFFFFF, 103 | .rom_highlight_shadow = 0x54000000, 104 | .keyaction_frame = 0xFFFF0000, 105 | .btn_fake_shadow = 0xFFA1A1A1, 106 | }, 107 | // 5 - dark blue 108 | { 109 | .background = 0xFF263238, 110 | .highlight_bg = 0xFF607D8B, 111 | .highlight_hover = 0xFF90A4AE, 112 | .highlight_text = 0xFFFFFFFF, 113 | .text = 0xFFFFFFFF, 114 | .text_secondary = 0xFFE6E6E6, 115 | .ncard_bg = 0xFF37474F, 116 | .ncard_text = 0xFFFFFFFF, 117 | .ncard_text_secondary = 0xFFE6E6E6, 118 | .ncard_shadow = 0x54000000, 119 | .rom_highlight = 0xFF607D8B, 120 | .rom_highlight_shadow = 0x54000000, 121 | .keyaction_frame = 0xFFFF0000, 122 | .btn_fake_shadow = 0xFF1C2529, 123 | }, 124 | // 6 - dark blue/black 125 | { 126 | .background = 0xFF000000, 127 | .highlight_bg = 0xFF263238, 128 | .highlight_hover = 0xFF607D8B, 129 | .highlight_text = 0xFFFFFFFF, 130 | .text = 0xFFFFFFFF, 131 | .text_secondary = 0xFFE6E6E6, 132 | .ncard_bg = 0xFF37474F, 133 | .ncard_text = 0xFFFFFFFF, 134 | .ncard_text_secondary = 0xFFE6E6E6, 135 | .ncard_shadow = 0x54424242, 136 | .rom_highlight = 0xFF263238, 137 | .rom_highlight_shadow = 0x54424242, 138 | .keyaction_frame = 0xFFFF0000, 139 | .btn_fake_shadow = 0x00000000, 140 | }, 141 | }; 142 | 143 | const struct mrom_color_theme *color_theme = &color_themes[0]; 144 | 145 | void colors_select(size_t color_theme_idx) 146 | { 147 | if(color_theme_idx >= ARRAY_SIZE(color_themes)) 148 | return; 149 | color_theme = &color_themes[color_theme_idx]; 150 | } 151 | 152 | const struct mrom_color_theme *colors_get(size_t color_theme_idx) 153 | { 154 | if(color_theme_idx >= ARRAY_SIZE(color_themes)) 155 | return NULL; 156 | return &color_themes[color_theme_idx]; 157 | } 158 | 159 | int colors_count(void) 160 | { 161 | return ARRAY_SIZE(color_themes); 162 | } 163 | -------------------------------------------------------------------------------- /lib/colors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef MROM_COLORS_H 19 | #define MROM_COLORS_H 20 | 21 | #include 22 | 23 | struct mrom_color_theme 24 | { 25 | uint32_t background; 26 | uint32_t highlight_bg; 27 | uint32_t highlight_hover; 28 | uint32_t highlight_text; 29 | uint32_t text; 30 | uint32_t text_secondary; 31 | uint32_t ncard_bg; 32 | uint32_t ncard_text; 33 | uint32_t ncard_text_secondary; 34 | uint32_t ncard_shadow; 35 | uint32_t rom_highlight; 36 | uint32_t rom_highlight_shadow; 37 | uint32_t keyaction_frame; 38 | uint32_t btn_fake_shadow; 39 | }; 40 | 41 | extern const struct mrom_color_theme *color_theme; 42 | #define C_BACKGROUND (color_theme->background) 43 | #define C_HIGHLIGHT_BG (color_theme->highlight_bg) 44 | #define C_HIGHLIGHT_HOVER (color_theme->highlight_hover) 45 | #define C_HIGHLIGHT_TEXT (color_theme->highlight_text) 46 | #define C_TEXT (color_theme->text) 47 | #define C_TEXT_SECONDARY (color_theme->text_secondary) 48 | #define C_NCARD_BG (color_theme->ncard_bg) 49 | #define C_NCARD_TEXT (color_theme->ncard_text) 50 | #define C_NCARD_TEXT_SECONDARY (color_theme->ncard_text_secondary) 51 | #define C_NCARD_SHADOW (color_theme->ncard_shadow) 52 | #define C_ROM_HIGHLIGHT (color_theme->rom_highlight) 53 | #define C_ROM_HIGHLIGHT_SHADOW (color_theme->rom_highlight_shadow) 54 | #define C_KEYACT_FRAME (color_theme->keyaction_frame) 55 | #define C_BTN_FAKE_SHADOW (color_theme->btn_fake_shadow) 56 | 57 | void colors_select(size_t color_theme_idx); 58 | const struct mrom_color_theme *colors_get(size_t color_theme_idx); 59 | int colors_count(void); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /lib/containers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "containers.h" 21 | #include "util.h" 22 | 23 | int list_item_count(listItself list) 24 | { 25 | void **l = (void**)list; 26 | int i = 0; 27 | while(l && l[i]) 28 | ++i; 29 | return i; 30 | } 31 | 32 | int list_size(listItself list) 33 | { 34 | return list_item_count(list)+1; 35 | } 36 | 37 | void list_add(ptrToList list_p, void *item) 38 | { 39 | void ***list = (void***)list_p; 40 | 41 | int i = 0; 42 | while(*list && (*list)[i]) 43 | ++i; 44 | i += 2; // NULL and the new item 45 | 46 | *list = realloc(*list, i*sizeof(item)); 47 | 48 | (*list)[--i] = NULL; 49 | (*list)[--i] = item; 50 | } 51 | 52 | void list_add_at(ptrToList list_p, int idx, void *item) 53 | { 54 | void ***list = (void***)list_p; 55 | int size = list_size(*list); 56 | int i; 57 | 58 | *list = realloc(*list, (size+1)*sizeof(void*)); 59 | 60 | if(idx < 0) 61 | idx = 0; 62 | else if(idx >= size) 63 | idx = size - 1; 64 | 65 | for(i = idx + 1; i < size; ++i) 66 | (*list)[i] = (*list)[i-1]; 67 | 68 | (*list)[idx] = item; 69 | (*list)[i] = NULL; 70 | } 71 | 72 | int list_add_from_list(ptrToList list_p, listItself src_p) 73 | { 74 | void **src = (void**)src_p; 75 | void ***list = (void***)list_p; 76 | int i, len_src = 0, len_list = 0; 77 | 78 | while(src && src[len_src]) 79 | ++len_src; 80 | 81 | if(len_src == 0) 82 | return 0; 83 | 84 | while(*list && (*list)[len_list]) 85 | ++len_list; 86 | 87 | ++len_src; // for NULL 88 | *list = realloc(*list, (len_list+len_src)*sizeof(void*)); 89 | 90 | for(i = 0; i < len_src; ++i) 91 | (*list)[i+len_list] = src[i]; 92 | return len_src-1; 93 | } 94 | 95 | int list_rm_opt(ptrToList list_p, void *item, callback destroy_callback_p, int reorder) 96 | { 97 | void ***list = (void***)list_p; 98 | callbackPtr destroy_callback = (callbackPtr)destroy_callback_p; 99 | 100 | int size = list_size(*list); 101 | 102 | int i; 103 | for(i = 0; *list && (*list)[i]; ++i) 104 | { 105 | if((*list)[i] != item) 106 | continue; 107 | 108 | if(destroy_callback) 109 | (*destroy_callback)(item); 110 | 111 | --size; 112 | if(size == 1) 113 | { 114 | free(*list); 115 | *list = NULL; 116 | return 0; 117 | } 118 | 119 | if(i != size-1) 120 | { 121 | if(reorder) 122 | (*list)[i] = (*list)[size-1]; 123 | else 124 | { 125 | for(; *list && (*list)[i]; ++i) 126 | (*list)[i] = (*list)[i+1]; 127 | } 128 | } 129 | 130 | *list= realloc(*list, size*sizeof(item)); 131 | (*list)[size-1] = NULL; 132 | return 0; 133 | } 134 | return -1; 135 | } 136 | 137 | int list_rm(ptrToList list_p, void *item, callback destroy_callback_p) 138 | { 139 | return list_rm_opt(list_p, item, destroy_callback_p, 1); 140 | } 141 | 142 | int list_rm_noreorder(ptrToList list_p, void *item, callback destroy_callback_p) 143 | { 144 | return list_rm_opt(list_p, item, destroy_callback_p, 0); 145 | } 146 | 147 | listItself list_rm_at(ptrToList list_p, int idx, callback destroy_callback_p) 148 | { 149 | void ***list = (void***)list_p; 150 | callbackPtr destroy_callback = (callbackPtr)destroy_callback_p; 151 | 152 | int size = list_size(*list); 153 | if(idx < 0 || idx >= size-1) 154 | return NULL; 155 | 156 | void *item = (*list)[idx]; 157 | if(destroy_callback) 158 | (*destroy_callback)(item); 159 | 160 | --size; 161 | if(size == 1) 162 | { 163 | free(*list); 164 | *list = NULL; 165 | return NULL; 166 | } 167 | 168 | int i = idx; 169 | for(; i < size; ++i) 170 | (*list)[i] = (*list)[i+1]; 171 | 172 | *list = realloc(*list, size*sizeof(item)); 173 | return *list + idx; 174 | } 175 | 176 | void list_clear(ptrToList list_p, callback destroy_callback_p) 177 | { 178 | void ***list = (void***)list_p; 179 | callbackPtr destroy_callback = (callbackPtr)destroy_callback_p; 180 | 181 | if(*list == NULL) 182 | return; 183 | 184 | if(destroy_callback) 185 | { 186 | int i; 187 | for(i = 0; *list && (*list)[i]; ++i) 188 | (*destroy_callback)((*list)[i]); 189 | } 190 | 191 | free(*list); 192 | *list = NULL; 193 | } 194 | 195 | int list_copy(ptrToList dest_p, listItself src) 196 | { 197 | void **source = (void**)src; 198 | void ***dest = (void***)dest_p; 199 | 200 | if(!source) 201 | return 0; 202 | 203 | if(*dest) 204 | return -1; 205 | 206 | int size = list_size(source); 207 | *dest = calloc(size, sizeof(*source)); 208 | 209 | int i; 210 | for(i = 0; source[i]; ++i) 211 | (*dest)[i] = source[i]; 212 | return 0; 213 | } 214 | 215 | int list_move(ptrToList dest_p, ptrToList source_p) 216 | { 217 | void ***source = (void***)source_p; 218 | void ***dest = (void***)dest_p; 219 | 220 | if(!source) 221 | return 0; 222 | 223 | if(*dest) 224 | return -1; 225 | 226 | *dest = *source; 227 | *source = NULL; 228 | return 0; 229 | } 230 | 231 | void list_swap(ptrToList a_p, ptrToList b_p) 232 | { 233 | void ***a = (void***)a_p; 234 | void ***b = (void***)b_p; 235 | void **tmp = *a; 236 | *a = *b; 237 | *b = tmp; 238 | } 239 | 240 | map *map_create(void) 241 | { 242 | map *m = mzalloc(sizeof(map)); 243 | return m; 244 | } 245 | 246 | void map_destroy(map *m, void (*destroy_callback)(void*)) 247 | { 248 | if(!m) 249 | return; 250 | 251 | list_clear(&m->keys, &free); 252 | list_clear(&m->values, destroy_callback); 253 | free(m); 254 | } 255 | 256 | void map_add(map *m, const char *key, void *val, void (*destroy_callback)(void*)) 257 | { 258 | int idx = map_find(m, key); 259 | if(idx >= 0) 260 | { 261 | if(destroy_callback) 262 | (*destroy_callback)(m->values[idx]); 263 | m->values[idx] = val; 264 | } 265 | else 266 | map_add_not_exist(m, key, val); 267 | } 268 | 269 | void map_add_not_exist(map *m, const char *key, void *val) 270 | { 271 | list_add(&m->keys, strdup(key)); 272 | list_add(&m->values, val); 273 | ++m->size; 274 | } 275 | 276 | void map_rm(map *m, const char *key, void (*destroy_callback)(void*)) 277 | { 278 | int idx = map_find(m, key); 279 | if(idx < 0) 280 | return; 281 | 282 | list_rm_at(&m->keys, idx, &free); 283 | list_rm_at(&m->values, idx, destroy_callback); 284 | --m->size; 285 | } 286 | 287 | int map_find(map *m, const char *key) 288 | { 289 | int i; 290 | for(i = 0; m->keys && m->keys[i]; ++i) 291 | if(strcmp(m->keys[i], key) == 0) 292 | return i; 293 | return -1; 294 | } 295 | 296 | void *map_get_val(map *m, const char *key) 297 | { 298 | int idx = map_find(m, key); 299 | if(idx < 0) 300 | return NULL; 301 | return m->values[idx]; 302 | } 303 | 304 | void *map_get_ref(map *m, const char *key) 305 | { 306 | int idx = map_find(m, key); 307 | if(idx < 0) 308 | return NULL; 309 | return &m->values[idx]; 310 | } 311 | 312 | 313 | 314 | imap *imap_create(void) 315 | { 316 | return mzalloc(sizeof(imap)); 317 | } 318 | 319 | void imap_destroy(imap *m, void (*destroy_callback)(void*)) 320 | { 321 | if(!m) 322 | return; 323 | 324 | list_clear(&m->values, destroy_callback); 325 | free(m->keys); 326 | free(m); 327 | } 328 | 329 | void imap_add(imap *m, int key, void *val, void (*destroy_callback)(void*)) 330 | { 331 | int idx = imap_find(m, key); 332 | if(idx >= 0) 333 | { 334 | if(destroy_callback) 335 | (*destroy_callback)(m->values[idx]); 336 | m->values[idx] = val; 337 | } 338 | else 339 | imap_add_not_exist(m, key, val); 340 | } 341 | 342 | void imap_add_not_exist(imap *m, int key, void *val) 343 | { 344 | m->keys = realloc(m->keys, sizeof(int)*(m->size+1)); 345 | m->keys[m->size++] = key; 346 | 347 | list_add(&m->values, val); 348 | } 349 | 350 | void imap_rm(imap *m, int key, void (*destroy_callback)(void*)) 351 | { 352 | size_t i; 353 | int idx = imap_find(m, key); 354 | if(idx < 0) 355 | return; 356 | 357 | for(i = idx; i < m->size-1; ++i) 358 | m->keys[i] = m->keys[i+1]; 359 | 360 | --m->size; 361 | m->keys = realloc(m->keys, sizeof(int)*m->size); 362 | list_rm_at(&m->values, idx, destroy_callback); 363 | } 364 | 365 | int imap_find(imap *m, int key) 366 | { 367 | size_t i; 368 | for(i = 0; i < m->size; ++i) 369 | if(key == m->keys[i]) 370 | return i; 371 | return -1; 372 | } 373 | 374 | void *imap_get_val(imap *m, int key) 375 | { 376 | int idx = imap_find(m, key); 377 | if(idx < 0) 378 | return NULL; 379 | return m->values[idx]; 380 | } 381 | 382 | void *imap_get_ref(imap *m, int key) 383 | { 384 | int idx = imap_find(m, key); 385 | if(idx < 0) 386 | return NULL; 387 | return &m->values[idx]; 388 | } 389 | 390 | -------------------------------------------------------------------------------- /lib/containers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef CONTAINERS_H 18 | #define CONTAINERS_H 19 | 20 | // auto-conversion of pointer type occurs only for 21 | // void*, not for void** nor void*** 22 | typedef void* ptrToList; // void *** 23 | typedef void* listItself; // void ** 24 | typedef void* callback; 25 | typedef void(*callbackPtr)(void*); 26 | 27 | void list_add(ptrToList list_p, void *item); 28 | void list_add_at(ptrToList list_p, int idx, void *item); 29 | int list_add_from_list(ptrToList list_p, listItself src_p); 30 | int list_rm(ptrToList list_p, void *item, callback destroy_callback_p); 31 | int list_rm_noreorder(ptrToList list_p, void *item, callback destroy_callback_p); 32 | int list_rm_opt(ptrToList list_p, void *item, callback destroy_callback_p, int reorder); 33 | listItself list_rm_at(ptrToList list_p, int idx, callback destroy_callback_p); // returns pointer to the next item in list or NULL 34 | int list_size(listItself list); 35 | int list_item_count(listItself list); 36 | int list_copy(ptrToList dest_p, listItself src); 37 | int list_move(ptrToList dest_p, ptrToList source_p); 38 | void list_clear(ptrToList list_p, callback destroy_callback_p); 39 | void list_swap(ptrToList a_p, ptrToList b_p); 40 | 41 | typedef struct 42 | { 43 | char **keys; 44 | void **values; 45 | size_t size; 46 | } map; 47 | 48 | map *map_create(void); 49 | void map_destroy(map *m, void (*destroy_callback)(void*)); 50 | void map_add(map *m, const char *key, void *val, void (*destroy_callback)(void*)); 51 | void map_add_not_exist(map *m, const char *key, void *val); 52 | void map_rm(map *m, const char *key, void (*destroy_callback)(void*)); 53 | int map_find(map *m, const char *key); 54 | void *map_get_val(map *m, const char *key); 55 | void *map_get_ref(map *m, const char *key); 56 | 57 | typedef struct 58 | { 59 | int *keys; 60 | void **values; 61 | size_t size; 62 | } imap; 63 | 64 | imap *imap_create(void); 65 | void imap_destroy(imap *m, void (*destroy_callback)(void*)); 66 | void imap_add(imap *m, int key, void *val, void (*destroy_callback)(void*)); 67 | void imap_add_not_exist(imap *m, int key, void *val); 68 | void imap_rm(imap *m, int key, void (*destroy_callback)(void*)); 69 | int imap_find(imap *m, int key); 70 | void *imap_get_val(imap *m, int key); 71 | void *imap_get_ref(imap *m, int key); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /lib/framebuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef H_FRAMEBUFFER 19 | #define H_FRAMEBUFFER 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #if defined(RECOVERY_BGRA) || defined(RECOVERY_RGBX) || defined(RECOVERY_RGBA) || defined(RECOVERY_ABGR) 27 | #define PIXEL_SIZE 4 28 | typedef uint32_t px_type; 29 | #else 30 | #define PIXEL_SIZE 2 31 | #ifndef RECOVERY_RGB_565 32 | #define RECOVERY_RGB_565 33 | #endif 34 | typedef uint16_t px_type; 35 | #endif 36 | 37 | #ifdef RECOVERY_BGRA 38 | #define PX_IDX_A 3 39 | #define PX_IDX_R 2 40 | #define PX_IDX_G 1 41 | #define PX_IDX_B 0 42 | #define PX_GET_R(px) ((px & 0xFF0000) >> 16) 43 | #define PX_GET_G(px) ((px & 0xFF00) >> 8) 44 | #define PX_GET_B(px) ((px & 0xFF)) 45 | #define PX_GET_A(px) ((px & 0xFF000000) >> 24) 46 | #elif defined(RECOVERY_RGBX) 47 | #define PX_IDX_A 3 48 | #define PX_IDX_R 0 49 | #define PX_IDX_G 1 50 | #define PX_IDX_B 2 51 | #define PX_GET_R(px) (px & 0xFF) 52 | #define PX_GET_G(px) ((px & 0xFF00) >> 8) 53 | #define PX_GET_B(px) ((px & 0xFF0000) >> 16) 54 | #define PX_GET_A(px) ((px & 0xFF000000) >> 24) 55 | #elif defined(RECOVERY_RGBA) 56 | #define PX_IDX_A 3 57 | #define PX_IDX_R 0 58 | #define PX_IDX_G 1 59 | #define PX_IDX_B 2 60 | #define PX_GET_R(px) (px & 0xFF) 61 | #define PX_GET_G(px) ((px & 0xFF00) >> 8) 62 | #define PX_GET_B(px) ((px & 0xFF0000) >> 16) 63 | #define PX_GET_A(px) ((px & 0xFF000000) >> 24) 64 | #elif defined(RECOVERY_RGB_565) 65 | #define PX_GET_R(px) ((((((px & 0xF800) >> 11)*100)/31)*0xFF)/100) 66 | #define PX_GET_G(px) ((((((px & 0x7E0) >> 5)*100)/63)*0xFF)/100) 67 | #define PX_GET_B(px) (((((px & 0x1F)*100)/31)*0xFF)/100) 68 | #define PX_GET_A(px) (0xFF) 69 | #elif defined(RECOVERY_ABGR) 70 | #define PX_IDX_A 3 71 | #define PX_IDX_R 0 72 | #define PX_IDX_G 1 73 | #define PX_IDX_B 2 74 | #define PX_GET_R(px) ((px & 0xFF)) 75 | #define PX_GET_G(px) ((px & 0xFF00) >> 8) 76 | #define PX_GET_B(px) ((px & 0xFF0000) >> 16) 77 | #define PX_GET_A(px) ((px & 0xFF000000) >> 24) 78 | #endif 79 | 80 | struct framebuffer { 81 | px_type *buffer; 82 | uint32_t size; 83 | uint32_t stride; 84 | int fd; 85 | struct fb_fix_screeninfo fi; 86 | struct fb_var_screeninfo vi; 87 | struct fb_impl *impl; 88 | void *impl_data; 89 | }; 90 | 91 | struct fb_impl { 92 | const char *name; 93 | const int impl_id; 94 | 95 | int (*open)(struct framebuffer *fb); 96 | void (*close)(struct framebuffer *fb); 97 | int (*update)(struct framebuffer *fb); 98 | void *(*get_frame_dest)(struct framebuffer *fb); 99 | }; 100 | 101 | enum 102 | { 103 | #ifdef MR_USE_QCOM_OVERLAY 104 | FB_IMPL_QCOM_OVERLAY, 105 | #endif 106 | 107 | FB_IMPL_GENERIC, // must be last 108 | 109 | FB_IMPL_CNT 110 | }; 111 | 112 | // Colors, 0xAARRGGBB 113 | #define BLACK 0xFF000000 114 | #define WHITE 0xFFFFFFFF 115 | #define LBLUE 0xFF0099CC 116 | #define LBLUE2 0xFFA8DFF4 117 | #define GRAYISH 0xFFBEBEBE 118 | #define GRAY 0xFF7F7F7F 119 | #define DRED 0xFFCC0000 120 | 121 | // Font sizes in 1/4 of a point 122 | enum 123 | { 124 | SIZE_SMALL = (7*4), 125 | SIZE_NORMAL = (10*4), 126 | SIZE_BIG = (13*4), 127 | SIZE_EXTRA = (15*4), 128 | }; 129 | 130 | extern uint32_t fb_width; 131 | extern uint32_t fb_height; 132 | extern int fb_rotation; 133 | 134 | int fb_open(int rotation); 135 | int fb_open_impl(void); 136 | void fb_close(void); 137 | void fb_update(void); 138 | void fb_dump_info(void); 139 | int fb_get_vi_xres(void); 140 | int fb_get_vi_yres(void); 141 | void fb_force_generic_impl(int force); 142 | 143 | enum 144 | { 145 | FB_IT_RECT, 146 | FB_IT_IMG, 147 | FB_IT_LISTVIEW, 148 | FB_IT_LINE, 149 | }; 150 | 151 | enum 152 | { 153 | FB_IMG_TYPE_GENERIC, 154 | FB_IMG_TYPE_PNG, 155 | FB_IMG_TYPE_TEXT, 156 | }; 157 | 158 | enum 159 | { 160 | JUSTIFY_LEFT, 161 | JUSTIFY_CENTER, 162 | JUSTIFY_RIGHT, 163 | }; 164 | 165 | enum 166 | { 167 | STYLE_NORMAL, 168 | STYLE_ITALIC, 169 | STYLE_BOLD, 170 | STYLE_BOLD_ITALIC, 171 | STYLE_MEDIUM, 172 | STYLE_CONDENSED, 173 | STYLE_MONOSPACE, 174 | 175 | STYLE_COUNT 176 | }; 177 | 178 | enum 179 | { 180 | LEVEL_LISTVIEW = 0, 181 | LEVEL_RECT = 1, 182 | LEVEL_CIRCLE = 1, 183 | LEVEL_PNG = 2, 184 | LEVEL_LINE = 2, 185 | LEVEL_TEXT = 3, 186 | }; 187 | 188 | struct fb_item_header; 189 | 190 | #define FB_ITEM_POS \ 191 | int x, y; \ 192 | int w, h; 193 | 194 | typedef struct 195 | { 196 | FB_ITEM_POS 197 | } fb_item_pos; 198 | 199 | extern fb_item_pos DEFAULT_FB_PARENT; 200 | 201 | #define FB_ITEM_HEAD \ 202 | FB_ITEM_POS \ 203 | int id; \ 204 | int type; \ 205 | int level; \ 206 | fb_item_pos *parent; \ 207 | struct fb_item_header *prev; \ 208 | struct fb_item_header *next; 209 | 210 | struct fb_item_header 211 | { 212 | FB_ITEM_HEAD 213 | }; 214 | typedef struct fb_item_header fb_item_header; 215 | 216 | typedef struct 217 | { 218 | FB_ITEM_HEAD 219 | 220 | uint32_t color; 221 | } fb_rect; 222 | 223 | /* 224 | * fb_img element draws pre-rendered image data, which can come for 225 | * example from a PNG file. 226 | * For RECOVERY_BGRA and RECOVERY_BGRX (4 bytes per px), data is just 227 | * array of pixels in selected px format. 228 | * For RECOVERY_RGB_565 (2 bytes per px), another 2 bytes with 229 | * alpha values are added after each pixel. So, one pixel is two uint16_t 230 | * entries in the result uint16_t array: 231 | * [0]: (R | (G << 5) | (B << 11)) 232 | * [1]: (alphaForRB | (alphaForG << 8)) 233 | * [2]: (R | (G << 5) | (B << 11)) 234 | * [3]: (alphaForRB | (alphaForG << 8)) 235 | * ... 236 | */ 237 | typedef struct 238 | { 239 | FB_ITEM_HEAD 240 | 241 | int img_type; 242 | px_type *data; 243 | void *extra; 244 | } fb_img; 245 | 246 | typedef fb_img fb_text; 247 | typedef fb_img fb_circle; 248 | 249 | typedef struct 250 | { 251 | FB_ITEM_HEAD; 252 | int x2, y2; 253 | int thickness; 254 | uint32_t color; 255 | } fb_line; 256 | 257 | typedef struct 258 | { 259 | uint32_t background_color; 260 | fb_item_header *first_item; 261 | pthread_mutex_t mutex; 262 | volatile int batch_started; 263 | volatile pthread_t batch_thread; 264 | } fb_context_t; 265 | 266 | typedef struct 267 | { 268 | int x, y; 269 | int level; 270 | fb_item_pos *parent; 271 | uint32_t color; 272 | int size; 273 | int justify; 274 | int style; 275 | char *text; 276 | int wrap_w; 277 | } fb_text_proto; 278 | 279 | void fb_remove_item(void *item); 280 | int fb_generate_item_id(void); 281 | px_type fb_convert_color(uint32_t c); 282 | uint32_t fb_convert_color_img(uint32_t c); 283 | 284 | fb_img *fb_add_text(int x, int y, uint32_t color, int size, const char *fmt, ...); 285 | fb_text_proto *fb_text_create(int x, int y, uint32_t color, int size, const char *text); 286 | fb_img *fb_text_finalize(fb_text_proto *p); 287 | void fb_text_set_color(fb_img *img, uint32_t color); 288 | void fb_text_set_size(fb_img *img, int size); 289 | void fb_text_set_content(fb_img *img, const char *text); 290 | char *fb_text_get_content(fb_img *img); 291 | 292 | void fb_text_drop_cache_unused(void); 293 | void fb_text_destroy(fb_img *i); 294 | 295 | fb_rect *fb_add_rect_lvl(int level, int x, int y, int w, int h, uint32_t color); 296 | #define fb_add_rect(x, y, w, h, color) fb_add_rect_lvl(LEVEL_RECT, x, y, w, h, color) 297 | void fb_add_rect_notfilled(int level, int x, int y, int w, int h, uint32_t color, int thickness, fb_rect ***list); 298 | 299 | fb_img *fb_add_img(int level, int x, int y, int w, int h, int img_type, px_type *data); 300 | fb_img *fb_add_png_img_lvl(int level, int x, int y, int w, int h, const char *path); 301 | #define fb_add_png_img(x, y, w, h, path) fb_add_png_img_lvl(LEVEL_PNG, x, y, w, h, path) 302 | 303 | fb_circle *fb_add_circle_lvl(int level, int x, int y, int radius, uint32_t color); 304 | #define fb_add_circle(x, y, radius, color) fb_add_circle_lvl(LEVEL_CIRCLE, x, y, radius, color) 305 | 306 | fb_line *fb_add_line_lvl(int level, int x1, int y1, int x2, int y2, int thickness, uint32_t color); 307 | #define fb_add_line(x1, y1, x2, y2, thickness, color) fb_add_line_lvl(LEVEL_LINE, x1, y1, x2, y2, thickness, color) 308 | 309 | void fb_rm_text(fb_img *i); 310 | void fb_rm_rect(fb_rect *r); 311 | void fb_rm_img(fb_img *i); 312 | void fb_rm_circle(fb_circle *c); 313 | void fb_rm_line(fb_line *l); 314 | 315 | void fb_draw_rect(fb_rect *r); 316 | void fb_draw_img(fb_img *i); 317 | void fb_draw_line(fb_line *l); 318 | void fb_fill(uint32_t color); 319 | void fb_request_draw(void); 320 | void fb_force_draw(void); 321 | void fb_clear(void); 322 | void fb_freeze(int freeze); 323 | int fb_clone(char **buff); 324 | int fb_save_screenshot(void); 325 | void fb_set_brightness(int val); 326 | 327 | void fb_push_context(void); 328 | void fb_pop_context(void); 329 | 330 | void fb_batch_start(void); 331 | void fb_batch_end(void); 332 | 333 | void fb_ctx_add_item(void *item); 334 | void fb_ctx_rm_item(void *item); 335 | inline void fb_items_lock(void); 336 | inline void fb_items_unlock(void); 337 | void fb_set_background(uint32_t color); 338 | 339 | px_type *fb_png_get(const char *path, int w, int h); 340 | void fb_png_release(px_type *data); 341 | void fb_png_drop_unused(void); 342 | int fb_png_save_img(const char *path, int w, int h, int stride, px_type *data); 343 | 344 | inline void center_text(fb_img *text, int targetX, int targetY, int targetW, int targetH); 345 | 346 | int vt_set_mode(int graphics); 347 | 348 | #endif 349 | -------------------------------------------------------------------------------- /lib/framebuffer_generic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "framebuffer.h" 30 | #include "log.h" 31 | #include "util.h" 32 | 33 | // only double-buffering is implemented, this define is just 34 | // for the code to know how many buffers we use 35 | #define NUM_BUFFERS 2 36 | 37 | struct fb_generic_data { 38 | px_type *mapped[NUM_BUFFERS]; 39 | int active_buff; 40 | }; 41 | 42 | static int impl_open(struct framebuffer *fb) 43 | { 44 | fb->vi.bits_per_pixel = PIXEL_SIZE * 8; 45 | INFO("Pixel format: %dx%d @ %dbpp\n", fb->vi.xres, fb->vi.yres, fb->vi.bits_per_pixel); 46 | 47 | #ifdef RECOVERY_BGRA 48 | INFO("Pixel format: BGRA_8888\n"); 49 | fb->vi.red.offset = 8; 50 | fb->vi.red.length = 8; 51 | fb->vi.green.offset = 16; 52 | fb->vi.green.length = 8; 53 | fb->vi.blue.offset = 24; 54 | fb->vi.blue.length = 8; 55 | fb->vi.transp.offset = 0; 56 | fb->vi.transp.length = 8; 57 | #elif defined(RECOVERY_RGBX) 58 | INFO("Pixel format: RGBX_8888\n"); 59 | fb->vi.red.offset = 24; 60 | fb->vi.red.length = 8; 61 | fb->vi.green.offset = 16; 62 | fb->vi.green.length = 8; 63 | fb->vi.blue.offset = 8; 64 | fb->vi.blue.length = 8; 65 | fb->vi.transp.offset = 0; 66 | fb->vi.transp.length = 8; 67 | #elif defined(RECOVERY_RGBA) 68 | INFO("Pixel format: RGBA_8888\n"); 69 | fb->vi.red.offset = 0; 70 | fb->vi.red.length = 8; 71 | fb->vi.green.offset = 8; 72 | fb->vi.green.length = 8; 73 | fb->vi.blue.offset = 16; 74 | fb->vi.blue.length = 8; 75 | fb->vi.transp.offset = 24; 76 | fb->vi.transp.length = 8; 77 | #elif defined(RECOVERY_RGB_565) 78 | INFO("Pixel format: RGB_565\n"); 79 | fb->vi.blue.offset = 0; 80 | fb->vi.green.offset = 5; 81 | fb->vi.red.offset = 11; 82 | fb->vi.blue.length = 5; 83 | fb->vi.green.length = 6; 84 | fb->vi.red.length = 5; 85 | fb->vi.blue.msb_right = 0; 86 | fb->vi.green.msb_right = 0; 87 | fb->vi.red.msb_right = 0; 88 | fb->vi.transp.offset = 0; 89 | fb->vi.transp.length = 0; 90 | #elif defined(RECOVERY_ABGR) 91 | INFO("Pixel format: ABGR_8888\n"); 92 | fb->vi.red.offset = 0; 93 | fb->vi.red.length = 8; 94 | fb->vi.green.offset = 8; 95 | fb->vi.green.length = 8; 96 | fb->vi.blue.offset = 16; 97 | fb->vi.blue.length = 8; 98 | fb->vi.transp.offset = 24; 99 | fb->vi.transp.length = 8; 100 | #else 101 | #error "Unknown pixel format" 102 | #endif 103 | 104 | fb->vi.vmode = FB_VMODE_NONINTERLACED; 105 | fb->vi.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; 106 | 107 | // mmap and memset to 0 before setting the vi to prevent screen flickering during init 108 | px_type *mapped = mmap(0, fb->fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0); 109 | 110 | if (mapped == MAP_FAILED) 111 | return -1; 112 | 113 | memset(mapped, 0, fb->fi.smem_len); 114 | munmap(mapped, fb->fi.smem_len); 115 | 116 | if (ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi) < 0) 117 | { 118 | ERROR("failed to set fb0 vi info"); 119 | return -1; 120 | } 121 | 122 | if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) 123 | return -1; 124 | 125 | mapped = mmap(0, fb->fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb->fd, 0); 126 | 127 | if (mapped == MAP_FAILED) 128 | return -1; 129 | 130 | struct fb_generic_data *data = mzalloc(sizeof(struct fb_generic_data)); 131 | data->mapped[0] = mapped; 132 | data->mapped[1] = (px_type*) (((uint8_t*)mapped) + (fb->vi.yres * fb->fi.line_length)); 133 | 134 | fb->impl_data = data; 135 | 136 | #ifdef TW_SCREEN_BLANK_ON_BOOT 137 | ioctl(fb->fd, FBIOBLANK, FB_BLANK_POWERDOWN); 138 | ioctl(fb->fd, FBIOBLANK, FB_BLANK_UNBLANK); 139 | #endif 140 | 141 | return 0; 142 | } 143 | 144 | static void impl_close(struct framebuffer *fb) 145 | { 146 | struct fb_generic_data *data = fb->impl_data; 147 | if(data) 148 | { 149 | munmap(data->mapped[0], fb->fi.smem_len); 150 | free(data); 151 | fb->impl_data = NULL; 152 | } 153 | } 154 | 155 | static int impl_update(struct framebuffer *fb) 156 | { 157 | struct fb_generic_data *data = fb->impl_data; 158 | 159 | fb->vi.yres_virtual = fb->vi.yres * NUM_BUFFERS; 160 | fb->vi.yoffset = data->active_buff * fb->vi.yres; 161 | 162 | if (ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi) < 0) 163 | { 164 | ERROR("active fb swap failed"); 165 | return -1; 166 | } 167 | 168 | return 0; 169 | } 170 | 171 | static void *impl_get_frame_dest(struct framebuffer *fb) 172 | { 173 | struct fb_generic_data *data = fb->impl_data; 174 | data->active_buff = !data->active_buff; 175 | return data->mapped[data->active_buff]; 176 | } 177 | 178 | const struct fb_impl fb_impl_generic = { 179 | .name = "Generic", 180 | .impl_id = FB_IMPL_GENERIC, 181 | 182 | .open = impl_open, 183 | .close = impl_close, 184 | .update = impl_update, 185 | .get_frame_dest = impl_get_frame_dest, 186 | }; 187 | -------------------------------------------------------------------------------- /lib/framebuffer_png.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "log.h" 30 | #include "framebuffer.h" 31 | #include "util.h" 32 | #include "containers.h" 33 | 34 | #if 0 35 | #define PNG_LOG(x...) INFO(x) 36 | #else 37 | #define PNG_LOG(x...) ; 38 | #endif 39 | 40 | struct png_cache_entry 41 | { 42 | char *path; 43 | px_type *data; 44 | int width; 45 | int height; 46 | int refcnt; 47 | }; 48 | 49 | static struct png_cache_entry **png_cache = NULL; 50 | 51 | // http://willperone.net/Code/codescaling.php 52 | static px_type *scale_png_img(px_type *fi_data, int orig_w, int orig_h, int new_w, int new_h) 53 | { 54 | if(orig_w == new_w && orig_h == new_h) 55 | return fi_data; 56 | 57 | uint32_t *in = (uint32_t*)fi_data; 58 | #if PIXEL_SIZE == 2 59 | // need another byte for alpha. Make it 4 to make it simpler 60 | uint32_t *out = malloc(4 * new_w * new_h); 61 | #else 62 | uint32_t *out = malloc(PIXEL_SIZE * new_w * new_h); 63 | #endif 64 | 65 | const int YD = (orig_h / new_h) * orig_w - orig_w; 66 | const int YR = orig_h % new_h; 67 | const int XD = orig_w / new_w; 68 | const int XR = orig_w % new_w; 69 | int in_off = 0, out_off = 0; 70 | int x, y, YE, XE; 71 | 72 | for(y = new_h, YE = 0; y > 0; --y) 73 | { 74 | for(x = new_w, XE = 0; x > 0; --x) 75 | { 76 | out[out_off++] = in[in_off]; 77 | in_off += XD; 78 | XE += XR; 79 | if(XE >= new_w) 80 | { 81 | XE -= new_w; 82 | ++in_off; 83 | } 84 | } 85 | in_off += YD; 86 | YE += YR; 87 | if(YE >= new_h) 88 | { 89 | YE -= new_h; 90 | in_off += orig_w; 91 | } 92 | } 93 | 94 | free(fi_data); 95 | return (px_type*)out; 96 | } 97 | 98 | static px_type *load_png(const char *path, int destW, int destH) 99 | { 100 | FILE *fp; 101 | unsigned char header[8]; 102 | png_structp png_ptr = NULL; 103 | png_infop info_ptr = NULL; 104 | uint32_t bytes_per_row; 105 | px_type *data_dest = NULL, *data_itr; 106 | size_t i, y; 107 | int si, alpha; 108 | int px_per_row; 109 | uint32_t src_pix; 110 | png_bytep *rows = NULL; 111 | 112 | fp = fopen(path, "rbe"); 113 | if(!fp) 114 | return NULL; 115 | 116 | size_t bytesRead = fread(header, 1, sizeof(header), fp); 117 | if (bytesRead != sizeof(header)) { 118 | goto exit; 119 | } 120 | 121 | if (png_sig_cmp(header, 0, sizeof(header))) { 122 | goto exit; 123 | } 124 | 125 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 126 | if (!png_ptr) { 127 | goto exit; 128 | } 129 | 130 | info_ptr = png_create_info_struct(png_ptr); 131 | if (!info_ptr) { 132 | goto exit; 133 | } 134 | 135 | if (setjmp(png_jmpbuf(png_ptr))) { 136 | goto exit; 137 | } 138 | 139 | png_set_packing(png_ptr); 140 | 141 | png_init_io(png_ptr, fp); 142 | png_set_sig_bytes(png_ptr, sizeof(header)); 143 | png_read_info(png_ptr, info_ptr); 144 | 145 | png_uint_32 width, height; 146 | size_t stride, pixelSize; 147 | int color_type, bit_depth, channels; 148 | 149 | png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 150 | NULL, NULL, NULL); 151 | 152 | channels = png_get_channels(png_ptr, info_ptr); 153 | stride = 4 * width; 154 | pixelSize = stride * height; 155 | 156 | if (!(bit_depth == 8 && 157 | ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || 158 | (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA)))) { 159 | goto exit; 160 | } 161 | 162 | if (color_type == PNG_COLOR_TYPE_PALETTE) 163 | png_set_palette_to_rgb(png_ptr); 164 | 165 | png_set_interlace_handling(png_ptr); 166 | png_read_update_info(png_ptr, info_ptr); 167 | 168 | #if PIXEL_SIZE == 2 169 | // need another byte for alpha. Make it 4 to make it simpler 170 | data_dest = malloc(4 * width * height); 171 | #else 172 | data_dest = malloc(PIXEL_SIZE * width * height); 173 | #endif 174 | data_itr = data_dest; 175 | 176 | bytes_per_row = png_get_rowbytes(png_ptr, info_ptr); 177 | rows = malloc(sizeof(png_bytep)*height); 178 | for(y = 0; y < height; ++y) 179 | rows[y] = malloc(bytes_per_row); 180 | png_read_image(png_ptr, rows); 181 | 182 | for(y = 0; y < height; ++y) 183 | { 184 | for(i = 0, si = 0; i < width; ++i) 185 | { 186 | if(channels == 4) 187 | { 188 | src_pix = ((uint32_t*)rows[y])[i]; 189 | src_pix = (src_pix & 0xFF00FF00) | ((src_pix & 0xFF0000) >> 16) | ((src_pix & 0xFF) << 16); 190 | } 191 | else //if(channels == 3) - no other option 192 | { 193 | src_pix = (rows[y][si++] << 16); // R 194 | src_pix |= (rows[y][si++] << 8); // G 195 | src_pix |= (rows[y][si++]); // B 196 | src_pix |= 0xFF000000; // A 197 | } 198 | 199 | *data_itr = (px_type)fb_convert_color(src_pix); 200 | ++data_itr; 201 | #if PIXEL_SIZE == 2 202 | // Store alpha value for 5 and 6 bit values in next two bytes 203 | alpha = ((src_pix & 0xFF000000) >> 24); 204 | ((uint8_t*)data_itr)[0] = ((((alpha*100)/0xFF)*31)/100); 205 | ((uint8_t*)data_itr)[1] = ((((alpha*100)/0xFF)*63)/100); 206 | ++data_itr; 207 | #endif 208 | } 209 | free(rows[y]); 210 | } 211 | free(rows); 212 | 213 | data_dest = scale_png_img(data_dest, width, height, destW, destH); 214 | exit: 215 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 216 | fclose(fp); 217 | 218 | return data_dest; 219 | } 220 | 221 | static void destroy_png_cache_entry(void *entry) 222 | { 223 | struct png_cache_entry *e = (struct png_cache_entry*)entry; 224 | free(e->path); 225 | free(e->data); 226 | free(e); 227 | } 228 | 229 | px_type *fb_png_get(const char *path, int w, int h) 230 | { 231 | // Try to find it in cache 232 | struct png_cache_entry **itr; 233 | for(itr = png_cache; itr && *itr; ++itr) 234 | { 235 | if((*itr)->width == w && (*itr)->height == h && strcmp(path, (*itr)->path) == 0) 236 | { 237 | ++(*itr)->refcnt; 238 | PNG_LOG("PNG %s (%dx%d) %p found in cache, refcnt increased to %d\n", path, w, h, (*itr)->data, (*itr)->refcnt); 239 | return (*itr)->data; 240 | } 241 | } 242 | 243 | // not in cache yet, load and create cache entry 244 | px_type *data = load_png(path, w, h); 245 | if(!data) 246 | { 247 | PNG_LOG("PNG %s (%dx%d) failed to load\n", path, w, h); 248 | return NULL; 249 | } 250 | PNG_LOG("PNG %s (%dx%d) loaded\n", path, w, h); 251 | 252 | struct png_cache_entry *e = mzalloc(sizeof(struct png_cache_entry)); 253 | e->path = strdup(path); 254 | e->data = data; 255 | e->width = w; 256 | e->height = h; 257 | e->refcnt = 1; 258 | 259 | list_add(&png_cache, e); 260 | PNG_LOG("PNG %s (%dx%d) %p added into cache\n", path, w, h, data); 261 | return data; 262 | } 263 | 264 | void fb_png_release(px_type *data) 265 | { 266 | struct png_cache_entry **itr; 267 | for(itr = png_cache; itr && *itr; ++itr) 268 | { 269 | if((*itr)->data == data) 270 | { 271 | --(*itr)->refcnt; 272 | PNG_LOG("PNG %s (%dx%d) %p released, refcnt is %d\n", (*itr)->path, (*itr)->width, (*itr)->height, data, (*itr)->refcnt); 273 | return; 274 | } 275 | } 276 | PNG_LOG("PNG %p not found in cache!\n", data); 277 | } 278 | 279 | void fb_png_drop_unused(void) 280 | { 281 | struct png_cache_entry **itr; 282 | for(itr = png_cache; itr && *itr;) 283 | { 284 | if((*itr)->refcnt <= 0) 285 | { 286 | PNG_LOG("PNG %s (%dx%d) %p removed from cache\n", (*itr)->path, (*itr)->width, (*itr)->height, data); 287 | list_rm(&png_cache, *itr, &destroy_png_cache_entry); 288 | itr = png_cache; 289 | } 290 | else 291 | { 292 | ++itr; 293 | } 294 | } 295 | } 296 | 297 | static inline void convert_fb_px_to_rgb888(px_type src, uint8_t *dest) 298 | { 299 | dest[0] = PX_GET_R(src); 300 | dest[1] = PX_GET_G(src); 301 | dest[2] = PX_GET_B(src); 302 | } 303 | 304 | int fb_png_save_img(const char *path, int w, int h, int stride, px_type *data) 305 | { 306 | FILE *fp = NULL; 307 | png_structp png_ptr = NULL; 308 | png_infop info_ptr = NULL; 309 | int res = -1; 310 | int y, x; 311 | uint8_t *row = NULL; 312 | const int stride_leftover = stride - w; 313 | const int w_png_bytes = w * 3; 314 | px_type * volatile itr = data; 315 | 316 | fp = fopen(path, "we"); 317 | if(!fp) 318 | { 319 | ERROR("Failed to open %s for writing\n", path); 320 | return -1; 321 | } 322 | 323 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 324 | if (!png_ptr) 325 | goto exit; 326 | 327 | info_ptr = png_create_info_struct(png_ptr); 328 | if (info_ptr == NULL) 329 | goto exit; 330 | 331 | if (setjmp(png_jmpbuf(png_ptr))) 332 | goto exit; 333 | 334 | png_init_io(png_ptr, fp); 335 | png_set_IHDR(png_ptr, info_ptr, w, h, 336 | 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, 337 | PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 338 | png_write_info(png_ptr, info_ptr); 339 | 340 | row = malloc(w*3); 341 | for(y = 0; y < h; ++y) 342 | { 343 | for(x = 0; x < w_png_bytes; x += 3) 344 | { 345 | convert_fb_px_to_rgb888(*itr, row + x); 346 | ++itr; 347 | } 348 | itr += stride_leftover; 349 | 350 | png_write_row(png_ptr, row); 351 | } 352 | 353 | png_write_end(png_ptr, NULL); 354 | res = 0; 355 | exit: 356 | if(info_ptr) 357 | png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); 358 | if(png_ptr) 359 | png_destroy_write_struct(&png_ptr, (png_infopp)NULL); 360 | if(fp) 361 | fclose(fp); 362 | if(row) 363 | free(row); 364 | return res; 365 | } 366 | -------------------------------------------------------------------------------- /lib/framebuffer_qcom_overlay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "framebuffer.h" 32 | #include "log.h" 33 | #include "util.h" 34 | 35 | #ifdef MR_QCOM_OVERLAY_HEADER 36 | #include MR_QCOM_OVERLAY_HEADER 37 | #endif 38 | 39 | #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) 40 | #define MAX_DISPLAY_DIM 2048 41 | #define NUM_BUFFERS 3 42 | 43 | struct fb_qcom_overlay_mem_info { 44 | uint8_t *mem_buf; 45 | int size; 46 | int ion_fd; 47 | int mem_fd; 48 | int offset; 49 | struct ion_handle_data handle_data; 50 | }; 51 | 52 | struct fb_qcom_vsync { 53 | int fb_fd; 54 | int enabled; 55 | volatile int _run_thread; 56 | pthread_t thread; 57 | pthread_mutex_t mutex; 58 | pthread_cond_t cond; 59 | struct timespec time; 60 | }; 61 | 62 | struct fb_qcom_overlay_data { 63 | struct fb_qcom_overlay_mem_info mem_info[NUM_BUFFERS]; 64 | struct fb_qcom_vsync *vsync; 65 | int active_mem; 66 | int overlayL_id; 67 | int overlayR_id; 68 | int leftSplit; 69 | int rightSplit; 70 | int width; 71 | }; 72 | 73 | #define VSYNC_PREFIX "VSYNC=" 74 | 75 | #ifdef MR_QCOM_OVERLAY_USE_VSYNC 76 | static int fb_qcom_vsync_enable(struct fb_qcom_vsync *vs, int enable) 77 | { 78 | clock_gettime(CLOCK_MONOTONIC, &vs->time); 79 | 80 | if(vs->enabled != enable) 81 | { 82 | if(vs->fb_fd < 0 || ioctl(vs->fb_fd, MSMFB_OVERLAY_VSYNC_CTRL, &enable) < 0) 83 | { 84 | ERROR("Failed to set vsync status\n"); 85 | return -1; 86 | } 87 | 88 | vs->enabled = enable; 89 | } 90 | 91 | return 0; 92 | } 93 | 94 | static void *fb_qcom_vsync_thread_work(void *data) 95 | { 96 | struct fb_qcom_vsync *vs = data; 97 | int fd, err, len; 98 | struct pollfd pfd; 99 | struct timespec now; 100 | uint64_t vsync_timestamp; 101 | uint64_t now_timestamp; 102 | char buff[64]; 103 | 104 | fd = open("/sys/class/graphics/fb0/vsync_event", O_RDONLY | O_CLOEXEC); 105 | if(fd < 0) 106 | { 107 | ERROR("Unable to open vsync_event!\n"); 108 | return NULL; 109 | } 110 | 111 | read(fd, buff, sizeof(buff)); 112 | pfd.fd = fd; 113 | pfd.events = POLLPRI | POLLERR; 114 | 115 | while(vs->_run_thread) 116 | { 117 | err = poll(&pfd, 1, 10); 118 | if(err <= 0) 119 | continue; 120 | 121 | if(pfd.revents & POLLPRI) 122 | { 123 | len = pread(pfd.fd, buff, sizeof(buff)-1, 0); 124 | if(len > 0) 125 | { 126 | buff[len] = 0; 127 | if(strncmp(buff, VSYNC_PREFIX, strlen(VSYNC_PREFIX)) == 0) 128 | { 129 | vsync_timestamp = strtoull(buff + strlen(VSYNC_PREFIX), NULL, 10); 130 | clock_gettime(CLOCK_MONOTONIC, &now); 131 | now_timestamp = ((uint64_t)now.tv_sec) * 1000000000ULL + now.tv_nsec; 132 | if(vsync_timestamp > now_timestamp) 133 | usleep((vsync_timestamp - now_timestamp)/1000); 134 | 135 | pthread_cond_signal(&vs->cond); 136 | } 137 | } 138 | else 139 | ERROR("Unable to read from vsync_event!"); 140 | } 141 | 142 | clock_gettime(CLOCK_MONOTONIC, &now); 143 | if(timespec_diff(&vs->time, &now) >= 60) 144 | fb_qcom_vsync_enable(vs, 0); 145 | } 146 | 147 | close(fd); 148 | return NULL; 149 | } 150 | #endif // #ifdef MR_QCOM_OVERLAY_USE_VSYNC 151 | 152 | static struct fb_qcom_vsync *fb_qcom_vsync_init(int fb_fd) 153 | { 154 | struct fb_qcom_vsync *res = mzalloc(sizeof(struct fb_qcom_vsync)); 155 | res->fb_fd = fb_fd; 156 | #ifdef MR_QCOM_OVERLAY_USE_VSYNC 157 | res->_run_thread = 1; 158 | pthread_mutex_init(&res->mutex, NULL); 159 | pthread_cond_init(&res->cond, NULL); 160 | pthread_create(&res->thread, NULL, &fb_qcom_vsync_thread_work, res); 161 | #endif 162 | return res; 163 | } 164 | 165 | static void fb_qcom_vsync_destroy(struct fb_qcom_vsync *vs) 166 | { 167 | #ifdef MR_QCOM_OVERLAY_USE_VSYNC 168 | pthread_mutex_lock(&vs->mutex); 169 | vs->_run_thread = 0; 170 | pthread_mutex_unlock(&vs->mutex); 171 | pthread_join(vs->thread, NULL); 172 | pthread_mutex_destroy(&vs->mutex); 173 | pthread_cond_destroy(&vs->cond); 174 | #endif 175 | 176 | free(vs); 177 | } 178 | 179 | static int fb_qcom_vsync_wait(UNUSED struct fb_qcom_vsync *vs) 180 | { 181 | #ifdef MR_QCOM_OVERLAY_USE_VSYNC 182 | int res; 183 | struct timespec ts; 184 | 185 | pthread_mutex_lock(&vs->mutex); 186 | 187 | if(!vs->_run_thread) 188 | { 189 | pthread_mutex_unlock(&vs->mutex); 190 | return 0; 191 | } 192 | 193 | fb_qcom_vsync_enable(vs, 1); 194 | 195 | clock_gettime(CLOCK_REALTIME, &ts); 196 | ts.tv_nsec += 20*1000*1000; 197 | if(ts.tv_nsec >= 1000000000) 198 | { 199 | ts.tv_nsec -= 1000000000; 200 | ++ts.tv_sec; 201 | } 202 | 203 | res = pthread_cond_timedwait(&vs->cond, &vs->mutex, &ts); 204 | pthread_mutex_unlock(&vs->mutex); 205 | 206 | return res; 207 | #else 208 | return 0; 209 | #endif 210 | } 211 | 212 | 213 | static int map_mdp_pixel_format() 214 | { 215 | int format; 216 | #ifdef MR_QCOM_OVERLAY_CUSTOM_PIXEL_FORMAT 217 | format = MR_QCOM_OVERLAY_CUSTOM_PIXEL_FORMAT; 218 | #else 219 | /* We can't set format here because their IDs are different on aosp and CM kernels. 220 | * There is literally just one line different between their headers, and it breaks it. 221 | * MDP_FB_FORMAT works because it translates to MDP_IMGTYPE2_START, which is the same 222 | * on both. It means it will take the format from the framebuffer. */ 223 | format = MDP_FB_FORMAT; 224 | #endif 225 | return format; 226 | } 227 | 228 | static void setDisplaySplit(struct fb_qcom_overlay_data *data) 229 | { 230 | char split[64] = { 0 }; 231 | FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "re"); 232 | if(fp) 233 | { 234 | //Format "left right" space as delimiter 235 | if(fread(split, sizeof(char), 64, fp)) 236 | { 237 | data->leftSplit = atoi(split); 238 | INFO("Left Split=%d\n",data->leftSplit); 239 | char *rght = strpbrk(split, " "); 240 | if(rght) 241 | data->rightSplit = atoi(rght + 1); 242 | INFO("Right Split=%d\n", data->rightSplit); 243 | } 244 | fclose(fp); 245 | } 246 | } 247 | 248 | static int isDisplaySplit(struct fb_qcom_overlay_data *data) 249 | { 250 | if(data->width > MAX_DISPLAY_DIM) 251 | return 1; 252 | 253 | //check if right split is set by driver 254 | if(data->rightSplit) 255 | return 1; 256 | 257 | return 0; 258 | } 259 | 260 | static int free_ion_mem(struct fb_qcom_overlay_data *data) 261 | { 262 | int ret = 0, i; 263 | struct fb_qcom_overlay_mem_info *info; 264 | for(i = 0; i < NUM_BUFFERS; ++i) 265 | { 266 | info = &data->mem_info[i]; 267 | 268 | if(info->mem_buf) 269 | munmap(info->mem_buf, info->size); 270 | 271 | if(info->ion_fd >= 0) 272 | { 273 | ret = ioctl(info->ion_fd, ION_IOC_FREE, &info->handle_data); 274 | if(ret < 0) 275 | ERROR("free_mem failed "); 276 | } 277 | 278 | if(info->mem_fd >= 0) 279 | close(info->mem_fd); 280 | 281 | if(info->ion_fd >= 0) 282 | close(info->ion_fd); 283 | } 284 | return 0; 285 | } 286 | 287 | static int alloc_ion_mem(struct fb_qcom_overlay_data *data, unsigned int size) 288 | { 289 | int result, i; 290 | struct ion_fd_data fd_data; 291 | struct ion_allocation_data ionAllocData; 292 | struct fb_qcom_overlay_mem_info *info; 293 | 294 | ionAllocData.flags = 0; 295 | ionAllocData.len = size; 296 | ionAllocData.align = sysconf(_SC_PAGESIZE); 297 | 298 | // are you kidding me -.- 299 | #if (PLATFORM_SDK_VERSION >= 21) 300 | ionAllocData.heap_id_mask = 301 | #else 302 | ionAllocData.heap_mask = 303 | #endif 304 | ION_HEAP(ION_IOMMU_HEAP_ID) | 305 | ION_HEAP(21); // ION_SYSTEM_CONTIG_HEAP_ID 306 | 307 | for(i = 0; i < NUM_BUFFERS; ++i) 308 | { 309 | info = &data->mem_info[i]; 310 | 311 | info->ion_fd = open("/dev/ion", O_RDWR|O_DSYNC|O_CLOEXEC); 312 | if(info->ion_fd < 0) 313 | { 314 | ERROR("ERROR: Can't open ion "); 315 | return -errno; 316 | } 317 | 318 | result = ioctl(info->ion_fd, ION_IOC_ALLOC, &ionAllocData); 319 | if(result) 320 | { 321 | ERROR("ION_IOC_ALLOC Failed "); 322 | close(info->ion_fd); 323 | return result; 324 | } 325 | 326 | fd_data.handle = ionAllocData.handle; 327 | info->handle_data.handle = ionAllocData.handle; 328 | result = ioctl(info->ion_fd, ION_IOC_MAP, &fd_data); 329 | if(result) 330 | { 331 | ERROR("ION_IOC_MAP Failed "); 332 | free_ion_mem(data); 333 | return result; 334 | } 335 | info->mem_buf = (uint8_t*)mmap(NULL, size, PROT_READ | 336 | PROT_WRITE, MAP_SHARED, fd_data.fd, 0); 337 | info->mem_fd = fd_data.fd; 338 | 339 | if(info->mem_buf == MAP_FAILED) 340 | { 341 | ERROR("ERROR: mem_buf MAP_FAILED "); 342 | info->mem_buf = NULL; 343 | free_ion_mem(data); 344 | return -ENOMEM; 345 | } 346 | 347 | info->offset = 0; 348 | } 349 | 350 | return 0; 351 | } 352 | 353 | 354 | static int allocate_overlay(struct fb_qcom_overlay_data *data, int fd, int width, int height) 355 | { 356 | int ret = 0; 357 | 358 | if(!isDisplaySplit(data)) 359 | { 360 | // Check if overlay is already allocated 361 | if(data->overlayL_id == MSMFB_NEW_REQUEST) 362 | { 363 | struct mdp_overlay overlayL; 364 | 365 | memset(&overlayL, 0 , sizeof (struct mdp_overlay)); 366 | 367 | /* Fill Overlay Data */ 368 | overlayL.src.width = ALIGN(width, 32); 369 | overlayL.src.height = height; 370 | overlayL.src.format = map_mdp_pixel_format(); 371 | overlayL.src_rect.w = width; 372 | overlayL.src_rect.h = height; 373 | overlayL.dst_rect.w = width; 374 | overlayL.dst_rect.h = height; 375 | overlayL.alpha = 0xFF; 376 | overlayL.transp_mask = MDP_TRANSP_NOP; 377 | overlayL.id = MSMFB_NEW_REQUEST; 378 | ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL); 379 | if(ret < 0) 380 | { 381 | ERROR("Overlay Set Failed"); 382 | return ret; 383 | } 384 | data->overlayL_id = overlayL.id; 385 | } 386 | } 387 | else 388 | { 389 | float xres = data->width; 390 | int lSplit = data->leftSplit; 391 | float lSplitRatio = lSplit / xres; 392 | float lCropWidth = width * lSplitRatio; 393 | int lWidth = lSplit; 394 | int rWidth = width - lSplit; 395 | 396 | if(data->overlayL_id == MSMFB_NEW_REQUEST) 397 | { 398 | struct mdp_overlay overlayL; 399 | 400 | memset(&overlayL, 0 , sizeof (struct mdp_overlay)); 401 | 402 | /* Fill OverlayL Data */ 403 | overlayL.src.width = ALIGN(width, 32); 404 | overlayL.src.height = height; 405 | overlayL.src.format = map_mdp_pixel_format(); 406 | overlayL.src_rect.x = 0; 407 | overlayL.src_rect.y = 0; 408 | overlayL.src_rect.w = lCropWidth; 409 | overlayL.src_rect.h = height; 410 | overlayL.dst_rect.x = 0; 411 | overlayL.dst_rect.y = 0; 412 | overlayL.dst_rect.w = lWidth; 413 | overlayL.dst_rect.h = height; 414 | overlayL.alpha = 0xFF; 415 | overlayL.transp_mask = MDP_TRANSP_NOP; 416 | overlayL.id = MSMFB_NEW_REQUEST; 417 | ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL); 418 | if(ret < 0) 419 | { 420 | ERROR("OverlayL Set Failed"); 421 | return ret; 422 | } 423 | data->overlayL_id = overlayL.id; 424 | } 425 | 426 | if(data->overlayR_id == MSMFB_NEW_REQUEST) 427 | { 428 | struct mdp_overlay overlayR; 429 | 430 | memset(&overlayR, 0 , sizeof (struct mdp_overlay)); 431 | 432 | /* Fill OverlayR Data */ 433 | overlayR.src.width = ALIGN(width, 32); 434 | overlayR.src.height = height; 435 | overlayR.src.format = map_mdp_pixel_format(); 436 | overlayR.src_rect.x = lCropWidth; 437 | overlayR.src_rect.y = 0; 438 | overlayR.src_rect.w = width - lCropWidth; 439 | overlayR.src_rect.h = height; 440 | overlayR.dst_rect.x = 0; 441 | overlayR.dst_rect.y = 0; 442 | overlayR.dst_rect.w = rWidth; 443 | overlayR.dst_rect.h = height; 444 | overlayR.alpha = 0xFF; 445 | overlayR.flags = MDSS_MDP_RIGHT_MIXER; 446 | overlayR.transp_mask = MDP_TRANSP_NOP; 447 | overlayR.id = MSMFB_NEW_REQUEST; 448 | ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayR); 449 | if(ret < 0) 450 | { 451 | ERROR("OverlayR Set Failed"); 452 | return ret; 453 | } 454 | data->overlayR_id = overlayR.id; 455 | } 456 | } 457 | 458 | return 0; 459 | } 460 | 461 | static int free_overlay(struct fb_qcom_overlay_data *data, int fd) 462 | { 463 | int ret = 0; 464 | struct mdp_display_commit ext_commit; 465 | 466 | if(!isDisplaySplit(data)) 467 | { 468 | if(data->overlayL_id != MSMFB_NEW_REQUEST) 469 | { 470 | ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &data->overlayL_id); 471 | if(ret) 472 | { 473 | ERROR("OverlayL Unset Failed"); 474 | data->overlayL_id = MSMFB_NEW_REQUEST; 475 | return ret; 476 | } 477 | } 478 | } 479 | else 480 | { 481 | if(data->overlayL_id != MSMFB_NEW_REQUEST) 482 | { 483 | ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &data->overlayL_id); 484 | if(ret) 485 | { 486 | ERROR("OverlayL Unset Failed"); 487 | data->overlayL_id = MSMFB_NEW_REQUEST; 488 | return ret; 489 | } 490 | } 491 | 492 | if(data->overlayR_id != MSMFB_NEW_REQUEST) 493 | { 494 | ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &data->overlayR_id); 495 | if(ret) 496 | { 497 | ERROR("OverlayR Unset Failed"); 498 | data->overlayR_id = MSMFB_NEW_REQUEST; 499 | return ret; 500 | } 501 | } 502 | } 503 | 504 | memset(&ext_commit, 0, sizeof(struct mdp_display_commit)); 505 | ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY; 506 | 507 | data->overlayL_id = MSMFB_NEW_REQUEST; 508 | data->overlayR_id = MSMFB_NEW_REQUEST; 509 | 510 | ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit); 511 | if(ret < 0) 512 | { 513 | ERROR("Clear MSMFB_DISPLAY_COMMIT failed!"); 514 | return ret; 515 | } 516 | 517 | return 0; 518 | } 519 | 520 | static int impl_open(struct framebuffer *fb) 521 | { 522 | struct fb_qcom_overlay_data *data = mzalloc(sizeof(struct fb_qcom_overlay_data)); 523 | data->overlayL_id = MSMFB_NEW_REQUEST; 524 | data->overlayR_id = MSMFB_NEW_REQUEST; 525 | data->width = fb->vi.xres; 526 | data->leftSplit = data->width / 2; 527 | 528 | setDisplaySplit(data); 529 | 530 | #ifdef TW_SCREEN_BLANK_ON_BOOT 531 | ioctl(fb->fd, FBIOBLANK, FB_BLANK_POWERDOWN); 532 | ioctl(fb->fd, FBIOBLANK, FB_BLANK_UNBLANK); 533 | #endif 534 | 535 | if(alloc_ion_mem(data, fb->fi.line_length * fb->vi.yres) < 0) 536 | goto fail; 537 | 538 | if(allocate_overlay(data, fb->fd, fb->vi.xres, fb->vi.yres) < 0) 539 | { 540 | free_ion_mem(data); 541 | goto fail; 542 | } 543 | 544 | data->vsync = fb_qcom_vsync_init(fb->fd); 545 | 546 | fb->impl_data = data; 547 | return 0; 548 | 549 | fail: 550 | free(data); 551 | return -1; 552 | } 553 | 554 | static void impl_close(struct framebuffer *fb) 555 | { 556 | struct fb_qcom_overlay_data *data = fb->impl_data; 557 | fb_qcom_vsync_destroy(data->vsync); 558 | free_overlay(data, fb->fd); 559 | free_ion_mem(data); 560 | free(data); 561 | fb->impl_data = NULL; 562 | } 563 | 564 | static int impl_update(struct framebuffer *fb) 565 | { 566 | int ret = 0; 567 | struct msmfb_overlay_data ovdataL, ovdataR; 568 | struct mdp_display_commit ext_commit; 569 | struct fb_qcom_overlay_data *data = fb->impl_data; 570 | struct fb_qcom_overlay_mem_info *info = &data->mem_info[data->active_mem]; 571 | 572 | if(!isDisplaySplit(data)) 573 | { 574 | if(data->overlayL_id == MSMFB_NEW_REQUEST) 575 | { 576 | ERROR("display_frame failed, no overlay\n"); 577 | return -EINVAL; 578 | } 579 | 580 | memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data)); 581 | 582 | ovdataL.id = data->overlayL_id; 583 | ovdataL.data.flags = 0; 584 | ovdataL.data.offset = info->offset; 585 | ovdataL.data.memory_id = info->mem_fd; 586 | ret = ioctl(fb->fd, MSMFB_OVERLAY_PLAY, &ovdataL); 587 | if(ret < 0) 588 | { 589 | ERROR("overlay_display_frame failed, overlay play Failed\n"); 590 | return -1; 591 | } 592 | } 593 | else 594 | { 595 | if(data->overlayL_id == MSMFB_NEW_REQUEST) 596 | { 597 | ERROR("display_frame failed, no overlayL \n"); 598 | return -EINVAL; 599 | } 600 | 601 | memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data)); 602 | 603 | ovdataL.id = data->overlayL_id; 604 | ovdataL.data.flags = 0; 605 | ovdataL.data.offset = info->offset; 606 | ovdataL.data.memory_id = info->mem_fd; 607 | ret = ioctl(fb->fd, MSMFB_OVERLAY_PLAY, &ovdataL); 608 | if(ret < 0) 609 | { 610 | ERROR("overlay_display_frame failed, overlayL play Failed\n"); 611 | return ret; 612 | } 613 | 614 | if(data->overlayR_id == MSMFB_NEW_REQUEST) 615 | { 616 | ERROR("display_frame failed, no overlayR \n"); 617 | return -EINVAL; 618 | } 619 | 620 | memset(&ovdataR, 0, sizeof(struct msmfb_overlay_data)); 621 | 622 | ovdataR.id = data->overlayR_id; 623 | ovdataR.data.flags = 0; 624 | ovdataR.data.offset = info->offset; 625 | ovdataR.data.memory_id = info->mem_fd; 626 | ret = ioctl(fb->fd, MSMFB_OVERLAY_PLAY, &ovdataR); 627 | if(ret < 0) 628 | { 629 | ERROR("overlay_display_frame failed, overlayR play Failed\n"); 630 | return ret; 631 | } 632 | } 633 | 634 | memset(&ext_commit, 0, sizeof(struct mdp_display_commit)); 635 | ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY; 636 | 637 | fb_qcom_vsync_wait(data->vsync); 638 | 639 | ret = ioctl(fb->fd, MSMFB_DISPLAY_COMMIT, &ext_commit); 640 | if(ret < 0) 641 | { 642 | ERROR("overlay_display_frame failed, overlay commit Failed\n!"); 643 | return -1; 644 | } 645 | 646 | if(++data->active_mem >= NUM_BUFFERS) 647 | data->active_mem = 0; 648 | 649 | return ret; 650 | } 651 | 652 | static void *impl_get_frame_dest(struct framebuffer *fb) 653 | { 654 | struct fb_qcom_overlay_data *data = fb->impl_data; 655 | return data->mem_info[data->active_mem].mem_buf; 656 | } 657 | 658 | const struct fb_impl fb_impl_qcom_overlay = { 659 | .name = "Qualcomm ION overlay", 660 | .impl_id = FB_IMPL_QCOM_OVERLAY, 661 | 662 | .open = impl_open, 663 | .close = impl_close, 664 | .update = impl_update, 665 | .get_frame_dest = impl_get_frame_dest, 666 | }; 667 | -------------------------------------------------------------------------------- /lib/fstab.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "fstab.h" 27 | #include "util.h" 28 | #include "log.h" 29 | #include "containers.h" 30 | 31 | // flags from system/core/fs_mgr/fs_mgr.c 32 | struct flag_list { 33 | const char *name; 34 | unsigned flag; 35 | }; 36 | 37 | static struct flag_list mount_flags[] = { 38 | { "noatime", MS_NOATIME }, 39 | { "noexec", MS_NOEXEC }, 40 | { "nosuid", MS_NOSUID }, 41 | { "nodev", MS_NODEV }, 42 | { "nodiratime", MS_NODIRATIME }, 43 | { "ro", MS_RDONLY }, 44 | { "rw", 0 }, 45 | { "remount", MS_REMOUNT }, 46 | { "bind", MS_BIND }, 47 | { "rec", MS_REC }, 48 | { "unbindable", MS_UNBINDABLE }, 49 | { "private", MS_PRIVATE }, 50 | { "slave", MS_SLAVE }, 51 | { "shared", MS_SHARED }, 52 | { "sync", MS_SYNCHRONOUS }, 53 | { "defaults", 0 }, 54 | { 0, 0 }, 55 | }; 56 | 57 | struct fstab *fstab_create_empty(int version) 58 | { 59 | struct fstab *t = mzalloc(sizeof(struct fstab)); 60 | t->version = version; 61 | return t; 62 | } 63 | 64 | struct fstab *fstab_load(const char *path, int resolve_symlinks) 65 | { 66 | FILE *f = fopen(path, "re"); 67 | if(!f) 68 | { 69 | ERROR("Failed to open fstab %s\n", path); 70 | return NULL; 71 | } 72 | 73 | struct fstab *t = fstab_create_empty(-1); 74 | const char *delim = " \t"; 75 | char *saveptr = NULL; 76 | char *p; 77 | char line[1024]; 78 | int len, is_dev_on_line = 0; 79 | struct fstab_part *part = NULL; 80 | 81 | t->path = strdup(path); 82 | 83 | while((p = fgets(line, sizeof(line), f))) 84 | { 85 | len = strlen(line); 86 | if(line[len-1] == '\n') 87 | line[len-1] = 0; 88 | 89 | while(isspace(*p)) 90 | ++p; 91 | 92 | if(*p == '#' || *p == 0) 93 | continue; 94 | 95 | if(t->version == -1) 96 | is_dev_on_line = (strstr(line, "/dev/") != NULL); 97 | 98 | part = mzalloc(sizeof(struct fstab_part)); 99 | 100 | if(!(p = strtok_r(line, delim, &saveptr))) 101 | { 102 | ERROR("Error first token\n"); 103 | goto fail; 104 | } 105 | 106 | if(t->version == -1) 107 | { 108 | if(is_dev_on_line && strstr(p, "/dev/") != p) 109 | t->version = 1; 110 | else 111 | t->version = 2; 112 | } 113 | 114 | if(t->version == 2) 115 | part->device = resolve_symlinks ? readlink_recursive(p) : strdup(p); 116 | else 117 | part->path = strdup (p); 118 | 119 | if(!(p = strtok_r(NULL, delim, &saveptr))) 120 | { 121 | ERROR("Error second token\n"); 122 | goto fail; 123 | } 124 | 125 | if(t->version == 2) 126 | part->path = strdup(p); 127 | else 128 | part->type = strdup(p); 129 | 130 | if(!(p = strtok_r(NULL, delim, &saveptr))) 131 | { 132 | ERROR("Error third token\n"); 133 | goto fail; 134 | } 135 | 136 | if(t->version == 2) 137 | part->type = strdup(p); 138 | else 139 | part->device = resolve_symlinks ? readlink_recursive(p) : strdup(p); 140 | 141 | if((p = strtok_r(NULL, delim, &saveptr))) 142 | { 143 | part->options_raw = strdup(p); 144 | fstab_parse_options(p, part); 145 | } 146 | 147 | if((p = strtok_r(NULL, delim, &saveptr))) 148 | part->options2 = strdup(p); 149 | 150 | // Check device 151 | if(!part->device) 152 | { 153 | if (strcmp(part->path, "/data") == 0 || strcmp(part->path, "/system") == 0 || 154 | strcmp(part->path, "/boot") == 0 || strcmp(part->path, "/cache") == 0) 155 | { 156 | ERROR("fstab: device for part %s does not exist!\n", part->path); 157 | } 158 | fstab_destroy_part(part); 159 | part = NULL; 160 | continue; 161 | } 162 | 163 | list_add(&t->parts, part); 164 | ++t->count; 165 | part = NULL; 166 | } 167 | 168 | fclose(f); 169 | return t; 170 | 171 | fail: 172 | fclose(f); 173 | free(part); 174 | fstab_destroy(t); 175 | return NULL; 176 | } 177 | 178 | int fstab_save(struct fstab *f, const char *path) 179 | { 180 | int i; 181 | FILE *out; 182 | struct fstab_part *p; 183 | 184 | out = fopen(path, "we"); 185 | if(!f) 186 | { 187 | ERROR("fstab_save: failed to open %s!", path); 188 | return -1; 189 | } 190 | 191 | for(i = 0; i < f->count; ++i) 192 | { 193 | p = f->parts[i]; 194 | if(p->disabled) 195 | fputc('#', out); 196 | 197 | if(f->version == 1) 198 | fprintf(out, "%s\t%s\t%s\t", p->path, p->type, p->device); 199 | else 200 | fprintf(out, "%s\t%s\t%s\t", p->device, p->path, p->type); 201 | fprintf(out, "%s\t%s\n", p->options_raw, p->options2); 202 | } 203 | fclose(out); 204 | return 0; 205 | } 206 | 207 | void fstab_destroy(struct fstab *f) 208 | { 209 | list_clear(&f->parts, fstab_destroy_part); 210 | free(f->path); 211 | free(f); 212 | } 213 | 214 | void fstab_destroy_part(struct fstab_part *p) 215 | { 216 | free(p->path); 217 | free(p->type); 218 | free(p->device); 219 | free(p->options); 220 | free(p->options_raw); 221 | free(p->options2); 222 | free(p); 223 | } 224 | 225 | void fstab_dump(struct fstab *f) 226 | { 227 | INFO("Dumping fstab:\n"); 228 | INFO("version: %d\n", f->version); 229 | INFO("count: %d\n", f->count); 230 | 231 | int i; 232 | for(i = 0; i < f->count; ++i) 233 | { 234 | INFO("Partition %d:\n", i); 235 | INFO(" path: %s\n", f->parts[i]->path); 236 | INFO(" device: %s\n", f->parts[i]->device); 237 | INFO(" type: %s\n", f->parts[i]->type); 238 | INFO(" mountflags: 0x%lX\n", f->parts[i]->mountflags); 239 | INFO(" options: %s\n", f->parts[i]->options); 240 | INFO(" options2: %s\n", f->parts[i]->options2); 241 | } 242 | } 243 | 244 | struct fstab_part *fstab_find_first_by_path(struct fstab *f, const char *path) 245 | { 246 | int i; 247 | for(i = 0; i < f->count; ++i) 248 | if(strcmp(f->parts[i]->path, path) == 0) 249 | return f->parts[i]; 250 | 251 | return NULL; 252 | } 253 | 254 | struct fstab_part *fstab_find_next_by_path(struct fstab *f, const char *path, struct fstab_part *prev) 255 | { 256 | int i, found_prev = 0; 257 | for(i = 0; i < f->count; ++i) 258 | { 259 | if(!found_prev) 260 | { 261 | if(f->parts[i] == prev) 262 | found_prev = 1; 263 | } 264 | else if(strcmp(f->parts[i]->path, path) == 0) 265 | { 266 | return f->parts[i]; 267 | } 268 | } 269 | return NULL; 270 | } 271 | 272 | int fstab_disable_parts(struct fstab *f, const char *path) 273 | { 274 | int i, cnt = 0; 275 | 276 | for(i = 0; i < f->count; ++i) 277 | { 278 | if(strcmp(f->parts[i]->path, path) == 0) 279 | { 280 | f->parts[i]->disabled = 1; 281 | ++cnt; 282 | } 283 | } 284 | 285 | if(cnt == 0) 286 | { 287 | ERROR("Failed to disable partition %s, couldn't find it in fstab!\n", path); 288 | return -1; 289 | } 290 | return cnt; 291 | } 292 | 293 | void fstab_parse_options(char *opt, struct fstab_part *part) 294 | { 295 | int i; 296 | char *p; 297 | char *saveptr = NULL; 298 | 299 | part->options = malloc(strlen(opt) + 2); // NULL and possible trailing comma 300 | part->options[0] = 0; 301 | 302 | p = strtok_r(opt, ",", &saveptr); 303 | while(p) 304 | { 305 | for(i = 0; mount_flags[i].name; ++i) 306 | { 307 | if(strcmp(mount_flags[i].name, p) == 0) 308 | { 309 | part->mountflags |= mount_flags[i].flag; 310 | break; 311 | } 312 | } 313 | 314 | if(!mount_flags[i].name) 315 | { 316 | strcat(part->options, p); 317 | strcat(part->options, ","); 318 | } 319 | 320 | p = strtok_r(NULL, ",", &saveptr); 321 | } 322 | 323 | int len = strlen(part->options); 324 | if(len != 0) 325 | { 326 | part->options[len-1] = 0; // remove trailing comma 327 | part->options = realloc(part->options, len); 328 | } 329 | else 330 | { 331 | free(part->options); 332 | part->options = NULL; 333 | } 334 | } 335 | 336 | struct fstab *fstab_auto_load(void) 337 | { 338 | char path[64]; 339 | path[0] = 0; 340 | 341 | if(access("/mrom.fstab", F_OK) >= 0) 342 | strcpy(path, "/mrom.fstab"); 343 | else 344 | { 345 | DIR *d = opendir("/"); 346 | if(!d) 347 | { 348 | ERROR("Failed to open /\n"); 349 | return NULL; 350 | } 351 | 352 | struct dirent *dt; 353 | while((dt = readdir(d))) 354 | { 355 | if(dt->d_type != DT_REG) 356 | continue; 357 | 358 | // For some reason, CM includes goldfish's fstab, ignore it 359 | // (goldfish is the virtual device for emulator) 360 | if(strcmp(dt->d_name, "fstab.goldfish") == 0) 361 | continue; 362 | 363 | if(strncmp(dt->d_name, "fstab.", sizeof("fstab.")-1) == 0) 364 | { 365 | strcpy(path, "/"); 366 | strcat(path, dt->d_name); 367 | 368 | // try to find specifically fstab.device 369 | #ifdef TARGET_DEVICE 370 | if(strcmp(dt->d_name, "fstab."TARGET_DEVICE) == 0) 371 | break; 372 | #endif 373 | } 374 | } 375 | closedir(d); 376 | } 377 | 378 | if(path[0] == 0) 379 | { 380 | ERROR("Failed to find fstab!\n"); 381 | return NULL; 382 | } 383 | 384 | ERROR("Loading fstab \"%s\"...\n", path); 385 | return fstab_load(path, 1); 386 | } 387 | 388 | void fstab_add_part(struct fstab *f, const char *dev, const char *path, const char *type, const char *options, const char *options2) 389 | { 390 | struct fstab_part *p = mzalloc(sizeof(struct fstab_part)); 391 | p->path = strdup(path); 392 | p->device = strdup(dev); 393 | p->type = strdup(type); 394 | p->options_raw = strdup(options); 395 | fstab_parse_options(p->options_raw, p); 396 | p->options2 = strdup(options2); 397 | 398 | list_add(&f->parts, p); 399 | ++f->count; 400 | } 401 | 402 | struct fstab_part *fstab_clone_part(struct fstab_part *p) 403 | { 404 | struct fstab_part *new_p = mzalloc(sizeof(struct fstab_part)); 405 | memcpy(new_p, p, sizeof(struct fstab_part)); 406 | 407 | new_p->path = strdup(p->path); 408 | new_p->device = strdup(p->device); 409 | new_p->type = strdup(p->type); 410 | new_p->options_raw = strdup(p->options_raw); 411 | new_p->options = strdup(p->options); 412 | new_p->options2 = strdup(p->options2); 413 | 414 | return new_p; 415 | } 416 | 417 | void fstab_add_part_struct(struct fstab *f, struct fstab_part *p) 418 | { 419 | list_add(&f->parts, p); 420 | ++f->count; 421 | } 422 | 423 | void fstab_update_device(struct fstab *f, const char *oldDev, const char *newDev) 424 | { 425 | int i; 426 | char *tmp = strdup(oldDev); 427 | 428 | for(i = 0; i < f->count; ++i) 429 | { 430 | if(strcmp(f->parts[i]->device, tmp) == 0) 431 | { 432 | f->parts[i]->device = realloc(f->parts[i]->device, strlen(newDev)+1); 433 | strcpy(f->parts[i]->device, newDev); 434 | } 435 | } 436 | 437 | free(tmp); 438 | } 439 | -------------------------------------------------------------------------------- /lib/fstab.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef FSTAB_H 19 | #define FSTAB_H 20 | 21 | struct fstab_part 22 | { 23 | char *path; 24 | char *device; 25 | char *type; 26 | char *options_raw; 27 | unsigned long mountflags; 28 | char *options; 29 | char *options2; 30 | int disabled; 31 | }; 32 | 33 | struct fstab 34 | { 35 | int version; 36 | int count; 37 | char *path; 38 | struct fstab_part **parts; 39 | }; 40 | 41 | struct fstab *fstab_create_empty(int version); 42 | struct fstab *fstab_load(const char *path, int resolve_symlinks); 43 | struct fstab *fstab_auto_load(void); 44 | void fstab_destroy(struct fstab *f); 45 | void fstab_destroy_part(struct fstab_part *p); 46 | void fstab_dump(struct fstab *f); 47 | struct fstab_part *fstab_find_first_by_path(struct fstab *f, const char *path); 48 | struct fstab_part *fstab_find_next_by_path(struct fstab *f, const char *path, struct fstab_part *prev); 49 | void fstab_parse_options(char *opt, struct fstab_part *p); 50 | int fstab_save(struct fstab *f, const char *path); 51 | int fstab_disable_parts(struct fstab *f, const char *path); 52 | void fstab_add_part(struct fstab *f, const char *dev, const char *path, const char *type, const char *options, const char *options2); 53 | void fstab_add_part_struct(struct fstab *f, struct fstab_part *p); 54 | struct fstab_part *fstab_clone_part(struct fstab_part *p); 55 | void fstab_update_device(struct fstab *f, const char *oldDev, const char *newDev); 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /lib/inject.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "inject.h" 25 | #include "mrom_data.h" 26 | #include "log.h" 27 | #include "util.h" 28 | #include "../version.h" 29 | 30 | // clone libbootimg to /system/extras/ from 31 | // https://github.com/Tasssadar/libbootimg.git 32 | #include 33 | 34 | #if LIBBOOTIMG_VERSION < 0x000200 35 | #error "libbootimg version 0.2.0 or higher is required. Please update libbootimg." 36 | #endif 37 | 38 | #define TMP_RD_UNPACKED_DIR "/mrom_rd" 39 | #define TMP_RD_INIT_REAL TMP_RD_UNPACKED_DIR "/init.real" 40 | #define TMP_RD2 TMP_RD_UNPACKED_DIR "/sbin/ramdisk.cpio" 41 | #define TMP_RD2_UNPACKED_DIR TMP_RD_UNPACKED_DIR "/second" 42 | 43 | static int get_img_trampoline_ver(struct bootimg *img) 44 | { 45 | int ver = 0; 46 | if (strncmp((char*)img->hdr.name, "tr_ver", 6) == 0) 47 | ver = atoi((char*)img->hdr.name + 6); 48 | return ver; 49 | } 50 | 51 | static int copy_rd_files(UNUSED const char *path, UNUSED const char *busybox_path) 52 | { 53 | char buf[256]; 54 | char init_file[64]; 55 | const int *secRD = access(TMP_RD2, F_OK); 56 | 57 | if (secRD != -1) { 58 | snprintf(init_file, sizeof(init_file), TMP_RD2_UNPACKED_DIR "/init"); 59 | } else if (access(TMP_RD_INIT_REAL, F_OK) != -1) { 60 | snprintf(init_file, sizeof(init_file), TMP_RD_INIT_REAL); 61 | } else { 62 | snprintf(init_file, sizeof(init_file), TMP_RD_UNPACKED_DIR "/init"); 63 | } 64 | 65 | if ((secRD != -1 && access(TMP_RD2_UNPACKED_DIR "/main_init", F_OK) < 0 && 66 | rename(init_file, TMP_RD2_UNPACKED_DIR "/main_init")) || 67 | (secRD == -1 && access(TMP_RD_UNPACKED_DIR "/main_init", F_OK) < 0 && 68 | rename(init_file, TMP_RD_UNPACKED_DIR "/main_init") < 0)) 69 | { 70 | ERROR("Failed to move /init to /main_init!\n"); 71 | return -1; 72 | } 73 | 74 | snprintf(buf, sizeof(buf), "%s/trampoline", mrom_dir()); 75 | if (copy_file(buf, init_file) < 0) 76 | { 77 | ERROR("Failed to copy trampoline to /init!\n"); 78 | return -1; 79 | } 80 | 81 | if (secRD != -1) 82 | { 83 | chmod(init_file, 0750); 84 | 85 | remove(TMP_RD2_UNPACKED_DIR "/sbin/ueventd"); 86 | remove(TMP_RD2_UNPACKED_DIR "/sbin/watchdogd"); 87 | symlink("../main_init", TMP_RD2_UNPACKED_DIR "/sbin/ueventd"); 88 | symlink("../main_init", TMP_RD2_UNPACKED_DIR "/sbin/watchdogd"); 89 | 90 | #ifdef MR_USE_MROM_FSTAB 91 | snprintf(buf, sizeof(buf), "%s/mrom.fstab", mrom_dir()); 92 | copy_file(buf, TMP_RD2_UNPACKED_DIR "/mrom.fstab"); 93 | #else 94 | remove(TMP_RD2_UNPACKED_DIR "/mrom.fstab"); 95 | #endif 96 | } else { 97 | chmod(init_file, 0750); 98 | 99 | remove(TMP_RD_UNPACKED_DIR "/sbin/ueventd"); 100 | remove(TMP_RD_UNPACKED_DIR "/sbin/watchdogd"); 101 | symlink("../main_init", TMP_RD_UNPACKED_DIR "/sbin/ueventd"); 102 | symlink("../main_init", TMP_RD_UNPACKED_DIR "/sbin/watchdogd"); 103 | 104 | #ifdef MR_USE_MROM_FSTAB 105 | snprintf(buf, sizeof(buf), "%s/mrom.fstab", mrom_dir()); 106 | copy_file(buf, TMP_RD_UNPACKED_DIR "/mrom.fstab"); 107 | #else 108 | remove(TMP_RD_UNPACKED_DIR "/mrom.fstab"); 109 | #endif 110 | } 111 | 112 | #ifdef MR_ENCRYPTION 113 | if (secRD != -1) 114 | remove_dir(TMP_RD2_UNPACKED_DIR "/mrom_enc"); 115 | else 116 | remove_dir(TMP_RD_UNPACKED_DIR "/mrom_enc"); 117 | 118 | if ((secRD != -1 && mr_system("busybox cp -a \"%s/enc\" \"%s/mrom_enc\"", mrom_dir(), TMP_RD2_UNPACKED_DIR) != 0) || 119 | (secRD == -1 && mr_system("busybox cp -a \"%s/enc\" \"%s/mrom_enc\"", mrom_dir(), TMP_RD_UNPACKED_DIR) != 0)) 120 | { 121 | ERROR("Failed to copy encryption files!\n"); 122 | return -1; 123 | } 124 | #endif 125 | return 0; 126 | } 127 | 128 | #define RD_GZIP 1 129 | #define RD_LZ4 2 130 | static int inject_second_rd(const char *path, const char *second_path) 131 | { 132 | int result = -1; 133 | uint32_t magic = 0; 134 | 135 | FILE *f = fopen(path, "re"); 136 | if (!f) 137 | { 138 | ERROR("Couldn't open %s!\n", path); 139 | return -1; 140 | } 141 | fread(&magic, sizeof(magic), 1, f); 142 | fclose(f); 143 | 144 | mkdir(TMP_RD2_UNPACKED_DIR, 0755); 145 | 146 | // Decompress initrd 147 | int type; 148 | char buff[256]; 149 | char busybox_path[256]; 150 | snprintf(busybox_path, sizeof(busybox_path), "%s/busybox", mrom_dir()); 151 | 152 | char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; 153 | 154 | snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" cat \"%s\" | \"$B\" cpio -i", busybox_path, TMP_RD2_UNPACKED_DIR, second_path); 155 | 156 | int r; 157 | char *out = run_get_stdout_with_exit(cmd, &r); 158 | if (r != 0) 159 | { 160 | ERROR("Output: %s\n", out); 161 | ERROR("Failed to unpack second ramdisk!%s\n", buff); 162 | goto fail; 163 | } 164 | 165 | // Update files 166 | if (copy_rd_files(second_path, busybox_path) < 0) 167 | goto fail; 168 | 169 | // Pack initrd again 170 | snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc > \"%s\"", busybox_path, TMP_RD2_UNPACKED_DIR, second_path); 171 | 172 | out = run_get_stdout_with_exit(cmd, &r); 173 | if (r != 0) 174 | { 175 | ERROR("Output: %s\n", out); 176 | ERROR("Failed to pack ramdisk.cpio!\n"); 177 | goto fail; 178 | } 179 | success: 180 | result = 0; 181 | fail: 182 | remove_dir(TMP_RD2_UNPACKED_DIR); 183 | return result; 184 | } 185 | 186 | static int inject_rd(const char *path, const char *second_path) 187 | { 188 | int result = -1; 189 | uint32_t magic = 0; 190 | 191 | FILE *f = fopen(path, "re"); 192 | if (!f) 193 | { 194 | ERROR("Couldn't open %s!\n", path); 195 | return -1; 196 | } 197 | fread(&magic, sizeof(magic), 1, f); 198 | fclose(f); 199 | 200 | remove_dir(TMP_RD_UNPACKED_DIR); 201 | mkdir(TMP_RD_UNPACKED_DIR, 0755); 202 | 203 | // Decompress initrd 204 | int type; 205 | char buff[256]; 206 | char busybox_path[256]; 207 | snprintf(busybox_path, sizeof(busybox_path), "%s/busybox", mrom_dir()); 208 | 209 | char *cmd[] = { busybox_path, "sh", "-c", buff, NULL }; 210 | 211 | if ((magic & 0xFFFF) == 0x8B1F) 212 | { 213 | type = RD_GZIP; 214 | snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" gzip -d -c \"%s\" | \"$B\" cpio -i", busybox_path, TMP_RD_UNPACKED_DIR, path); 215 | } 216 | else if (magic == 0x184C2102) 217 | { 218 | type = RD_LZ4; 219 | snprintf(buff, sizeof(buff), "cd \"%s\"; \"%s/lz4\" -d \"%s\" stdout | \"%s\" cpio -i", TMP_RD_UNPACKED_DIR, mrom_dir(), path, busybox_path); 220 | } 221 | else 222 | { 223 | ERROR("Unknown ramdisk magic 0x%08X, can't update trampoline\n", magic); 224 | goto success; 225 | } 226 | 227 | int r = run_cmd(cmd); 228 | if (r != 0) 229 | { 230 | ERROR("Failed to unpack ramdisk! %s\n", buff); 231 | goto fail; 232 | } 233 | 234 | if (access(TMP_RD2, F_OK) != -1) { 235 | if (inject_second_rd(path, second_path) < 0) 236 | goto fail; 237 | } else { 238 | if (copy_rd_files(path, busybox_path) < 0) 239 | goto fail; 240 | } 241 | 242 | // Pack ramdisk 243 | switch(type) 244 | { 245 | case RD_GZIP: 246 | snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc | \"$B\" gzip > \"%s\"", busybox_path, TMP_RD_UNPACKED_DIR, path); 247 | break; 248 | case RD_LZ4: 249 | snprintf(buff, sizeof(buff), "B=\"%s\"; cd \"%s\"; \"$B\" find . | \"$B\" cpio -o -H newc | \"%s/lz4\" stdin \"%s\"", busybox_path, TMP_RD_UNPACKED_DIR, mrom_dir(), path); 250 | break; 251 | } 252 | 253 | r = run_cmd(cmd); 254 | if (r != 0) 255 | { 256 | ERROR("Failed to pack ramdisk!\n"); 257 | goto fail; 258 | } 259 | 260 | success: 261 | result = 0; 262 | fail: 263 | remove_dir(TMP_RD_UNPACKED_DIR); 264 | return result; 265 | } 266 | 267 | int inject_bootimg(const char *img_path, int force) 268 | { 269 | int res = -1; 270 | struct bootimg img; 271 | int img_ver; 272 | char initrd_path[256]; 273 | static const char *initrd_tmp_name = "/inject-initrd.img"; 274 | static const char *initrd2_tmp_name = "/mrom_rd/sbin/ramdisk.cpio"; 275 | 276 | if (libbootimg_init_load(&img, img_path, LIBBOOTIMG_LOAD_ALL) < 0) 277 | { 278 | ERROR("Could not open boot image (%s)!\n", img_path); 279 | return -1; 280 | } 281 | 282 | img_ver = get_img_trampoline_ver(&img); 283 | if (!force && img_ver == VERSION_TRAMPOLINE) 284 | { 285 | INFO("No need to update trampoline.\n"); 286 | res = 0; 287 | goto exit; 288 | } 289 | 290 | INFO("Updating trampoline from ver %d to %d\n", img_ver, VERSION_TRAMPOLINE); 291 | 292 | if (libbootimg_dump_ramdisk(&img, initrd_tmp_name) < 0) 293 | { 294 | ERROR("Failed to dump ramdisk to %s!\n", initrd_path); 295 | goto exit; 296 | } 297 | 298 | if (inject_rd(initrd_tmp_name, initrd2_tmp_name) >= 0) 299 | { 300 | // Update the boot.img 301 | snprintf((char*)img.hdr.name, BOOT_NAME_SIZE, "tr_ver%d", VERSION_TRAMPOLINE); 302 | #ifdef MR_RD_ADDR 303 | img.hdr.ramdisk_addr = MR_RD_ADDR; 304 | #endif 305 | 306 | if (libbootimg_load_ramdisk(&img, initrd_tmp_name) < 0) 307 | { 308 | ERROR("Failed to load ramdisk from %s!\n", initrd_tmp_name); 309 | goto exit; 310 | } 311 | 312 | char tmp[256]; 313 | strcpy(tmp, img_path); 314 | strcat(tmp, ".new"); 315 | if (libbootimg_write_img(&img, tmp) >= 0) 316 | { 317 | INFO("Writing boot.img updated with trampoline v%d\n", VERSION_TRAMPOLINE); 318 | if (copy_file(tmp, img_path) < 0) 319 | ERROR("Failed to copy %s to %s!\n", tmp, img_path); 320 | else 321 | res = 0; 322 | remove(tmp); 323 | } 324 | else 325 | ERROR("Failed to libbootimg_write_img!\n"); 326 | } 327 | 328 | exit: 329 | libbootimg_destroy(&img); 330 | remove("/inject-initrd.img"); 331 | return res; 332 | } 333 | -------------------------------------------------------------------------------- /lib/inject.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef INJECT_H 19 | #define INJECT_H 20 | 21 | int inject_bootimg(const char *img_path, int force); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /lib/input.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef INPUT_H 19 | #define INPUT_H 20 | 21 | #include 22 | #include "framebuffer.h" 23 | 24 | #define KEY_VOLUMEUP 115 25 | #define KEY_VOLUMEDOWN 114 26 | #define KEY_POWER 116 27 | 28 | enum 29 | { 30 | TCHNG_POS = 0x01, 31 | //TCHNG_PRESSURE = 0x02, // unused 32 | TCHNG_ADDED = 0x04, 33 | TCHNG_REMOVED = 0x08 34 | }; 35 | 36 | typedef struct 37 | { 38 | int id; 39 | int x, orig_x; 40 | int y, orig_y; 41 | int changed; 42 | int consumed; 43 | 44 | struct timeval time; 45 | int64_t us_diff; 46 | } touch_event; 47 | 48 | typedef int (*touch_callback)(touch_event*, void*); // event, data 49 | 50 | void start_input_thread(void); 51 | void start_input_thread_wait(int wait_for_start); 52 | void stop_input_thread(void); 53 | 54 | int get_last_key(void); 55 | int wait_for_key(void); 56 | int is_any_key_pressed(void); 57 | 58 | void add_touch_handler(touch_callback callback, void *data); 59 | void rm_touch_handler(touch_callback callback, void *data); 60 | void add_touch_handler_async(touch_callback callback, void *data); 61 | void rm_touch_handler_async(touch_callback callback, void *data); 62 | 63 | void input_push_context(void); 64 | void input_pop_context(void); 65 | 66 | 67 | enum 68 | { 69 | KEYACT_NONE = 0, 70 | KEYACT_UP, 71 | KEYACT_DOWN, 72 | KEYACT_CONFIRM, 73 | KEYACT_CLEAR, 74 | }; 75 | 76 | #define KEYACT_FRAME_W (8*DPI_MUL) 77 | 78 | typedef int (*keyaction_call)(void *, int); // data, action 79 | void keyaction_add(void *parent, keyaction_call call, void *data); 80 | void keyaction_remove(keyaction_call call, void *data); 81 | void keyaction_clear(void); 82 | void keyaction_clear_active(void); 83 | int keyaction_handle_keyevent(int key, int press); 84 | void keyaction_enable(int enable); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /lib/input_priv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef INPUT_PRIV_H 19 | #define INPUT_PRIV_H 20 | 21 | #include 22 | #include "input.h" 23 | 24 | #define MAX_DEVICES 16 25 | #define MAX_FINGERS 10 26 | 27 | // for touch calculation 28 | extern int mt_screen_res[2]; 29 | extern touch_event mt_events[MAX_FINGERS]; 30 | extern int mt_slot; 31 | extern int mt_switch_xy; 32 | extern int mt_range_x[2]; 33 | extern int mt_range_y[2]; 34 | 35 | typedef struct 36 | { 37 | void *data; 38 | touch_callback callback; 39 | } touch_handler; 40 | 41 | struct handler_list_it 42 | { 43 | touch_handler *handler; 44 | 45 | struct handler_list_it *prev; 46 | struct handler_list_it *next; 47 | }; 48 | 49 | typedef struct handler_list_it handler_list_it; 50 | 51 | typedef struct 52 | { 53 | int handlers_mode; 54 | handler_list_it *handlers; 55 | } handlers_ctx; 56 | 57 | void touch_commit_events(struct timeval ev_time); 58 | inline int calc_mt_pos(int val, int *range, int d_max); 59 | 60 | // Implemented in input_touch*.c files 61 | void handle_abs_event(struct input_event *ev); 62 | void handle_syn_event(struct input_event *ev); 63 | void init_touch_specifics(void); 64 | void destroy_touch_specifics(void); 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /lib/input_type_a.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | // Implementation of "Protocol Example A" from kernel's 19 | // Documentation/input/multi-touch-protocol.txt 20 | 21 | // This protocol requires client to keep track of ids, 22 | // I don't really like this implementation, but I can't 23 | // come up with anything better :/ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "input.h" 30 | #include "input_priv.h" 31 | #include "util.h" 32 | 33 | static int *active_touches = NULL; 34 | static int *curr_touches = NULL; 35 | 36 | static void idlist_clear(int *list) 37 | { 38 | int i; 39 | for(i = 0; i < MAX_FINGERS && list[i] != -1; ++i) 40 | list[i] = -1; 41 | } 42 | 43 | static int *idlist_init(void) 44 | { 45 | int *res = malloc(MAX_FINGERS*sizeof(int)); 46 | 47 | int i; 48 | for(i = 0; i < MAX_FINGERS; ++i) 49 | res[i] = -1; 50 | 51 | return res; 52 | } 53 | 54 | static void idlist_swap(int **list_a, int **list_b) 55 | { 56 | int *tmp = *list_a; 57 | *list_a = *list_b; 58 | *list_b = tmp; 59 | } 60 | 61 | static int idlist_add(int *list, int id) 62 | { 63 | int i; 64 | for(i = 0; i < MAX_FINGERS; ++i) 65 | { 66 | if(list[i] == id) 67 | return -1; 68 | 69 | if(list[i] == -1) 70 | { 71 | list[i] = id; 72 | return 0; 73 | } 74 | } 75 | assert(0); 76 | return -1; 77 | } 78 | 79 | static int idlist_rm(int *list, int id) 80 | { 81 | int i; 82 | for(i = 0; i < MAX_FINGERS; ++i) 83 | { 84 | if(list[i] == -1) 85 | return -1; 86 | 87 | if(list[i] == id) 88 | { 89 | for(++i; i < MAX_FINGERS && list[i] != -1; ++i) 90 | list[i-1] = list[i]; 91 | list[i-1] = -1; 92 | return 0; 93 | } 94 | } 95 | return -1; 96 | } 97 | 98 | void init_touch_specifics(void) 99 | { 100 | active_touches = idlist_init(); 101 | curr_touches = idlist_init(); 102 | } 103 | 104 | void destroy_touch_specifics(void) 105 | { 106 | free(active_touches); 107 | free(curr_touches); 108 | active_touches = NULL; 109 | curr_touches = NULL; 110 | } 111 | 112 | void handle_abs_event(struct input_event *ev) 113 | { 114 | switch(ev->code) 115 | { 116 | case ABS_MT_TRACKING_ID: 117 | { 118 | mt_events[mt_slot++].id = ev->value; 119 | break; 120 | } 121 | case ABS_MT_POSITION_X: 122 | case ABS_MT_POSITION_Y: 123 | { 124 | if((ev->code == ABS_MT_POSITION_X) ^ (mt_switch_xy != 0)) 125 | { 126 | mt_events[mt_slot].orig_x = calc_mt_pos(ev->value, mt_range_x, mt_screen_res[0]); 127 | if(mt_switch_xy) 128 | mt_events[mt_slot].orig_x = mt_screen_res[0] - mt_events[mt_slot].orig_x; 129 | } 130 | else 131 | mt_events[mt_slot].orig_y = calc_mt_pos(ev->value, mt_range_y, mt_screen_res[1]); 132 | 133 | mt_events[mt_slot].changed |= TCHNG_POS; 134 | break; 135 | } 136 | } 137 | } 138 | 139 | void handle_syn_event(struct input_event *ev) 140 | { 141 | if(ev->code != SYN_REPORT) 142 | return; 143 | 144 | idlist_swap(&curr_touches, &active_touches); 145 | 146 | int i; 147 | for(i = 0; i < mt_slot; ++i) 148 | { 149 | idlist_add(active_touches, mt_events[i].id); 150 | if(idlist_rm(curr_touches, mt_events[i].id) == -1) 151 | mt_events[i].changed |= TCHNG_ADDED; 152 | } 153 | 154 | for(i = 0; mt_slot < MAX_FINGERS && i < MAX_FINGERS && curr_touches[i] != -1; ++i) 155 | { 156 | mt_events[mt_slot].id = curr_touches[i]; 157 | mt_events[mt_slot].changed = TCHNG_REMOVED; 158 | curr_touches[i] = -1; 159 | ++mt_slot; 160 | } 161 | 162 | mt_slot = 0; 163 | touch_commit_events(ev->time); 164 | } 165 | -------------------------------------------------------------------------------- /lib/input_type_b.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | // Implementation of "Protocol Example B" from kernel's 19 | // Documentation/input/multi-touch-protocol.txt 20 | 21 | #include 22 | #include "input.h" 23 | #include "input_priv.h" 24 | #include "util.h" 25 | 26 | void init_touch_specifics(void) 27 | { 28 | 29 | } 30 | 31 | void destroy_touch_specifics(void) 32 | { 33 | 34 | } 35 | 36 | void handle_abs_event(struct input_event *ev) 37 | { 38 | switch(ev->code) 39 | { 40 | case ABS_MT_SLOT: 41 | if(ev->value < (int)ARRAY_SIZE(mt_events)) 42 | mt_slot = ev->value; 43 | break; 44 | case ABS_MT_TRACKING_ID: 45 | { 46 | if(ev->value != -1) 47 | { 48 | mt_events[mt_slot].id = ev->value; 49 | mt_events[mt_slot].changed |= TCHNG_ADDED; 50 | } 51 | else 52 | mt_events[mt_slot].changed |= TCHNG_REMOVED; 53 | break; 54 | } 55 | case ABS_MT_POSITION_X: 56 | case ABS_MT_POSITION_Y: 57 | { 58 | if((ev->code == ABS_MT_POSITION_X) ^ (mt_switch_xy != 0)) 59 | { 60 | mt_events[mt_slot].orig_x = calc_mt_pos(ev->value, mt_range_x, mt_screen_res[0]); 61 | if(mt_switch_xy) 62 | mt_events[mt_slot].orig_x = mt_screen_res[0] - mt_events[mt_slot].orig_x; 63 | } 64 | else 65 | mt_events[mt_slot].orig_y = calc_mt_pos(ev->value, mt_range_y, mt_screen_res[1]); 66 | 67 | mt_events[mt_slot].changed |= TCHNG_POS; 68 | break; 69 | } 70 | } 71 | } 72 | 73 | void handle_syn_event(struct input_event *ev) 74 | { 75 | if(ev->code == SYN_REPORT) 76 | touch_commit_events(ev->time); 77 | } 78 | -------------------------------------------------------------------------------- /lib/keyboard.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | 20 | #include "containers.h" 21 | #include "keyboard.h" 22 | #include "util.h" 23 | #include "log.h" 24 | #include "workers.h" 25 | 26 | #define KS(x) ((x-1) << 16) 27 | #define GET_KS(x) ((x & 0xFF0000)>> 16) 28 | 29 | #define KF(x) ((x) << 8) 30 | #define GET_KF(x) ((x & 0xFF00) >> 8) 31 | #define KFLAG_HALF KF(0x01) 32 | #define KFLAG_PLUS_HALF KF(0x02) 33 | 34 | static const char *specialKeys[] = { 35 | NULL, // OSK_EMPTY 36 | "OK", // OSK_ENTER 37 | "<", // OSK_BACKSPACE 38 | "X", // OSK_CLEAR 39 | "abc", // OSK_CHARSET1 40 | "ABC", // OSK_CHARSET2 41 | "?123",// OSK_CHARSET3 42 | "=\\<",// OSK_CHARSET4 43 | }; 44 | 45 | // One keycode 46 | // bits | 0 | 8 | 16 | 47 | // data | character | flags | colspan | 48 | static const uint32_t pinKeycodeMap[] = { 49 | OSK_EMPTY | KFLAG_HALF, '1', '2', '3', OSK_EMPTY, 50 | OSK_EMPTY | KFLAG_HALF, '4', '5', '6', OSK_CLEAR, 51 | OSK_EMPTY | KFLAG_HALF, '7', '8', '9', OSK_BACKSPACE, 52 | OSK_EMPTY | KFLAG_HALF, '0' | KS(3), OSK_ENTER, 53 | 0 54 | }; 55 | 56 | // rows, cols 57 | static const uint32_t pinKeycodeMapDimensions[] = { 4, 5 }; 58 | 59 | static const uint32_t normalKeycodeMapCharset1[] = { 60 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 61 | OSK_EMPTY| KFLAG_HALF, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 62 | OSK_CHARSET2 | KFLAG_PLUS_HALF, 'z', 'x', 'c', 'v', 'b', 'n', 'm', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY, 63 | OSK_CHARSET3 | KS(2), ' ' | KS(5), '.', OSK_ENTER | KS(2), 64 | 0 65 | }; 66 | 67 | static const uint32_t normalKeycodeMapCharset2[] = { 68 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 69 | OSK_EMPTY| KFLAG_HALF, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 70 | OSK_CHARSET1 | KFLAG_PLUS_HALF, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY, 71 | OSK_CHARSET3 | KS(2), ' ' | KS(5), '.', OSK_ENTER | KS(2), 72 | 0 73 | }; 74 | 75 | static const uint32_t normalKeycodeMapCharset3[] = { 76 | '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 77 | OSK_EMPTY | KFLAG_HALF, '@', '#', '$', '%', '&', '-', '+', '(', ')', 78 | OSK_CHARSET4 | KFLAG_PLUS_HALF, '*', '"', '\'', ':', ';', '!', '?', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY, 79 | OSK_CHARSET1 | KS(2), ',', '_', ' ' | KS(3), '/', OSK_ENTER | KS(2), 80 | 0 81 | }; 82 | 83 | static const uint32_t normalKeycodeMapCharset4[] = { 84 | '~', '`', '|', '<', '>', '-', '+', '!', '?', ';', 85 | OSK_EMPTY | KFLAG_HALF, '^', '\\', '$', '%', '&', '-', '+', '{', '}', 86 | OSK_CHARSET3 | KFLAG_PLUS_HALF, '*', '"', '\'', ':', ';', '[', ']', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY, 87 | OSK_CHARSET1 | KS(2), ',', ' ' | KS(4), '/', OSK_ENTER | KS(2), 88 | 0 89 | }; 90 | 91 | static const uint32_t *normalKeycodeMapCharsetMapping[] = { 92 | normalKeycodeMapCharset4, // OSK_CHARSET4 93 | normalKeycodeMapCharset3, // OSK_CHARSET3 94 | normalKeycodeMapCharset2, // OSK_CHARSET2 95 | normalKeycodeMapCharset1, // OSK_CHARSET1 96 | }; 97 | 98 | // rows, cols 99 | static const uint32_t normalKeycodeMapDimensions[] = { 4, 10 }; 100 | 101 | #define PADDING (8*DPI_MUL) 102 | 103 | struct keyboard_btn_data { 104 | struct keyboard *k; 105 | int btn_idx; 106 | }; 107 | 108 | static int keyboard_init_map(struct keyboard *k, const uint32_t *map, const uint32_t *dimen); 109 | 110 | 111 | static int keyboard_charset_switch_worker(UNUSED uint32_t diff, void *data) 112 | { 113 | void **keyboard_bnt_data_old = NULL; 114 | struct keyboard_btn_data *d = data; 115 | uint8_t keycode = (d->k->keycode_map[d->btn_idx] & 0xFF); 116 | 117 | fb_batch_start(); 118 | list_clear(&d->k->btns, &button_destroy); 119 | list_swap(&d->k->keyboard_bnt_data, &keyboard_bnt_data_old); 120 | keyboard_init_map(d->k, normalKeycodeMapCharsetMapping[keycode - OSK_CHARSET4], normalKeycodeMapDimensions); 121 | fb_batch_end(); 122 | fb_request_draw(); 123 | 124 | list_clear(&keyboard_bnt_data_old, free); 125 | return 1; 126 | } 127 | 128 | static void keyboard_btn_clicked(void *data) 129 | { 130 | struct keyboard_btn_data *d = data; 131 | uint8_t keycode = (d->k->keycode_map[d->btn_idx] & 0xFF); 132 | 133 | if(keycode >= OSK_CHARSET4 && keycode <= OSK_CHARSET1) 134 | workers_add(keyboard_charset_switch_worker, data); 135 | else if(d->k->key_pressed) 136 | d->k->key_pressed(d->k->key_pressed_data, keycode); 137 | } 138 | 139 | int keyboard_init_map(struct keyboard *k, const uint32_t *map, const uint32_t *dimen) 140 | { 141 | button *btn; 142 | int i, idx = 0; 143 | uint32_t col = 0; 144 | char buf[2] = { 0 }; 145 | uint8_t code; 146 | 147 | int x = k->x + PADDING; 148 | int y = k->y + PADDING; 149 | int w; 150 | const int btn_w = (k->w - PADDING*(dimen[1]+1)) /dimen[1]; 151 | const int btn_h = (k->h - PADDING*(dimen[0]+1)) /dimen[0]; 152 | 153 | for(i = 0; map[i]; ++i) 154 | { 155 | code = (map[i] & 0xFF); 156 | w = (GET_KS(map[i])+1)*btn_w + PADDING*GET_KS(map[i]); 157 | 158 | if(map[i] & KFLAG_HALF) 159 | w /= 2; 160 | else if(map[i] & KFLAG_PLUS_HALF) 161 | w = w*1.5 + PADDING*0.5; 162 | 163 | if(code != OSK_EMPTY) 164 | { 165 | btn = mzalloc(sizeof(button)); 166 | btn->x = x; 167 | btn->y = y; 168 | btn->w = w; 169 | btn->h = btn_h; 170 | 171 | struct keyboard_btn_data *d = mzalloc(sizeof(struct keyboard_btn_data)); 172 | d->k = k; 173 | d->btn_idx = i; 174 | btn->clicked_data = d; 175 | btn->clicked = keyboard_btn_clicked; 176 | 177 | buf[0] = (map[i] & 0xFF); 178 | button_init_ui(btn, ((int8_t)buf[0]) >= 0 ? buf : specialKeys[0xFF - (map[i] & 0xFF)], SIZE_NORMAL); 179 | list_add(&k->btns, btn); 180 | list_add(&k->keyboard_bnt_data, d); 181 | } 182 | 183 | col += GET_KS(map[i])+1; 184 | if(col < dimen[1]) 185 | x += w + PADDING; 186 | else 187 | { 188 | x = k->x + PADDING; 189 | y += btn_h + PADDING; 190 | col = 0; 191 | } 192 | } 193 | 194 | k->keycode_map = map; 195 | return 0; 196 | } 197 | 198 | struct keyboard *keyboard_create(int type, int x, int y, int w, int h) 199 | { 200 | struct keyboard *k = mzalloc(sizeof(struct keyboard)); 201 | k->x = x; 202 | k->y = y; 203 | k->w = w; 204 | k->h = h; 205 | 206 | switch(type) 207 | { 208 | case KEYBOARD_PIN: 209 | keyboard_init_map(k, pinKeycodeMap, pinKeycodeMapDimensions); 210 | break; 211 | case KEYBOARD_NORMAL: 212 | default: 213 | keyboard_init_map(k, normalKeycodeMapCharset1, normalKeycodeMapDimensions); 214 | break; 215 | } 216 | 217 | return k; 218 | } 219 | 220 | void keyboard_destroy(struct keyboard *k) 221 | { 222 | list_clear(&k->btns, &button_destroy); 223 | list_clear(&k->keyboard_bnt_data, free); 224 | free(k); 225 | } 226 | 227 | void keyboard_set_callback(struct keyboard *k, keyboard_on_pressed_callback callback, void *data) 228 | { 229 | k->key_pressed = callback; 230 | k->key_pressed_data = data; 231 | } 232 | -------------------------------------------------------------------------------- /lib/keyboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef KEYBOARD_H 19 | #define KEYBOARD_H 20 | 21 | #include 22 | 23 | #include "framebuffer.h" 24 | #include "button.h" 25 | 26 | #define OSK_EMPTY 0xFF 27 | #define OSK_ENTER 0xFE 28 | #define OSK_BACKSPACE 0xFD 29 | #define OSK_CLEAR 0xFC 30 | #define OSK_CHARSET1 0xFB 31 | #define OSK_CHARSET2 0xFA 32 | #define OSK_CHARSET3 0xF9 33 | #define OSK_CHARSET4 0xF8 34 | 35 | typedef void (*keyboard_on_pressed_callback)(void *data, uint8_t keycode); 36 | struct keyboard 37 | { 38 | FB_ITEM_POS 39 | button **btns; 40 | void **keyboard_bnt_data; 41 | const uint32_t *keycode_map; 42 | keyboard_on_pressed_callback key_pressed; 43 | void *key_pressed_data; 44 | }; 45 | 46 | #define KEYBOARD_PIN 0 47 | #define KEYBOARD_NORMAL 1 48 | 49 | struct keyboard *keyboard_create(int type, int x, int y, int w, int h); 50 | void keyboard_set_callback(struct keyboard *k, keyboard_on_pressed_callback callback, void *data); 51 | void keyboard_destroy(struct keyboard *k); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /lib/listview.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef LISTVIEW_H 19 | #define LISTVIEW_H 20 | 21 | #include "input.h" 22 | #include "framebuffer.h" 23 | #include "touch_tracker.h" 24 | 25 | enum 26 | { 27 | IT_VISIBLE = 0x01, 28 | IT_HOVER = 0x02, 29 | IT_SELECTED = 0x04, 30 | }; 31 | 32 | typedef struct 33 | { 34 | int id; 35 | void *data; 36 | int flags; 37 | fb_item_pos *parent_rect; 38 | int touchX, touchY; 39 | } listview_item; 40 | 41 | typedef struct 42 | { 43 | int id; 44 | listview_item *hover; 45 | int fast_scroll; 46 | } listview_touch_data; 47 | 48 | typedef struct 49 | { 50 | FB_ITEM_HEAD 51 | 52 | fb_item_pos last_rendered_pos; 53 | 54 | int pos; // scroll pos 55 | int fullH; // height of all items 56 | 57 | listview_item **items; 58 | listview_item *selected; 59 | 60 | void (*item_draw)(int, int, int, listview_item *); // x, y, w, item 61 | void (*item_hide)(void*); // data 62 | int (*item_height)(listview_item *); // item 63 | 64 | void (*item_destroy)(listview_item *); 65 | void (*item_selected)(listview_item *, listview_item *); // prev, now 66 | void (*item_confirmed)(listview_item *); // item - confirmed by keyaction 67 | 68 | fb_item_header **ui_items; 69 | fb_rect *scroll_mark; 70 | fb_rect *overscroll_marks[2]; 71 | fb_rect *scroll_line; 72 | int keyact_item_selected; 73 | 74 | listview_touch_data touch; 75 | touch_tracker *tracker; 76 | } listview; 77 | 78 | int listview_touch_handler(touch_event *ev, void *data); 79 | 80 | void listview_init_ui(listview *view); 81 | void listview_destroy(listview *view); 82 | listview_item *listview_add_item(listview *view, int id, void *data); 83 | void listview_clear(listview *view); 84 | inline void listview_update_ui(listview *view); 85 | void listview_update_ui_args(listview *view, int only_if_moved, int mutex_locked); 86 | void listview_enable_scroll(listview *view, int enable); 87 | void listview_update_scroll_mark(listview *view); 88 | void listview_update_overscroll_mark(listview *v, int side, float overscroll); 89 | void listview_scroll_by(listview *view, int y); 90 | void listview_scroll_to(listview *view, int pct); 91 | int listview_ensure_visible(listview *view, listview_item *it); 92 | int listview_ensure_selected_visible(listview *view); 93 | listview_item *listview_item_at(listview *view, int y_pos); 94 | inline int listview_select_item(listview *view, listview_item *it); 95 | void listview_update_keyact_frame(listview *view); 96 | int listview_keyaction_call(void *data, int act); 97 | 98 | void *rom_item_create(const char *text, const char *partition, const char *icon); 99 | void rom_item_draw(int x, int y, int w, listview_item *it); 100 | void rom_item_hide(void *data); 101 | int rom_item_height(listview_item *it); 102 | void rom_item_destroy(listview_item *it); 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /lib/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _INIT_LOG_H_ 18 | #define _INIT_LOG_H_ 19 | 20 | #include "mrom_data.h" 21 | 22 | #ifdef LOG_TO_STDOUT 23 | #include 24 | #define ERROR(fmt, ...) fprintf(stderr, "%s: " fmt "\n", mrom_log_tag(), ##__VA_ARGS__) 25 | #define INFO(fmt, ...) printf("%s: " fmt "\n", mrom_log_tag(), ##__VA_ARGS__) 26 | #else 27 | #include 28 | 29 | #define ERROR(fmt, ...) klog_write(3, "<3>%s: " fmt, mrom_log_tag(), ##__VA_ARGS__) 30 | #define INFO(fmt, ...) klog_write(6, "<6>%s: " fmt, mrom_log_tag(), ##__VA_ARGS__) 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /lib/mrom_data.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "mrom_data.h" 22 | 23 | static char multirom_dir[128] = { 0 }; 24 | static char log_tag[64] = { 0 }; 25 | 26 | void mrom_set_dir(const char *mrom_dir) 27 | { 28 | snprintf(multirom_dir, sizeof(multirom_dir), "%s", mrom_dir); 29 | } 30 | 31 | void mrom_set_log_tag(const char *tag) 32 | { 33 | snprintf(log_tag, sizeof(log_tag), "%s", tag); 34 | } 35 | 36 | const char *mrom_log_tag(void) 37 | { 38 | return log_tag; 39 | } 40 | 41 | const char *mrom_dir(void) 42 | { 43 | return multirom_dir; 44 | } 45 | 46 | int mrom_is_second_boot(void) 47 | { 48 | int i; 49 | int res = 0; 50 | FILE *f = NULL; 51 | char buff[2048]; 52 | 53 | static const char *kmsg_paths[] = { 54 | "/proc/last_kmsg", 55 | "/sys/fs/pstore/console-ramoops", 56 | NULL, 57 | }; 58 | 59 | f = fopen("/proc/cmdline", "re"); 60 | if(f) 61 | { 62 | if(fgets(buff, sizeof(buff), f) && strstr(buff, "mrom_kexecd=1")) 63 | { 64 | res = 1; 65 | goto exit; 66 | } 67 | 68 | fclose(f); 69 | f = NULL; 70 | } 71 | 72 | for(i = 0; !f && kmsg_paths[i]; ++i) 73 | f = fopen(kmsg_paths[i], "re"); 74 | 75 | if(!f) 76 | return 0; 77 | 78 | while(fgets(buff, sizeof(buff), f)) 79 | { 80 | if(strstr(buff, SECOND_BOOT_KMESG)) 81 | { 82 | res = 1; 83 | goto exit; 84 | } 85 | } 86 | 87 | exit: 88 | fclose(f); 89 | return res; 90 | } 91 | -------------------------------------------------------------------------------- /lib/mrom_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef MROM_DATA_H 19 | #define MROM_DATA_H 20 | 21 | #define SECOND_BOOT_KMESG "MultiromSaysNextBootShouldBeSecondMagic108\n" 22 | 23 | void mrom_set_dir(const char *mrom_dir); 24 | void mrom_set_log_tag(const char *tag); 25 | 26 | const char *mrom_log_tag(void); 27 | const char *mrom_dir(void); 28 | int mrom_is_second_boot(void); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /lib/notification_card.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "util.h" 23 | #include "animation.h" 24 | #include "framebuffer.h" 25 | #include "notification_card.h" 26 | #include "containers.h" 27 | #include "log.h" 28 | #include "input.h" 29 | #include "colors.h" 30 | 31 | enum 32 | { 33 | LEVEL_NCARD_SHADOW = 49, 34 | LEVEL_NCARD_BG = 50, 35 | LEVEL_NCARD_BTN_HOVER = 55, 36 | LEVEL_NCARD_TEXT = 60, 37 | 38 | LEVEL_NCARD_CENTER_OFFSET = 1000, 39 | }; 40 | 41 | #define CARD_PADDING_H (40*DPI_MUL) 42 | #define CARD_PADDING_V (30*DPI_MUL) 43 | #define CARD_MARGIN (40*DPI_MUL) 44 | #define CARD_WIDTH (fb_width - CARD_MARGIN*2) 45 | #define CARD_SHADOW_OFF (7*DPI_MUL) 46 | 47 | ncard_builder *ncard_create_builder(void) 48 | { 49 | return mzalloc(sizeof(ncard_builder)); 50 | } 51 | 52 | void ncard_set_title(ncard_builder *b, const char *title) 53 | { 54 | b->title = realloc(b->title, strlen(title)+1); 55 | strcpy(b->title, title); 56 | } 57 | 58 | void ncard_set_text(ncard_builder *b, const char *text) 59 | { 60 | b->text = realloc(b->text, strlen(text)+1); 61 | strcpy(b->text, text); 62 | } 63 | 64 | void ncard_set_pos(ncard_builder *b, int pos) 65 | { 66 | b->pos = pos; 67 | } 68 | 69 | void ncard_set_cancelable(ncard_builder *b, int cancelable) 70 | { 71 | b->cancelable = cancelable; 72 | } 73 | 74 | void ncard_avoid_item(ncard_builder *b, void *item) 75 | { 76 | fb_item_pos *it = item; 77 | b->avoid_item = mzalloc(sizeof(fb_item_pos)); 78 | b->avoid_item->x = it->x; 79 | b->avoid_item->y = it->y; 80 | b->avoid_item->w = it->w; 81 | b->avoid_item->h = it->h; 82 | } 83 | 84 | void ncard_add_btn(ncard_builder *b, int btn_type, const char *text, ncard_callback callback, void *callback_data) 85 | { 86 | if(b->buttons[btn_type]) 87 | { 88 | free(b->buttons[btn_type]->text); 89 | free(b->buttons[btn_type]); 90 | } 91 | 92 | ncard_builder_btn *btn = mzalloc(sizeof(ncard_builder_btn)); 93 | btn->text = strtoupper(text); 94 | btn->callback_data = callback_data; 95 | btn->callback = callback; 96 | b->buttons[btn_type] = btn; 97 | } 98 | 99 | void ncard_set_on_hidden(ncard_builder *b, ncard_callback callback, void *data) 100 | { 101 | b->on_hidden_call = callback; 102 | b->on_hidden_data = data; 103 | } 104 | 105 | void ncard_set_from_black(ncard_builder *b, int from_black) 106 | { 107 | b->reveal_from_black = from_black; 108 | } 109 | 110 | static int ncard_calc_pos(ncard_builder* b, int max_y) 111 | { 112 | if(b->pos == NCARD_POS_AUTO) 113 | { 114 | if(!b->avoid_item) 115 | return NCARD_POS_TOP; 116 | if(b->avoid_item->y > max_y) 117 | return NCARD_POS_TOP; 118 | return NCARD_POS_BOTTOM; 119 | } 120 | else 121 | return b->pos; 122 | } 123 | 124 | struct ncard_btn 125 | { 126 | fb_item_pos pos; 127 | void *callback_data; 128 | ncard_callback callback; 129 | }; 130 | 131 | struct ncard 132 | { 133 | fb_rect *bg; 134 | fb_rect *shadow; 135 | fb_rect *alpha_bg; 136 | fb_text **texts; 137 | fb_rect *hover_rect; 138 | struct ncard_btn btns[BTN_COUNT]; 139 | int active_btns; 140 | int pos; 141 | int targetH; 142 | int top_offset; 143 | int last_y; 144 | int hiding; 145 | int moving; 146 | int touch_handler_registered; 147 | int touch_id; 148 | int hover_btn; 149 | int cancelable; 150 | ncard_callback on_hidden_call; 151 | void *on_hidden_data; 152 | int reveal_from_black; 153 | pthread_mutex_t mutex; 154 | } ncard = { 155 | .bg = NULL, 156 | .shadow = NULL, 157 | .texts = NULL, 158 | .active_btns = 0, 159 | .top_offset = 0, 160 | .hiding = 0, 161 | .hover_rect = NULL, 162 | .touch_handler_registered = 0, 163 | .touch_id = -1, 164 | .hover_btn = 0, 165 | .cancelable = 0, 166 | .on_hidden_call = NULL, 167 | .on_hidden_data = NULL, 168 | .reveal_from_black = 0, 169 | .mutex = PTHREAD_MUTEX_INITIALIZER, 170 | }; 171 | 172 | static int ncard_touch_handler(touch_event *ev, void *data) 173 | { 174 | struct ncard *c = data; 175 | 176 | pthread_mutex_lock(&c->mutex); 177 | 178 | if(c->touch_id == -1 && (ev->changed & TCHNG_ADDED)) 179 | { 180 | int i; 181 | for(i = 0; i < BTN_COUNT; ++i) 182 | { 183 | if(!(c->active_btns & (1 << i))) 184 | continue; 185 | 186 | if(in_rect(ev->x, ev->y, c->btns[i].pos.x, c->btns[i].pos.y, c->btns[i].pos.w, c->btns[i].pos.h)) 187 | { 188 | fb_rm_rect(c->hover_rect); 189 | int level = LEVEL_NCARD_BTN_HOVER; 190 | if(c->pos == NCARD_POS_CENTER) 191 | level += LEVEL_NCARD_CENTER_OFFSET; 192 | c->hover_rect = fb_add_rect_lvl(level, c->btns[i].pos.x, c->btns[i].pos.y, c->btns[i].pos.w, c->btns[i].pos.h, C_NCARD_SHADOW); 193 | 194 | c->touch_id = ev->id; 195 | c->hover_btn = i; 196 | break; 197 | } 198 | } 199 | } 200 | 201 | if(c->touch_id != ev->id) 202 | { 203 | if(c->cancelable) 204 | { 205 | pthread_mutex_unlock(&c->mutex); 206 | ncard_hide(); 207 | return 0; 208 | } 209 | else 210 | { 211 | pthread_mutex_unlock(&c->mutex); 212 | return c->pos == NCARD_POS_CENTER ? 0 : -1; 213 | } 214 | } 215 | 216 | if(ev->changed & TCHNG_REMOVED) 217 | { 218 | struct ncard_btn *b = &c->btns[c->hover_btn]; 219 | if(b->callback && in_rect(ev->x, ev->y, b->pos.x, b->pos.y, b->pos.w, b->pos.h)) 220 | { 221 | ncard_callback call = b->callback; 222 | void *call_data = b->callback_data; 223 | pthread_mutex_unlock(&c->mutex); 224 | call(call_data); 225 | pthread_mutex_lock(&c->mutex); 226 | } 227 | else 228 | { 229 | fb_rm_rect(c->hover_rect); 230 | c->hover_rect = NULL; 231 | } 232 | c->touch_id = -1; 233 | } 234 | 235 | pthread_mutex_unlock(&c->mutex); 236 | return 0; 237 | } 238 | 239 | static void ncard_move_step(void *data, float interpolated) 240 | { 241 | int i; 242 | struct ncard *c = data; 243 | 244 | pthread_mutex_lock(&c->mutex); 245 | 246 | const int diff = c->bg->y - c->last_y; 247 | 248 | for(i = 0; c->texts && c->texts[i]; ++i) 249 | c->texts[i]->y += diff; 250 | 251 | for(i = 0; i < BTN_COUNT; ++i) 252 | { 253 | if(!(c->active_btns & (1 << i))) 254 | continue; 255 | c->btns[i].pos.y += diff; 256 | } 257 | 258 | c->shadow->y += diff; 259 | c->shadow->h = c->bg->h; 260 | if(c->hover_rect) 261 | c->hover_rect->y += diff; 262 | c->last_y = c->bg->y; 263 | 264 | if(c->alpha_bg && (c->hiding || (c->alpha_bg->color & (0xFF << 24)) != 0xCC000000)) 265 | { 266 | if(interpolated > 1.f) 267 | interpolated = 1.f; 268 | if(c->hiding) 269 | interpolated = 1.f - interpolated; 270 | 271 | if(!c->hiding && c->reveal_from_black) 272 | c->alpha_bg->color = (c->alpha_bg->color & ~(0xFF << 24)) | ((0xFF - (int)(0x33*interpolated)) << 24); 273 | else 274 | c->alpha_bg->color = (c->alpha_bg->color & ~(0xFF << 24)) | (((int)(0xCC*interpolated)) << 24); 275 | } 276 | 277 | pthread_mutex_unlock(&c->mutex); 278 | 279 | fb_request_draw(); 280 | } 281 | 282 | static void ncard_reveal_finished(UNUSED void *data) 283 | { 284 | pthread_mutex_lock(&ncard.mutex); 285 | ncard.bg->h = ncard.targetH; 286 | ncard.shadow->h = ncard.targetH; 287 | ncard.moving = 0; 288 | pthread_mutex_unlock(&ncard.mutex); 289 | } 290 | 291 | static void ncard_hide_finished(void *data) 292 | { 293 | struct ncard *c = data; 294 | list_clear(&c->texts, fb_remove_item); 295 | fb_rm_rect(c->shadow); 296 | fb_rm_rect(c->alpha_bg); 297 | fb_rm_rect(c->hover_rect); 298 | free(c); 299 | ncard.moving = 0; 300 | } 301 | 302 | void ncard_set_top_offset(int top_offset) 303 | { 304 | pthread_mutex_lock(&ncard.mutex); 305 | ncard.top_offset = top_offset; 306 | pthread_mutex_unlock(&ncard.mutex); 307 | } 308 | 309 | void ncard_show(ncard_builder *b, int destroy_builder) 310 | { 311 | int i, items_h, btn_x, btn_h, has_btn = 0, it_y = 0, lvl_offset = 0; 312 | fb_text *title = 0, *text = 0, *btns[BTN_COUNT]; 313 | int interpolator; 314 | 315 | pthread_mutex_lock(&ncard.mutex); 316 | 317 | if(ncard.bg) 318 | anim_cancel_for(ncard.bg, 0); 319 | 320 | if(b->pos == NCARD_POS_CENTER) 321 | lvl_offset = LEVEL_NCARD_CENTER_OFFSET; 322 | 323 | items_h = CARD_PADDING_V*2; 324 | if(b->title) 325 | { 326 | fb_text_proto *p = fb_text_create(CARD_MARGIN + CARD_PADDING_H, fb_height, C_NCARD_TEXT, SIZE_EXTRA, b->title); 327 | p->level = LEVEL_NCARD_TEXT + lvl_offset; 328 | p->style = STYLE_MEDIUM; 329 | p->wrap_w = CARD_WIDTH - CARD_PADDING_H*2; 330 | title = fb_text_finalize(p); 331 | items_h += title->h; 332 | } 333 | 334 | if(b->text) 335 | { 336 | fb_text_proto *p = fb_text_create(CARD_MARGIN + CARD_PADDING_H, fb_height, C_NCARD_TEXT_SECONDARY, SIZE_NORMAL, b->text);\ 337 | p->level = LEVEL_NCARD_TEXT + lvl_offset; 338 | p->wrap_w = CARD_WIDTH - CARD_PADDING_H*2; 339 | if(!title) 340 | { 341 | p->style = STYLE_ITALIC; 342 | p->justify = JUSTIFY_CENTER; 343 | } 344 | text = fb_text_finalize(p); 345 | items_h += text->h; 346 | } 347 | 348 | if(title && text) 349 | items_h += title->h; 350 | 351 | ncard.active_btns = 0; 352 | btn_x = CARD_MARGIN + CARD_WIDTH - CARD_PADDING_H; 353 | btn_h = 0; 354 | for(i = 0; i < BTN_COUNT; ++i) 355 | { 356 | if(!b->buttons[i]) 357 | continue; 358 | 359 | ncard.active_btns |= (1 << i); 360 | 361 | fb_text_proto *p = fb_text_create(btn_x, fb_height, C_NCARD_TEXT, SIZE_NORMAL, b->buttons[i]->text); 362 | p->level = LEVEL_NCARD_TEXT + lvl_offset; 363 | p->style = STYLE_MEDIUM; 364 | fb_text *t = fb_text_finalize(p); 365 | t->x -= t->w; 366 | btn_x -= t->w + t->h*2; 367 | btn_h = imax(t->h*2, btn_h); 368 | btns[i] = t; 369 | 370 | ncard.btns[i].callback_data = b->buttons[i]->callback_data; 371 | ncard.btns[i].callback = b->buttons[i]->callback; 372 | ncard.btns[i].pos.w = t->w + t->h*2; 373 | ncard.btns[i].pos.h = t->h*3; 374 | ncard.btns[i].pos.x = btn_x + t->h; 375 | } 376 | 377 | items_h += btn_h*1.25; 378 | 379 | int new_pos = ncard_calc_pos(b, ncard.top_offset + items_h + CARD_MARGIN); 380 | 381 | if(new_pos != ncard.pos && ncard.bg) 382 | { 383 | pthread_mutex_unlock(&ncard.mutex); 384 | ncard_hide(); 385 | pthread_mutex_lock(&ncard.mutex); 386 | } 387 | 388 | ncard.pos = new_pos; 389 | 390 | list_clear(&ncard.texts, fb_remove_item); 391 | fb_rm_rect(ncard.hover_rect); 392 | ncard.hover_rect = NULL; 393 | 394 | if(!ncard.bg) 395 | { 396 | ncard.bg = fb_add_rect_lvl(LEVEL_NCARD_BG + lvl_offset, CARD_MARGIN, 0, CARD_WIDTH, items_h, C_NCARD_BG); 397 | ncard.bg->y = ncard.pos == NCARD_POS_BOTTOM ? (int)fb_height : -items_h; 398 | ncard.shadow = fb_add_rect_lvl(LEVEL_NCARD_SHADOW + lvl_offset, CARD_MARGIN + CARD_SHADOW_OFF, 0, CARD_WIDTH, items_h, C_NCARD_SHADOW); 399 | interpolator = INTERPOLATOR_OVERSHOOT; 400 | } 401 | else 402 | interpolator = INTERPOLATOR_ACCEL_DECEL; 403 | 404 | ncard.targetH = items_h; 405 | if(ncard.pos != NCARD_POS_CENTER) 406 | ncard.targetH *= 1.3; 407 | else if(!ncard.alpha_bg) 408 | { 409 | ncard.alpha_bg = fb_add_rect_lvl(LEVEL_NCARD_SHADOW + lvl_offset - 1, 0, 0, fb_width, fb_height, 410 | b->reveal_from_black ? BLACK : 0x00000000); 411 | } 412 | 413 | if(items_h >= ncard.bg->h) 414 | { 415 | ncard.bg->h = ncard.targetH; 416 | ncard.shadow->h = ncard.bg->h; 417 | } 418 | 419 | it_y = ncard.bg->y + CARD_PADDING_V; 420 | if(ncard.pos == NCARD_POS_TOP) 421 | it_y += ncard.bg->h - items_h; 422 | 423 | if(title) 424 | { 425 | title->y = it_y; 426 | it_y += title->h*1.5; 427 | list_add(&ncard.texts, title); 428 | } 429 | 430 | if(text) 431 | { 432 | text->y = it_y; 433 | it_y += text->h + btn_h*0.75; 434 | if(!title) 435 | center_text(text, 0, -1, fb_width, -1); 436 | list_add(&ncard.texts, text); 437 | } 438 | 439 | for(i = 0; i < BTN_COUNT; ++i) 440 | { 441 | if(!(ncard.active_btns & (1 << i))) 442 | continue; 443 | btns[i]->y = it_y; 444 | ncard.btns[i].pos.y = it_y - ncard.btns[i].pos.h/3; 445 | list_add(&ncard.texts, btns[i]); 446 | } 447 | 448 | if(ncard.active_btns && !ncard.touch_handler_registered) 449 | { 450 | add_touch_handler_async(ncard_touch_handler, &ncard); 451 | ncard.touch_handler_registered = 1; 452 | } 453 | else if(!ncard.active_btns && ncard.touch_handler_registered) 454 | { 455 | rm_touch_handler_async(ncard_touch_handler, &ncard); 456 | ncard.touch_handler_registered = 0; 457 | } 458 | 459 | ncard.shadow->y = ncard.pos == NCARD_POS_BOTTOM ? ncard.bg->y - CARD_SHADOW_OFF : ncard.bg->y + CARD_SHADOW_OFF; 460 | 461 | ncard.last_y = ncard.bg->y; 462 | ncard.cancelable = b->cancelable; 463 | ncard.on_hidden_call = b->on_hidden_call; 464 | ncard.on_hidden_data = b->on_hidden_data; 465 | ncard.reveal_from_black = b->reveal_from_black; 466 | 467 | item_anim *a = item_anim_create(ncard.bg, 400, interpolator); 468 | switch(ncard.pos) 469 | { 470 | case NCARD_POS_TOP: 471 | a->targetY = ncard.top_offset - (ncard.bg->h - items_h); 472 | break; 473 | case NCARD_POS_BOTTOM: 474 | a->targetY = fb_height - items_h; 475 | break; 476 | case NCARD_POS_CENTER: 477 | a->targetY = fb_height/2 - items_h/2; 478 | break; 479 | } 480 | a->targetH = ncard.targetH; 481 | a->on_step_call = ncard_move_step; 482 | a->on_step_data = &ncard; 483 | a->on_finished_call = ncard_reveal_finished; 484 | item_anim_add(a); 485 | ncard.moving = 1; 486 | 487 | pthread_mutex_unlock(&ncard.mutex); 488 | 489 | if(destroy_builder) 490 | ncard_destroy_builder(b); 491 | } 492 | 493 | void ncard_hide(void) 494 | { 495 | if(!ncard.bg) 496 | return; 497 | 498 | anim_cancel_for(ncard.bg, 0); 499 | 500 | struct ncard *c = mzalloc(sizeof(struct ncard)); 501 | pthread_mutex_lock(&ncard.mutex); 502 | c->bg = ncard.bg; 503 | c->shadow = ncard.shadow; 504 | c->hover_rect = ncard.hover_rect; 505 | c->texts = ncard.texts; 506 | c->last_y = c->bg->y; 507 | c->alpha_bg = ncard.alpha_bg; 508 | c->hiding = 1; 509 | ncard.moving = 1; 510 | ncard.shadow = NULL; 511 | ncard.hover_rect = NULL; 512 | ncard.bg = NULL; 513 | ncard.texts = NULL; 514 | ncard.alpha_bg = NULL; 515 | 516 | if(ncard.touch_handler_registered) 517 | { 518 | rm_touch_handler(ncard_touch_handler, &ncard); 519 | ncard.touch_handler_registered = 0; 520 | } 521 | 522 | pthread_mutex_unlock(&ncard.mutex); 523 | 524 | item_anim *a = item_anim_create(c->bg, 400, INTERPOLATOR_ACCELERATE); 525 | a->targetY = ncard.pos == NCARD_POS_TOP ? -c->bg->h : (int)fb_height + c->bg->h; 526 | a->destroy_item_when_finished = 1; 527 | a->on_step_call = ncard_move_step; 528 | a->on_step_data = c; 529 | a->on_finished_call = ncard_hide_finished; 530 | a->on_finished_data = c; 531 | item_anim_add(a); 532 | 533 | if(ncard.on_hidden_call) 534 | ncard.on_hidden_call(ncard.on_hidden_data); 535 | } 536 | 537 | void ncard_hide_callback(UNUSED void *data) 538 | { 539 | ncard_hide(); 540 | } 541 | 542 | void ncard_destroy_builder(ncard_builder *b) 543 | { 544 | free(b->title); 545 | free(b->text); 546 | free(b->avoid_item); 547 | 548 | int i; 549 | for(i = 0; i < BTN_COUNT; ++i) 550 | { 551 | if(b->buttons[i]) 552 | { 553 | free(b->buttons[i]->text); 554 | free(b->buttons[i]); 555 | } 556 | } 557 | free(b); 558 | } 559 | 560 | int ncard_try_cancel(void) 561 | { 562 | if(ncard.bg && ncard.cancelable) 563 | { 564 | ncard_hide(); 565 | return 1; 566 | } 567 | return 0; 568 | } 569 | 570 | int ncard_is_visible(void) 571 | { 572 | return ncard.bg != NULL; 573 | } 574 | 575 | int ncard_is_moving(void) 576 | { 577 | return ncard.moving == 1; 578 | } 579 | -------------------------------------------------------------------------------- /lib/notification_card.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef NOTIFICATION_CARD_H 19 | #define NOTIFICATION_CARD_H 20 | 21 | #include "framebuffer.h" 22 | 23 | enum // order from right to left 24 | { 25 | BTN_POSITIVE, 26 | BTN_NEGATIVE, 27 | 28 | BTN_COUNT 29 | }; 30 | 31 | enum 32 | { 33 | NCARD_POS_AUTO, 34 | NCARD_POS_TOP, 35 | NCARD_POS_BOTTOM, 36 | NCARD_POS_CENTER, 37 | }; 38 | 39 | typedef void (*ncard_callback)(void*); 40 | 41 | typedef struct 42 | { 43 | char *text; 44 | void *callback_data; 45 | ncard_callback callback; 46 | } ncard_builder_btn; 47 | 48 | typedef struct 49 | { 50 | char *title; 51 | char *text; 52 | ncard_builder_btn *buttons[BTN_COUNT]; 53 | int pos; 54 | fb_item_pos *avoid_item; 55 | int cancelable; 56 | ncard_callback on_hidden_call; 57 | void *on_hidden_data; 58 | int reveal_from_black; 59 | } ncard_builder; 60 | 61 | ncard_builder *ncard_create_builder(void); 62 | void ncard_set_title(ncard_builder *b, const char *title); 63 | void ncard_set_text(ncard_builder *b, const char *text); 64 | void ncard_set_pos(ncard_builder *b, int pos); 65 | void ncard_set_cancelable(ncard_builder *b, int cancelable); 66 | void ncard_avoid_item(ncard_builder *b, void *item); 67 | void ncard_add_btn(ncard_builder *b, int btn_type, const char *text, ncard_callback callback, void *callback_data); 68 | void ncard_set_on_hidden(ncard_builder *b, ncard_callback callback, void *data); 69 | void ncard_set_from_black(ncard_builder *b, int from_black); 70 | 71 | void ncard_set_top_offset(int offset); 72 | void ncard_show(ncard_builder *b, int destroy_builder); 73 | void ncard_hide(void); 74 | int ncard_is_visible(void); 75 | int ncard_is_moving(void); 76 | int ncard_try_cancel(void); 77 | void ncard_hide_callback(void *data); 78 | void ncard_destroy_builder(ncard_builder *b); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /lib/progressdots.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "progressdots.h" 22 | #include "colors.h" 23 | #include "workers.h" 24 | #include "util.h" 25 | #include "animation.h" 26 | 27 | static void progdots_anim_finished(void *data) 28 | { 29 | progdots *p = data; 30 | 31 | item_anim *a = item_anim_create(p->rect, 1000, INTERPOLATOR_ACCEL_DECEL); 32 | if(p->rect->x == p->x) 33 | a->targetX = p->x + PROGDOTS_W - p->rect->w; 34 | else 35 | a->targetX = p->x; 36 | a->start_offset = 300; 37 | a->on_finished_call = progdots_anim_finished; 38 | a->on_finished_data = p; 39 | item_anim_add(a); 40 | } 41 | 42 | progdots *progdots_create(int x, int y) 43 | { 44 | progdots *p = mzalloc(sizeof(progdots)); 45 | p->x = x; 46 | p->y = y; 47 | 48 | p->rect = fb_add_rect(x, y, PROGDOTS_H*4, PROGDOTS_H, C_HIGHLIGHT_BG); 49 | item_anim *a = item_anim_create(p->rect, 1000, INTERPOLATOR_ACCEL_DECEL); 50 | a->targetX = x + PROGDOTS_W - p->rect->w; 51 | a->on_finished_call = progdots_anim_finished; 52 | a->on_finished_data = p; 53 | item_anim_add(a); 54 | return p; 55 | } 56 | 57 | void progdots_destroy(progdots *p) 58 | { 59 | anim_cancel_for(p->rect, 0); 60 | fb_rm_rect(p->rect); 61 | free(p); 62 | } 63 | -------------------------------------------------------------------------------- /lib/progressdots.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef PROGRESSDOTS_H 19 | #define PROGRESSDOTS_H 20 | 21 | #include "framebuffer.h" 22 | 23 | #define PROGDOTS_W (400*DPI_MUL) 24 | #define PROGDOTS_H (10*DPI_MUL) 25 | #define PROGDOTS_CNT 8 26 | 27 | typedef struct 28 | { 29 | FB_ITEM_POS 30 | 31 | fb_rect *rect; 32 | } progdots; 33 | 34 | progdots *progdots_create(int x, int y); 35 | void progdots_destroy(progdots *p); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /lib/tabview.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "tabview.h" 23 | #include "containers.h" 24 | #include "util.h" 25 | #include "animation.h" 26 | #include "log.h" 27 | #include "input.h" 28 | 29 | struct tabview_page 30 | { 31 | fb_item_pos **items; 32 | int last_offset; 33 | }; 34 | 35 | typedef struct tabview_page tabview_page; 36 | 37 | static void tabview_page_destroy(tabview_page *p) 38 | { 39 | list_clear(&p->items, NULL); 40 | free(p); 41 | } 42 | 43 | static void tabview_page_update_offset(tabview_page *p, int offset) 44 | { 45 | if(!p->items || offset == p->last_offset) 46 | return; 47 | 48 | fb_item_pos **itr; 49 | const int diff = offset - p->last_offset; 50 | 51 | for(itr = p->items; *itr; ++itr) 52 | (*itr)->x += diff; 53 | 54 | p->last_offset = offset; 55 | } 56 | 57 | int tabview_touch_handler(touch_event *ev, void *data) 58 | { 59 | tabview *t = data; 60 | if(t->touch_id == -1 && (ev->changed & TCHNG_ADDED)) 61 | { 62 | if (ev->x < t->x || ev->y < t->y || 63 | ev->x > t->x+t->w || ev->y > t->y+t->h) 64 | { 65 | return -1; 66 | } 67 | 68 | t->touch_id = ev->id; 69 | t->touch_moving = 0; 70 | touch_tracker_start(t->tracker, ev); 71 | 72 | if(t->anim_id != ANIM_INVALID_ID) 73 | { 74 | anim_cancel(t->anim_id, 0); 75 | t->anim_id = ANIM_INVALID_ID; 76 | } 77 | return -1; 78 | } 79 | 80 | if(t->touch_id != ev->id) 81 | return -1; 82 | 83 | if(ev->changed & TCHNG_REMOVED) 84 | { 85 | t->touch_id = -1; 86 | touch_tracker_finish(t->tracker, ev); 87 | 88 | if(!t->touch_moving) 89 | return -1; 90 | 91 | if(t->pos % t->w != 0) 92 | { 93 | int page_idx, duration = 100; 94 | float page = ((float)t->pos)/t->w; 95 | if(page < 0) 96 | page_idx = 0; 97 | else if(page >= t->count - 1) 98 | page_idx = t->count - 1; 99 | else 100 | { 101 | float velocity = touch_tracker_get_velocity(t->tracker, TRACKER_X); 102 | if(fabs(velocity) >= 1000.f) 103 | { 104 | page_idx = (int)page; 105 | if(velocity < 0.f) 106 | ++page_idx; 107 | duration = iabs(t->pos - page_idx*t->w)/(fabs(velocity*DPI_MUL)/1000); 108 | } 109 | else 110 | page_idx = (int)(page + 0.5f); 111 | } 112 | 113 | if(page_idx != t->curr_page) 114 | { 115 | if(t->on_page_changed_by_swipe) 116 | t->on_page_changed_by_swipe(page_idx); 117 | t->curr_page = page_idx; 118 | } 119 | 120 | tabview_set_active_page(t, page_idx, duration); 121 | } 122 | return -1; 123 | } 124 | 125 | if(ev->changed & TCHNG_POS) 126 | { 127 | touch_tracker_add(t->tracker, ev); 128 | 129 | if(!t->touch_moving) 130 | { 131 | if (t->tracker->distance_abs_x >= 25*DPI_MUL && t->tracker->distance_abs_x > t->tracker->distance_abs_y*3) 132 | { 133 | t->touch_moving = 1; 134 | ev->changed |= TCHNG_REMOVED; 135 | ev->x = -1; 136 | ev->y = -1; 137 | 138 | t->pos += -t->tracker->distance_x; 139 | tabview_update_positions(t); 140 | } 141 | return -1; 142 | } 143 | 144 | t->pos += t->tracker->prev_x - ev->x; 145 | tabview_update_positions(t); 146 | return 1; 147 | } 148 | 149 | return -1; 150 | } 151 | 152 | tabview *tabview_create(int x, int y, int w, int h) 153 | { 154 | tabview *t = mzalloc(sizeof(tabview)); 155 | t->x = x; 156 | t->y = y; 157 | t->w = w; 158 | t->h = h; 159 | t->anim_id = ANIM_INVALID_ID; 160 | t->touch_id = -1; 161 | t->tracker = touch_tracker_create(); 162 | pthread_mutex_init(&t->mutex, NULL); 163 | return t; 164 | } 165 | 166 | void tabview_destroy(tabview *t) 167 | { 168 | rm_touch_handler(&tabview_touch_handler, t); 169 | pthread_mutex_destroy(&t->mutex); 170 | list_clear(&t->pages, tabview_page_destroy); 171 | touch_tracker_destroy(t->tracker); 172 | free(t); 173 | } 174 | 175 | void tabview_add_page(tabview *t, int idx) 176 | { 177 | if(idx == -1) 178 | idx = t->count; 179 | 180 | tabview_page *p = mzalloc(sizeof(tabview_page)); 181 | 182 | pthread_mutex_lock(&t->mutex); 183 | list_add_at(&t->pages, idx, p); 184 | ++t->count; 185 | t->fullW = t->count*t->w; 186 | pthread_mutex_unlock(&t->mutex); 187 | } 188 | 189 | void tabview_rm_page(tabview *t, int idx) 190 | { 191 | if(idx < 0 || idx >= t->count) 192 | return; 193 | 194 | pthread_mutex_lock(&t->mutex); 195 | list_rm_at(&t->pages, idx, tabview_page_destroy); 196 | --t->count; 197 | t->fullW = t->count*t->w; 198 | pthread_mutex_unlock(&t->mutex); 199 | } 200 | 201 | void tabview_add_item(tabview *t, int page_idx, void *fb_item) 202 | { 203 | if(page_idx < 0 || page_idx >= t->count) 204 | return; 205 | 206 | pthread_mutex_lock(&t->mutex); 207 | list_add(&t->pages[page_idx]->items, fb_item); 208 | pthread_mutex_unlock(&t->mutex); 209 | } 210 | 211 | void tabview_add_items(tabview *t, int page_idx, void *fb_items) 212 | { 213 | if(page_idx < 0 || page_idx >= t->count || !fb_items) 214 | return; 215 | 216 | pthread_mutex_lock(&t->mutex); 217 | list_add_from_list(&t->pages[page_idx]->items, fb_items); 218 | pthread_mutex_unlock(&t->mutex); 219 | } 220 | 221 | void tabview_rm_item(tabview *t, int page_idx, void *fb_item) 222 | { 223 | if(page_idx < 0 || page_idx >= t->count) 224 | return; 225 | 226 | pthread_mutex_lock(&t->mutex); 227 | list_rm(&t->pages[page_idx]->items, fb_item, NULL); 228 | pthread_mutex_unlock(&t->mutex); 229 | } 230 | 231 | void tabview_update_positions(tabview *t) 232 | { 233 | int i; 234 | int x = 0; 235 | 236 | if(t->last_reported_pos != t->pos) 237 | { 238 | if(t->on_pos_changed) 239 | t->on_pos_changed(((float)t->pos)/t->w); 240 | t->last_reported_pos = t->pos; 241 | } 242 | 243 | fb_batch_start(); 244 | pthread_mutex_lock(&t->mutex); 245 | for(i = 0; i < t->count; ++i) 246 | { 247 | tabview_page_update_offset(t->pages[i], x - t->pos); 248 | x += t->w; 249 | } 250 | pthread_mutex_unlock(&t->mutex); 251 | fb_batch_end(); 252 | fb_request_draw(); 253 | } 254 | 255 | static void tabview_move_anim_step(void *data, float interpolated) 256 | { 257 | tabview *t = data; 258 | t->pos = t->anim_pos_start + (t->anim_pos_diff * interpolated); 259 | tabview_update_positions(t); 260 | } 261 | 262 | void tabview_set_active_page(tabview *t, int page_idx, int anim_duration) 263 | { 264 | if(page_idx < 0 || page_idx >= t->count) 265 | return; 266 | 267 | if(t->curr_page == page_idx && t->pos == page_idx*t->w) 268 | return; 269 | 270 | if(t->anim_id != ANIM_INVALID_ID) 271 | anim_cancel(t->anim_id, 0); 272 | 273 | t->curr_page = page_idx; 274 | 275 | if(anim_duration == 0) 276 | { 277 | t->pos = page_idx*t->w; 278 | tabview_update_positions(t); 279 | return; 280 | } 281 | 282 | t->anim_pos_start = t->pos; 283 | t->anim_pos_diff = page_idx*t->w - t->pos; 284 | 285 | call_anim *a = call_anim_create(t, tabview_move_anim_step, anim_duration, INTERPOLATOR_DECELERATE); 286 | t->anim_id = a->id; 287 | call_anim_add(a); 288 | } 289 | -------------------------------------------------------------------------------- /lib/tabview.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef TABVIEW_H 19 | #define TABVIEW_H 20 | 21 | #include 22 | #include "framebuffer.h" 23 | #include "input.h" 24 | #include "touch_tracker.h" 25 | 26 | struct tabview_page; 27 | 28 | typedef struct { 29 | FB_ITEM_POS 30 | 31 | int pos; 32 | int anim_pos_start; 33 | int anim_pos_diff; 34 | int fullW; 35 | 36 | struct tabview_page **pages; 37 | int count; 38 | int curr_page; 39 | 40 | uint32_t anim_id; 41 | pthread_mutex_t mutex; 42 | 43 | void (*on_page_changed_by_swipe)(int); // new_page 44 | void (*on_pos_changed)(float); 45 | 46 | int last_reported_pos; 47 | 48 | int touch_id; 49 | int touch_moving; 50 | touch_tracker *tracker; 51 | } tabview; 52 | 53 | tabview *tabview_create(int x, int y, int w, int h); 54 | int tabview_touch_handler(touch_event *ev, void *data); 55 | void tabview_destroy(tabview *t); 56 | void tabview_add_page(tabview *t, int idx); 57 | void tabview_rm_page(tabview *t, int idx); 58 | void tabview_add_item(tabview *t, int page_idx, void *fb_item); 59 | void tabview_add_items(tabview *t, int page_idx, void *fb_items); 60 | void tabview_rm_item(tabview *t, int page_idx, void *fb_item); 61 | void tabview_update_positions(tabview *t); 62 | void tabview_set_active_page(tabview *t, int page_idx, int anim_duration); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /lib/touch_tracker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | 20 | #include "touch_tracker.h" 21 | #include "util.h" 22 | 23 | touch_tracker *touch_tracker_create(void) 24 | { 25 | touch_tracker *t = mzalloc(sizeof(touch_tracker)); 26 | return t; 27 | } 28 | 29 | void touch_tracker_destroy(touch_tracker *t) 30 | { 31 | free(t); 32 | } 33 | 34 | void touch_tracker_start(touch_tracker *t, touch_event *ev) 35 | { 36 | t->distance_abs_x = t->distance_abs_y = 0; 37 | t->distance_x = t->distance_y = 0; 38 | t->start_x = ev->x; 39 | t->start_y = ev->y; 40 | t->last_x = ev->x; 41 | t->last_y = ev->y; 42 | t->prev_x = ev->x; 43 | t->prev_y = ev->y; 44 | memcpy(&t->time_start, &ev->time, sizeof(struct timeval)); 45 | } 46 | 47 | void touch_tracker_finish(touch_tracker *t, touch_event *ev) 48 | { 49 | t->period = timeval_us_diff(ev->time, t->time_start); 50 | } 51 | 52 | void touch_tracker_add(touch_tracker *t, touch_event *ev) 53 | { 54 | t->prev_x = t->last_x; 55 | t->prev_y = t->last_y; 56 | t->distance_x += ev->x - t->last_x; 57 | t->distance_y += ev->y - t->last_y; 58 | t->distance_abs_x += iabs(ev->x - t->last_x); 59 | t->distance_abs_y += iabs(ev->y - t->last_y); 60 | t->last_x = ev->x; 61 | t->last_y = ev->y; 62 | } 63 | 64 | float touch_tracker_get_velocity(touch_tracker *t, int axis) 65 | { 66 | if(axis == TRACKER_X) 67 | return ((((float)t->distance_x) / t->period) * 1000000) / DPI_MUL; 68 | else 69 | return ((((float)t->distance_y) / t->period) * 1000000) / DPI_MUL; 70 | } 71 | 72 | float touch_tracker_get_velocity_abs(touch_tracker *t, int axis) 73 | { 74 | if(axis == TRACKER_X) 75 | return ((((float)t->distance_abs_x) / t->period) * 1000000) / DPI_MUL; 76 | else 77 | return ((((float)t->distance_abs_y) / t->period) * 1000000) / DPI_MUL; 78 | } 79 | -------------------------------------------------------------------------------- /lib/touch_tracker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef TOUCH_TRACKER_H 19 | #define TOUCH_TRACKER_H 20 | 21 | #include 22 | #include 23 | #include "input.h" 24 | 25 | #define TRACKER_X 0 26 | #define TRACKER_Y 1 27 | 28 | typedef struct 29 | { 30 | struct timeval time_start; 31 | int64_t period; 32 | int distance_x, distance_y; 33 | int distance_abs_x, distance_abs_y; 34 | int last_x, last_y; 35 | int prev_x, prev_y; 36 | int start_x, start_y; 37 | } touch_tracker; 38 | 39 | touch_tracker *touch_tracker_create(void); 40 | void touch_tracker_destroy(touch_tracker *t); 41 | void touch_tracker_start(touch_tracker *t, touch_event *ev); 42 | void touch_tracker_finish(touch_tracker *t, touch_event *ev); 43 | void touch_tracker_add(touch_tracker *t, touch_event *ev); 44 | float touch_tracker_get_velocity(touch_tracker *t, int axis); 45 | float touch_tracker_get_velocity_abs(touch_tracker *t, int axis); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /lib/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _INIT_UTIL_H_ 18 | #define _INIT_UTIL_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define UNUSED __attribute__((unused)) 26 | 27 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 28 | 29 | #define REBOOT_SYSTEM 0 30 | #define REBOOT_RECOVERY 1 31 | #define REBOOT_BOOTLOADER 2 32 | #define REBOOT_SHUTDOWN 3 33 | 34 | time_t gettime(void); 35 | unsigned int decode_uid(const char *s); 36 | int mkdir_recursive(const char *pathname, mode_t mode); 37 | int mkdir_recursive_with_perms(const char *pathname, mode_t mode, const char *owner, const char *group); 38 | void sanitize(char *p); 39 | int make_link(const char *oldpath, const char *newpath); 40 | void remove_link(const char *oldpath, const char *newpath); 41 | int wait_for_file(const char *filename, int timeout); 42 | int copy_file(const char *from, const char *to); 43 | int copy_dir(const char *from, const char *to); 44 | int mkdir_with_perms(const char *path, mode_t mode, const char *owner, const char *group); 45 | int write_file(const char *path, const char *value); 46 | int remove_dir(const char *dir); 47 | int run_cmd(char **cmd); 48 | int run_cmd_with_env(char **cmd, char *const *envp); 49 | char *run_get_stdout(char **cmd); 50 | char *run_get_stdout_with_exit(char **cmd, int *exit_code); 51 | char *run_get_stdout_with_exit_with_env(char **cmd, int *exit_code, char *const *envp); 52 | char *readlink_recursive(const char *link); 53 | void stdio_to_null(); 54 | char *parse_string(char *src); 55 | uint32_t timespec_diff(struct timespec *f, struct timespec *s); 56 | inline int64_t timeval_us_diff(struct timeval now, struct timeval prev); 57 | void emergency_remount_ro(void); 58 | int create_loop_device(const char *dev_path, const char *img_path, int loop_num, int loop_chmod); 59 | int mount_image(const char *src, const char *dst, const char *fs, int flags, const void *data); 60 | void do_reboot(int type); 61 | int mr_system(const char *shell_fmt, ...); 62 | 63 | inline int imin(int a, int b); 64 | inline int imax(int a, int b); 65 | inline int iabs(int a); 66 | inline int in_rect(int x, int y, int rx, int ry, int rw, int rh); 67 | 68 | inline void *mzalloc(size_t size); // alloc and fill with 0s 69 | char *strtoupper(const char *str); 70 | int strstartswith(const char *haystack, const char *needle); 71 | int strendswith(const char *haystack, const char *needle); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /lib/velocity_tracker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #include "touch_tracker.h" 20 | #include "util.h" 21 | 22 | touch_tracker *touch_tracker_create(void) 23 | { 24 | touch_tracker *t = mzalloc(sizeof(touch_tracker)); 25 | return t; 26 | } 27 | 28 | void touch_tracker_destroy(touch_tracker *t) 29 | { 30 | free(t); 31 | } 32 | 33 | void touch_tracker_start(touch_tracker *t, touch_event *ev) 34 | { 35 | t->distance_abs_x = t->distance_abs_y = 0; 36 | t->start_x = ev->x; 37 | t->start_y = ev->y; 38 | t->last_x = ev->x; 39 | t->last_y = ev->y; 40 | memcpy(&v->time_start, &ev->time, sizeof(struct timeval)); 41 | } 42 | 43 | void touch_tracker_finish(touch_tracker *t, touch_event *ev) 44 | { 45 | t->distance_x = ev->x - t->start_x; 46 | t->distance_y = ev->y - t->start_y; 47 | t->period = timeval_us_diff(ev->time, t->time_start); 48 | } 49 | 50 | void touch_tracker_add(touch_tracker *t, touch_event *ev) 51 | { 52 | t->distance_abs_x += iabs(ev->x - t->last_x); 53 | t->distance_abs_y += iabs(ev->y - t->last_y); 54 | t->last_x = ev->x; 55 | t->last_y = ev->y; 56 | } 57 | 58 | float touch_tracker_get_velocity(touch_tracker *t, int axis) 59 | { 60 | if(axis == TRACKER_X) 61 | return ((((float)t->distance_x) / t->period) * 1000000) / DPI_MUL; 62 | else 63 | return ((((float)t->distance_y) / t->period) * 1000000) / DPI_MUL; 64 | } 65 | 66 | float touch_tracker_get_velocity_abs(touch_tracker *t, int axis) 67 | { 68 | if(axis == TRACKER_X) 69 | return ((((float)t->distance_abs_x) / t->period) * 1000000) / DPI_MUL; 70 | else 71 | return ((((float)t->distance_abs_y) / t->period) * 1000000) / DPI_MUL; 72 | } 73 | -------------------------------------------------------------------------------- /lib/workers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "util.h" 23 | #include "workers.h" 24 | #include "log.h" 25 | #include "containers.h" 26 | 27 | struct worker 28 | { 29 | void *data; 30 | worker_call call; 31 | }; 32 | 33 | struct worker_thread 34 | { 35 | pthread_t thread; 36 | pthread_mutex_t mutex; 37 | struct worker **workers; 38 | volatile int run; 39 | }; 40 | 41 | static struct worker_thread worker_thread = { 42 | .mutex = PTHREAD_MUTEX_INITIALIZER, 43 | .workers = NULL, 44 | .run = 0, 45 | }; 46 | 47 | #define SLEEP_CONST 10 48 | static void *worker_thread_work(void *data) 49 | { 50 | struct worker_thread *t = (struct worker_thread*)data; 51 | struct worker **w; 52 | 53 | struct timespec last, curr; 54 | uint32_t diff = 0, prev_sleep = 0; 55 | clock_gettime(CLOCK_MONOTONIC, &last); 56 | 57 | while(t->run) 58 | { 59 | pthread_mutex_lock(&t->mutex); 60 | 61 | clock_gettime(CLOCK_MONOTONIC, &curr); 62 | diff = timespec_diff(&last, &curr); 63 | 64 | for(w = t->workers; w && *w;) 65 | { 66 | if((*w)->call(diff, (*w)->data)) 67 | w = list_rm_at(&worker_thread.workers, w - t->workers, &free); 68 | else 69 | ++w; 70 | } 71 | 72 | pthread_mutex_unlock(&t->mutex); 73 | 74 | last = curr; 75 | if(diff <= SLEEP_CONST+prev_sleep) 76 | { 77 | prev_sleep = SLEEP_CONST+prev_sleep-diff; 78 | usleep(prev_sleep*1000); 79 | } 80 | else 81 | prev_sleep = 0; 82 | } 83 | return NULL; 84 | } 85 | 86 | void workers_start(void) 87 | { 88 | if(worker_thread.run != 0) 89 | return; 90 | 91 | worker_thread.run = 1; 92 | pthread_create(&worker_thread.thread, NULL, worker_thread_work, &worker_thread); 93 | } 94 | 95 | void workers_stop(void) 96 | { 97 | if(worker_thread.run != 1) 98 | return; 99 | 100 | worker_thread.run = 0; 101 | pthread_join(worker_thread.thread, NULL); 102 | 103 | list_clear(&worker_thread.workers, &free); 104 | } 105 | 106 | void workers_add(worker_call call, void *data) 107 | { 108 | if(worker_thread.run != 1) 109 | { 110 | ERROR("workers: adding worker when the thread isn't running'\n"); 111 | return; 112 | } 113 | 114 | struct worker *w = mzalloc(sizeof(struct worker)); 115 | w->call = call; 116 | w->data = data; 117 | 118 | pthread_mutex_lock(&worker_thread.mutex); 119 | list_add(&worker_thread.workers, w); 120 | pthread_mutex_unlock(&worker_thread.mutex); 121 | } 122 | 123 | void workers_remove(worker_call call, void *data) 124 | { 125 | if(worker_thread.run != 1) 126 | { 127 | ERROR("workers: removing worker when the thread isn't running'\n"); 128 | return; 129 | } 130 | 131 | pthread_mutex_lock(&worker_thread.mutex); 132 | if(worker_thread.workers) 133 | { 134 | int i; 135 | struct worker *w; 136 | for(i = 0; worker_thread.workers[i]; ++i) 137 | { 138 | w = worker_thread.workers[i]; 139 | if(w->call == call && w->data == data) 140 | { 141 | list_rm_at(&worker_thread.workers, i, &free); 142 | break; 143 | } 144 | } 145 | } 146 | pthread_mutex_unlock(&worker_thread.mutex); 147 | } 148 | 149 | pthread_t workers_get_thread_id(void) 150 | { 151 | return worker_thread.thread; 152 | } 153 | -------------------------------------------------------------------------------- /lib/workers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef WORKERS_H 19 | #define WORKERS_H 20 | 21 | #include 22 | #include 23 | 24 | typedef int (*worker_call)(uint32_t, void *); // ms_diff, data. Returns 1 if it should be removed 25 | 26 | void workers_start(void); 27 | void workers_stop(void); 28 | void workers_add(worker_call call, void *data); 29 | void workers_remove(worker_call call, void *data); 30 | pthread_t workers_get_thread_id(void); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdrianDC/kernel_permissive_patcher/469049c626fd16ad0a9a66fe902a80627d2f2a44/logo.png -------------------------------------------------------------------------------- /release/kernel_permissive_patcher.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdrianDC/kernel_permissive_patcher/469049c626fd16ad0a9a66fe902a80627d2f2a44/release/kernel_permissive_patcher.zip -------------------------------------------------------------------------------- /release/kernel_safetynet_verified.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdrianDC/kernel_permissive_patcher/469049c626fd16ad0a9a66fe902a80627d2f2a44/release/kernel_safetynet_verified.zip -------------------------------------------------------------------------------- /release/kernel_selinuxaudit_patcher.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdrianDC/kernel_permissive_patcher/469049c626fd16ad0a9a66fe902a80627d2f2a44/release/kernel_selinuxaudit_patcher.zip -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of MultiROM. 3 | * 4 | * MultiROM is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * MultiROM is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with MultiROM. If not, see . 16 | */ 17 | 18 | #ifndef VERSION_H 19 | #define VERSION_H 20 | #define VERSION_MULTIROM 33 21 | #define VERSION_TRAMPOLINE 27 22 | 23 | // For device-specific fixes. Use letters, the version will then be like "12a" 24 | #define VERSION_DEV_FIX "x" 25 | #endif 26 | --------------------------------------------------------------------------------