├── 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 |
--------------------------------------------------------------------------------