diff --git a/data.cpp b/data.cpp
index 62709a59..eda23399 100644
--- a/data.cpp
+++ b/data.cpp
@@ -827,6 +827,16 @@ void DataManager::SetDefaultValues()
mConst.SetValue("tw_has_boot_slots", "0");
#endif
+#ifdef TW_OEM_BUILD
+ LOGINFO("TW_OEM_BUILD := true\n");
+ mConst.SetValue("tw_oem_build", "1");
+#else
+ mConst.SetValue("tw_oem_build", "0");
+ mPersist.SetValue("tw_app_prompt", "1");
+ mPersist.SetValue("tw_app_install_system", "1");
+ mData.SetValue("tw_app_install_status", "0"); // 0 = no status, 1 = not installed, 2 = already installed
+#endif
+
pthread_mutex_unlock(&m_valuesLock);
}
diff --git a/gui/action.cpp b/gui/action.cpp
index 8600186e..fe573697 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -198,6 +198,7 @@ GUIAction::GUIAction(xml_node<>* node)
ADD_ACTION(checkpartitionlifetimewrites);
ADD_ACTION(mountsystemtoggle);
ADD_ACTION(setlanguage);
+ ADD_ACTION(checkforapp);
// remember actions that run in the caller thread
for (mapFunc::const_iterator it = mf.begin(); it != mf.end(); ++it)
@@ -229,6 +230,7 @@ GUIAction::GUIAction(xml_node<>* node)
ADD_ACTION(flashimage);
ADD_ACTION(twcmd);
ADD_ACTION(setbootslot);
+ ADD_ACTION(installapp);
}
// First, get the action
@@ -1879,3 +1881,157 @@ int GUIAction::setbootslot(std::string arg)
operation_end(0);
return 0;
}
+
+int GUIAction::checkforapp(std::string arg __unused)
+{
+ int op_status = 1;
+ operation_start("Check for TWRP App");
+ if (!simulate)
+ {
+ string sdkverstr = TWFunc::System_Property_Get("ro.build.version.sdk");
+ int sdkver = 0;
+ if (!sdkverstr.empty()) {
+ sdkver = atoi(sdkverstr.c_str());
+ }
+ if (sdkver <= 13) {
+ if (sdkver == 0)
+ LOGINFO("Unable to read sdk version from build prop\n");
+ else
+ LOGINFO("SDK version too low for TWRP app (%i < 14)\n", sdkver);
+ DataManager::SetValue("tw_app_install_status", 1); // 0 = no status, 1 = not installed, 2 = already installed
+ goto exit;
+ }
+ if (PartitionManager.Mount_By_Path("/system", false)) {
+ string base_path = "/system";
+ if (TWFunc::Path_Exists("/system/system"))
+ base_path += "/system"; // For devices with system as a root file system (e.g. Pixel)
+ string install_path = base_path + "/priv-app";
+ if (!TWFunc::Path_Exists(install_path))
+ install_path = base_path + "/app";
+ install_path += "/twrpapp";
+ if (TWFunc::Path_Exists(install_path)) {
+ LOGINFO("App found at '%s'\n", install_path.c_str());
+ DataManager::SetValue("tw_app_install_status", 2); // 0 = no status, 1 = not installed, 2 = already installed
+ goto exit;
+ }
+ } else if (PartitionManager.Mount_By_Path("/data", false)) {
+ string parent_path = "/data/app";
+ DIR *d = opendir("/data/app");
+ struct dirent *p;
+ int len = strlen("me.twrp.twrpapp-");
+ while ((p = readdir(d))) {
+ if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
+ continue;
+ if (p->d_type == DT_DIR && strlen(p->d_name) >= len && strncmp(p->d_name, "me.twrp.twrpapp-", len) == 0) {
+ LOGINFO("App found at %s/%s\n", parent_path.c_str(), p->d_name);
+ closedir(d);
+ DataManager::SetValue("tw_app_install_status", 2); // 0 = no status, 1 = not installed, 2 = already installed
+ goto exit;
+ }
+ }
+ closedir(d);
+ }
+ } else
+ simulate_progress_bar();
+ LOGINFO("App not installed\n");
+ DataManager::SetValue("tw_app_install_status", 1); // 0 = no status, 1 = not installed, 2 = already installed
+exit:
+ operation_end(0);
+ return 0;
+}
+
+int GUIAction::installapp(std::string arg __unused)
+{
+ int op_status = 1;
+ operation_start("Install TWRP App");
+ if (!simulate)
+ {
+ if (DataManager::GetIntValue("tw_mount_system_ro") > 0 || DataManager::GetIntValue("tw_app_install_system") == 0) {
+ if (PartitionManager.Mount_By_Path("/data", true)) {
+ string install_path = "/data/app";
+ string context = "u:object_r:apk_data_file:s0";
+ if (!TWFunc::Path_Exists(install_path)) {
+ if (mkdir(install_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
+ LOGERR("Error making %s directory: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ if (chown(install_path.c_str(), 1000, 1000)) {
+ LOGERR("chown %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ if (setfilecon(install_path.c_str(), context.c_str()) < 0) {
+ LOGERR("setfilecon %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ }
+ install_path += "/me.twrp.twrpapp-1";
+ if (mkdir(install_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
+ LOGERR("Error making %s directory: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ if (chown(install_path.c_str(), 1000, 1000)) {
+ LOGERR("chown %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ if (setfilecon(install_path.c_str(), context.c_str()) < 0) {
+ LOGERR("setfilecon %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ install_path += "/base.apk";
+ if (TWFunc::copy_file("/sbin/me.twrp.twrpapp.apk", install_path, 0644)) {
+ LOGERR("Error copying apk file\n");
+ goto exit;
+ }
+ if (chown(install_path.c_str(), 1000, 1000)) {
+ LOGERR("chown %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ if (setfilecon(install_path.c_str(), context.c_str()) < 0) {
+ LOGERR("setfilecon %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ sync();
+ sync();
+ }
+ } else {
+ if (PartitionManager.Mount_By_Path("/system", true)) {
+ string base_path = "/system";
+ if (TWFunc::Path_Exists("/system/system"))
+ base_path += "/system"; // For devices with system as a root file system (e.g. Pixel)
+ string install_path = base_path + "/priv-app";
+ string context = "u:object_r:system_file:s0";
+ if (!TWFunc::Path_Exists(install_path))
+ install_path = base_path + "/app";
+ if (TWFunc::Path_Exists(install_path)) {
+ install_path += "/twrpapp";
+ LOGINFO("Installing app to '%s'\n", install_path.c_str());
+ if (mkdir(install_path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0) {
+ if (setfilecon(install_path.c_str(), context.c_str()) < 0) {
+ LOGERR("setfilecon %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ install_path += "/me.twrp.twrpapp.apk";
+ if (TWFunc::copy_file("/sbin/me.twrp.twrpapp.apk", install_path, 0644)) {
+ LOGERR("Error copying apk file\n");
+ goto exit;
+ }
+ if (setfilecon(install_path.c_str(), context.c_str()) < 0) {
+ LOGERR("setfilecon %s error: %s\n", install_path.c_str(), strerror(errno));
+ goto exit;
+ }
+ sync();
+ sync();
+ PartitionManager.UnMount_By_Path("/system", true);
+ op_status = 0;
+ } else {
+ LOGERR("Error making app directory '%s': %s\n", strerror(errno));
+ }
+ }
+ }
+ }
+ } else
+ simulate_progress_bar();
+exit:
+ operation_end(0);
+ return 0;
+}
diff --git a/gui/objects.hpp b/gui/objects.hpp
index 8d4484ae..2a95022d 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -320,6 +320,7 @@ protected:
int getpartitiondetails(std::string arg);
int screenshot(std::string arg);
int setbrightness(std::string arg);
+ int checkforapp(std::string arg);
// (originally) threaded actions
int fileexists(std::string arg);
@@ -358,6 +359,7 @@ protected:
int setlanguage(std::string arg);
int twcmd(std::string arg);
int setbootslot(std::string arg);
+ int installapp(std::string arg);
int simulate;
};
diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml
index 77164184..d9113129 100644
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -114,6 +114,13 @@
Rebooting...
Swipe to Reboot
Reboot
+ Install TWRP App?
+ Would you like to install the Official TWRP App?
+ The app can check for new TWRP versions.
+ Prompt to install TWRP app if not installed
+ Install as a System App
+ Installing App...
+ Swipe to Install TWRP App
Swipe to confirm Flash
Confirm Action
Press back button to cancel.
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index f0ba791f..b36b5a61 100644
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -678,7 +678,7 @@
tw_action=reboot
- tw_action_param=system
+ tw_reboot_param=system
tw_has_action2=0
tw_text1={@no_os1=No OS Installed! Are you}
tw_text2={@no_osrb=sure you wish to reboot?}
@@ -924,7 +924,7 @@
- %tw_action_param%
+ appcheck
@@ -933,6 +933,28 @@
+
+
+
+
+
+
+
+
+ %tw_reboot_param%
+
+
+
+
+ rebootapp
+
+
+
+
+ %tw_reboot_param%
+
+
+
@@ -2752,7 +2774,7 @@
tw_back=reboot
tw_action=reboot
- tw_action_param=poweroff
+ tw_reboot_param=poweroff
tw_has_action2=0
tw_text1={@no_os1=No OS Installed! Are you}
tw_text2={@no_ospo=sure you wish to power off?}
@@ -2770,7 +2792,7 @@
tw_back=reboot
tw_action=reboot
- tw_action_param=recovery
+ tw_reboot_param=recovery
tw_has_action2=0
tw_text1={@no_os1=No OS Installed! Are you}
tw_text2={@no_osrb=sure you wish to reboot?}
@@ -2788,7 +2810,7 @@
tw_back=reboot
tw_action=reboot
- tw_action_param=bootloader
+ tw_reboot_param=bootloader
tw_has_action2=0
tw_text1={@no_os1=No OS Installed! Are you}
tw_text2={@no_osrb=sure you wish to reboot?}
@@ -2806,7 +2828,7 @@
tw_back=reboot
tw_action=reboot
- tw_action_param=download
+ tw_reboot_param=download
tw_has_action2=0
tw_text1={@no_os1=No OS Installed! Are you}
tw_text2={@no_osrb=sure you wish to reboot?}
@@ -2866,6 +2888,80 @@
+
+
+
+
+
+ {@reboot_hdr=Reboot}
+
+
+
+
+ {@reboot_install_app_hdr=Install TWRP App?}
+
+
+
+
+ {@reboot_install_app1=Would you like to install the Official TWRP App?}
+
+
+
+
+ {@reboot_install_app2=The app can check for new TWRP versions.}
+
+
+
+
+ {@reboot_install_app_prompt_install=Prompt to install TWRP app if not installed}
+
+
+
+
+
+
+ {@reboot_install_app_system=Install as a System App}
+
+
+
+
+
+
+ {@swipe_to_install_app=Swipe to Install TWRP App}
+
+ tw_back=reboot
+ tw_action=installapp
+ tw_action_text1={@reboot_installing_app=Installing App...}
+ tw_action_text2=
+ tw_has_action2=1
+ tw_action2=reboot
+ tw_action2_param=%tw_reboot_param%
+ tw_complete_text1={@rebooting=Rebooting...}
+ action_page
+
+
+
+
+
+
+ tw_app_install_status=0
+ main
+
+
+
+
+
+
+ tw_app_install_status=0
+ reboot
+
+
+
+
@@ -2988,6 +3084,9 @@
+
+
+
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 67aa86b4..b5891acd 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -501,3 +501,12 @@ ifneq ($(TW_EXCLUDE_SUPERSU), true)
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
endif
+
+#TWRP App "placeholder"
+include $(CLEAR_VARS)
+LOCAL_MODULE := me.twrp.twrpapp.apk
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
diff --git a/prebuilt/me.twrp.twrpapp.apk b/prebuilt/me.twrp.twrpapp.apk
new file mode 100644
index 00000000..cb19986f
Binary files /dev/null and b/prebuilt/me.twrp.twrpapp.apk differ
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 9b0356ff..92d3a3b9 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -788,7 +788,10 @@ string TWFunc::System_Property_Get(string Prop_Name) {
string propvalue;
if (!PartitionManager.Mount_By_Path("/system", true))
return propvalue;
- if (TWFunc::read_file("/system/build.prop", buildprop) != 0) {
+ string prop_file = "/system/build.prop";
+ if (!TWFunc::Path_Exists(prop_file))
+ prop_file = "/system/system/build.prop"; // for devices with system as a root file system (e.g. Pixel)
+ if (TWFunc::read_file(prop_file, buildprop) != 0) {
LOGINFO("Unable to open /system/build.prop for getting '%s'.\n", Prop_Name.c_str());
DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
if (!mount_state)