gecko-dev/widget/android/PrefsHelper.h

328 строки
12 KiB
C++

/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PrefsHelper_h
#define PrefsHelper_h
#include "GeneratedJNINatives.h"
#include "MainThreadUtils.h"
#include "nsAppShell.h"
#include "nsCOMPtr.h"
#include "nsVariant.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
class PrefsHelper
: public widget::PrefsHelper::Natives<PrefsHelper>
, public UsesGeckoThreadProxy
{
PrefsHelper() = delete;
static bool GetVariantPref(nsIObserverService* aObsServ,
nsIWritableVariant* aVariant,
jni::Object::Param aPrefHandler,
const jni::String::LocalRef& aPrefName)
{
if (NS_FAILED(aObsServ->NotifyObservers(aVariant, "android-get-pref",
aPrefName->ToString().get()))) {
return false;
}
uint16_t varType = nsIDataType::VTYPE_EMPTY;
if (NS_FAILED(aVariant->GetDataType(&varType))) {
return false;
}
int32_t type = widget::PrefsHelper::PREF_INVALID;
bool boolVal = false;
int32_t intVal = 0;
nsAutoString strVal;
switch (varType) {
case nsIDataType::VTYPE_BOOL:
type = widget::PrefsHelper::PREF_BOOL;
if (NS_FAILED(aVariant->GetAsBool(&boolVal))) {
return false;
}
break;
case nsIDataType::VTYPE_INT32:
type = widget::PrefsHelper::PREF_INT;
if (NS_FAILED(aVariant->GetAsInt32(&intVal))) {
return false;
}
break;
case nsIDataType::VTYPE_ASTRING:
type = widget::PrefsHelper::PREF_STRING;
if (NS_FAILED(aVariant->GetAsAString(strVal))) {
return false;
}
break;
default:
return false;
}
const auto& jstrVal = type == widget::PrefsHelper::PREF_STRING ?
jni::StringParam(strVal, aPrefName.Env()) :
jni::StringParam(nullptr);
if (aPrefHandler) {
widget::PrefsHelper::CallPrefHandler(
aPrefHandler, type, aPrefName, boolVal, intVal, jstrVal);
} else {
widget::PrefsHelper::OnPrefChange(
aPrefName, type, boolVal, intVal, jstrVal);
}
return true;
}
static bool SetVariantPref(nsIObserverService* aObsServ,
nsIWritableVariant* aVariant,
jni::String::Param aPrefName,
bool aFlush,
int32_t aType,
bool aBoolVal,
int32_t aIntVal,
jni::String::Param aStrVal)
{
nsresult rv = NS_ERROR_FAILURE;
switch (aType) {
case widget::PrefsHelper::PREF_BOOL:
rv = aVariant->SetAsBool(aBoolVal);
break;
case widget::PrefsHelper::PREF_INT:
rv = aVariant->SetAsInt32(aIntVal);
break;
case widget::PrefsHelper::PREF_STRING:
rv = aVariant->SetAsAString(aStrVal->ToString());
break;
}
if (NS_SUCCEEDED(rv)) {
rv = aObsServ->NotifyObservers(aVariant, "android-set-pref",
aPrefName->ToString().get());
}
uint16_t varType = nsIDataType::VTYPE_EMPTY;
if (NS_SUCCEEDED(rv)) {
rv = aVariant->GetDataType(&varType);
}
// We use set-to-empty to signal the pref was handled.
const bool handled = varType == nsIDataType::VTYPE_EMPTY;
if (NS_SUCCEEDED(rv) && handled && aFlush) {
rv = Preferences::GetService()->SavePrefFile(nullptr);
}
if (NS_SUCCEEDED(rv)) {
return handled;
}
NS_WARNING(nsPrintfCString("Failed to set pref %s",
aPrefName->ToCString().get()).get());
// Pretend we handled the pref.
return true;
}
public:
static void GetPrefs(const jni::Class::LocalRef& aCls,
jni::ObjectArray::Param aPrefNames,
jni::Object::Param aPrefHandler)
{
nsTArray<jni::Object::LocalRef> nameRefArray(aPrefNames->GetElements());
nsCOMPtr<nsIObserverService> obsServ;
nsCOMPtr<nsIWritableVariant> value;
nsAdoptingString strVal;
for (jni::Object::LocalRef& nameRef : nameRefArray) {
jni::String::LocalRef nameStr(mozilla::Move(nameRef));
const nsCString& name = nameStr->ToCString();
int32_t type = widget::PrefsHelper::PREF_INVALID;
bool boolVal = false;
int32_t intVal = 0;
switch (Preferences::GetType(name.get())) {
case nsIPrefBranch::PREF_BOOL:
type = widget::PrefsHelper::PREF_BOOL;
boolVal = Preferences::GetBool(name.get());
break;
case nsIPrefBranch::PREF_INT:
type = widget::PrefsHelper::PREF_INT;
intVal = Preferences::GetInt(name.get());
break;
case nsIPrefBranch::PREF_STRING:
type = widget::PrefsHelper::PREF_STRING;
strVal = Preferences::GetLocalizedString(name.get());
if (!strVal) {
strVal = Preferences::GetString(name.get());
}
break;
default:
// Pref not found; try to find it.
if (!obsServ) {
obsServ = services::GetObserverService();
if (!obsServ) {
continue;
}
}
if (value) {
value->SetAsEmpty();
} else {
value = new nsVariant();
}
if (!GetVariantPref(obsServ, value,
aPrefHandler, nameStr)) {
NS_WARNING(nsPrintfCString("Failed to get pref %s",
name.get()).get());
}
continue;
}
const auto& jstrVal = type == widget::PrefsHelper::PREF_STRING ?
jni::StringParam(strVal, aCls.Env()) :
jni::StringParam(nullptr);
widget::PrefsHelper::CallPrefHandler(
aPrefHandler, type, nameStr, boolVal, intVal, jstrVal);
}
widget::PrefsHelper::CallPrefHandler(
aPrefHandler, widget::PrefsHelper::PREF_FINISH,
nullptr, false, 0, nullptr);
}
static void SetPref(jni::String::Param aPrefName,
bool aFlush,
int32_t aType,
bool aBoolVal,
int32_t aIntVal,
jni::String::Param aStrVal)
{
const nsCString& name = aPrefName->ToCString();
if (Preferences::GetType(name.get()) == nsIPrefBranch::PREF_INVALID) {
// No pref; try asking first.
nsCOMPtr<nsIObserverService> obsServ =
services::GetObserverService();
nsCOMPtr<nsIWritableVariant> value = new nsVariant();
if (obsServ && SetVariantPref(obsServ, value, aPrefName, aFlush,
aType, aBoolVal, aIntVal, aStrVal)) {
// The "pref" has changed; send a notification.
GetVariantPref(obsServ, value, nullptr,
jni::String::LocalRef(aPrefName));
return;
}
}
switch (aType) {
case widget::PrefsHelper::PREF_BOOL:
Preferences::SetBool(name.get(), aBoolVal);
break;
case widget::PrefsHelper::PREF_INT:
Preferences::SetInt(name.get(), aIntVal);
break;
case widget::PrefsHelper::PREF_STRING:
Preferences::SetString(name.get(), aStrVal->ToString());
break;
default:
MOZ_ASSERT(false, "Invalid pref type");
}
if (aFlush) {
Preferences::GetService()->SavePrefFile(nullptr);
}
}
static void AddObserver(const jni::Class::LocalRef& aCls,
jni::ObjectArray::Param aPrefNames,
jni::Object::Param aPrefHandler,
jni::ObjectArray::Param aPrefsToObserve)
{
// Call observer immediately with existing pref values.
GetPrefs(aCls, aPrefNames, aPrefHandler);
if (!aPrefsToObserve) {
return;
}
nsTArray<jni::Object::LocalRef> nameRefArray(
aPrefsToObserve->GetElements());
nsAppShell* const appShell = nsAppShell::Get();
MOZ_ASSERT(appShell);
for (jni::Object::LocalRef& nameRef : nameRefArray) {
jni::String::LocalRef nameStr(mozilla::Move(nameRef));
MOZ_ALWAYS_SUCCEEDS(Preferences::AddStrongObserver(
appShell, nameStr->ToCString().get()));
}
}
static void RemoveObserver(const jni::Class::LocalRef& aCls,
jni::ObjectArray::Param aPrefsToUnobserve)
{
nsTArray<jni::Object::LocalRef> nameRefArray(
aPrefsToUnobserve->GetElements());
nsAppShell* const appShell = nsAppShell::Get();
MOZ_ASSERT(appShell);
for (jni::Object::LocalRef& nameRef : nameRefArray) {
jni::String::LocalRef nameStr(mozilla::Move(nameRef));
MOZ_ALWAYS_SUCCEEDS(Preferences::RemoveObserver(
appShell, nameStr->ToCString().get()));
}
}
static void OnPrefChange(const char16_t* aData)
{
const nsCString& name = NS_LossyConvertUTF16toASCII(aData);
int32_t type = -1;
bool boolVal = false;
int32_t intVal = false;
nsAdoptingString strVal;
switch (Preferences::GetType(name.get())) {
case nsIPrefBranch::PREF_BOOL:
type = widget::PrefsHelper::PREF_BOOL;
boolVal = Preferences::GetBool(name.get());
break;
case nsIPrefBranch::PREF_INT:
type = widget::PrefsHelper::PREF_INT;
intVal = Preferences::GetInt(name.get());
break;
case nsIPrefBranch::PREF_STRING:
type = widget::PrefsHelper::PREF_STRING;
strVal = Preferences::GetLocalizedString(name.get());
if (!strVal) {
strVal = Preferences::GetString(name.get());
}
break;
default:
NS_WARNING(nsPrintfCString("Invalid pref %s",
name.get()).get());
return;
}
const auto& jstrVal = type == widget::PrefsHelper::PREF_STRING ?
jni::StringParam(strVal) :
jni::StringParam(nullptr);
widget::PrefsHelper::OnPrefChange(name, type, boolVal, intVal, jstrVal);
}
};
} // namespace
#endif // PrefsHelper_h