namespace {
-const char kThemeMetadataKey[] = "http://tizen.org/metadata/theme";
+const char kDefaultThemeKey[] = "http://tizen.org/metadata/theme/default";
+const char kThemeKey[] = "http://tizen.org/metadata/theme";
std::string GetThemeFilePath(const char* pkgid) {
pkgmgrinfo_pkginfo_h handle;
}
bool ParseAndCommitTheme(ThemeParser::ThemeOperation op, const std::string& id,
- const std::string& pkgid, const std::string& path) {
+ const std::string& pkgid, const std::string& path, bool is_default) {
uid_t uid;
int r = pkgmgr_installer_info_get_target_uid(&uid);
if (r < 0) {
LOG(ERROR) << "Failed to get target uid";
return false;
}
+
ThemeParser parser(path);
- ThemeInfo theme = parser.Inflate(id, pkgid, uid);
+ ThemeInfo theme = parser.Inflate(id, pkgid, uid, is_default);
if (!theme.IsValid()) {
LOG(ERROR) << "Failed to parse theme";
return false;
if (root_path.empty())
return -1;
+ bool is_default = false;
+ std::string json_file;
for (__metadata_t* md : GListRange<__metadata_t*>(metadata)) {
- if (!strcmp(md->key, kThemeMetadataKey)) {
- if (!ParseAndCommitTheme(ThemeParser::ThemeOperation::ADD, appid, pkgid,
- (root_path + md->value)))
- return -1;
- }
+ // Assume that there is a only json file for theme
+ if (!strcmp(md->key, kThemeKey))
+ json_file = root_path + md->value;
+ else if (!strcmp(md->key, kDefaultThemeKey))
+ is_default = true;
}
+
+ if (!ParseAndCommitTheme(ThemeParser::ThemeOperation::ADD, appid, pkgid,
+ json_file, is_default))
+ return -1;
return 0;
}
if (root_path.empty())
return -1;
+ std::string json_file;
for (__metadata_t* md : GListRange<__metadata_t*>(metadata)) {
- if (!strcmp(md->key, kThemeMetadataKey)) {
- if (!ParseAndCommitTheme(ThemeParser::ThemeOperation::UPDATE, appid,
- pkgid, (root_path + md->value)))
- return -1;
- }
+ // Assume that there is a only json file for theme
+ if (!strcmp(md->key, kThemeKey))
+ json_file = root_path + md->value;
}
+
+ // Upgrading default theme is not allowed
+ if (!ParseAndCommitTheme(ThemeParser::ThemeOperation::UPDATE, appid, pkgid,
+ json_file, false))
+ return -1;
return 0;
}
if (root_path.empty())
return -1;
+ std::string json_file;
for (__metadata_t* md : GListRange<__metadata_t*>(metadata)) {
- if (!strcmp(md->key, kThemeMetadataKey)) {
- if (!ParseAndCommitTheme(ThemeParser::ThemeOperation::REMOVE, appid,
- pkgid, (root_path + md->value)))
- return -1;
- }
+ // Assume that there is a only json file for theme
+ if (!strcmp(md->key, kThemeKey))
+ json_file = root_path + md->value;
}
+
+ // Removing default theme is not allowed
+ if (!ParseAndCommitTheme(ThemeParser::ThemeOperation::REMOVE, appid, pkgid,
+ json_file, false))
+ return -1;
return 0;
}
namespace plugin {
loader::ThemeInfo ThemeParser::Inflate(const std::string id,
- const std::string pkgid, uid_t uid) {
+ const std::string pkgid, uid_t uid, bool is_default) {
Json::CharReaderBuilder rbuilder;
rbuilder["collectComments"] = false;
ThemeInfoBuilder builder(id);
builder.PutString("pkgid", pkgid).
PutString("uid", std::to_string(uid)).
+ PutString("is_default", is_default ? "true" : "false").
PutString("version", root["version"].asString()).
PutString("tool_version", root["tool_version"].asString()).
PutString("title", root["header"]["title"].asString()).
explicit ThemeParser(const std::string& path) : path_(path) {}
loader::ThemeInfo Inflate(const std::string id, const std::string pkgid,
- uid_t uid);
+ uid_t uid, bool is_default);
bool Commit(ThemeOperation operation, const loader::ThemeInfo& theme);
private:
" description TEXT,\n"
" preview TEXT,\n"
" resolution TEXT,\n"
+ " is_default TEXT DEFAULT 'false',\n"
" details BLOB,\n"
+ " CHECK (is_default IN ('true', 'false'))\n"
" PRIMARY KEY (id))";
+const char kCreateIndexQuery[] =
+ "CREATE UNIQUE INDEX IF NOT EXISTS 'is_default_INDEX' "
+ "ON theme (is_default) WHERE is_default = 'true'";
const char kInsertQuery[] =
"INSERT INTO theme (id, pkgid, version, tool_version, title, description,"
- " preview, resolution, details) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ " preview, resolution, is_default, details) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
const char kUpdateQuery[] =
"UPDATE theme SET version = ?, tool_version = ?, title = ?,"
" description = ?, preview = ?, resolution = ?, details = ? "
conn_ = std::make_shared<SQLiteConnection>(db_path, false);
if (!conn_->Execute(kCreateThemeTableQuery))
LOG(ERROR) << "Failed to create theme table";
+ if (!conn_->Execute(kCreateIndexQuery))
+ LOG(ERROR) << "Failed to create unique index for theme table";
if (!conn_->Execute(kCreateThemeSettingTableQuery))
LOG(ERROR) << "Failed to create theme_setting table";
}
return false;
if (!stmt->BindString(idx++, info.GetString("resolution")))
return false;
+ if (!stmt->BindString(idx++, info.GetString("is_default")))
+ return false;
if (!stmt->BindBlob(idx++, info.GetByte("details")))
return false;
return res;
}
+bool SQLiteStatement::BindNull(int pos) {
+ int r = sqlite3_bind_null(stmt_, pos);
+ if (r != SQLITE_OK) {
+ LOG(ERROR) << "sqlite3_bind_null() failed: " << GetErrorMessage();
+ sql_conn_->SetErrorCode(r);
+ return false;
+ }
+ return true;
+}
+
bool SQLiteStatement::BindString(int pos, const std::string& val) {
+ if (val.empty())
+ return BindNull(pos);
+
int r = sqlite3_bind_text(stmt_, pos, val.c_str(), -1, SQLITE_TRANSIENT);
if (r != SQLITE_OK) {
LOG(ERROR) << "sqlite3_bind_text() failed: " << GetErrorMessage();
enum class StepResult : int { DONE, ROW, ERROR, };
StepResult Step();
+ bool BindNull(int pos);
bool BindString(int pos, const std::string& val);
bool BindBlob(int pos, const std::vector<unsigned char>& val);
TEST_F(ThemeParserTest, Inflate) {
ttm::plugin::ThemeParser parser("test_samples/test_theme.json");
- auto info = parser.Inflate("testid", "testpkgid", 5001);
+ auto info = parser.Inflate("testid", "testpkgid", 5001, false);
EXPECT_EQ(info.GetId(), "testid");
EXPECT_EQ(info.GetPkgid(), "testpkgid");
EXPECT_EQ(info.GetUid(), 5001);