%bcond_with wayland
Name: crosswalk
-Version: 6.35.121.0
+Version: 6.35.131.0
Release: 0
Summary: Crosswalk is an app runtime based on Chromium
License: (BSD-3-Clause and LGPL-2.1+)
BuildRequires: pkgconfig(libxslt)
BuildRequires: pkgconfig(pango)
BuildRequires: pkgconfig(pkgmgr-info)
+BuildRequires: pkgconfig(pkgmgr-installer)
BuildRequires: pkgconfig(pkgmgr-parser)
BuildRequires: pkgconfig(nspr)
BuildRequires: pkgconfig(nss)
fi
%if %{with wayland}
-GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ozone=1 -Denable_ozone_wayland_vkb=1"
+GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ozone=1 -Denable_ozone_wayland_vkb=1 -Denable_xdg_shell=1"
%endif
# --no-parallel is added because chroot does not mount a /dev/shm, this will
sCachedApplicationState = null;
ActivityInfo info = sActivityInfo.get(activity);
+ // Ignore status from none tracked activitys.
+ if (info == null) return;
+
info.setStatus(newState);
// Notify all state observers that are specifically listening to this activity.
MessagePumpOzone::~MessagePumpOzone() {
}
-void MessagePumpOzone::AddObserver(MessagePumpObserver* /* observer */) {
- NOTIMPLEMENTED();
+void MessagePumpOzone::AddObserver(MessagePumpObserver* observer) {
+ observers_.AddObserver(observer);
}
-void MessagePumpOzone::RemoveObserver(MessagePumpObserver* /* observer */) {
- NOTIMPLEMENTED();
+void MessagePumpOzone::RemoveObserver(MessagePumpObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void MessagePumpOzone::WillProcessEvent(const NativeEvent& event) {
+ FOR_EACH_OBSERVER(MessagePumpObserver,
+ observers_,
+ WillProcessEvent(event));
+}
+
+void MessagePumpOzone::DidProcessEvent(const NativeEvent& event) {
+ FOR_EACH_OBSERVER(MessagePumpObserver,
+ observers_,
+ DidProcessEvent(event));
}
// static
void MessagePumpOzone::AddDispatcherForRootWindow(
MessagePumpDispatcher* dispatcher) {
// Only one root window is supported.
- DCHECK(dispatcher_.size() == 0);
- dispatcher_.insert(dispatcher_.begin(),dispatcher);
+ DCHECK_EQ(dispatcher_.size(), 0);
+ dispatcher_.insert(dispatcher_.begin(), dispatcher);
}
void MessagePumpOzone::RemoveDispatcherForRootWindow(
MessagePumpDispatcher* dispatcher) {
- DCHECK(dispatcher_.size() == 1);
+ DCHECK_EQ(dispatcher_.size(), 1);
dispatcher_.pop_back();
}
uint32_t MessagePumpOzone::Dispatch(const NativeEvent& dev) {
- if (dispatcher_.size() > 0)
- return dispatcher_[0]->Dispatch(dev);
- return POST_DISPATCH_NONE;
+ uint32_t result = POST_DISPATCH_NONE;
+ WillProcessEvent(dev);
+ if (!dispatcher_.empty()) {
+ result = dispatcher_[0]->Dispatch(dev);
+ }
+ DidProcessEvent(dev);
+ return result;
}
// This code assumes that the caller tracks the lifetime of the |dispatcher|.
#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_
+#include <vector>
+
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_pump_dispatcher.h"
// Overridden from MessagePumpDispatcher.
virtual uint32_t Dispatch(const NativeEvent& event) OVERRIDE;
+ // List of observers.
+ ObserverList<MessagePumpObserver> observers_;
+
private:
+ void WillProcessEvent(const NativeEvent& event);
+ void DidProcessEvent(const NativeEvent& event);
+
std::vector<MessagePumpDispatcher*> dispatcher_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpOzone);
-LASTCHANGE=261600
+LASTCHANGE=260856
},
'dependencies': [
'../base/base.gyp:base',
+ '../base/base.gyp:base_static',
'../ipc/ipc.gyp:ipc',
'../ppapi/native_client/src/trusted/plugin/plugin.gyp:ppGoogleNaClPluginChrome',
'../ppapi/ppapi_internal.gyp:ppapi_shared',
String timestampFile = checkPakTimestamp();
if (timestampFile != null) {
- deleteFiles();
+ deleteFiles(mContext);
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
// returning null? It might be useful to gather UMA here too to track if
// this happens with regularity.
Log.w(LOGTAG, "Exception unpacking required pak resources: " + e.getMessage());
- deleteFiles();
+ deleteFiles(mContext);
return null;
}
}
private ResourceExtractor(Context context) {
- mContext = context.getApplicationContext();
- mAppDataDir = getAppDataDir();
- mOutputDir = getOutputDir();
+ mContext = context;
+ mAppDataDir = getAppDataDirFromContext(mContext);
+ mOutputDir = getOutputDirFromContext(mContext);
}
public void waitForCompletion() {
try {
mExtractTask.get();
+ // ResourceExtractor is not needed any more.
+ // Release static objects to avoid leak of Context.
+ sIntercepter = null;
+ sInstance = null;
} catch (CancellationException e) {
// Don't leave the files in an inconsistent state.
- deleteFiles();
+ deleteFiles(mContext);
} catch (ExecutionException e2) {
- deleteFiles();
+ deleteFiles(mContext);
} catch (InterruptedException e3) {
- deleteFiles();
+ deleteFiles(mContext);
}
}
mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- private File getAppDataDir() {
- return new File(PathUtils.getDataDirectory(mContext));
+ public static File getAppDataDirFromContext(Context context) {
+ return new File(PathUtils.getDataDirectory(context.getApplicationContext()));
}
- private File getOutputDir() {
- return new File(getAppDataDir(), "paks");
+ public static File getOutputDirFromContext(Context context) {
+ return new File(getAppDataDirFromContext(context), "paks");
}
/**
* lead to malfunction/UX misbehavior. So, we regard failing to update them
* as an error.
*/
- private void deleteFiles() {
- File icudata = new File(getAppDataDir(), ICU_DATA_FILENAME);
+ public static void deleteFiles(Context context) {
+ File icudata = new File(getAppDataDirFromContext(context), ICU_DATA_FILENAME);
if (icudata.exists() && !icudata.delete()) {
Log.e(LOGTAG, "Unable to remove the icudata " + icudata.getName());
}
- File dir = getOutputDir();
+ File dir = getOutputDirFromContext(context);
if (dir.exists()) {
File[] files = dir.listFiles();
for (File file : files) {
// Scrollbars should not be stylable.
settings->setAllowCustomScrollbarInMainFrame(false);
- // Don't auto play music on Tizen devices.
- settings->setMediaPlaybackRequiresUserGesture(true);
-
// IME support
settings->setAutoZoomFocusedNodeToLegibleScale(true);
'v8_use_snapshot%': 'true',
+ # Enable XDK profiling support by default.
+ 'v8_enable_xdkprof': 1,
+
# With post mortem support enabled, metadata is embedded into libv8 that
# describes various parameters of the VM for use by debuggers. See
# tools/gen-postmortem-metadata.py for details.
__ b(eq, instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::FLOAT32x4)) {
+ // Float32x4 value -> true.
+ __ CompareInstanceType(map, ip, FLOAT32x4_TYPE);
+ __ b(eq, instr->TrueLabel(chunk_));
+ }
+
+ if (expected.Contains(ToBooleanStub::INT32x4)) {
+ // Int32x4 value -> true.
+ __ CompareInstanceType(map, ip, INT32x4_TYPE);
+ __ b(eq, instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
DwVfpRegister dbl_scratch = double_scratch0();
if (Contains(STRING)) printer.Add("String");
if (Contains(SYMBOL)) printer.Add("Symbol");
if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber");
+ if (Contains(FLOAT32x4)) printer.Add("Float32x4");
+ if (Contains(INT32x4)) printer.Add("Int32x4");
stream->Add(")");
}
} else if (object->IsSymbol()) {
Add(SYMBOL);
return true;
+ } else if (object->IsFloat32x4()) {
+ Add(FLOAT32x4);
+ return true;
+ } else if (object->IsInt32x4()) {
+ Add(INT32x4);
+ return true;
} else if (object->IsHeapNumber()) {
ASSERT(!object->IsUndetectableObject());
Add(HEAP_NUMBER);
return Contains(ToBooleanStub::SPEC_OBJECT)
|| Contains(ToBooleanStub::STRING)
|| Contains(ToBooleanStub::SYMBOL)
+ || Contains(ToBooleanStub::FLOAT32x4)
+ || Contains(ToBooleanStub::INT32x4)
|| Contains(ToBooleanStub::HEAP_NUMBER);
}
STRING,
SYMBOL,
HEAP_NUMBER,
+ FLOAT32x4,
+ INT32x4,
NUMBER_OF_TYPES
};
// At most 8 different types can be distinguished, because the Code object
// only has room for a single byte to hold a set of these types. :-P
- STATIC_ASSERT(NUMBER_OF_TYPES <= 8);
+ STATIC_ASSERT(NUMBER_OF_TYPES <= 10);
- class Types : public EnumSet<Type, byte> {
+ class Types : public EnumSet<Type, int> {
public:
- Types() : EnumSet<Type, byte>(0) {}
- explicit Types(byte bits) : EnumSet<Type, byte>(bits) {}
+ Types() : EnumSet<Type, int>(0) {}
+ explicit Types(int bits) : EnumSet<Type, int>(bits) {}
- byte ToByte() const { return ToIntegral(); }
void Print(StringStream* stream) const;
bool UpdateStatus(Handle<Object> object);
bool NeedsMap() const;
explicit ToBooleanStub(Types types = Types())
: types_(types) { }
explicit ToBooleanStub(ExtraICState state)
- : types_(static_cast<byte>(state)) { }
+ : types_(static_cast<int>(state)) { }
bool UpdateStatus(Handle<Object> object);
Types GetTypes() { return types_; }
Representation::Integer32());
}
+ static HObjectAccess ForSIMD128XYLanes() {
+ return HObjectAccess(
+ kDouble, Float32x4::kValueOffset, Representation::Double());
+ }
+
+ static HObjectAccess ForSIMD128ZWLanes() {
+ return HObjectAccess(kDouble,
+ Float32x4::kValueOffset + kDoubleSize,
+ Representation::Double());
+ }
+
static HObjectAccess ForElementsPointer() {
return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
}
Add<HStoreNamedField>(elements,
HObjectAccess::ForFixedArrayLength(),
length);
+
HValue* filler = Add<HConstant>(static_cast<int32_t>(0));
+ if (IsFixedFloat32x4ElementsKind(fixed_elements_kind)) {
+ if (CPU::SupportsSIMD128InCrankshaft()) {
+ filler = AddUncasted<HNullarySIMDOperation>(kFloat32x4Zero);
+ } else {
+ HValue* size = Add<HConstant>(Float32x4::kSize);
+ filler = Add<HAllocate>(size, HType::Tagged(), NOT_TENURED,
+ Float32x4::kInstanceType);
+ AddStoreMapConstant(filler, isolate()->factory()->float32x4_map());
+ HValue* zero = Add<HConstant>(static_cast<double>(0.0));
+ Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128XYLanes(), zero);
+ Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128ZWLanes(), zero);
+ }
+ } else if (IsFixedInt32x4ElementsKind(fixed_elements_kind)) {
+ if (CPU::SupportsSIMD128InCrankshaft()) {
+ filler = AddUncasted<HNullarySIMDOperation>(kInt32x4Zero);
+ } else {
+ HValue* size = Add<HConstant>(Int32x4::kSize);
+ filler = Add<HAllocate>(size, HType::Tagged(), NOT_TENURED,
+ Int32x4::kInstanceType);
+ AddStoreMapConstant(filler, isolate()->factory()->int32x4_map());
+ HValue* zero = Add<HConstant>(static_cast<double>(0.0));
+ Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128XYLanes(), zero);
+ Add<HStoreNamedField>(filler, HObjectAccess::ForSIMD128ZWLanes(), zero);
+ }
+ }
{
LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
__ xorps(xmm_scratch, xmm_scratch);
__ ucomisd(reg, xmm_scratch);
EmitBranch(instr, not_equal);
+ } else if (r.IsSIMD128()) {
+ ASSERT(!info()->IsStub());
+ EmitBranch(instr, no_condition);
} else {
ASSERT(r.IsTagged());
Register reg = ToRegister(instr->value());
} else if (type.IsJSArray()) {
ASSERT(!info()->IsStub());
EmitBranch(instr, no_condition);
+ } else if (type.IsSIMD128()) {
+ ASSERT(!info()->IsStub());
+ EmitBranch(instr, no_condition);
} else if (type.IsHeapNumber()) {
ASSERT(!info()->IsStub());
CpuFeatureScope scope(masm(), SSE2);
__ j(equal, instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::FLOAT32x4)) {
+ // Float32x4 value -> true.
+ __ CmpInstanceType(map, FLOAT32x4_TYPE);
+ __ j(equal, instr->TrueLabel(chunk_));
+ }
+
+ if (expected.Contains(ToBooleanStub::INT32x4)) {
+ // Int32x4 value -> true.
+ __ CmpInstanceType(map, INT32x4_TYPE);
+ __ j(equal, instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
- type.IsJSArray() || type.IsHeapNumber() || type.IsString();
+ type.IsJSArray() || type.IsHeapNumber() || type.IsSIMD128() ||
+ type.IsString();
LOperand* temp = !easy_case && expected.NeedsMap() ? TempRegister() : NULL;
LInstruction* branch = new(zone()) LBranch(UseRegister(value), temp);
if (!easy_case &&
#include "string-stream.h"
#include "vm-state-inl.h"
+// XDK support
+#include "third_party/xdk/xdk-v8.h"
+
namespace v8 {
namespace internal {
}
}
+ // XDK needs this function temporarily. It will be removed later.
+ void AppendAddress(Address address) {
+ Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
+ int size = OS::SNPrintF(buffer, "0x%x", address);
+ if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
+ utf8_pos_ += size;
+ }
+ }
+
const char* get() { return utf8_buffer_; }
int size() const { return utf8_pos_; }
void* StartCodePosInfoEvent();
void EndCodePosInfoEvent(Code* code, void* jit_handler_data);
+
+ // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ // XDK needs all this stuff below to generate the strings like
+ // "code-creation:..." in the same format as Logger generates.
+ // This string is sent to XDK by code_event_handler and then used for
+ // postprocessing. All these CodeCreateEvent(...) functions and helpers
+ // will be removed before commit.
+ void AppendCodeCreateHeader(NameBuffer* msg,
+ Logger::LogEventsAndTags tag,
+ Code* code) {
+ CHECK(msg);
+ msg->AppendBytes(kLogEventsNames[Logger::CODE_CREATION_EVENT]);
+ msg->AppendByte(',');
+ msg->AppendBytes(kLogEventsNames[tag]);
+ msg->AppendByte(',');
+ msg->AppendInt(code->kind());
+ msg->AppendByte(',');
+ msg->AppendAddress(code->instruction_start());
+ msg->AppendByte(',');
+ msg->AppendInt(code->instruction_size());
+ msg->AppendByte(',');
+ }
+
+
+ void AppendDetailed(NameBuffer* msg, String* str, bool show_impl_info) {
+ CHECK(msg);
+ if (str == NULL) return;
+ DisallowHeapAllocation no_gc; // Ensure string stay valid.
+ int len = str->length();
+ if (len > 0x1000)
+ len = 0x1000;
+ if (show_impl_info) {
+ msg->AppendByte(str->IsOneByteRepresentation() ? 'a' : '2');
+ if (StringShape(str).IsExternal())
+ msg->AppendByte('e');
+ if (StringShape(str).IsInternalized())
+ msg->AppendByte('#');
+ msg->AppendByte(':');
+ msg->AppendInt(str->length());
+ msg->AppendByte(':');
+ }
+ for (int i = 0; i < len; i++) {
+ uc32 c = str->Get(i);
+ if (c > 0xff) {
+ msg->AppendBytes("\\u");
+ msg->AppendHex(c);
+ } else if (c < 32 || c > 126) {
+ msg->AppendBytes("\\x");
+ msg->AppendHex(c);
+ } else if (c == ',') {
+ msg->AppendBytes("\\,");
+ } else if (c == '\\') {
+ msg->AppendBytes("\\\\");
+ } else if (c == '\"') {
+ msg->AppendBytes("\"\"");
+ } else {
+ msg->AppendByte(c);
+ }
+ }
+ }
+
+
+ void AppendDoubleQuotedString(NameBuffer* msg, const char* string) {
+ CHECK(msg);
+ msg->AppendByte('"');
+ for (const char* p = string; *p != '\0'; p++) {
+ if (*p == '"') {
+ msg->AppendByte('\\');
+ }
+ msg->AppendByte(*p);
+ }
+ msg->AppendByte('"');
+ }
+
+
+ void AppendSymbolName(NameBuffer* msg, Symbol* symbol) {
+ CHECK(msg);
+ ASSERT(symbol);
+ msg->AppendBytes("symbol(");
+ if (!symbol->name()->IsUndefined()) {
+ msg->AppendByte('"');
+ AppendDetailed(msg, String::cast(symbol->name()), false);
+ msg->AppendBytes("\" ");
+ }
+ msg->AppendBytes("hash ");
+ msg->AppendHex(symbol->Hash());
+ msg->AppendByte(')');
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, const char* comment) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, comment);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ AppendDoubleQuotedString(name_buffer_, comment);
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code, Name* name) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, name);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ if (name->IsString()) {
+ name_buffer_->AppendByte('"');
+ AppendDetailed(name_buffer_, String::cast(name), false);
+ name_buffer_->AppendByte('"');
+ } else {
+ AppendSymbolName(name_buffer_, Symbol::cast(name));
+ }
+ LogRecordedBuffer(code, NULL, name_buffer_->get(), name_buffer_->size());
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* name) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, shared, info, name);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ if (name->IsString()) {
+ SmartArrayPointer<char> str =
+ String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ name_buffer_->AppendByte('"');
+ name_buffer_->AppendBytes(str.get());
+ name_buffer_->AppendByte('"');
+ } else {
+ AppendSymbolName(name_buffer_, Symbol::cast(name));
+ }
+ name_buffer_->AppendByte(',');
+ name_buffer_->AppendAddress(shared->address());
+ name_buffer_->AppendByte(',');
+ name_buffer_->AppendBytes(ComputeMarker(code));
+ LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
+ }
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ SharedFunctionInfo* shared,
+ CompilationInfo* info,
+ Name* source,
+ int line, int column) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, shared,
+ info, source, line, column);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ SmartArrayPointer<char> name =
+ shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+ name_buffer_->AppendByte('"');
+ name_buffer_->AppendBytes(name.get());
+ name_buffer_->AppendByte(' ');
+ if (source->IsString()) {
+ SmartArrayPointer<char> sourcestr =
+ String::cast(source)->ToCString(DISALLOW_NULLS,
+ ROBUST_STRING_TRAVERSAL);
+ name_buffer_->AppendBytes(sourcestr.get());
+ } else {
+ AppendSymbolName(name_buffer_, Symbol::cast(source));
+ }
+ name_buffer_->AppendByte(':');
+ name_buffer_->AppendInt(line);
+ name_buffer_->AppendByte(':');
+ name_buffer_->AppendInt(column);
+ name_buffer_->AppendBytes("\",");
+ name_buffer_->AppendAddress(shared->address());
+ name_buffer_->AppendByte(',');
+ name_buffer_->AppendBytes(ComputeMarker(code));
+ LogRecordedBuffer(code, shared, name_buffer_->get(), name_buffer_->size());
+ }
+
+
+ virtual void CodeCreateEvent(Logger::LogEventsAndTags tag,
+ Code* code,
+ int args_count) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::CodeCreateEvent(tag, code, args_count);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, tag, code);
+ name_buffer_->AppendBytes("\"args_count: ");
+ name_buffer_->AppendInt(args_count);
+ name_buffer_->AppendByte('"');
+ }
+
+
+ virtual void RegExpCodeCreateEvent(Code* code, String* source) {
+ if (!xdk::XDKIsAgentAlive()) {
+ CodeEventLogger::RegExpCodeCreateEvent(code, source);
+ return;
+ }
+
+ name_buffer_->Reset();
+ AppendCodeCreateHeader(name_buffer_, Logger::REG_EXP_TAG, code);
+ name_buffer_->AppendByte('"');
+ AppendDetailed(name_buffer_, source, false);
+ name_buffer_->AppendByte('"');
+ }
+
private:
virtual void LogRecordedBuffer(Code* code,
SharedFunctionInfo* shared,
kLogEventsNames[Logger::CODE_CREATION_EVENT],
kLogEventsNames[tag],
code->kind());
- msg->AppendAddress(code->address());
- msg->Append(",%d,", code->ExecutableSize());
+ if (xdk::XDKIsAgentAlive()) {
+ msg->AppendAddress(code->instruction_start());
+ msg->Append(",%d,", code->instruction_size());
+ } else {
+ msg->AppendAddress(code->address());
+ msg->Append(",%d,", code->ExecutableSize());
+ }
}
Address from,
Address to) {
if (!FLAG_log_code || !log_->IsEnabled()) return;
+
+ Code* from_code = NULL;
+ Address to_code = NULL;
+ if (xdk::XDKIsAgentAlive()) {
+ from_code = Code::cast(HeapObject::FromAddress(from));
+ const size_t header_size =
+ from_code->instruction_start() - reinterpret_cast<byte*>(from_code);
+ to_code =
+ reinterpret_cast<byte*>(HeapObject::FromAddress(to)) + header_size;
+ }
+
Log::MessageBuilder msg(log_);
msg.Append("%s,", kLogEventsNames[event]);
- msg.AppendAddress(from);
+ if (xdk::XDKIsAgentAlive()) {
+ msg.AppendAddress(from_code->instruction_start());
+ } else {
+ msg.AppendAddress(from);
+ }
msg.Append(',');
- msg.AppendAddress(to);
+ if (xdk::XDKIsAgentAlive()) {
+ msg.AppendAddress(to_code);
+ } else {
+ msg.AppendAddress(to);
+ }
msg.Append('\n');
msg.WriteToLogFile();
}
}
+void Logger::XDKResumeProfiler() {
+ if (!log_->IsEnabled()) return;
+ if (profiler_ != NULL) {
+ profiler_->resume();
+ is_logging_ = true;
+ }
+}
+
+
void Logger::StopProfiler() {
if (!log_->IsEnabled()) return;
if (profiler_ != NULL) {
void Logger::LogCodeObjects() {
+ // Starting from Chromium v34 this function is also called from
+ // V8::Initialize. This causes reading the heap to collect already
+ // compiled methods. For XDK that must be done because XDK profiler
+ // consumes CODE_ADDED events and mantains a map of compiled methods.
+ if (xdk::XDKIsAgentAlive()) return;
+
Heap* heap = isolate_->heap();
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
"Logger::LogCodeObjects");
void Logger::LogCompiledFunctions() {
+ // Starting from Chromium v34 this function is also called from
+ // V8::Initialize. This causes reading the heap to collect already
+ // compiled methods. For XDK that must be done because XDK profiler
+ // consumes CODE_ADDED events and mantains a map of compiled methods.
+ if (xdk::XDKIsAgentAlive()) return;
+
Heap* heap = isolate_->heap();
heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
"Logger::LogCompiledFunctions");
is_logging_ = true;
}
+ xdk::XDKInitializeForV8(isolate);
+
if (FLAG_prof) {
profiler_ = new Profiler(isolate);
is_logging_ = true;
profiler_->Engage();
+
+ if (xdk::XDKIsAgentAlive()) {
+ // A way to to start profiler in pause mode was removed.
+ // To pause collection of the CPU ticks we need to emulate pause.
+ // This will be removed later once XDK agent will have own sampler.
+ profiler_->pause();
+ }
}
if (FLAG_log_internal_timer_events || FLAG_prof) timer_.Start();
// When data collection is paused, CPU Tick events are discarded.
void StopProfiler();
+ // Resumes collection of CPU Tick events.
+ void XDKResumeProfiler();
+
+ // XDK agent uses it log code map (list of CodeAdded event
+ // before resume CPU Tick events.
+ Log* XDKGetLog() { return log_; }
+
void LogExistingFunction(Handle<SharedFunctionInfo> shared,
Handle<Code> code);
// Logs all compiled functions found in the heap.
virtual void SharedFunctionInfoMoveEvent(Address from, Address to) { }
virtual void CodeMovingGCEvent() { }
- private:
+ protected:
class NameBuffer;
+ NameBuffer* name_buffer_;
+ private:
virtual void LogRecordedBuffer(Code* code,
SharedFunctionInfo* shared,
const char* name,
int length) = 0;
-
- NameBuffer* name_buffer_;
};
if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y);
if (IS_BOOLEAN(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y));
if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal
+ if (IsFloat32x4(y) || IsInt32x4(y)) {
+ return %StringEquals(x, %ToString(y));
+ }
y = %ToPrimitive(y, NO_HINT);
}
} else if (IS_SYMBOL(x)) {
if (IS_SYMBOL(y)) return %_ObjectEquals(x, y) ? 0 : 1;
return 1; // not equal
+ } else if (IsFloat32x4(x)) {
+ while (true) {
+ if (IsFloat32x4(y) || IsInt32x4(y)) {
+ return (x.x == y.x && x.y == y.y && x.z == y.z && x.w == y.w) ? 0 : 1;
+ }
+ if (IS_STRING(y)) return %StringEquals(%ToString(x), y);
+ if (IS_NUMBER(y)) return 1; // not equal
+ if (IS_SYMBOL(y)) return 1; // not equal
+ if (IS_BOOLEAN(y)) return y ? 0 : 1;
+ if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal
+ y = %ToPrimitive(y, NO_HINT);
+ }
+ } else if (IsInt32x4(x)) {
+ while (true) {
+ if (IsFloat32x4(y) || IsInt32x4(y)) {
+ return (x.x == y.x && x.y == y.y && x.z == y.z && x.w == y.w) ? 0 : 1;
+ }
+ if (IS_STRING(y)) return %StringEquals(%ToString(x), y);
+ if (IS_NUMBER(y)) return 1; // not equal
+ if (IS_SYMBOL(y)) return 1; // not equal
+ if (IS_BOOLEAN(y)) return y ? 0 : 1;
+ if (IS_NULL_OR_UNDEFINED(y)) return 1; // not equal
+ y = %ToPrimitive(y, NO_HINT);
+ }
} else if (IS_BOOLEAN(x)) {
if (IS_BOOLEAN(y)) return %_ObjectEquals(x, y) ? 0 : 1;
if (IS_NULL_OR_UNDEFINED(y)) return 1;
if (IS_NUMBER(y)) return %NumberEquals(%ToNumber(x), y);
if (IS_STRING(y)) return %NumberEquals(%ToNumber(x), %ToNumber(y));
if (IS_SYMBOL(y)) return 1; // not equal
+ if (IsFloat32x4(y) || IsInt32x4(y)) return x ? 0 : 1;
// y is object.
x = %ToNumber(x);
y = %ToPrimitive(y, NO_HINT);
return %NumberEquals(this, x);
}
+ if (IsFloat32x4(this)) {
+ if (!IsFloat32x4(x)) return 1; // not equal
+ return (this.x == x.x && this.y == x.y &&
+ this.z == x.z && this.w == x.w) ? 0 : 1;
+ }
+
+ if (IsInt32x4(this)) {
+ if (!IsInt32x4(x)) return 1; // not equal
+ return (this.x == x.x && this.y == x.y &&
+ this.z == x.z && this.w == x.w) ? 0 : 1;
+ }
+
// If anything else gets here, we just do simple identity check.
// Objects (including functions), null, undefined and booleans were
// checked in the CompareStub, so there should be nothing left.
right = %ToPrimitive(x, NUMBER_HINT);
if (IS_STRING(left) && IS_STRING(right)) {
return %_StringCompare(left, right);
+ } else if ((IsFloat32x4(left) || IsInt32x4(left)) &&
+ (IsFloat32x4(right) || IsInt32x4(right))) {
+ if ((left.x == right.x) && (left.y == right.y) &&
+ (left.z == right.z) && (left.w == right.w)) {
+ return 0; // equal
+ }
+ if ((left.x < right.x) && (left.y < right.y) &&
+ (left.z < right.z) && (left.w < right.w)) {
+ return -1; // less
+ }
+ if ((left.x > right.x) && (left.y > right.y) &&
+ (left.z > right.z) && (left.w > right.w)) {
+ return 1; // great
+ }
} else {
var left_number = %ToNumber(left);
var right_number = %ToNumber(right);
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return NAN;
if (IS_SYMBOL(x)) return NAN;
+ if (IsFloat32x4(x)) return NAN;
+ if (IsInt32x4(x)) return NAN;
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
}
if (IS_BOOLEAN(x)) return x ? 1 : 0;
if (IS_UNDEFINED(x)) return NAN;
if (IS_SYMBOL(x)) return NAN;
- if (IsFloat32x4(x)) return NaN;
- if (IsInt32x4(x)) return NaN;
+ if (IsFloat32x4(x)) return NAN;
+ if (IsInt32x4(x)) return NAN;
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
}
if (IS_STRING(x)) return new $String(x);
if (IS_NUMBER(x)) return new $Number(x);
if (IS_BOOLEAN(x)) return new $Boolean(x);
+ if (IsFloat32x4(x)) return new $Float32x4(x.x, x.y, x.z, x.w);
+ if (IsInt32x4(x)) return new $Int32x4(x.x, x.y, x.z, x.w);
if (IS_SYMBOL(x)) return %NewSymbolWrapper(x);
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
throw %MakeTypeError('undefined_or_null_to_object', []);
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef __linux__
+#include <sys/stat.h>
+#endif // __linux__
+
+#include "xdk-agent.h"
+#include <vector>
+#include <string>
+#include <sstream>
+#include "platform.h"
+#include "log-utils.h"
+
+namespace xdk {
+namespace internal {
+
+static unsigned int XDK_COMMAND_LENGTH = 100; // It should be enough.
+
+static const char* XDK_TRACE_FILE =
+ "/data/data/com.intel.app_analyzer/files/result.xdk2v8";
+
+static const char* XDK_MARKER_FILE =
+ "/data/data/com.intel.app_analyzer/files/profiler.run";
+
+XDKAgent XDKAgent::instance_;
+
+// SetIdle has the same semantics as CpuProfiler::SetIdle has (v8/src/api.cc)
+// It is used to tell the sampler that XDK agent is idle (it is not busy with
+// some tasks). If the agent is idle that the sampler put a IDLE VM state into
+// the Tick record. The samples happen during IDLE will be attributed to (idle)
+// line in the XDK viewer.
+static void SetIdle(bool isIdle, v8engine::Isolate* isolate) {
+ CHECK(isolate);
+ v8engine::StateTag state = isolate->current_vm_state();
+ if (isolate->js_entry_sp() != NULL) return;
+ if (state == v8engine::EXTERNAL || state == v8engine::IDLE) {
+ if (isIdle) {
+ isolate->set_current_vm_state(v8engine::IDLE);
+ } else if (state == v8engine::IDLE) {
+ isolate->set_current_vm_state(v8engine::EXTERNAL);
+ }
+ }
+}
+
+
+bool XDKAgent::setUp(v8engine::Isolate* isolate) {
+ CHECK(isolate);
+
+ if (m_isolate) {
+ // The setUp method is called for the main thread first, then may be called
+ // again if the app uses Workers (each Worker object has own V8 instance).
+ // XDK agent does not support JavaScript Worker currently.
+ XDKLog("xdk: Agent is already initialized\n");
+ return false;
+ }
+
+ FILE* file = v8engine::OS::FOpen(XDK_MARKER_FILE, "r");
+ if (file == NULL) {
+ return false;
+ }
+
+ fclose(file);
+ m_alive = true;
+ m_isolate = isolate;
+
+ return m_alive;
+}
+
+
+void XDKAgent::resumeSampling() {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ CHECK(m_isolate);
+
+ v8engine::Log* log = m_isolate->logger()->XDKGetLog();
+ CHECK(log);
+
+ // Create a new log file for new profiling session
+ CHECK(!log->IsEnabled());
+ log->Initialize(XDK_TRACE_FILE);
+
+#ifdef __linux__
+ int mode = S_IRUSR|S_IROTH|S_IRGRP|S_IWUSR|S_IWOTH|S_IWGRP;
+ if (chmod(XDK_TRACE_FILE, mode) != 0) {
+ XDKLog("xdk: Couldn't change permissions for a trace file\n");
+ }
+#endif // __linux__
+
+ CHECK(log->IsEnabled());
+
+ logFunctionSnapshot();
+
+ // Write a marker line into the log for testing purpose
+ v8engine::Log::MessageBuilder msg(log);
+ msg.Append("Profiler started.\n");
+ msg.WriteToLogFile();
+
+ // Resume collection the CPU Tick events
+ m_isolate->logger()->XDKResumeProfiler();
+ XDKLog("xdk: Sampling is resumed\n");
+
+ SetIdle(true, m_isolate);
+}
+
+
+void XDKAgent::pauseSampling() {
+ // Pause collection the CPU Tick events
+ CHECK(m_isolate);
+ m_isolate->logger()->StopProfiler();
+
+ // Use v8 logger internals to close the trace file.
+ // Once XDK agent implements own sampler this will be removed.
+ v8engine::Log* log = m_isolate->logger()->XDKGetLog();
+ CHECK(log);
+ log->stop();
+ log->Close();
+
+ XDKLog("xdk: Sampling is stopped\n");
+}
+
+
+struct ObjectDeallocator {
+ template<typename T>
+ void operator()(const T& obj) const { delete obj.second; }
+};
+
+
+XDKAgent::~XDKAgent() {
+ CHECK(m_server != NULL);
+ CHECK(m_agent_access != NULL);
+
+ if (m_alive) {
+ CHECK(m_isolate != NULL);
+
+ m_terminate = true;
+
+ std::for_each(m_lineMaps.begin(), m_lineMaps.end(), ObjectDeallocator());
+ m_lineMaps.clear();
+
+ m_server->Shutdown();
+
+ Join();
+ }
+
+ delete m_server;
+ m_server = NULL;
+
+ delete m_agent_access;
+ m_agent_access = NULL;
+
+ m_isolate = NULL;
+}
+
+
+// The XDK listener thread.
+void XDKAgent::Run() {
+ v8engine::Isolate::EnsureDefaultIsolate();
+ v8engine::DisallowHeapAllocation no_allocation;
+ v8engine::DisallowHandleAllocation no_handles;
+ v8engine::DisallowHandleDereference no_deref;
+
+ XDKLog("xdk: Listener thread is running\n");
+ CHECK(m_server);
+
+ bool ok = m_server->Bind(m_port);
+ if (!ok) {
+ XDKLog("xdk: Unable to bind port=%d %d\n",
+ m_port, v8engine::Socket::GetLastError());
+ return;
+ }
+
+ std::vector<char> buf(XDK_COMMAND_LENGTH);
+
+ const std::string cmdStart = "start";
+ const std::string cmdStop = "stop";
+
+ while (!m_terminate) {
+ XDKLog("xdk: Listener thread is waiting for connection\n");
+
+ ok = m_server->Listen(1);
+ XDKLog("xdk: Listener thread got a connection request. Return value=%d\n",
+ v8engine::Socket::GetLastError());
+ if (ok) {
+ v8engine::Socket* client = m_server->Accept();
+ if (client == NULL) {
+ XDKLog("xdk: Accept failed %d\n", v8engine::Socket::GetLastError());
+ continue;
+ }
+
+ XDKLog("xdk: Connected\n");
+
+ int bytes_read = client->Receive(&buf[0], buf.size() - 1);
+ if (bytes_read == 0) {
+ XDKLog("xdk: Receive failed %d\n", v8engine::Socket::GetLastError());
+ break;
+ }
+ buf[bytes_read] = '\0';
+
+ #ifdef WIN32
+ if (bytes_read > 3) buf[bytes_read - 2] = '\0'; // remove CR+LF symbols
+ #else
+ if (bytes_read > 2) buf[bytes_read - 1] = '\0'; // remove LF symbol
+ #endif
+
+ std::string clientCommand(&buf[0]);
+ XDKLog("xdk: Got '%s' profiling command\n", clientCommand.c_str());
+
+ if (clientCommand == cmdStart) {
+ resumeSampling();
+ } else if (clientCommand == cmdStop) {
+ pauseSampling();
+ } else {
+ XDKLog("xdk: '%s' is not handled command\n", clientCommand.c_str());
+ break;
+ }
+ }
+ }
+
+ XDKLog("xdk: Listener thread is stopped\n");
+ return;
+}
+
+
+void XDKAgent::processCodeMovedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ v8engine::Address from = static_cast<v8engine::Address>(event->code_start);
+ v8engine::Address to = static_cast<v8engine::Address>(event->new_code_start);
+
+ if (!from || !to) return;
+ XDKLog("xdk: CODE_MOVED from=0x%x to=0x%x\n", from, to);
+ m_snapshot.move(from, to);
+}
+
+
+void XDKAgent::processCodeRemovedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ v8engine::Address addr = static_cast<v8engine::Address>(event->code_start);
+
+ if (!addr) return;
+ XDKLog("xdk: CODE_REMOVED for addr=0x%x\n", addr);
+ m_snapshot.remove(addr);
+}
+
+
+void XDKAgent::processCodeAddedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+
+ v8engine::Address codeAddr =
+ static_cast<v8engine::Address>(event->code_start);
+ uint32_t codeLen = event->code_len;
+
+ if (!codeAddr || !codeLen) return;
+ XDKLog("xdk: CODE_ADDED for addr=0x%x len=0x%x\n", codeAddr, codeLen);
+
+ // Look for line number information
+ LineMap* lineMap = NULL;
+ LineMaps::iterator itr = m_lineMaps.find(codeAddr);
+ if (itr == m_lineMaps.end()) {
+ XDKLog("xdk: Unable to find line info for addr=0x%x\n", codeAddr);
+ } else {
+ lineMap = itr->second;
+
+ // Remove line map if no chance to get source lines for it
+ v8::Handle<v8::Script> script = event->script;
+ if (*script != NULL && *(script->GetUnboundScript()) != NULL) {
+ // Convert V8 pos value into source line number.
+ LineMap::Entries* entries =
+ const_cast<LineMap::Entries*>(lineMap->getEntries());
+ CHECK(entries);
+ CHECK(entries->size());
+ XDKLog("xdk: Found line info (%d lines) for addr=0x%x\n",
+ entries->size(), codeAddr);
+ size_t srcLine = 0;
+ LineMap::Entries::iterator lineItr = entries->begin();
+ LineMap::Entries::iterator lineEnd = entries->end();
+ for (; lineItr != lineEnd; ++lineItr) {
+ srcLine = script->GetUnboundScript()->GetLineNumber(lineItr->line) + 1;
+ lineItr->line = srcLine;
+ XDKLog("xdk: offset=%p line=%d\n", lineItr->pcOffset, lineItr->line);
+ }
+ } else {
+ XDKLog("xdk: Script is empty. No line info for addr=0x%x.\n", codeAddr);
+ delete lineMap;
+ lineMap = NULL;
+ m_lineMaps.erase(codeAddr);
+ }
+ }
+
+ std::string funcType;
+ std::string name(event->name.str, event->name.len);
+ Function func(codeAddr, codeLen, name, funcType, lineMap);
+
+ if (lineMap) {
+ // Put the line number information for the given method into the trace file
+ // if profiling session is running.
+ logLineNumberInfo(codeAddr, *lineMap);
+
+ // Release memory allocated on CODE_START_LINE_INFO_RECORDING
+ delete lineMap;
+ lineMap = NULL;
+ m_lineMaps.erase(codeAddr);
+ }
+
+ m_snapshot.insert(func);
+}
+
+
+void XDKAgent::processLineMapAddedEvent(const v8::JitCodeEvent* event) {
+ v8engine::LockGuard<v8engine::Mutex> l(m_agent_access);
+ v8engine::Address codeAddr =
+ static_cast<v8engine::Address>(event->code_start);
+ void* userData = event->user_data;
+
+ if (!userData || !codeAddr) return;
+
+ LineMap* lineMap = reinterpret_cast<LineMap*>(userData);
+ if (lineMap->getSize() == 0) {
+ XDKLog("xdk: CODE_END_LINE no entries for user_data=%p addr=0x%x\n",
+ userData, codeAddr);
+ return;
+ }
+
+ std::pair<LineMaps::iterator, bool>
+ result = m_lineMaps.insert(std::make_pair(codeAddr, lineMap));
+ if (!result.second) {
+ m_lineMaps.erase(codeAddr);
+ XDKLog("xdk: removed unprocessed line info for addr=0x%x\n", codeAddr);
+ result = m_lineMaps.insert(std::make_pair(codeAddr, lineMap));
+ CHECK(result.second);
+ }
+
+ XDKLog("xdk: CODE_END_LINE added %d entries for user_data=%p addr=0x%x\n",
+ lineMap->getSize(), userData, codeAddr);
+}
+
+
+void EventHandler(const v8::JitCodeEvent* event) {
+ // This callback is called regardless of whether profiling is running.
+ //
+ // By default profiling is launched in paused mode, the agent is awaiting
+ // a command to resume profiling. At the same time, V8's JIT compiler is
+ // working. The functions which are JIT-compiled while sampling is paused
+ // are cached by V8's Logger and will be written in log (trace file) when
+ // XDK resumes the profiling. The line number info for such functions are not
+ // cached. We need to capture and cache the line number info and flush
+ // the cache on resume profiling.
+
+ if (event == NULL) return;
+
+ switch (event->type) {
+ case v8::JitCodeEvent::CODE_MOVED:
+ XDKAgent::instance().processCodeMovedEvent(event);
+ break;
+
+ case v8::JitCodeEvent::CODE_REMOVED:
+ XDKAgent::instance().processCodeRemovedEvent(event);
+ break;
+
+ case v8::JitCodeEvent::CODE_ADDED:
+ XDKAgent::instance().processCodeAddedEvent(event);
+
+ case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
+ void* userData = event->user_data;
+ if (!userData) return;
+ LineMap* lineMap = reinterpret_cast<LineMap*>(userData);
+ size_t offset = event->line_info.offset;
+ size_t pos = event->line_info.pos;
+ lineMap->setPosition(offset, pos);
+ XDKLog("xdk: CODE_ADD_LINE_POS for user_data=%p offset=0x%x pos=%d\n",
+ userData, offset, pos);
+ break;
+ }
+
+ case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
+ v8::JitCodeEvent* data = const_cast<v8::JitCodeEvent*>(event);
+ data->user_data = new LineMap();
+ XDKLog("xdk: CODE_START_LINE for user_data=%p\n", event->user_data);
+ break;
+ }
+
+ case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
+ XDKAgent::instance().processLineMapAddedEvent(event);
+ break;
+ }
+
+ default:
+ XDKLog("xdk: Unknown event\n");
+ break;
+ }
+
+ SetIdle(true, XDKAgent::instance().isolate());
+
+ return;
+}
+
+
+void XDKAgent::logLineNumberInfo(v8engine::Address addr,
+ const LineMap& lineInfo) {
+ CHECK(addr);
+ v8engine::Log* log = m_isolate->logger()->XDKGetLog();
+ CHECK(log);
+ if (!log->IsEnabled()) return;
+ if (lineInfo.getSize() == 0) return;
+ const LineMap::Entries* lines = lineInfo.getEntries();
+ CHECK(lines);
+ LineMap::Entries::const_iterator lineItr = lines->begin();
+ LineMap::Entries::const_iterator lineEnd = lines->end();
+
+ // Put 'src-pos' lines into the log in our own format
+ for (; lineItr != lineEnd; ++lineItr) {
+ v8engine::Log::MessageBuilder msg(m_isolate->logger()->XDKGetLog());
+ msg.Append("src-pos,");
+ msg.Append("0x%x,%d,%d\n", addr, lineItr->pcOffset, lineItr->line);
+ msg.WriteToLogFile();
+ }
+}
+
+
+void XDKAgent::logFunctionSnapshot() {
+ CHECK(m_isolate);
+
+ CodeMap::const_iterator funcItr = m_snapshot.entries().begin();
+ CodeMap::const_iterator funcEnd = m_snapshot.entries().end();
+
+ XDKLog("FunctionSnapshot: %d entries\n", m_snapshot.entries().size());
+ if (m_snapshot.entries().size() == 0) return;
+
+ unsigned int i = 1;
+
+ for (; funcItr != funcEnd; ++funcItr, i++) {
+ const Range& range = funcItr->first;
+ const Function& func = funcItr->second;
+
+ XDKLog("%d %s\n", i, func.getLogLine().c_str());
+
+ const LineMap& map = func.getLineMap();
+ if (map.getSize()) {
+ v8engine::Address codeAddr = range.start();
+ XDKLog(" Found %d lines for addr=%p\n", map.getSize(), codeAddr);
+ logLineNumberInfo(codeAddr, map);
+ }
+
+ // Write 'code-creation' line into the log
+ v8engine::Log::MessageBuilder msg(m_isolate->logger()->XDKGetLog());
+ msg.Append("%s\n", func.getLogLine().c_str());
+ msg.WriteToLogFile();
+ }
+}
+
+}} // namespace xdk::internal
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XDK_AGENT_H_
+#define XDK_AGENT_H_
+
+#include "v8.h"
+#include "sampler.h"
+#include "platform.h"
+#include "platform/socket.h"
+#include "platform/mutex.h"
+#include "xdk-types.h"
+#include "xdk-code-map.h"
+
+// ----------------------------------------------------------------------------
+//
+// This file declares XDKAgent class which does
+//
+// - Handles the code events to maintain the code map.
+// - Handles the line info events to assosiate the line info with code event.
+// - Accepts start / stop profiling commands from AppAnalyzer.
+//
+// ----------------------------------------------------------------------------
+
+namespace xdk {
+namespace internal {
+
+const int XDK_AGENT_PORT = 48899;
+
+// Callback called by V8 builtin logger.
+void EventHandler(const v8::JitCodeEvent* event);
+
+// XDK profiling agent. It starts a socket listener on the specific port and
+// handles commands to start and stop sampling.
+class XDKAgent : public v8engine::Thread {
+ public:
+ static XDKAgent& instance() {
+ return instance_;
+ }
+
+ void Run();
+
+ bool setUp(v8engine::Isolate* isolate);
+ bool isAlive() const { return m_alive; }
+
+ void processCodeMovedEvent(const v8::JitCodeEvent* event);
+ void processCodeRemovedEvent(const v8::JitCodeEvent* event);
+ void processCodeAddedEvent(const v8::JitCodeEvent* event);
+ void processLineMapAddedEvent(const v8::JitCodeEvent* event);
+
+ inline v8engine::Isolate* isolate() { return m_isolate; }
+
+ private:
+ virtual ~XDKAgent();
+ XDKAgent()
+ : v8engine::Thread("xdk:agent"),
+ m_alive(false),
+ m_port(XDK_AGENT_PORT),
+ m_server(new v8engine::Socket()),
+ m_agent_access(new v8engine::Mutex()),
+ m_isolate(NULL),
+ m_terminate(false) {
+ CHECK(m_server != NULL);
+ CHECK(m_agent_access != NULL);
+ }
+ XDKAgent(const XDKAgent&);
+ XDKAgent& operator=(const XDKAgent&);
+
+ void logFunctionSnapshot();
+ void logLineNumberInfo(v8engine::Address codeAddr, const LineMap& lineInfo);
+
+ void resumeSampling();
+ void pauseSampling();
+
+ bool m_alive;
+
+ const int m_port; // Port to use for the agent.
+ v8engine::Socket* m_server; // Server socket for listen/accept.
+ v8engine::Mutex* m_agent_access;
+ v8engine::Isolate* m_isolate;
+
+ // The snapshot of compiled methods at present moment.
+ FunctionSnapshot m_snapshot;
+
+ // The processLineMapAddedEvent function adds a new map for code starting
+ // address. Newly added map describes how ps offsets maps to internal pos,
+ // but not how ps offsets maps to line number within source file.
+ //
+ // On CodeAdd event, processCodeAddedEvent function looks for line map for
+ // a code address. If map is found that assign it to a object of Function type
+ // in FunctionSnapshot. Before assign the pc offset to pos map is converted
+ // to pc offset to source line.
+ //
+ // CodeMoved and CodeRemoved must not affect this map.
+ // Current understanding of V8 code generator: V8 first emits LineStart event,
+ // then bunch of LineAdd events, then LineEnd event, finally CodeAdded event.
+ // Based on above no need to add any 'smart' logic on CodeMoved and
+ // CodeRemoved for line map.
+ //
+ // Basically it should be always empty.
+ LineMaps m_lineMaps;
+
+ bool m_terminate; // Termination flag for listening thread.
+
+ static XDKAgent instance_;
+};
+
+} } // namespace xdk::internal
+
+#endif // XDK_AGENT_H_
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xdk-code-map.h"
+#include <sstream>
+
+namespace xdk {
+namespace internal {
+
+static std::string replaceAddress(const std::string& str,
+ v8engine::Address addr) {
+ // The input str: code-creation,LazyCompile,0,0x3851c4e0,200," native uri.js"
+ std::string first;
+ std::string end;
+
+ std::size_t found = str.find(',');
+ if (found != std::string::npos) {
+ found = str.find(',', found + 1);
+ if (found != std::string::npos) {
+ found = str.find(',', found + 1);
+ if (found != std::string::npos) {
+ first = str.substr(0, found);
+ found = str.find(',', found + 1);
+ if (found != std::string::npos) {
+ end = str.substr(found, str.size() - found);
+ }
+ }
+ }
+ }
+
+ if (!first.size() || !end.size()) return str;
+
+ std::stringstream ss;
+ ss << first << ','
+ << std::showbase << std::hex << static_cast<void*>(addr) << end;
+ return ss.str();
+}
+
+
+Function::Function(v8engine::Address codeAddr, uint32_t codeLen,
+ const std::string& name, const std::string& type,
+ const LineMap* lineMap)
+ : m_codeAddr(codeAddr), m_codeLen(codeLen), m_name(name), m_type(type) {
+ CHECK(codeAddr);
+ CHECK(codeLen);
+ // Can't be empty because it's came from CodeCreation(...) events
+ CHECK(!name.empty());
+ m_logLine = m_name;
+
+ if (lineMap && lineMap->getSize()) m_lineMap = *lineMap;
+}
+
+
+void FunctionSnapshot::removeAll(const Range& range) {
+ CodeMap::iterator low = m_impl.lower_bound(range);
+ CodeMap::iterator up = m_impl.upper_bound(range);
+ CodeMap::iterator::difference_type num = std::distance(low, up);
+
+ if (num) {
+ XDKLog("xdk: %d ranges were overlapped and removed\n", num);
+
+ CodeMap::iterator itr = low;
+ for (; itr != up; ++itr) {
+ XDKLog("xdk: ovrl&removed addr=0x%x len=0x%x name=%s\n",
+ itr->first.start(), itr->first.length(),
+ itr->second.getLogLine().c_str());
+ }
+ m_impl.erase(low, up);
+ }
+}
+
+
+void FunctionSnapshot::insert(const Function& func) {
+ v8engine::Address codeAddr = func.getCodeAddress();
+ uint32_t codeLen = func.getCodeLength();
+ CHECK(codeAddr);
+ CHECK(codeLen);
+
+ Range range(codeAddr, codeLen);
+
+ removeAll(range);
+
+ std::pair<CodeMap::iterator, bool> res =
+ m_impl.insert(std::make_pair(range, func));
+ CHECK(res.second);
+
+ XDKLog("xdk: size=%d added addr=0x%x name=%s\n",
+ m_impl.size(), range.start(), func.getLogLine().c_str());
+}
+
+
+void FunctionSnapshot::remove(v8engine::Address codeAddr) {
+ if (!codeAddr) return;
+ CodeMap::iterator itr = m_impl.find(Range(codeAddr, 1));
+ if (itr != m_impl.end()) {
+ std::string name = itr->second.getLogLine();
+ uint32_t len = itr->first.length();
+ m_impl.erase(itr);
+ XDKLog("xdk: size=%d removed addr=0x%x name=%s\n",
+ m_impl.size(), codeAddr, len, name.c_str());
+ }
+}
+
+
+void FunctionSnapshot::move(v8engine::Address from, v8engine::Address to) {
+ if (!from || !to) return;
+ if (from == to) return;
+
+ CodeMap::iterator itr = m_impl.find(Range(from, 1));
+ if (itr == m_impl.end()) {
+ XDKLog("xdk: couldn't find a code to move from=0x%x to=0x%x\n", from, to);
+ return;
+ }
+ if (itr->first.start() != from) {
+ XDKLog("xdk: discarded move from=0x%x to=0x%x\n", from, to);
+ return;
+ }
+
+ uint32_t codeLen = itr->second.getCodeLength();
+ const LineMap& lines = itr->second.getLineMap();
+
+ // In case of CodeMoved we have to check that name contains the same code
+ // addr and code length as the input params and replace if they are different.
+ const std::string& orig = itr->second.getName();
+ std::string name = replaceAddress(orig, to);
+
+ const std::string& type = itr->second.getType();
+ Function toEntry(to, codeLen, name, type, &lines);
+
+ m_impl.erase(itr);
+
+ Range range(to, codeLen);
+ removeAll(range);
+
+ // Now ready to move
+
+ bool ok = m_impl.insert(std::make_pair(range, toEntry)).second;
+ CHECK(ok);
+
+ XDKLog("xdk: size=%d moved from=0x%x to=0x%x name=%s\n",
+ m_impl.size(), from, to, toEntry.getLogLine().c_str());
+}
+
+} } // namespace xdk::internal
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XDK_CODE_MAP_H_
+#define XDK_CODE_MAP_H_
+
+// ----------------------------------------------------------------------------
+//
+// This file contains the FunctionSnapshot and related objects declarations
+//
+// The FunctionSnapshot object maintains a map of JIT compiled functions.
+// It is modified on code events(CodeAdded, CodeMoved and CodeDeleted) from
+// V8 built-in profiler.
+//
+// ----------------------------------------------------------------------------
+
+#include "xdk-types.h"
+#include <map>
+#include <list>
+#include <string>
+#include <algorithm>
+
+namespace xdk {
+namespace internal {
+
+class LineMap;
+typedef std::map<
+ v8engine::Address, // start address of code
+ LineMap*> LineMaps;
+
+// This class is used to record the JITted code position info for JIT
+// code profiling.
+class LineMap {
+ public:
+ struct LineEntry {
+ LineEntry(size_t offset, size_t line)
+ : pcOffset(offset), line(line) { }
+
+ size_t pcOffset; // PC offset from the begining of the code trace.
+ size_t line; // Can be either position returned from V8 assembler
+ // (which needs to be converted to src line) or src line
+ // number.
+ };
+
+ typedef std::list<LineEntry> Entries;
+
+ void setPosition(size_t offset, size_t line) {
+ addCodeLineEntry(LineEntry(offset, line));
+ }
+
+ inline size_t getSize() const { return m_lines.size(); }
+ const Entries* getEntries() const { return &m_lines; }
+
+ private:
+ void addCodeLineEntry(const LineEntry& entry) { m_lines.push_back(entry); }
+
+ Entries m_lines;
+};
+
+// This class describes the function reported with CodeAdded event.
+class Function {
+ public:
+ explicit Function(v8engine::Address codeAddr, uint32_t codeLen,
+ const std::string& name, const std::string& type,
+ const LineMap* lineMap);
+
+ inline v8engine::Address getCodeAddress() const { return m_codeAddr; }
+ inline uint32_t getCodeLength() const { return m_codeLen; }
+
+ inline const std::string& getType() const { return m_type; }
+ inline const std::string& getName() const { return m_name; }
+ inline const std::string& getLogLine() const { return m_logLine; }
+
+ const LineMap& getLineMap() const { return m_lineMap; }
+
+ private:
+ v8engine::Address m_codeAddr;
+ uint32_t m_codeLen;
+ std::string m_name;
+ std::string m_type;
+ std::string m_logLine;
+ LineMap m_lineMap;
+};
+
+// This class describes the code range related to object of Function type.
+// The start address and length are taken from CodeAdded event.
+class Range {
+ public:
+ class Comparator : public std::binary_function<Range&, Range&, bool> {
+ public:
+ bool operator()(const Range& l, const Range& r) const {
+ return (l.start() + l.length() <= r.start());
+ }
+ };
+
+ Range(v8engine::Address start, uint32_t length)
+ : m_start(start), m_length(length) { }
+
+ inline v8engine::Address start() const { return m_start; }
+ inline uint32_t length() const { return m_length; }
+
+ private:
+ v8engine::Address m_start;
+ uint32_t m_length;
+};
+
+// This class maintains a map of JIT compiled functions.
+// The content is changed on CodeAdded, CodeMoved and CodeDeleted events.
+typedef std::map<Range, const Function, Range::Comparator> CodeMap;
+
+class FunctionSnapshot {
+ public:
+ explicit FunctionSnapshot() {}
+ virtual ~FunctionSnapshot() { m_impl.clear(); }
+
+ void insert(const Function& func);
+ void move(v8engine::Address from, v8engine::Address to);
+ void remove(v8engine::Address addr);
+
+ inline const CodeMap& entries() { return m_impl; }
+
+ private:
+ FunctionSnapshot(const FunctionSnapshot&);
+ FunctionSnapshot& operator=(const FunctionSnapshot&);
+
+ void removeAll(const Range& range);
+
+ CodeMap m_impl;
+};
+
+} } // namespace xdk::internal
+
+#endif // XDK_CODE_MAP_H_
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XDK_TYPES_H_
+#define XDK_TYPES_H_
+
+#include "v8.h"
+#include "platform.h"
+
+namespace v8engine = v8::internal;
+
+static void XDKLog(const char* msg, ...) {
+#if DEBUG
+ va_list arguments;
+ va_start(arguments, msg);
+ v8engine::OS::VPrint(msg, arguments);
+ va_end(arguments);
+#endif
+}
+
+#endif // XDK_TYPES__H_
+
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "../../../include/v8.h"
+#include "xdk-v8.h"
+#include "xdk-agent.h"
+
+namespace xdk {
+
+void XDKInitializeForV8(v8::internal::Isolate* isolate) {
+ if (!internal::XDKAgent::instance().setUp(isolate)) return;
+
+ XDKLog("xdk: XDKInitializeForV8\n");
+
+ // The --prof flag is requred for now to enable the CPU ticks collection.
+ // This flag will be removed once xdk agent implements own sampler.
+ const char* flags = "--prof";
+ v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
+
+ v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+ xdk::internal::EventHandler);
+
+ internal::XDKAgent::instance().Start();
+}
+
+
+bool XDKIsAgentAlive() {
+ return internal::XDKAgent::instance().isAlive();
+}
+
+} // namespace xdk
--- /dev/null
+# Copyright (c) 2013 Intel Corporation. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'v8_code': 1,
+ },
+ 'includes': ['../../../build/toolchain.gypi', '../../../build/features.gypi'],
+ 'targets': [
+ {
+ 'target_name': 'v8_xdk',
+ 'type': 'static_library',
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host', 'target'],
+ }, {
+ 'toolsets': ['target'],
+ }],
+ ],
+ 'include_dirs+': [
+ '../../',
+ ],
+ 'sources': [
+ 'xdk-v8.h',
+ 'xdk-v8.cc',
+ 'xdk-agent.h',
+ 'xdk-agent.cc',
+ 'xdk-code-map.h',
+ 'xdk-code-map.cc',
+ 'xdk-types.h',
+ ],
+ 'direct_dependent_settings': {
+ 'conditions': [
+ ['OS != "win"', {
+ 'libraries': ['-ldl',],
+ }],
+ ],
+ },
+ },
+ ]
+}
--- /dev/null
+// Copyright (c) 2013 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_XDK_H_
+#define V8_XDK_H_
+
+// ----------------------------------------------------------------------------
+//
+// XDK profiling support for V8
+//
+// SOURCES:
+//
+// 1. XDK agent source files are located in v8/src/third_party/xdk folder.
+//
+// To integrate this stuff into V8 build system you need to modify
+// two v8 files:
+//
+// 1. v8/build/features.gypi
+// 'v8_enable_xdkprof': 1,
+// 2. v8/tools/gyp/v8.gyp
+// ['v8_enable_xdkprof==1', {
+// 'dependencies': ['../../src/third_party/xdk/xdk-v8.gyp:v8_xdk',],
+// }],
+//
+// 2. Two V8 files v8/src/log.cc and v8/src/log.h need to be modified
+//
+// The changes related to start CPU ticks collection using V8 built-in
+// profiler.
+// We are working on reduce these changes up to 2 lines:
+//
+// #include "third_party/xdk/xdk-v8.h"
+// bool Logger::SetUp(Isolate* isolate) {
+// ...
+// xdk::XDKInitializeForV8(isolate);
+// ...
+// }
+//
+// OVERVIEW:
+//
+// Start up
+//
+// XDK agent is initialized as a part of V8 built-in profiler on process
+// start up. V8 built-in profiler should be paused (CPU ticks are not
+// collected).
+//
+// v8/src/log.cc:
+// bool Logger::SetUp(Isolate* isolate) {
+// ...
+// xdk::XDKInitializeForV8(isolate);
+// ...
+// }
+//
+// XDKInitializeForV8() function
+// 1. Checks whether XDK agent can be initialized. If a marker file is not
+// found that initialization will be discarded.
+// 2. Starts a listener thread to accept start / stop profiling command
+// from AppAnalyzer (xdk/xdk-agent.cc).
+// 3. Registeres a callback to consume the CodeAdded, CodeMoved,
+// CodeDeleted events and events related to source line info by
+// the agent.
+//
+// Runtime
+//
+// XDK profiler consumes the code events (EventHandler() in xdk/xdk-agent.cc)
+// V8 emits these events even when CPU ticks collection is paused.
+// The profiler uses the code events to maintain a function snapshot (list of
+// code ranges assosiated with function name and source line info)
+// (xdk-code-map.cc).
+//
+// Start profiling
+//
+// When the profiler receives a command to start profiling that it calls
+// resumeSampling() (xdk/xdk-agent.cc) which
+// 1. Creates a new trace file to log the ticks and code events
+// 2. Puts the function snapshot into the trace file
+// 3. Resumes CPU ticks collection
+//
+// Stop profiling
+//
+// When the profiler receives a command to stop profiling that it calls
+// pauseSampling() (xdk/xdk-agent.cc) which stops the CPU ticks collection.
+// Note that the agent continues to consume the code events to maintain
+// the function snapshot.
+//
+// When collection is stopped that AppAnalyzer takes the trace file for
+// processing.
+//
+// ----------------------------------------------------------------------------
+
+namespace xdk {
+
+// This function
+// - Overrides the V8 flags to specify a new logfile for writting profiling data
+// (CPU ticks and Code* events).
+// - Registers callback to get line number info and code events from V8 built-in
+// profiler. These data are needed to mantain the code map.
+// - Starts the XDK agent listener thread which is awaiting for start and stop
+// profiling commands.
+void XDKInitializeForV8(v8::internal::Isolate* isolate);
+
+bool XDKIsAgentAlive();
+
+} // namespace XDK
+
+#endif // V8_XDK_H_
+
void Assembler::shufps(XMMRegister dst, XMMRegister src, byte imm8) {
ASSERT(is_uint8(imm8));
EnsureSpace ensure_space(this);
- emit_optional_rex_32(src, dst);
+ emit_optional_rex_32(dst, src);
emit(0x0F);
emit(0xC6);
emit_sse_operand(dst, src);
__ xorps(xmm_scratch, xmm_scratch);
__ ucomisd(reg, xmm_scratch);
EmitBranch(instr, not_equal);
+ } else if (r.IsSIMD128()) {
+ ASSERT(!info()->IsStub());
+ EmitBranch(instr, no_condition);
} else {
ASSERT(r.IsTagged());
Register reg = ToRegister(instr->value());
} else if (type.IsJSArray()) {
ASSERT(!info()->IsStub());
EmitBranch(instr, no_condition);
+ } else if (type.IsSIMD128()) {
+ ASSERT(!info()->IsStub());
+ EmitBranch(instr, no_condition);
} else if (type.IsHeapNumber()) {
ASSERT(!info()->IsStub());
XMMRegister xmm_scratch = double_scratch0();
__ j(equal, instr->TrueLabel(chunk_));
}
+ if (expected.Contains(ToBooleanStub::FLOAT32x4)) {
+ // Float32x4 value -> true.
+ __ CmpInstanceType(map, FLOAT32x4_TYPE);
+ __ j(equal, instr->TrueLabel(chunk_));
+ }
+
+ if (expected.Contains(ToBooleanStub::INT32x4)) {
+ // Int32x4 value -> true.
+ __ CmpInstanceType(map, INT32x4_TYPE);
+ __ j(equal, instr->TrueLabel(chunk_));
+ }
+
if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
// heap number -> false iff +0, -0, or NaN.
Label not_heap_number;
if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
- type.IsJSArray() || type.IsHeapNumber() || type.IsString();
+ type.IsJSArray() || type.IsHeapNumber() || type.IsSIMD128() ||
+ type.IsString();
LInstruction* branch = new(zone()) LBranch(UseRegister(value));
if (!easy_case &&
((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
--- /dev/null
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --simd_object --allow-natives-syntax
+
+function testArithmeticOperators() {
+ var a = SIMD.float32x4.zero();
+ var b = SIMD.float32x4.zero();
+ var c;
+
+ c = a + b;
+ assertEquals(NaN, c);
+ c = a++;
+ assertEquals(NaN, c);
+ c = a - b;
+ assertEquals(NaN, c);
+ c = a--;
+ assertEquals(NaN, c);
+ c = a * b;
+ assertEquals(NaN, c);
+ c = a / b;
+ assertEquals(NaN, c);
+ c = a % b;
+ assertEquals(NaN, c);
+}
+
+testArithmeticOperators();
+testArithmeticOperators();
+%OptimizeFunctionOnNextCall(testArithmeticOperators);
+testArithmeticOperators();
+
+
+function testBitwiseOperators() {
+ var a = SIMD.float32x4.zero();
+ var b = SIMD.float32x4.zero();
+ var c;
+ c = a | b;
+ assertEquals(0, c);
+ c = a & b;
+ assertEquals(0, c);
+ c = a ^ b;
+ assertEquals(0, c);
+ c = ~a;
+ assertEquals(-1, c);
+ c = a << 0;
+ assertEquals(0, c);
+ c = a >> 0;
+ assertEquals(0, c);
+ c = a >>> 0;
+ assertEquals(0, c);
+}
+
+testBitwiseOperators();
+testBitwiseOperators();
+%OptimizeFunctionOnNextCall(testBitwiseOperators);
+testBitwiseOperators();
+
+
+function testAssignmentOperators() {
+ var a = SIMD.float32x4.zero();
+ var b = SIMD.float32x4.zero();
+ var c = a;
+ c += b;
+ assertEquals(NaN, c);
+ c -= b;
+ assertEquals(NaN, c);
+ c *= b;
+ assertEquals(NaN, c);
+ c /= b;
+ assertEquals(NaN, c);
+ c %= b;
+ assertEquals(NaN, c);
+
+ c &= b;
+ assertEquals(0, c);
+ c |= b;
+ assertEquals(0, c);
+ c ^= b;
+ assertEquals(0, c);
+ c <<= b;
+ assertEquals(0, c);
+ c >>= b;
+ assertEquals(0, c);
+ c >>>= b;
+ assertEquals(0, c);
+}
+
+testAssignmentOperators();
+testAssignmentOperators();
+%OptimizeFunctionOnNextCall(testAssignmentOperators);
+testAssignmentOperators();
+
+
+function testStringOperators() {
+ var a = SIMD.float32x4.zero();
+ var b = "0";
+ var c = a;
+ c += b;
+ assertEquals("float32x4(0,0,0,0)0", c);
+ c = b + a;
+ assertEquals("0float32x4(0,0,0,0)", c);
+}
+
+testStringOperators();
+testStringOperators();
+%OptimizeFunctionOnNextCall(testStringOperators);
+testStringOperators();
+
+
+function testComparisionOperators() {
+ var a = SIMD.float32x4.zero();
+ var b = SIMD.float32x4.zero();
+ assertEquals(true, a == b);
+ assertEquals(false, a != b);
+ assertEquals(true, a === b);
+ assertEquals(false, a !== b);
+ assertEquals(false, a > b);
+ assertEquals(true, a >= b);
+ assertEquals(false, a < b);
+ assertEquals(true, a <= b);
+}
+
+testComparisionOperators();
+testComparisionOperators();
+%OptimizeFunctionOnNextCall(testComparisionOperators);
+testComparisionOperators();
+
+
+function testLogicalOperators() {
+ var a = SIMD.float32x4.zero();
+ var b = SIMD.float32x4.splat(1);
+ assertEquals(1, (a && b).x);
+ assertEquals(1, (a && b).y);
+ assertEquals(1, (a && b).z);
+ assertEquals(1, (a && b).w);
+ assertEquals(0, (a || b).x);
+ assertEquals(0, (a || b).y);
+ assertEquals(0, (a || b).z);
+ assertEquals(0, (a || b).w);
+ assertEquals(false, !a);
+}
+
+testLogicalOperators();
+testLogicalOperators();
+%OptimizeFunctionOnNextCall(testLogicalOperators);
+testLogicalOperators();
+
+
+function testConditionalOperators() {
+ var a = SIMD.int32x4.zero();
+ var c = a ? 1 : 0;
+ assertEquals(1, c);
+}
+
+testConditionalOperators();
+testConditionalOperators();
+%OptimizeFunctionOnNextCall(testConditionalOperators);
+testConditionalOperators();
--- /dev/null
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --simd_object --allow-natives-syntax
+
+function testObject() {
+ var a = SIMD.float32x4.zero();
+ var b = Object(a);
+ assertEquals(0, b.x);
+ assertEquals(0, b.y);
+ assertEquals(0, b.z);
+ assertEquals(0, b.w);
+ assertEquals(typeof(b), "object");
+ assertEquals(typeof(b.valueOf()), "float32x4");
+ assertEquals(Object.prototype.toString.call(b), "[object float32x4]");
+}
+
+testObject();
+testObject();
+%OptimizeFunctionOnNextCall(testObject);
+testObject();
+
+
+function testNumber() {
+ var a = SIMD.float32x4.zero();
+ var b = Number(a);
+ assertEquals(NaN, b);
+}
+
+testNumber();
+testNumber();
+%OptimizeFunctionOnNextCall(testNumber);
+testNumber();
+
+
+function testString() {
+ var a = SIMD.float32x4.zero();
+ var b = String(a);
+ assertEquals("float32x4(0,0,0,0)", b);
+}
+
+testString();
+testString();
+%OptimizeFunctionOnNextCall(testString);
+testString();
+
+
+function testBoolean() {
+ var a = SIMD.float32x4.zero();
+ var b = Boolean(a);
+ assertEquals(true, b);
+}
+
+testBoolean();
+testBoolean();
+%OptimizeFunctionOnNextCall(testBoolean);
+testBoolean();
# - _GLOBAL__I__ZN2v810LineEditor6first_E
# - _GLOBAL__I__ZN2v88internal32AtomicOps_Internalx86CPUFeaturesE
# - _GLOBAL__I__ZN2v88internal8ThreadId18highest_thread_id_E
-expected_static_init_count=3
+
+# The XDK CPU profiler patch adds one more static initializer.
+# - _GLOBAL__sub_I__ZN3xdk8internal8XDKAgent9instance_E
+expected_static_init_count=4
v8_root=$(readlink -f $(dirname $BASH_SOURCE)/../)
}, {
'toolsets': ['target'],
}],
+ ['v8_enable_xdkprof==1', {
+ 'dependencies': ['../../src/third_party/xdk/xdk-v8.gyp:v8_xdk',],
+ }],
['v8_target_arch=="arm"', {
'sources': [ ### gcmole(arch:arm) ###
'../../src/arm/assembler-arm-inl.h',
# Use 'Trunk' for trunk.
# If using trunk, will use '.DEPS.git' for gclient.
chromium_version = '35.0.1916.17'
-chromium_crosswalk_point = '634d34e4cf82b4f7400357c53ec12efaffe94add'
+chromium_crosswalk_point = 'e62582858402995e841741a28af1c418d815897f'
blink_crosswalk_point = '2c4e1889f37db55c77215de4f113748f071cb7aa'
-v8_crosswalk_point = 'da94d1be519a0dc5ebc3d7bad06a973be91683c9'
+v8_crosswalk_point = 'd27abf42d305c5ee30cabed4926783bb105953c0'
ozone_wayland_point = 'f4faec532d7d2f482b3ffe1e52be6fa3e6fc8629'
deps_xwalk = {
MAJOR=6
MINOR=35
-BUILD=121
+BUILD=131
PATCH=0
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<string name="dialog_message_update_runtime_lib_warning">An update is recommended for "Crosswalk Runtime Library".</string>
<string name="dialog_title_install_runtime_lib">Crosswalk Runtime Library not found</string>
<string name="dialog_message_install_runtime_lib">Please install "Crosswalk Runtime Library" first.</string>
- <string name="dialog_title_install_right_abi">Mismatch on process architecture between Crosswalk and your device</string>
- <string name="dialog_message_install_right_abi_embedded">Please install %1$s packaged with Crosswalk for %2$s.</string>
- <string name="dialog_message_install_right_abi_shared">Please install "Crosswalk Runtime Library" for %1$s.</string>
</resources>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+Copyright (c) 2014 Intel Corporation. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <!-- Background Color -->
+ <item>
+ <shape android:shape="rectangle" >
+ <solid android:color="#000000" />
+ </shape>
+ </item>
+ <!-- Background Image -->
+
+</layer-list>
<string name="dialog_message_update_runtime_lib_warning">An update is recommended for "Crosswalk Runtime Library".</string>
<string name="dialog_title_install_runtime_lib">Crosswalk Runtime Library not found</string>
<string name="dialog_message_install_runtime_lib">Please install "Crosswalk Runtime Library" first.</string>
- <string name="dialog_title_install_right_abi">Mismatch on process architecture between Crosswalk and your device</string>
- <string name="dialog_message_install_right_abi_embedded">Please install %1$s packaged with Crosswalk for %2$s.</string>
- <string name="dialog_message_install_right_abi_shared">Please install "Crosswalk Runtime Library" for %1$s.</string>
</resources>
title = getString("dialog_title_install_runtime_lib");
message = getString("dialog_message_install_runtime_lib");
break;
- case XWalkRuntimeLibraryException.XWALK_CORE_LIBRARY_SO_NOT_EXIST:
- title = getString("dialog_title_install_right_abi");
- if (XWalkRuntimeClient.libraryIsEmbedded()) {
- String appName = getPackageManager().getApplicationLabel(
- getApplicationContext().getApplicationInfo()).toString();
- if (appName == null) appName = getApplicationContext().getPackageName();
- message = String.format(getString("dialog_message_install_right_abi_embedded"),
- appName, System.getProperty("os.arch"));
- } else {
- message = String.format(getString("dialog_message_install_right_abi_shared"),
- System.getProperty("os.arch"));
- }
- break;
case XWalkRuntimeLibraryException.XWALK_RUNTIME_LIBRARY_INVOKE_FAILED:
default:
Exception originException = runtimeException.getOriginException();
@Override
public void handleException(Exception e) {
+ // Here is for handling runtime library not found,
+ // Should never happen if runtime is embedded.
+ if (libraryIsEmbedded()) throw new RuntimeException(e);
+
+ // XWalkView will handle UnsatisfiedLinkError which indicates mismatch of CPU architecture.
+ // So exception here should be either library not installed for shared mode or invoke error.
Exception toHandle = e;
- boolean wrongNativeLibraryAbi = false;
if (mRuntimeLoaded) {
toHandle = new XWalkRuntimeLibraryException(
XWalkRuntimeLibraryException.XWALK_RUNTIME_LIBRARY_INVOKE_FAILED, e);
} else {
if (!(e instanceof XWalkRuntimeLibraryException)) {
- Throwable rootCause = e;
- while (rootCause.getCause() != null && rootCause.getCause() != rootCause) {
- rootCause = rootCause.getCause();
- }
- // UnsatisfiedLinkError happens when the libxwalkcore.so is not found.
- // If the runtime library package exist, but the native library not, it can
- // be considered that the installed runtime lib apk is for another cpu
- // architecture.
- if (rootCause instanceof UnsatisfiedLinkError) {
- wrongNativeLibraryAbi = true;
- toHandle = new XWalkRuntimeLibraryException(
- XWalkRuntimeLibraryException.XWALK_CORE_LIBRARY_SO_NOT_EXIST, e);
- } else {
- toHandle = new XWalkRuntimeLibraryException(
- XWalkRuntimeLibraryException.XWALK_RUNTIME_LIBRARY_NOT_INSTALLED, e);
- }
+ toHandle = new XWalkRuntimeLibraryException(
+ XWalkRuntimeLibraryException.XWALK_RUNTIME_LIBRARY_NOT_INSTALLED, e);
}
}
- // Here is for handling runtime library not found or not match,
- // if library is embedded, should not invoke it.
- // Except the error is for incorrect abi, which could also happen for
- // embedded mode.
- if (!libraryIsEmbedded() || wrongNativeLibraryAbi) super.handleException(toHandle);
+ super.handleException(toHandle);
}
public FrameLayout get() {
public final static int XWALK_RUNTIME_LIBRARY_NOT_INSTALLED = 1;
public final static int XWALK_RUNTIME_LIBRARY_NOT_UP_TO_DATE_CRITICAL = 2;
public final static int XWALK_RUNTIME_LIBRARY_NOT_UP_TO_DATE_WARNING = 3;
- public final static int XWALK_CORE_LIBRARY_SO_NOT_EXIST = 4;
- public final static int XWALK_RUNTIME_LIBRARY_INVOKE_FAILED = 5;
+ public final static int XWALK_RUNTIME_LIBRARY_INVOKE_FAILED = 4;
private int mType;
private Exception mOriginException;
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
import shutil
import sys
+from customize_launch_screen import CustomizeLaunchScreen
from handle_xml import AddElementAttribute
from handle_xml import AddElementAttributeAndText
from handle_xml import EditElementAttribute
if mode == 'default':
invalid_chars = '\/:*?"<>|- '
elif mode == 'apkname':
- invalid_chars = '\/:.*?"<>|-'
+ invalid_chars = '\/:.*?"<>|- '
for c in invalid_chars:
if mode == 'apkname' and c in value:
print("Illegal character: '%s' is replaced with '_'" % c)
strings_file.close()
-def CustomizeThemeXML(sanitized_name, fullscreen, launch_screen_img):
+def CustomizeThemeXML(sanitized_name, fullscreen, app_manifest):
theme_path = os.path.join(sanitized_name, 'res', 'values', 'theme.xml')
if not os.path.isfile(theme_path):
print('Error: theme.xml is missing in the build tool.')
sys.exit(6)
- xmldoc = minidom.parse(theme_path)
+ theme_xmldoc = minidom.parse(theme_path)
if fullscreen:
- EditElementValueByNodeName(xmldoc, 'item',
+ EditElementValueByNodeName(theme_xmldoc, 'item',
'android:windowFullscreen', 'true')
- if launch_screen_img:
- EditElementValueByNodeName(xmldoc, 'item',
+ has_background = CustomizeLaunchScreen(app_manifest, sanitized_name)
+ if has_background:
+ EditElementValueByNodeName(theme_xmldoc, 'item',
'android:windowBackground',
- '@drawable/launchscreen')
- default_image = launch_screen_img
- if os.path.isfile(default_image):
- drawable_path = os.path.join(sanitized_name, 'res', 'drawable')
- if not os.path.exists(drawable_path):
- os.makedirs(drawable_path)
- # Get the extension of default_image.
- # Need to take care of special case, such as 'img.9.png'
- name = os.path.basename(default_image)
- extlist = name.split('.')
- # Remove the file name from the list.
- extlist.pop(0)
- ext = '.' + '.'.join(extlist)
- final_launch_screen_path = os.path.join(drawable_path,
- 'launchscreen' + ext)
- shutil.copyfile(default_image, final_launch_screen_path)
- else:
- print('Error: Please make sure \"' + default_image + '\" exists!')
- sys.exit(6)
- theme_file = open(theme_path, 'w')
- xmldoc.writexml(theme_file, encoding='utf-8')
+ '@drawable/launchscreen_bg')
+ theme_file = open(theme_path, 'wb')
+ theme_xmldoc.writexml(theme_file, encoding='utf-8')
theme_file.close()
def CustomizeXML(sanitized_name, package, app_versionCode, app_version,
description, name, orientation, icon_dict, fullscreen,
- icon, launch_screen_img, permissions, app_root):
+ icon, app_manifest, permissions, app_root):
manifest_path = os.path.join(sanitized_name, 'AndroidManifest.xml')
if not os.path.isfile(manifest_path):
print ('Please make sure AndroidManifest.xml'
sys.exit(6)
CustomizeStringXML(sanitized_name, description)
- CustomizeThemeXML(sanitized_name, fullscreen, launch_screen_img)
+ CustomizeThemeXML(sanitized_name, fullscreen, app_manifest)
xmldoc = minidom.parse(manifest_path)
EditElementAttribute(xmldoc, 'manifest', 'package', package)
if app_versionCode:
def CustomizeJava(sanitized_name, package, app_url, app_local_path,
- enable_remote_debugging, display_as_fullscreen):
+ enable_remote_debugging, display_as_fullscreen,
+ keep_screen_on):
root_path = os.path.join(sanitized_name, 'src',
package.replace('.', os.path.sep))
dest_activity = os.path.join(root_path, sanitized_name + 'Activity.java')
SetVariable(dest_activity,
'super.onCreate(savedInstanceState)',
'IsFullscreen', 'true')
+ if keep_screen_on:
+ ReplaceString(
+ dest_activity,
+ 'super.onCreate(savedInstanceState);',
+ 'super.onCreate(savedInstanceState);\n '+
+ 'getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);')
def CopyExtensionFile(extension_name, suffix, src_path, dest_path):
# Write to the manifest file to save the update.
file_handle = open(manifest_path, 'w')
- xmldoc.writexml(file_handle)
+ xmldoc.writexml(file_handle, encoding='utf-8')
file_handle.close()
# Write configuration of extensions into the target extensions-config.json.
def CustomizeAll(app_versionCode, description, icon_dict, permissions, app_url,
app_root, app_local_path, enable_remote_debugging,
- display_as_fullscreen, extensions, launch_screen_img,
- icon, package='org.xwalk.app.template', name='AppTemplate',
- app_version='1.0.0', orientation='unspecified',
- xwalk_command_line=''):
+ display_as_fullscreen, keep_screen_on, extensions,
+ app_manifest, icon, package='org.xwalk.app.template',
+ name='AppTemplate', app_version='1.0.0',
+ orientation='unspecified', xwalk_command_line=''):
sanitized_name = ReplaceInvalidChars(name, 'apkname')
try:
Prepare(sanitized_name, package, app_root)
CustomizeXML(sanitized_name, package, app_versionCode, app_version,
description, name, orientation, icon_dict,
- display_as_fullscreen, icon, launch_screen_img, permissions,
+ display_as_fullscreen, icon, app_manifest, permissions,
app_root)
CustomizeJava(sanitized_name, package, app_url, app_local_path,
- enable_remote_debugging, display_as_fullscreen)
+ enable_remote_debugging, display_as_fullscreen,
+ keep_screen_on)
CustomizeExtensions(sanitized_name, name, extensions)
GenerateCommandLineFile(sanitized_name, xwalk_command_line)
except SystemExit as ec:
parser.add_option('-f', '--fullscreen', action='store_true',
dest='fullscreen', default=False,
help='Make application fullscreen.')
+ parser.add_option('--keep-screen-on', action='store_true', default=False,
+ help='Support keeping screen on')
info = ('The path list for external extensions separated by os separator.'
'On Linux and Mac, the separator is ":". On Windows, it is ";".'
'Such as: --extensions="/path/to/extension1:/path/to/extension2"')
'http://developer.android.com/guide/topics/manifest/'
'activity-element.html#screen')
parser.add_option('--orientation', help=info)
- parser.add_option('--launch-screen-img',
- help='The fallback image for launch_screen')
+ parser.add_option('--manifest', help='The manifest path')
info = ('Use command lines.'
'Crosswalk is powered by Chromium and supports Chromium command line.'
'For example, '
'--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
parser.add_option('--xwalk-command-line', default='', help=info)
+
options, _ = parser.parse_args()
try:
icon_dict = {144: 'icons/icon_144.png',
CustomizeAll(options.app_versionCode, options.description, icon_dict,
options.permissions, options.app_url, options.app_root,
options.app_local_path, options.enable_remote_debugging,
- options.fullscreen, options.extensions,
- options.launch_screen_img, icon, options.package, options.name,
+ options.fullscreen, options.keep_screen_on, options.extensions,
+ options.manifest, icon, options.package, options.name,
options.app_version, options.orientation,
options.xwalk_command_line)
+
except SystemExit as ec:
print('Exiting with error code: %d' % ec.code)
return ec.code
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Intel Corporation. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import sys
+
+from manifest_json_parser import ManifestJsonParser
+
+def CopyToPathWithName(root, name, final_path, rename):
+ if name == '':
+ return False
+ origin_path = os.path.join(root, name)
+ if not os.path.exists(origin_path):
+ print ('Error: \'' + origin_path + '\' not found.' )
+ sys.exit(6)
+ if not os.path.exists(final_path):
+ os.makedirs(final_path)
+ # Get the extension.
+ # Need to take care of special case, such as 'img.9.png'
+ name_components = name.split('.')
+ name_components[0] = rename
+ new_name = '.'.join(name_components)
+ final_path_with_name = os.path.join(final_path, new_name)
+ shutil.copyfile(origin_path, final_path_with_name)
+ return True
+
+
+def CopyDrawables(image_dict, orientation, sanitized_name, name, app_root):
+ drawable = os.path.join(sanitized_name, 'res', 'drawable')
+ if orientation == 'landscape':
+ drawable = drawable + '-land'
+ elif orientation == 'portrait':
+ drawable = drawable + '-port'
+ drawable_ldpi = drawable + '-ldpi'
+ drawable_mdpi = drawable + '-mdpi'
+ drawable_hdpi = drawable + '-hdpi'
+ drawable_xhdpi = drawable + '-xhdpi'
+
+ image_075x = image_dict.get('0.75x', '')
+ image_1x = image_dict.get('1x', '')
+ image_15x = image_dict.get('1.5x', '')
+ image_2x = image_dict.get('2x', '')
+
+ # Copy all supported images: 0.75x, 1x, 1.5x, 2x.
+ has_image = False
+ if image_075x:
+ if CopyToPathWithName(app_root, image_075x, drawable_ldpi, name):
+ has_image = True
+ if image_1x:
+ if CopyToPathWithName(app_root, image_1x, drawable_mdpi, name):
+ has_image = True
+ if image_15x:
+ if CopyToPathWithName(app_root, image_15x, drawable_hdpi, name):
+ has_image = True
+ if image_2x:
+ if CopyToPathWithName(app_root, image_2x, drawable_xhdpi, name):
+ has_image = True
+
+ # If no supported images found, find the closest one as 1x.
+ if not has_image:
+ closest = ''
+ delta = sys.maxint
+ for (k , v) in image_dict.items():
+ items = k.split('x')
+ if len(items) == 2:
+ float_value = sys.maxint
+ try:
+ float_value = float(items[0])
+ except ValueError:
+ continue
+ if abs(float_value - 1) < delta:
+ closest = v
+ if CopyToPathWithName(app_root, closest, drawable_mdpi, name):
+ delta = float_value
+
+
+def CustomizeDrawable(image, orientation, sanitized_name, app_root, name):
+ # Parse the image.
+ # The format of image: 'image-1x.png [1x], image-75x.png 0.75x,
+ # image-15x.png 1.5x, image-2x.png 2x'
+ image_list = image.split(',')
+
+ # The first image: 'image-1x.png', the density is not provided.
+ image_pair_1 = image_list[0].strip()
+ items = image_pair_1.split(' ')
+ image_1x = ''
+ if len(items) == 1:
+ image_1x = items[0]
+ image_list.pop(0)
+ # The dictionary which contains the image pair.
+ image_dict = {'1x': image_1x}
+
+ for image_pair in image_list:
+ items = image_pair.strip().split(' ')
+ if len(items) >= 2:
+ x = items[len(items)-1]
+ image_item = items[0]
+ image_dict[x] = image_item
+
+ CopyDrawables(image_dict, orientation, sanitized_name, name, app_root)
+
+
+def CustomizeForeground(image, orientation, sanitized_name, app_root):
+ CustomizeDrawable(image, orientation, sanitized_name,
+ app_root, "launchscreen_img")
+
+
+def CustomizeBackground(background_color,
+ background_image,
+ orientation,
+ sanitized_name,
+ app_root):
+ background_path = os.path.join(sanitized_name, 'res',
+ 'drawable', 'launchscreen_bg.xml')
+ if not os.path.isfile(background_path):
+ print('Error: launchscreen_bg.xml is missing in the build tool.')
+ sys.exit(6)
+
+ has_background = False
+ background_file = open(background_path, 'r')
+ content = background_file.read()
+ background_file.close()
+ # Fill the background_color.
+ if background_color:
+ content = content.replace('#000000', background_color, 1)
+ has_background = True
+ # Fill the background_image.
+ if background_image:
+ CustomizeDrawable(background_image, orientation, sanitized_name,
+ app_root, "launchscreen_bg_img")
+ # Only set Background Image once for each orientation.
+ tmp = '<item>\n' \
+ ' <bitmap\n' \
+ ' android:src=\"@drawable/launchscreen_bg_img\"\n' \
+ ' android:tileMode=\"repeat\" />\n' \
+ '</item>\n'
+ content = content.replace('<!-- Background Image -->', tmp, 1)
+ has_background = True
+ if has_background:
+ background_file = file(background_path,'w')
+ background_file.write(content)
+ background_file.close()
+ return has_background
+
+
+def CustomizeByOrientation(parser, orientation, sanitized_name, app_root):
+ background_color = parser.GetLaunchScreenBackgroundColor(orientation)
+ background_image = parser.GetLaunchScreenBackgroundImage(orientation)
+ image = parser.GetLaunchScreenImage(orientation)
+ # Customize background: background_color, background_image.
+ has_background = CustomizeBackground(background_color, background_image,
+ orientation, sanitized_name, app_root)
+ # Customize foreground: image.
+ CustomizeForeground(image, orientation, sanitized_name, app_root)
+ return has_background
+
+
+def CustomizeLaunchScreen(app_manifest, sanitized_name):
+ if not app_manifest:
+ return False
+ parser = ManifestJsonParser(os.path.expanduser(app_manifest))
+ app_root = os.path.dirname(app_manifest)
+ default = CustomizeByOrientation(parser, 'default',
+ sanitized_name, app_root)
+ portrait = CustomizeByOrientation(parser, 'portrait',
+ sanitized_name, app_root)
+ landscape = CustomizeByOrientation(parser, 'landscape',
+ sanitized_name, app_root)
+ return default or portrait or landscape
options.fullscreen = True
elif parser.GetFullScreenFlag().lower() == 'false':
options.fullscreen = False
- if parser.GetLaunchScreenImg():
- options.launch_screen_img = os.path.join(options.app_root,
- parser.GetLaunchScreenImg())
def ParseXPK(options, out_dir):
CustomizeAll(app_versionCode, options.description, options.icon_dict,
options.permissions, options.app_url, app_root,
options.app_local_path, remote_debugging,
- fullscreen_flag, options.extensions,
- options.launch_screen_img, icon, package, name, app_version,
+ fullscreen_flag, options.keep_screen_on, options.extensions,
+ options.manifest, icon, package, name, app_version,
orientation, options.xwalk_command_line)
valid_archs = ['x86', 'armeabi-v7a']
packaged_archs = []
for arch in valid_archs:
- if os.path.isfile(os.path.join('native_libs', arch, 'libs',
- arch, 'libxwalkcore.so')):
+ lib_path = os.path.join('native_libs', arch, 'libs',
+ arch, 'libxwalkcore.so')
+ if os.path.isfile(lib_path):
if arch.find('x86') != -1:
options.arch = 'x86'
elif arch.find('arm') != -1:
options.arch = 'arm'
Execution(options, sanitized_name)
packaged_archs.append(options.arch)
+ else:
+ print('Warning: failed to create package for arch "%s" '
+ 'due to missing library %s' %
+ (arch, lib_path))
+
+ if len(packaged_archs) == 0:
+ print('No packages created, aborting')
+ sys.exit(13)
+
multi_arch = False
if len(packaged_archs) >=2:
multi_arch = True
group.add_option('-f', '--fullscreen', action='store_true',
dest='fullscreen', default=False,
help='Make application fullscreen.')
+ group.add_option('--keep-screen-on', action='store_true', default=False,
+ help='Support keeping screen on')
info = ('The path of application icon. '
'Such as: --icon=/path/to/your/customized/icon')
group.add_option('--icon', help=info)
parser.print_help()
return 0
- # This option will not export to users.
- # Initialize here and will be read from manifest.json.
- options.launch_screen_img = ''
-
if options.version:
if os.path.isfile('VERSION'):
print(GetVersion('VERSION'))
if not options.package:
parser.error('The package name is required! '
'Please use "--package" option.')
+ elif len(options.package) >= 128 :
+ parser.error('To be safe, the length of package name '
+ 'should be less than 128.')
+
if not options.name:
parser.error('The APK name is required! Please use "--name" option.')
if not ((options.app_url and not options.app_root
cmd = ['python', 'make_apk.py', '--app-version=1.0.0',
'--package=org.xwalk.example', self._mode]
out = RunCommand(cmd)
- self.assertTrue(out.find('The APK name is required!') != -1)
Clean('Example', '1.0.0')
+ self.assertTrue(out.find('The APK name is required!') != -1)
cmd = ['python', 'make_apk.py', '--name="Test Example"',
'--app-version=1.0.0',
'--package=org.xwalk.example', self._mode]
out = RunCommand(cmd)
- self.assertTrue(out.find('The APK name is required!') == -1)
Clean('Test Example', '1.0.0')
+ self.assertTrue(out.find('The APK name is required!') == -1)
# The following invalid chars verification is too heavy for embedded mode,
# and the result of verification should be the same between shared mode
# and embedded mode. So only do the verification in the shared mode.
'--app-version=1.0.0', '--package=org.xwalk.example',
'--app-url=http://www.intel.com', self._mode]
out = RunCommand(cmd)
- self.assertTrue(out.find('Illegal character') != -1)
Clean('Example_', '1.0.0')
+ self.assertTrue(out.find('Illegal character') != -1)
def testToolVersion(self):
cmd = ['python', 'make_apk.py', '--version']
'--description=a sample application',
'--app-url=http://www.intel.com', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
self.assertTrue(content.find('description') != -1)
self.assertTrue(content.find('versionName') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testAppVersionCode(self):
cmd = ['python', 'make_apk.py', '--name=Example',
'--app-versionCode=3',
'--app-url=http://www.intel.com', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
self.assertTrue(os.path.exists(manifest))
self.assertTrue(content.find('versionCode="3"') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testAppVersionCodeBase(self):
# Arch option only works for embedded mode,
arch,
'--app-url=http://www.intel.com', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
self.assertTrue(os.path.exists(manifest))
self.assertTrue(content.find(versionCode) != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testAppBigVersionCodeBase(self):
# Arch option only works for embedded mode,
arch,
'--app-url=http://www.intel.com', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
self.assertFalse(os.path.exists(manifest))
- Clean('Example', '1.0.0')
def testPermissions(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', '--permissions=geolocation',
'--app-url=http://www.intel.com', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
self.assertTrue(os.path.exists(manifest))
self.assertTrue(content.find('ACCESS_FINE_LOCATION') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testPermissionsWithError(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
self._mode]
out = RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(out.find('The package name is required!') != -1)
Clean('Example', '1.0.0')
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', self._mode]
out = RunCommand(cmd)
self.assertTrue(out.find('The package name is required!') == -1)
- Clean('Example', '1.0.0')
def testEntry(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
self._mode]
out = RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(out.find('The entry is required.') == -1)
self.checkApks('Example', '1.0.0')
Clean('Example', '1.0.0')
out = RunCommand(cmd)
self.assertTrue(out.find('The entry is required.') == -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testEntryWithErrors(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', self._mode]
out = RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(out.find('The entry is required.') != -1)
self.assertFalse(os.path.exists('Example.apk'))
Clean('Example', '1.0.0')
out = RunCommand(cmd)
self.assertTrue(out.find('Please make sure that the local path file') != -1)
self.assertFalse(os.path.exists('Example.apk'))
- Clean('Example', '1.0.0')
def testIconByOption(self):
icon = os.path.join('test_data', 'manifest', 'icons', 'icon_96.png')
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--icon=%s' % icon, self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
self.assertTrue(content.find('drawable/icon_96') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testIconByManifest(self):
manifest_path = os.path.join('test_data', 'manifest', 'manifest_icon.json')
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--manifest=%s' % manifest_path, self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
self.assertTrue(content.find('drawable/icon') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testFullscreen(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'-f', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
theme = 'Example/res/values/theme.xml'
with open(theme, 'r') as content_file:
content = content_file.read()
content.find(
'<item name="android:windowFullscreen">true</item>') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testEnableRemoteDebugging(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--enable-remote-debugging', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
activity = 'Example/src/org/xwalk/example/ExampleActivity.java'
with open(activity, 'r') as content_file:
content = content_file.read()
self.assertTrue(os.path.exists(activity))
self.assertTrue(content.find('setRemoteDebugging') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testKeystore(self):
keystore_path = os.path.join('test_data', 'keystore', 'xwalk-test.keystore')
'--keystore-path=%s' % keystore_path, '--keystore-alias=xwalk-test',
'--keystore-passcode=xwalk-test', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(os.path.exists('Example'))
apk_list = ['Example.apk', 'Example_x86.apk', 'Example_arm.apk']
for apk in apk_list:
out = RunCommand(cmd)
self.assertTrue(out.find('smk') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testManifest(self):
manifest_path = os.path.join('test_data', 'manifest', 'manifest.json')
cmd = ['python', 'make_apk.py', '--manifest=%s' % manifest_path, self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
'<item name="android:windowFullscreen">true</item>') != -1)
self.assertTrue(os.path.exists('Example'))
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testManifestWithSpecificValue(self):
manifest_path = os.path.join('test_data', 'manifest',
'manifest_app_launch_local_path.json')
cmd = ['python', 'make_apk.py', '--manifest=%s' % manifest_path, self._mode]
out = RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(out.find('no app launch path') == -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testManifestWithError(self):
manifest_path = os.path.join('test_data', 'manifest',
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--extensions=%s' % extension_path, self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(os.path.exists('Example'))
extensions_config_json = 'Example/assets/extensions-config.json'
self.assertTrue(os.path.exists(extensions_config_json))
extension_jar = 'Example/xwalk-extensions/myextension/myextension.jar'
self.assertTrue(os.path.exists(extension_jar))
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testExtensionsWithNonExtension(self):
# Test with a non-existed extension.
'--app-local-path=contactextension.html',
'--extensions=%s' % extension_path, self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(os.path.exists('Example'))
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
self.assertTrue(content.find('android.permission.WRITE_CONTACTS') != -1)
self.assertTrue(content.find('android.permission.READ_CONTACTS') != -1)
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testXPK(self):
xpk_file = os.path.join('test_data', 'xpk', 'example.xpk')
cmd = ['python', 'make_apk.py', '--xpk=%s' % xpk_file, self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(os.path.exists('Example'))
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testXPKWithError(self):
xpk_file = os.path.join('test_data', 'xpk', 'error.xpk')
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--orientation=landscape', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
content = content_file.read()
self.assertTrue(content.find('landscape') != -1)
self.assertTrue(os.path.exists('Example'))
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def testArch(self):
# Arch option only works for embedded mode,
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--arch=x86', self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
if 'x86' in self.archs():
self.assertTrue(os.path.isfile('Example_1.0.0_x86.apk'))
self.checkApk('Example_1.0.0_x86.apk', 'x86')
else:
self.assertFalse(os.path.isfile('Example_1.0.0._arm.apk'))
self.assertFalse(os.path.isfile('Example_1.0.0_x86.apk'))
- Clean('Example', '1.0.0')
def testVerbose(self):
cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--verbose', self._mode]
result = RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
self.assertTrue(result.find('aapt') != -1)
self.assertTrue(result.find('crunch') != -1)
self.assertTrue(result.find('apkbuilder') != -1)
self.assertTrue(os.path.exists('Example'))
self.checkApks('Example', '1.0.0')
- Clean('Example', '1.0.0')
def executeCommandAndVerifyResult(self, exec_file):
# Test all of supported options with empty 'mode' option.
'--enable-remote-debugging',
'--extensions=%s' % extension_path,
'--fullscreen',
+ '--keep-screen-on',
'%s' % icon,
'--name=Example',
'--orientation=landscape',
'--package=org.xwalk.example',
'--permissions=geolocation']
RunCommand(cmd)
+ self.addCleanup(Clean, 'Example', '1.0.0')
activity = 'Example/src/org/xwalk/example/ExampleActivity.java'
with open(activity, 'r') as content_file:
content = content_file.read()
self.assertTrue(os.path.exists(activity))
# Test remote debugging option.
self.assertTrue(content.find('setRemoteDebugging') != -1)
+ # Test keep screen on option
+ self.assertTrue(content.find('FLAG_KEEP_SCREEN_ON') != -1)
manifest = 'Example/AndroidManifest.xml'
with open(manifest, 'r') as content_file:
self.assertTrue(os.path.exists(extension_js))
extension_jar = 'Example/xwalk-extensions/myextension/myextension.jar'
self.assertTrue(os.path.exists(extension_jar))
- # Test arch option.
- if 'x86' in self.archs():
- self.assertTrue(os.path.isfile('Example_1.0.0_x86.apk'))
- self.checkApk('Example_1.0.0_x86.apk', 'x86')
- else:
- self.assertFalse(os.path.isfile('Example_1.0.0_x86.apk'))
- self.assertFalse(os.path.isfile('Example_1.0.0_arm.apk'))
- Clean('Example', '1.0.0')
def testEmptyMode(self):
self.executeCommandAndVerifyResult('make_apk.py')
'--package=org.xwalk.example', '--app-url=http://www.intel.com',
'--target-dir=%s' % option, self._mode]
RunCommand(cmd)
+ self.addCleanup(Clean, os.path.expanduser('%sExample' % option), '1.0.0')
if self._mode.find('shared') != -1:
apk_path = os.path.expanduser('%sExample_1.0.0.apk' % option)
self.assertTrue(os.path.exists(apk_path))
% (option, arch))
self.assertTrue(os.path.exists(apk_path))
self.checkApk(apk_path, arch)
- Clean(os.path.expanduser('%sExample' % option), '1.0.0')
def SuiteWithModeOption():
options.mode = 'shared'
print 'Run tests in shared mode.'
test_result = TestSuiteRun(runner, mode_suite) and test_result
+ options.mode = ''
print 'Run test without \'--mode\' option.'
test_result = TestSuiteRun(runner, empty_mode_suite) and test_result
if not test_result:
ret_dict['fullscreen'] = 'true'
else:
ret_dict['fullscreen'] = ''
- ret_dict['launch_screen_img'] = ''
if 'launch_screen' in self.data_src:
- if 'default' not in self.data_src['launch_screen']:
- print('Error: no \'default\' field for \'launch_screen\'.')
- sys.exit(1)
- default = self.data_src['launch_screen']['default']
- if 'image' not in default:
- print('Error: no \'image\' field for \'launch_screen.default\'.')
- sys.exit(1)
- ret_dict['launch_screen_img'] = default['image']
+ self.ParseLaunchScreen(ret_dict, 'default')
+ self.ParseLaunchScreen(ret_dict, 'portrait')
+ self.ParseLaunchScreen(ret_dict, 'landscape')
return ret_dict
+ def ParseLaunchScreen(self, ret_dict, orientation):
+ if orientation in self.data_src['launch_screen']:
+ sub_dict = self.data_src['launch_screen'][orientation]
+ if 'background_color' in sub_dict:
+ ret_dict['launch_screen_background_color_' + orientation] = (
+ sub_dict['background_color'])
+ if 'background_image' in sub_dict:
+ ret_dict['launch_screen_background_image_' + orientation] = (
+ sub_dict['background_image'])
+ if 'image' in sub_dict:
+ ret_dict['launch_screen_image_' + orientation] = (
+ sub_dict['image'])
+ if 'image_border' in sub_dict:
+ ret_dict['launch_screen_image_border_' + orientation] = (
+ sub_dict['image_border'])
+
def ShowItems(self):
"""Show the processed results, it is used for command-line
internal debugging."""
print("required_version: %s" % self.GetRequiredVersion())
print("plugins: %s" % self.GetPlugins())
print("fullscreen: %s" % self.GetFullScreenFlag())
- print('launch_screen.default.image: %s' % self.GetLaunchScreenImg())
+ print('launch_screen.default.background_color: %s' %
+ self.GetLaunchScreenBackgroundColor('default'))
+ print('launch_screen.default.background_image: %s' %
+ self.GetLaunchScreenBackgroundImage('default'))
+ print('launch_screen.default.image: %s' %
+ self.GetLaunchScreenImage('default'))
+ print('launch_screen.default.image_border: %s' %
+ self.GetLaunchScreenImageBorder('default'))
+ print('launch_screen.portrait.background_color: %s' %
+ self.GetLaunchScreenBackgroundColor('portrait'))
+ print('launch_screen.portrait.background_image: %s' %
+ self.GetLaunchScreenBackgroundImage('portrait'))
+ print('launch_screen.portrait.image: %s' %
+ self.GetLaunchScreenImage('portrait'))
+ print('launch_screen.portrait.image_border: %s' %
+ self.GetLaunchScreenImageBorder('portrait'))
+ print('launch_screen.landscape.background_color: %s' %
+ self.GetLaunchScreenBackgroundColor('landscape'))
+ print('launch_screen.landscape.background_image: %s' %
+ self.GetLaunchScreenBackgroundImage('landscape'))
+ print('launch_screen.landscape.image: %s' %
+ self.GetLaunchScreenImage('landscape'))
+ print('launch_screen.landscape.image_border: %s' %
+ self.GetLaunchScreenImageBorder('landscape'))
def GetAppName(self):
"""Return the set fullscreen flag of the application."""
return self.ret_dict['fullscreen']
- def GetLaunchScreenImg(self):
- """Return the default img for launch_screen."""
- return self.ret_dict['launch_screen_img']
+ def GetLaunchScreenBackgroundColor(self, orientation):
+ """Return the background color for launch_screen."""
+ if 'launch_screen_background_color_' + orientation in self.ret_dict:
+ return self.ret_dict['launch_screen_background_color_' + orientation]
+ else:
+ return ''
+
+ def GetLaunchScreenBackgroundImage(self, orientation):
+ """Return the background image for launch_screen."""
+ if 'launch_screen_background_image_' + orientation in self.ret_dict:
+ return self.ret_dict['launch_screen_background_image_' + orientation]
+ else:
+ return ''
+
+ def GetLaunchScreenImage(self, orientation):
+ """Return the image for launch_screen."""
+ if 'launch_screen_image_' + orientation in self.ret_dict:
+ return self.ret_dict['launch_screen_image_' + orientation]
+ else:
+ return ''
+
+ def GetLaunchScreenImageBorder(self, orientation):
+ """Return the image border for launch_screen."""
+ if 'launch_screen_image_border_' + orientation in self.ret_dict:
+ return self.ret_dict['launch_screen_image_border_' + orientation]
+ else:
+ return ''
def main(argv):
#include "xwalk/runtime/browser/xwalk_runner.h"
#include "xwalk/runtime/common/xwalk_common_messages.h"
+#if defined(OS_TIZEN)
+#include "xwalk/runtime/browser/ui/native_app_window.h"
+#endif
+
+#if defined(USE_OZONE) && defined(OS_TIZEN)
+#include "base/message_loop/message_pump_ozone.h"
+#include "content/public/browser/render_view_host.h"
+#include "ui/events/event.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
+#include "xwalk/application/common/manifest_handlers/tizen_setting_handler.h"
+#endif
+
+#if defined(OS_TIZEN)
+#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
+#endif
+
namespace xwalk {
namespace keys = application_manifest_keys;
observer_(observer),
entry_point_used_(Default),
termination_mode_used_(Normal),
- weak_factory_(this) {
+ weak_factory_(this),
+ is_security_mode_(false) {
DCHECK(runtime_context_);
DCHECK(application_data_);
DCHECK(observer_);
+#if defined(USE_OZONE) && defined(OS_TIZEN)
+ base::MessagePumpOzone::Current()->AddObserver(this);
+#endif
}
Application::~Application() {
+#if defined(USE_OZONE) && defined(OS_TIZEN)
+ base::MessagePumpOzone::Current()->RemoveObserver(this);
+#endif
Terminate(Immediate);
}
return false;
}
- GURL url = GetURLForLaunch(launch_params, &entry_point_used_);
+ GURL url = GetStartURL(launch_params, &entry_point_used_);
if (!url.is_valid())
return false;
if (entry_point_used_ != AppMainKey) {
NativeAppWindow::CreateParams params;
params.net_wm_pid = launch_params.launcher_pid;
- params.state = launch_params.window_state;
-
+ params.state = GetWindowShowState(launch_params);
main_runtime_->AttachWindow(params);
}
return true;
}
-GURL Application::GetURLForLaunch(const LaunchParams& params,
+GURL Application::GetStartURL(const LaunchParams& params,
LaunchEntryPoint* used) {
+ if (params.entry_points & URLKey) {
+ GURL url = GetURLFromURLKey();
+ if (url.is_valid()) {
+ *used = URLKey;
+ return url;
+ }
+ }
+
if (params.entry_points & AppMainKey) {
GURL url = GetURLFromAppMainKey();
if (url.is_valid()) {
}
}
- if (params.entry_points & URLKey) {
- GURL url = GetURLFromURLKey();
- if (url.is_valid()) {
- *used = URLKey;
- return url;
- }
- }
LOG(WARNING) << "Failed to find a valid launch URL for the app.";
return GURL();
}
return main_info->GetMainURL();
}
+ui::WindowShowState Application::GetWindowShowState(
+ const LaunchParams& params) {
+ if (params.force_fullscreen)
+ return ui::SHOW_STATE_FULLSCREEN;
+
+ const Manifest* manifest = application_data_->GetManifest();
+ std::string display_string;
+ if (manifest->GetString(keys::kDisplay, &display_string)) {
+ // FIXME: ATM only 'fullscreen' and 'standalone' (which is fallback value)
+ // values are supported.
+ if (display_string.find("fullscreen") != std::string::npos)
+ return ui::SHOW_STATE_FULLSCREEN;
+ }
+
+ return ui::SHOW_STATE_DEFAULT;
+}
+
GURL Application::GetURLFromLocalPathKey() {
const Manifest* manifest = application_data_->GetManifest();
std::string entry_page;
std::mem_fun(&Runtime::Close));
}
+#if defined(OS_TIZEN)
+void Application::Hide() {
+ DCHECK(runtimes_.size());
+ std::set<Runtime*>::iterator it = runtimes_.begin();
+ for (; it != runtimes_.end(); ++it) {
+ if ((*it)->window())
+ (*it)->window()->Hide();
+ }
+}
+#endif
+
Runtime* Application::GetMainDocumentRuntime() const {
return HasMainDocument() ? main_runtime_ : NULL;
}
void Application::InitSecurityPolicy() {
if (application_data_->GetPackageType() != Manifest::TYPE_WGT)
return;
- const WARPInfo* info = static_cast<WARPInfo*>(
- application_data_->GetManifestData(widget_keys::kAccessKey));
- if (!info
+
#if defined(OS_TIZEN)
- // On Tizen, CSP mode has higher priority, and WARP will be disabled
- // if the application is under CSP mode.
- || application_data_->HasCSPDefined()
+ // On Tizen, CSP mode has higher priority, and WARP will be disabled
+ // if the application is under CSP mode.
+ if (application_data_->HasCSPDefined()) {
+ // Always enable security mode when under CSP mode.
+ is_security_mode_ = true;
+ NavigationInfo* info = static_cast<NavigationInfo*>(
+ application_data_->GetManifestData(widget_keys::kAllowNavigationKey));
+ if (info) {
+ const std::vector<std::string>& allowed_list = info->GetAllowedDomains();
+ for (std::vector<std::string>::const_iterator it = allowed_list.begin();
+ it != allowed_list.end(); ++it) {
+ // If the policy start with "*.", like this: *.domain,
+ // means that can access to all subdomains for 'domain',
+ // otherwise, the host of request url should exactly the same
+ // as policy.
+ bool subdomains = ((*it).find("*.") == 0);
+ std::string host = subdomains ? (*it).substr(2) : (*it);
+ AddSecurityPolicy(GURL("http://" + host), subdomains);
+ AddSecurityPolicy(GURL("https://" + host), subdomains);
+ }
+ }
+ GetHost(main_runtime_)->Send(
+ new ViewMsg_EnableSecurityMode(
+ ApplicationData::GetBaseURLFromApplicationId(id()),
+ SecurityPolicy::CSP));
+ return;
+ }
#endif
- )
+ const WARPInfo* info = static_cast<WARPInfo*>(
+ application_data_->GetManifestData(widget_keys::kAccessKey));
+ // FIXME(xinchao): Need to enable WARP mode by default.
+ if (!info)
return;
- GURL app_url = application_data_->URL();
+
const base::ListValue* whitelist = info->GetWARP();
- bool enable_warp_mode = true;
for (base::ListValue::const_iterator it = whitelist->begin();
it != whitelist->end(); ++it) {
base::DictionaryValue* value = NULL;
dest.empty())
continue;
if (dest == "*") {
- enable_warp_mode = false;
+ is_security_mode_ = false;
break;
}
// The default subdomains attrubute should be "false".
std::string subdomains = "false";
value->GetString(widget_keys::kAccessSubdomainsKey, &subdomains);
- GetHost(main_runtime_)->Send(
- new ViewMsg_SetAccessWhiteList(
- app_url, dest_url, (subdomains == "true")));
+ AddSecurityPolicy(dest_url, (subdomains == "true"));
+ is_security_mode_ = true;
}
- if (enable_warp_mode)
+ if (is_security_mode_)
GetHost(main_runtime_)->Send(
- new ViewMsg_EnableWarpMode(
- ApplicationData::GetBaseURLFromApplicationId(
- application_data_->ID())));
+ new ViewMsg_EnableSecurityMode(
+ ApplicationData::GetBaseURLFromApplicationId(id()),
+ SecurityPolicy::WARP));
+}
+
+void Application::AddSecurityPolicy(const GURL& url, bool subdomains) {
+ GURL app_url = application_data_->URL();
+ GetHost(main_runtime_)->Send(
+ new ViewMsg_SetAccessWhiteList(
+ app_url, url, subdomains));
+ security_policy_.push_back(new SecurityPolicy(url, subdomains));
+}
+
+bool Application::CanRequestURL(const GURL& url) const {
+ if (!is_security_mode_)
+ return true;
+
+ // Only WGT package need to check the url request permission.
+ if (application_data_->GetPackageType() != Manifest::TYPE_WGT)
+ return true;
+
+ // Always can request itself resources.
+ if (url.SchemeIs(application::kApplicationScheme) &&
+ url.host() == id())
+ return true;
+
+ for (int i = 0; i < security_policy_.size(); ++i) {
+ const GURL& policy = security_policy_[i]->url();
+ bool subdomains = security_policy_[i]->subdomains();
+ bool is_host_matched = subdomains ?
+ url.DomainIs(policy.host().c_str()) : url.host() == policy.host();
+ if (url.scheme() == policy.scheme() && is_host_matched)
+ return true;
+ }
+ return false;
+}
+
+#if defined(USE_OZONE) && defined(OS_TIZEN)
+base::EventStatus Application::WillProcessEvent(
+ const base::NativeEvent& event) {
+ return base::EVENT_CONTINUE;
}
+void Application::DidProcessEvent(
+ const base::NativeEvent& event) {
+ ui::Event* eve = static_cast<ui::Event*>(event);
+ if (!eve->IsKeyEvent() || eve->type() != ui::ET_KEY_PRESSED)
+ return;
+
+ ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(eve);
+
+ // FIXME: Most Wayland devices don't have similar hardware button for 'back'
+ // and 'memu' as Tizen Mobile, even that hardare buttons could be different
+ // across different kinds of Wayland platforms.
+ // Here use external keyboard button 'Backspace' & 'HOME' to emulate 'back'
+ // and 'menu' key. Should change this if there is customized key binding.
+ if (key_event->key_code() != ui::VKEY_BACK &&
+ key_event->key_code() != ui::VKEY_HOME)
+ return;
+
+ TizenSettingInfo* info = static_cast<TizenSettingInfo*>(
+ data()->GetManifestData(widget_keys::kTizenSettingKey));
+ if (info && !info->hwkey_enabled())
+ return;
+
+ for (std::set<xwalk::Runtime*>::iterator it = runtimes_.begin();
+ it != runtimes_.end(); ++it) {
+ (*it)->web_contents()->GetRenderViewHost()->Send(new ViewMsg_HWKeyPressed(
+ (*it)->web_contents()->GetRoutingID(), key_event->key_code()));
+ }
+}
+#endif
+
} // namespace application
} // namespace xwalk
#include <map>
#include <set>
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "ui/base/ui_base_types.h"
#include "xwalk/application/browser/event_observer.h"
#include "xwalk/application/common/application_data.h"
+#include "xwalk/application/common/security_policy.h"
#include "xwalk/runtime/browser/runtime.h"
+#if defined(USE_OZONE) && defined(OS_TIZEN)
+#include "base/message_loop/message_pump_observer.h"
+#endif
+
namespace xwalk {
class RuntimeContext;
class ApplicationHost;
class Manifest;
+class SecurityPolicy;
// The Application class is representing an active (running) application.
// Application instances are owned by ApplicationService.
// terminated.
// There's one-to-one correspondence between Application and Render Process
// Host, obtained from its "runtimes" (pages).
-class Application : public Runtime::Observer {
+class Application
+ :
+#if defined(USE_OZONE) && defined(OS_TIZEN)
+ public base::MessagePumpObserver,
+#endif
+ public Runtime::Observer {
public:
virtual ~Application();
enum LaunchEntryPoint {
AppMainKey = 1 << 0, // app.main
LaunchLocalPathKey = 1 << 1, // app.launch.local_path
- // NOTE: The following key is only used for "dummy" hosted apps,
- // which can be using any arbitrary URL, incl. remote ones.
- // For now this should be disabled for all other cases as this will
- // require special care with permissions etc.
URLKey = 1 << 2, // url
- Default = AppMainKey | LaunchLocalPathKey
+ Default = AppMainKey | LaunchLocalPathKey | URLKey
};
typedef unsigned LaunchEntryPoints;
LaunchParams() :
entry_points(Default),
launcher_pid(0),
- window_state(ui::SHOW_STATE_DEFAULT) {}
+ force_fullscreen(false) {}
LaunchEntryPoints entry_points;
// process.
int32 launcher_pid;
- // Sets the initial state for the application windows.
- ui::WindowShowState window_state;
+ bool force_fullscreen;
};
// Closes all the application's runtimes (application pages).
};
void Terminate(TerminationMode = Normal);
+#if defined(OS_TIZEN)
+ void Hide();
+#endif
+
// Returns Runtime (application page) containing the application's
// 'main document'. The main document is the main entry point of
// the application to the system. This method will return 'NULL'
bool SetPermission(PermissionType type,
const std::string& permission_name,
StoredPermission perm);
+ bool CanRequestURL(const GURL& url) const;
private:
bool HasMainDocument() const;
// Try to extract the URL from different possible keys for entry points in the
// manifest, returns it and the entry point used.
- GURL GetURLForLaunch(const LaunchParams& params, LaunchEntryPoint* used);
+ GURL GetStartURL(const LaunchParams& params, LaunchEntryPoint* used);
+ ui::WindowShowState GetWindowShowState(const LaunchParams& params);
GURL GetURLFromAppMainKey();
GURL GetURLFromLocalPathKey();
bool IsTerminating() const { return finish_observer_; }
void InitSecurityPolicy();
+ void AddSecurityPolicy(const GURL& url, bool subdomains);
+
+#if defined(USE_OZONE) && defined(OS_TIZEN)
+ virtual base::EventStatus WillProcessEvent(
+ const base::NativeEvent& event) OVERRIDE;
+ virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
+#endif
RuntimeContext* runtime_context_;
const scoped_refptr<ApplicationData> application_data_;
std::map<std::string, std::string> name_perm_map_;
// Application's session permissions.
StoredPermissionMap permission_map_;
+ // Security policy set.
+ ScopedVector<SecurityPolicy> security_policy_;
+ bool is_security_mode_;
DISALLOW_COPY_AND_ASSIGN(Application);
};
#include <algorithm>
#include <map>
+#include <list>
#include <string>
#include <utility>
#include <vector>
const base::FilePath& directory_path,
const base::FilePath& relative_path,
const std::string& content_security_policy,
+ const std::list<std::string>& locales,
bool is_authority_match)
: net::URLRequestFileJob(
request, network_delegate, base::FilePath(), file_task_runner),
content_security_policy_(content_security_policy),
is_authority_match_(is_authority_match),
resource_(application_id, directory_path, relative_path),
+ locales_(locales),
weak_factory_(this) {
}
virtual void Start() OVERRIDE {
base::FilePath* read_file_path = new base::FilePath;
+ resource_.SetLocales(locales_);
bool posted = base::WorkerPool::PostTaskAndReply(
FROM_HERE,
base::Bind(&ReadResourceFilePath, resource_,
std::string content_security_policy_;
bool is_authority_match_;
ApplicationResource resource_;
+ std::list<std::string> locales_;
base::WeakPtrFactory<URLRequestApplicationJob> weak_factory_;
};
content_security_policy);
}
+ std::list<std::string> locales;
+ // FIXME(Xinchao): Get the user agent locales into |locales|.
return new URLRequestApplicationJob(
request,
network_delegate,
directory_path,
relative_path,
content_security_policy,
+ locales,
application);
}
namespace {
-void CloseMessageLoop() {
- // FIXME: Quit message loop here at present. This should go away once
- // we have Application in place.
- base::MessageLoop::current()->QuitWhenIdle();
-}
-
void WaitForEventAndClose(
- const std::string& app_id, const std::string& event_name,
+ const std::string& app_id,
+ const std::string& event_name,
+ ApplicationService* application_service,
ApplicationEventManager* event_manager) {
+
class CloseOnEventArrived : public EventObserver {
public:
- static CloseOnEventArrived* Create(const std::string& event_name,
- ApplicationEventManager* event_manager) {
- return new CloseOnEventArrived(event_name, event_manager);
- }
+ CloseOnEventArrived(
+ const std::string& event_name,
+ ApplicationService* application_service,
+ ApplicationEventManager* event_manager)
+ : EventObserver(event_manager),
+ event_name_(event_name),
+ application_service_(application_service) {}
virtual void Observe(
const std::string& app_id,
event->args()->GetString(0, &ack_event_name);
if (ack_event_name != event_name_)
return;
- CloseMessageLoop();
+
+ if (Application* app = application_service_->GetApplicationByID(app_id))
+ app->Terminate(Application::Immediate);
+
delete this;
}
private:
- CloseOnEventArrived(
- const std::string& event_name,
- ApplicationEventManager* event_manager)
- : EventObserver(event_manager),
- event_name_(event_name) {}
-
std::string event_name_;
+ ApplicationService* application_service_;
};
DCHECK(event_manager);
CloseOnEventArrived* observer =
- CloseOnEventArrived::Create(event_name, event_manager);
+ new CloseOnEventArrived(event_name, application_service, event_manager);
event_manager->AttachObserver(app_id,
kOnJavaScriptEventAck, observer);
}
void WaitForFinishLoad(
- scoped_refptr<ApplicationData> application,
+ const std::string& app_id,
+ ApplicationService* application_service,
ApplicationEventManager* event_manager,
content::WebContents* contents) {
class CloseAfterLoadObserver : public content::WebContentsObserver {
public:
CloseAfterLoadObserver(
- scoped_refptr<ApplicationData> application,
+ const std::string& app_id,
+ ApplicationService* application_service,
ApplicationEventManager* event_manager,
content::WebContents* contents)
: content::WebContentsObserver(contents),
- application_(application),
+ id_(app_id),
+ application_service_(application_service),
event_manager_(event_manager) {
- DCHECK(application_);
+ DCHECK(application_service_);
DCHECK(event_manager_);
}
const GURL& validate_url,
bool is_main_frame,
content::RenderViewHost* render_view_host) OVERRIDE {
- if (!IsEventHandlerRegistered(kOnInstalled)) {
- CloseMessageLoop();
+ Application* app = application_service_->GetApplicationByID(id_);
+ if (!app) {
+ delete this;
+ return;
+ }
+
+ if (!IsEventHandlerRegistered(app->data(), kOnInstalled)) {
+ app->Terminate(Application::Immediate);
} else {
scoped_ptr<base::ListValue> event_args(new base::ListValue);
scoped_refptr<Event> event =
- Event::CreateEvent(
- kOnInstalled, event_args.Pass());
- event_manager_->SendEvent(application_->ID(), event);
+ Event::CreateEvent(kOnInstalled, event_args.Pass());
+ event_manager_->SendEvent(id_, event);
WaitForEventAndClose(
- application_->ID(), event->name(), event_manager_);
+ id_, event->name(), application_service_, event_manager_);
}
delete this;
}
private:
- bool IsEventHandlerRegistered(const std::string& event_name) const {
- const std::set<std::string>& events = application_->GetEvents();
+ bool IsEventHandlerRegistered(scoped_refptr<ApplicationData> app_data,
+ const std::string& event_name) const {
+ const std::set<std::string>& events = app_data->GetEvents();
return events.find(event_name) != events.end();
}
- scoped_refptr<ApplicationData> application_;
+ std::string id_;
+ ApplicationService* application_service_;
ApplicationEventManager* event_manager_;
};
// This object is self-destroyed when an event occurs.
- new CloseAfterLoadObserver(application, event_manager, contents);
+ new CloseAfterLoadObserver(
+ app_id, application_service, event_manager, contents);
}
void SaveSystemEventsInfo(
- ApplicationService* application_service,
scoped_refptr<ApplicationData> application_data,
+ ApplicationService* application_service,
ApplicationEventManager* event_manager) {
// We need to run main document after installation in order to
// register system events.
if (application_data->HasMainDocument()) {
if (Application* application =
application_service->Launch(application_data->ID())) {
- WaitForFinishLoad(application->data(), event_manager,
+ WaitForFinishLoad(application->id(), application_service, event_manager,
application->GetMainDocumentRuntime()->web_contents());
}
}
<< " successfully.";
*id = application_data->ID();
- SaveSystemEventsInfo(this, application_data, event_manager_);
+ SaveSystemEventsInfo(application_data, this, event_manager_);
FOR_EACH_OBSERVER(Observer, observers_,
OnApplicationInstalled(application_data->ID()));
#endif
base::DeleteFile(tmp_dir, true);
- SaveSystemEventsInfo(this, new_application, event_manager_);
+ SaveSystemEventsInfo(new_application, this, event_manager_);
FOR_EACH_OBSERVER(Observer, observers_,
OnApplicationUpdated(app_id));
return result;
}
+bool ApplicationService::ChangeLocale(const std::string& locale) {
+ const ApplicationData::ApplicationDataMap& apps =
+ application_storage_->GetInstalledApplications();
+ ApplicationData::ApplicationDataMap::const_iterator it;
+ for (it = apps.begin(); it != apps.end(); ++it) {
+ base::string16 error;
+ std::string old_name = it->second->Name();
+ if (!it->second->SetApplicationLocale(locale, &error)) {
+ LOG(ERROR) << "Error when set locale " << locale
+ << " to application " << it->second->ID()
+ << "error : " << error;
+ }
+ if (old_name != it->second->Name()) {
+ // After we has changed the application locale, we might get a new name in
+ // the new locale, so call all observer for this event.
+ FOR_EACH_OBSERVER(
+ Observer, observers_,
+ OnApplicationNameChanged(it->second->ID(), it->second->Name()));
+ }
+ }
+}
+
Application* ApplicationService::Launch(
scoped_refptr<ApplicationData> application_data,
const Application::LaunchParams& launch_params) {
FOR_EACH_OBSERVER(Observer, observers_,
WillDestroyApplication(application));
applications_.erase(found);
- if (applications_.empty()) {
+ if (!XWalkRunner::GetInstance()->is_running_as_service() &&
+ applications_.empty()) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitClosure());
}
virtual void OnApplicationInstalled(const std::string& app_id) {}
virtual void OnApplicationUninstalled(const std::string& app_id) {}
virtual void OnApplicationUpdated(const std::string& app_id) {}
+ // When we change the application locale, we might get a new name in
+ // the new locale.
+ virtual void OnApplicationNameChanged(const std::string& app_id,
+ const std::string& app_name) {}
virtual void DidLaunchApplication(Application* app) {}
virtual void WillDestroyApplication(Application* app) {}
bool Install(const base::FilePath& path, std::string* id);
bool Uninstall(const std::string& id);
bool Update(const std::string& id, const base::FilePath& path);
+ bool ChangeLocale(const std::string& locale);
Application* Launch(scoped_refptr<ApplicationData> application_data,
const Application::LaunchParams& launch_params);
kOnLaunched, scoped_ptr<base::ListValue>(new base::ListValue));
Application::LaunchParams launch_params;
- if (cmd_line.HasSwitch(switches::kFullscreen))
- launch_params.window_state = ui::SHOW_STATE_FULLSCREEN;
+ launch_params.force_fullscreen = cmd_line.HasSwitch(switches::kFullscreen);
if (application_service_->Launch(param, launch_params)) {
return true;
}
Application::LaunchParams launch_params;
- if (cmd_line.HasSwitch(switches::kFullscreen))
- launch_params.window_state = ui::SHOW_STATE_FULLSCREEN;
+ launch_params.force_fullscreen = cmd_line.HasSwitch(switches::kFullscreen);
launch_params.entry_points = Application::URLKey;
return !!application_service_->Launch(application_data, launch_params);
#include <unistd.h>
#include <pkgmgr/pkgmgr_parser.h>
#include <algorithm>
+#include <map>
#include <string>
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/process/launch.h"
#include "third_party/libxml/chromium/libxml_utils.h"
#include "xwalk/application/common/application_data.h"
+#include "xwalk/application/common/application_manifest_constants.h"
+#include "xwalk/application/common/manifest_handlers/tizen_metadata_handler.h"
#include "xwalk/application/browser/application_storage.h"
#include "xwalk/application/browser/installer/tizen/packageinfo_constants.h"
namespace {
+namespace widget_keys = xwalk::application_widget_keys;
+
const base::FilePath kPkgHelper("/usr/bin/xwalk-pkg-helper");
const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
bool recursive_;
};
+void WriteMetaDataElement(
+ XmlWriter& writer,
+ xwalk::application::TizenMetaDataInfo* info) {
+ if (!info)
+ return;
+
+ const std::map<std::string, std::string>& metadata = info->metadata();
+ std::map<std::string, std::string>::const_iterator it;
+ for (it = metadata.begin(); it != metadata.end(); ++it) {
+ writer.StartElement("metadata");
+ writer.AddAttribute("key", it->first);
+ writer.AddAttribute("value", it->second);
+ writer.EndElement();
+ }
+}
+
bool GeneratePkgInfoXml(xwalk::application::ApplicationData* application,
const std::string& icon_name,
const base::FilePath& app_dir,
xml_writer.AddAttribute("taskmanage", "true");
xml_writer.WriteElement("label", application->Name());
+ xwalk::application::TizenMetaDataInfo* info =
+ static_cast<xwalk::application::TizenMetaDataInfo*>(
+ application->GetManifestData(widget_keys::kTizenMetaDataKey));
+ WriteMetaDataElement(xml_writer, info);
+
if (icon_name.empty())
xml_writer.WriteElement("icon", info::kDefaultIconName);
else
properties()->Set(kInstalledApplicationDBusInterface, "Name", name.Pass());
}
+void InstalledApplicationObject::OnApplicationNameChanged(
+ const std::string& app_name) {
+ scoped_ptr<base::Value> name(base::Value::CreateStringValue(app_name));
+ properties()->Set(kInstalledApplicationDBusInterface, "Name", name.Pass());
+}
+
void InstalledApplicationObject::ExportUninstallMethod(
dbus::ExportedObject::MethodCallCallback method_call_callback,
dbus::ExportedObject::OnExportedCallback on_exported_callback) {
scoped_refptr<dbus::Bus> bus, const dbus::ObjectPath& path,
const ApplicationData* app);
+ void OnApplicationNameChanged(const std::string& app_name);
// Set the callback used when the Uninstall() method is called in an
// ApplicationObject.
void ExportUninstallMethod(
adaptor_.RemoveManagedObject(GetInstalledPathForAppID(app_id));
}
+void InstalledApplicationsManager::OnApplicationNameChanged(
+ const std::string& app_id, const std::string& app_name) {
+ InstalledApplicationObject* object =
+ static_cast<InstalledApplicationObject*>(
+ adaptor_.GetManagedObject(GetInstalledPathForAppID(app_id)));
+ object->OnApplicationNameChanged(app_name);
+}
+
void InstalledApplicationsManager::AddInitialObjects() {
const ApplicationData::ApplicationDataMap& apps =
app_storage_->GetInstalledApplications();
// ApplicationService::Observer implementation.
void virtual OnApplicationInstalled(const std::string& app_id) OVERRIDE;
void virtual OnApplicationUninstalled(const std::string& app_id) OVERRIDE;
+ void virtual OnApplicationNameChanged(const std::string& app_id,
+ const std::string& app_name) OVERRIDE;
void AddInitialObjects();
void AddObject(scoped_refptr<const ApplicationData> app);
base::Unretained(this)),
base::Bind(&RunningApplicationObject::OnExported,
base::Unretained(this)));
+
+#if defined(OS_TIZEN)
+ dbus_object()->ExportMethod(
+ kRunningApplicationDBusInterface, "Hide",
+ base::Bind(&RunningApplicationObject::OnHide,
+ base::Unretained(this)),
+ base::Bind(&RunningApplicationObject::OnExported,
+ base::Unretained(this)));
+#endif
}
RunningApplicationObject::~RunningApplicationObject() {
response_sender.Run(response.Pass());
}
+#if defined(OS_TIZEN)
+void RunningApplicationObject::OnHide(
+ dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender) {
+ if (method_call->GetSender() != launcher_name_) {
+ scoped_ptr<dbus::ErrorResponse> error_response =
+ dbus::ErrorResponse::FromMethodCall(method_call,
+ kRunningApplicationDBusError,
+ "Not permitted");
+ response_sender.Run(error_response.PassAs<dbus::Response>());
+ return;
+ }
+
+ application_->Hide();
+
+ scoped_ptr<dbus::Response> response =
+ dbus::Response::FromMethodCall(method_call);
+ response_sender.Run(response.Pass());
+}
+#endif
+
void RunningApplicationObject::ListenForOwnerChange() {
owner_change_callback_ =
base::Bind(&RunningApplicationObject::OnNameOwnerChanged,
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
+#if defined(OS_TIZEN)
+ void OnHide(dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender);
+#endif
+
void ListenForOwnerChange();
void UnlistenForOwnerChange();
void OnNameOwnerChanged(const std::string& service_owner);
Application::LaunchParams params;
params.launcher_pid = launcher_pid;
- if (fullscreen)
- params.window_state = ui::SHOW_STATE_FULLSCREEN;
+ params.force_fullscreen = fullscreen;
Application* application = application_service_->Launch(app_id, params);
if (!application) {
}
#endif
+bool ApplicationData::SetApplicationLocale(const std::string& locale,
+ base::string16* error) {
+ manifest_->SetSystemLocale(locale);
+ if (!LoadName(error))
+ return false;
+ if (!LoadDescription(error))
+ return false;
+ return true;
+}
+
} // namespace application
} // namespace xwalk
bool HasCSPDefined() const;
#endif
+ bool SetApplicationLocale(const std::string& locale, base::string16* error);
+
private:
friend class base::RefCountedThreadSafe<ApplicationData>;
friend class ApplicationStorageImpl;
const char kDisplay[] = "display";
const char kLaunchLocalPathKey[] = "app.launch.local_path";
const char kLaunchScreen[] = "launch_screen";
+const char kLaunchScreenDefault[] = "launch_screen.default";
+const char kLaunchScreenImageBorderDefault[] =
+ "launch_screen.default.image_border";
+const char kLaunchScreenImageBorderLandscape[] =
+ "launch_screen.landscape.image_border";
+const char kLaunchScreenImageBorderPortrait[] =
+ "launch_screen.portrait.image_border";
+const char kLaunchScreenLandscape[] = "launch_screen.landscape";
+const char kLaunchScreenPortrait[] = "launch_screen.portrait";
const char kLaunchScreenReadyWhen[] = "launch_screen.ready_when";
const char kLaunchWebURLKey[] = "app.launch.web_url";
const char kManifestVersionKey[] = "manifest_version";
const char kURLKey[] = "url";
const char kVersionKey[] = "version";
const char kWebURLsKey[] = "app.urls";
+const char kXWalkHostsKey[] = "xwalk_hosts";
#if defined(OS_TIZEN)
const char kTizenAppIdKey[] = "tizen_app_id";
// manifest keys for widget applications.
namespace application_widget_keys {
const char kNamespaceKey[] = "@namespace";
+const char kXmlLangKey[] = "@lang";
+const char kDefaultLocaleKey[] = "widget.@defaultlocale";
const char kNameKey[] = "widget.name.#text";
const char kVersionKey[] = "widget.@version";
const char kWidgetKey[] = "widget";
"widget.content-security-policy-report-only.#text";
const char kTizenSettingKey[] = "widget.setting";
const char kTizenHardwareKey[] = "widget.setting.@hwkey";
+const char kTizenMetaDataKey[] = "widget.metadata";
+// Child keys inside 'kTizenMetaDataKey'
+const char kTizenMetaDataNameKey[] = "@key";
+const char kTizenMetaDataValueKey[] = "@value";
#endif
} // namespace application_widget_keys
extern const char kDisplay[];
extern const char kLaunchLocalPathKey[];
extern const char kLaunchScreen[];
+ extern const char kLaunchScreenDefault[];
+ extern const char kLaunchScreenImageBorderDefault[];
+ extern const char kLaunchScreenImageBorderLandscape[];
+ extern const char kLaunchScreenImageBorderPortrait[];
+ extern const char kLaunchScreenLandscape[];
+ extern const char kLaunchScreenPortrait[];
extern const char kLaunchScreenReadyWhen[];
extern const char kLaunchWebURLKey[];
extern const char kManifestVersionKey[];
extern const char kURLKey[];
extern const char kVersionKey[];
extern const char kWebURLsKey[];
+ extern const char kXWalkHostsKey[];
#if defined(OS_TIZEN)
extern const char kTizenAppIdKey[];
namespace application_widget_keys {
extern const char kNamespaceKey[];
+ extern const char kXmlLangKey[];
+ extern const char kDefaultLocaleKey[];
extern const char kNameKey[];
extern const char kLaunchLocalPathKey[];
extern const char kWebURLsKey[];
extern const char kCSPReportOnlyKey[];
extern const char kTizenSettingKey[];
extern const char kTizenHardwareKey[];
+ extern const char kTizenMetaDataKey[];
+ extern const char kTizenMetaDataNameKey[];
+ extern const char kTizenMetaDataValueKey[];
#endif
} // namespace application_widget_keys
namespace xwalk {
namespace application {
+namespace {
+const base::FilePath::StringType WGT_LOCALE_DIRECTORY =
+ FILE_PATH_LITERAL("locales");
+} // namespace
ApplicationResource::ApplicationResource() : follow_symlinks_anywhere_(false) {
}
if (!full_resource_path_.empty())
return full_resource_path_;
+ for (std::list<std::string>::const_iterator it = locales_.begin();
+ it != locales_.end(); ++it) {
+ full_resource_path_ = GetFilePath(
+ application_root_,
+ base::FilePath(WGT_LOCALE_DIRECTORY)
+ .AppendASCII(*it).Append(relative_path_),
+ follow_symlinks_anywhere_ ?
+ FOLLOW_SYMLINKS_ANYWHERE : SYMLINKS_MUST_RESOLVE_WITHIN_ROOT);
+ if (!full_resource_path_.empty())
+ return full_resource_path_;
+ }
full_resource_path_ = GetFilePath(
application_root_, relative_path_,
follow_symlinks_anywhere_ ?
#ifndef XWALK_APPLICATION_COMMON_APPLICATION_RESOURCE_H_
#define XWALK_APPLICATION_COMMON_APPLICATION_RESOURCE_H_
+#include <list>
#include <string>
#include "base/files/file_path.h"
const base::FilePath& application_root() const { return application_root_; }
const base::FilePath& relative_path() const { return relative_path_; }
+ // Setters
+ void SetLocales(const std::list<std::string>& locales) {
+ locales_ = locales;
+ full_resource_path_.clear();
+ }
+
bool empty() const { return application_root().empty(); }
// Unit test helpers.
// Full path to application resource. Starts empty.
mutable base::FilePath full_resource_path_;
+
+ // The User Agent localization information.
+ std::list<std::string> locales_;
};
} // namespace application
#include "xwalk/application/common/manifest.h"
+#include <list>
+
#include "base/basictypes.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "xwalk/application/common/application_manifest_constants.h"
+#include "xwalk/runtime/browser/xwalk_runner.h"
namespace errors = xwalk::application_manifest_errors;
namespace keys = xwalk::application_manifest_keys;
namespace xwalk {
namespace application {
+namespace {
+const char kLocaleUnlocalized[] = "@unlocalized";
+#if defined(OS_TIZEN)
+const char kLocaleAuto[] = "en-gb";
+#else
+const char kLocaleAuto[] = "en-us";
+#endif
+const char kLocaleFirstOne[] = "*";
+
+const char kWidgetNamePath[] = "widget.name";
+const char kWidgetDecriptionPath[] = "widget.description";
+const char kWidgetLicensePath[] = "widget.license";
+
+const char kPathConnectSymbol = '.';
+
+typedef std::list<std::string> List;
+
+std::string GetLocalizedKey(const std::string& key,
+ const std::string& local) {
+ std::string lower_local = StringToLowerASCII(local);
+ if (lower_local.empty())
+ lower_local = kLocaleUnlocalized;
+ return key + kPathConnectSymbol + lower_local;
+}
+
+scoped_ptr<List> ExpandUserAgentLocalesList(const scoped_ptr<List>& list) {
+ scoped_ptr<List> expansion_list(new List);
+ for (List::const_iterator it = list->begin(); it != list->end(); ++it) {
+ std::string copy_locale(*it);
+ size_t position;
+ do {
+ expansion_list->push_back(copy_locale);
+ position = copy_locale.find_last_of("-");
+ copy_locale = copy_locale.substr(0, position);
+ } while (position != std::string::npos);
+ }
+ return expansion_list.Pass();
+}
+
+} // namespace
Manifest::Manifest(SourceType source_type,
scoped_ptr<base::DictionaryValue> value)
: source_type_(source_type),
data_(value.Pass()),
+ i18n_data_(new base::DictionaryValue),
type_(TYPE_UNKNOWN) {
if (data_->HasKey(keys::kAppKey)) {
if (data_->Get(keys::kWebURLsKey, NULL) ||
package_type_ = TYPE_WGT;
else
package_type_ = TYPE_XPK;
+
+ if (IsWGTPackaged())
+ ParseWGTI18n();
+
+ // Unittest may not have an xwalkrunner, so we should check here.
+ if (XWalkRunner* xwalk_runner = XWalkRunner::GetInstance())
+ SetSystemLocale(xwalk_runner->GetLocale());
+ else
+ SetSystemLocale(kLocaleUnlocalized);
}
Manifest::~Manifest() {
bool Manifest::GetString(
const std::string& path, std::string* out_value) const {
- return CanAccessPath(path) && data_->GetString(path, out_value);
+ if (!CanAccessPath(path))
+ return false;
+
+ if (i18n_data_->Get(path, NULL)) {
+ List::const_iterator it = user_agent_locales_->begin();
+ for (; it != user_agent_locales_->end(); ++it) {
+ if (i18n_data_->GetString(GetLocalizedKey(path, *it), out_value))
+ return true;
+ }
+ return false;
+ }
+
+ return data_->GetString(path, out_value);
}
bool Manifest::GetString(
const std::string& path, base::string16* out_value) const {
- return CanAccessPath(path) && data_->GetString(path, out_value);
+ if (!CanAccessPath(path))
+ return false;
+
+ if (i18n_data_->Get(path, NULL)) {
+ List::const_iterator it = user_agent_locales_->begin();
+ for (; it != user_agent_locales_->end(); ++it) {
+ if (i18n_data_->GetString(GetLocalizedKey(path, *it), out_value))
+ return true;
+ }
+ return false;
+ }
+
+ return data_->GetString(path, out_value);
}
bool Manifest::GetDictionary(
return true;
}
+void Manifest::SetSystemLocale(const std::string& locale) {
+ scoped_ptr<List> list_for_expand(new List);
+ list_for_expand->push_back(locale);
+ list_for_expand->push_back(default_locale_);
+ list_for_expand->push_back(kLocaleUnlocalized);
+ list_for_expand->push_back(kLocaleAuto);
+ list_for_expand->push_back(kLocaleFirstOne);
+ user_agent_locales_ = ExpandUserAgentLocalesList(list_for_expand);
+}
+
+void Manifest::ParseWGTI18n() {
+ data_->GetString(application_widget_keys::kDefaultLocaleKey,
+ &default_locale_);
+ default_locale_ = StringToLowerASCII(default_locale_);
+
+ ParseWGTI18nEachPath(kWidgetNamePath);
+ ParseWGTI18nEachPath(kWidgetDecriptionPath);
+ ParseWGTI18nEachPath(kWidgetLicensePath);
+}
+
+// We might get one element of a list of element from path,
+// and we parse each element for fast access.
+// For example config.xml is:
+// <widget>
+// <name>unlocalized name</name>
+// <name xml:lang="zh-CN">zh-CN name</name>
+// <name xml:lang="en-US" short="en-US short">en-US name</name>
+// </widget>
+// The path for value in i18n_data_ are :
+// "widget.name.#text.@unlocalized" => "unlocalized name".
+// "widget.name.#text.zh-cn" => "zh-CN name".
+// "widget.name.#text.en-us" => "en-US name".
+// "widget.name.@short.en-us" => "en-US short".
+// "widget.name.#text.*" => "unlocalized name". (the first one)
+// "widget.name.@short.*" => "". (the first one do not have a short name)
+void Manifest::ParseWGTI18nEachPath(const std::string& path) {
+ base::Value* value = NULL;
+ if (!data_->Get(path, &value))
+ return;
+
+ if (value->IsType(base::Value::TYPE_DICTIONARY)) {
+ ParseWGTI18nEachElement(value, path);
+ ParseWGTI18nEachElement(value, path, kLocaleFirstOne);
+ } else if (value->IsType(base::Value::TYPE_LIST)) {
+ base::ListValue* list;
+ value->GetAsList(&list);
+
+ bool get_first_one = false;
+ for (base::ListValue::iterator it = list->begin();
+ it != list->end(); ++it) {
+ ParseWGTI18nEachElement(*it, path);
+ if (!get_first_one)
+ get_first_one = ParseWGTI18nEachElement(*it, path, kLocaleFirstOne);
+ }
+ }
+ // After Parse we remove this path from data_ for saving memory.
+ scoped_ptr<base::Value> remove_value;
+ data_->Remove(path, &remove_value);
+}
+
+bool Manifest::ParseWGTI18nEachElement(base::Value* value,
+ const std::string& path,
+ const std::string& locale) {
+ base::DictionaryValue* dict;
+ if (!value->GetAsDictionary(&dict))
+ return false;
+
+ std::string xml_lang(locale);
+ if (locale.empty())
+ dict->GetString(application_widget_keys::kXmlLangKey, &xml_lang);
+
+ base::DictionaryValue::Iterator iter(*dict);
+ while (!iter.IsAtEnd()) {
+ std::string locale_key(
+ GetLocalizedKey(path + kPathConnectSymbol + iter.key(), xml_lang));
+ if (!i18n_data_->Get(locale_key, NULL))
+ i18n_data_->Set(locale_key, iter.value().DeepCopy());
+
+ iter.Advance();
+ }
+
+ return true;
+}
+
} // namespace application
} // namespace xwalk
#ifndef XWALK_APPLICATION_COMMON_MANIFEST_H_
#define XWALK_APPLICATION_COMMON_MANIFEST_H_
+#include <list>
#include <map>
#include <string>
#include <set>
PackageType GetPackageType() const { return package_type_; }
bool IsXPKPackaged() const { return package_type_ == TYPE_XPK; }
+ bool IsWGTPackaged() const { return package_type_ == TYPE_WGT; }
// These access the wrapped manifest value, returning false when the property
// does not exist or if the manifest type can't access it.
bool Get(const std::string& path, base::Value** out_value) const;
bool GetBoolean(const std::string& path, bool* out_value) const;
bool GetInteger(const std::string& path, int* out_value) const;
+
+ // If the path is supported by i18n, we can get a locale string from
+ // this two GetString function. The following is locale priority:
+ // Application locale (locale get from system). | high
+ // Default locale (defaultlocale attribute of widget element)
+ // Unlocalized (the element without xml:lang attribute)
+ // Auto ("en-us"(tizen is "en-gb") will be considered as a default)
+ // First (the worst case we get the first element) | low
bool GetString(const std::string& path, std::string* out_value) const;
bool GetString(const std::string& path, base::string16* out_value) const;
+
bool GetDictionary(const std::string& path,
const base::DictionaryValue** out_value) const;
bool GetList(const std::string& path,
// Note: only use this when you KNOW you don't need the validation.
const base::DictionaryValue* value() const { return data_.get(); }
+ const std::string& default_locale() const {
+ return default_locale_;
+ }
+
+ // Update user agent locale when system locale is changed.
+ void SetSystemLocale(const std::string& locale);
+
private:
+ void ParseWGTI18n();
+ void ParseWGTI18nEachPath(const std::string& path);
+ bool ParseWGTI18nEachElement(base::Value* value,
+ const std::string& path,
+ const std::string& locale = "");
+
// Returns true if the application can specify the given |path|.
bool CanAccessPath(const std::string& path) const;
bool CanAccessKey(const std::string& key) const;
// The underlying dictionary representation of the manifest.
scoped_ptr<base::DictionaryValue> data_;
+ scoped_ptr<base::DictionaryValue> i18n_data_;
+
+ std::string default_locale_;
+ scoped_ptr<std::list<std::string> > user_agent_locales_;
Type type_;
#if defined(OS_TIZEN)
#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
#include "xwalk/application/common/manifest_handlers/tizen_application_handler.h"
+#include "xwalk/application/common/manifest_handlers/tizen_metadata_handler.h"
#include "xwalk/application/common/manifest_handlers/tizen_setting_handler.h"
#endif
#include "xwalk/application/common/manifest_handlers/permissions_handler.h"
handlers.push_back(new NavigationHandler);
handlers.push_back(new TizenApplicationHandler);
handlers.push_back(new TizenSettingHandler);
+ handlers.push_back(new TizenMetaDataHandler);
#endif
widget_registry_ = new ManifestHandlerRegistry(handlers);
return widget_registry_;
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/common/manifest_handlers/tizen_metadata_handler.h"
+
+#include <map>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "xwalk/application/common/application_manifest_constants.h"
+
+
+namespace xwalk {
+
+namespace keys = application_widget_keys;
+
+typedef std::pair<std::string, std::string> MetaDataPair;
+typedef std::map<std::string, std::string> MetaDataMap;
+typedef std::map<std::string, std::string>::const_iterator MetaDataIter;
+
+namespace {
+
+MetaDataPair ParseMetaDataItem(const base::DictionaryValue* dict,
+ base::string16* error) {
+ DCHECK(dict && dict->IsType(base::Value::TYPE_DICTIONARY));
+ MetaDataPair result;
+ std::string value;
+ if (!dict->GetString(keys::kTizenMetaDataNameKey, &result.first) ||
+ !dict->GetString(keys::kTizenMetaDataValueKey, &result.second)) {
+ *error = base::ASCIIToUTF16("Invalid key/value of tizen metaData.");
+ }
+
+ return result;
+}
+} // namespace
+
+namespace application {
+
+TizenMetaDataInfo::TizenMetaDataInfo() {}
+
+TizenMetaDataInfo::~TizenMetaDataInfo() {}
+
+bool TizenMetaDataInfo::HasKey(const std::string& key) const {
+ return metadata_.find(key) != metadata_.end();
+}
+
+std::string TizenMetaDataInfo::GetValue(const std::string& key) const {
+ MetaDataIter it = metadata_.find(key);
+ if (it != metadata_.end())
+ return it->second;
+ return std::string("");
+}
+
+void TizenMetaDataInfo::SetValue(const std::string& key,
+ const std::string& value) {
+ metadata_.insert(MetaDataPair(key, value));
+}
+
+TizenMetaDataHandler::TizenMetaDataHandler() {
+}
+
+TizenMetaDataHandler::~TizenMetaDataHandler() {}
+
+bool TizenMetaDataHandler::Parse(scoped_refptr<ApplicationData> application,
+ base::string16* error) {
+ scoped_ptr<TizenMetaDataInfo> metadata_info(new TizenMetaDataInfo);
+ const Manifest* manifest = application->GetManifest();
+ DCHECK(manifest);
+
+ base::Value* metadata_value = NULL;
+ if (!manifest->Get(keys::kTizenMetaDataKey, &metadata_value)) {
+ *error = base::ASCIIToUTF16("Failed to get value of tizen metaData");
+ }
+
+ MetaDataPair metadata_item;
+ if (metadata_value && metadata_value->IsType(base::Value::TYPE_DICTIONARY)) {
+ base::DictionaryValue* dict;
+ metadata_value->GetAsDictionary(&dict);
+ metadata_item = ParseMetaDataItem(dict, error);
+ metadata_info->SetValue(metadata_item.first, metadata_item.second);
+ } else if (metadata_value && metadata_value->IsType(base::Value::TYPE_LIST)) {
+ base::ListValue* list;
+ metadata_value->GetAsList(&list);
+
+ for (base::ListValue::iterator it = list->begin();
+ it != list->end(); ++it) {
+ base::DictionaryValue* dict;
+ (*it)->GetAsDictionary(&dict);
+ metadata_item = ParseMetaDataItem(dict, error);
+ metadata_info->SetValue(metadata_item.first, metadata_item.second);
+ }
+ }
+
+ application->SetManifestData(keys::kTizenMetaDataKey,
+ metadata_info.release());
+ return true;
+}
+
+std::vector<std::string> TizenMetaDataHandler::Keys() const {
+ return std::vector<std::string>(1, keys::kTizenMetaDataKey);
+}
+
+} // namespace application
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_TIZEN_METADATA_HANDLER_H_
+#define XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_TIZEN_METADATA_HANDLER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/values.h"
+#include "xwalk/application/common/application_data.h"
+#include "xwalk/application/common/manifest_handler.h"
+
+namespace xwalk {
+namespace application {
+
+class TizenMetaDataInfo : public ApplicationData::ManifestData {
+ public:
+ TizenMetaDataInfo();
+ virtual ~TizenMetaDataInfo();
+
+ bool HasKey(const std::string& key) const;
+ std::string GetValue(const std::string& key) const;
+ void SetValue(const std::string& key, const std::string& value);
+ const std::map<std::string, std::string>& metadata() const {
+ return metadata_;
+ }
+
+ private:
+ std::map<std::string, std::string> metadata_;
+};
+
+class TizenMetaDataHandler : public ManifestHandler {
+ public:
+ TizenMetaDataHandler();
+ virtual ~TizenMetaDataHandler();
+
+ virtual bool Parse(scoped_refptr<ApplicationData> application,
+ base::string16* error) OVERRIDE;
+ virtual std::vector<std::string> Keys() const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TizenMetaDataHandler);
+};
+
+} // namespace application
+} // namespace xwalk
+
+#endif // XWALK_APPLICATION_COMMON_MANIFEST_HANDLERS_TIZEN_METADATA_HANDLER_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/common/security_policy.h"
+
+namespace xwalk {
+namespace application {
+
+SecurityPolicy::SecurityPolicy(const GURL& url, bool subdomains)
+ : url_(url),
+ subdomains_(subdomains) {
+}
+
+} // namespace application
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_APPLICATION_COMMON_SECURITY_POLICY_H_
+#define XWALK_APPLICATION_COMMON_SECURITY_POLICY_H_
+#include "url/gurl.h"
+
+namespace xwalk {
+namespace application {
+
+class SecurityPolicy {
+ public:
+ enum SecurityMode {
+ NoSecurity,
+ CSP,
+ WARP
+ };
+ SecurityPolicy(const GURL& url, bool subdomains);
+ const GURL& url() const { return url_; }
+ bool subdomains() const { return subdomains_; }
+
+ private:
+ GURL url_;
+ bool subdomains_;
+};
+
+} // namespace application
+} // namespace xwalk
+
+#endif // XWALK_APPLICATION_COMMON_SECURITY_POLICY_H_
#include <string>
#include "base/file_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "xwalk/application/common/application_manifest_constants.h"
db_initialized_(false) {
sqlite_db_.reset(new sql::Connection);
- base::FilePath name(application_->id());
+ base::FilePath name;
+#if defined(OS_WIN)
+ name = base::FilePath(base::UTF8ToWide(application_->id()));
+#else
+ name = base::FilePath(application_->id());
+#endif
base::FilePath::StringType storage_name =
name.value() + kWidgetStorageExtension;
data_path_ = data_dir.Append(storage_name);
: base::Thread("LauncherExtensionService"),
is_started_(false) {
base::Thread::Options thread_options;
- thread_options.message_loop_type = base::MessageLoop::TYPE_UI;
+ thread_options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
StartWithOptions(thread_options);
}
static gboolean init_extension_process_channel(gpointer data) {
GDBusProxy* app_proxy = static_cast<GDBusProxy*>(data);
if (ep_launcher->is_started())
- return TRUE;
+ return FALSE;
// Get the client socket file descriptor from fd_list. The reply will
// contains an index to the list.
GUnixFDList* fd_list;
int client_fd = g_unix_fd_list_get(fd_list, client_fd_idx, NULL);
ep_launcher->Launch(channel_id, client_fd);
- return TRUE;
+ return FALSE;
}
static void on_app_signal(GDBusProxy* proxy,
// be called by Crosswalk (now running as a normal user) so all the activities
// that required 'root' access are done by a small code base.
-
-#if defined(OS_TIZEN)
-#include <pkgmgr/pkgmgr_parser.h>
-#else
-// So we can compile this on Linux Desktop
-static int pkgmgr_parser_parse_manifest_for_installation(
- const char* path, char *const tagv[]) {
- return 0;
-}
-
-static int pkgmgr_parser_parse_manifest_for_uninstallation(
- const char* path, char *const tagv[]) {
- return 0;
-}
-
-#endif
-
#include "base/files/file_path.h"
#include "base/file_util.h"
+#include "xwalk/application/tools/tizen/xwalk_pkg_installer.h"
namespace {
-const base::FilePath kIconDir("/opt/share/icons/default/small/");
-const base::FilePath kXmlDir("/opt/share/packages/");
-const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
-const std::string kServicePrefix("xwalk-service.");
-
-class FileDeleter {
- public:
- FileDeleter(const base::FilePath& path, bool recursive)
- : path_(path),
- recursive_(recursive) {}
-
- ~FileDeleter() {
- if (path_.empty())
- return;
-
- base::DeleteFile(path_, recursive_);
- }
-
- void Dismiss() {
- path_.clear();
- }
-
- private:
- base::FilePath path_;
- bool recursive_;
-};
-
-bool InstallApplication(const char* appid, const char* xmlpath,
- const char* iconpath) {
- base::FilePath icon_src(iconpath);
- // icon_dst == /opt/share/icons/default/small/xwalk-service.<appid>.png
- // FIXME(vcgomes): Add support for more icon types
- base::FilePath icon_dst = kIconDir.Append(
- kServicePrefix + std::string(appid) + ".png");
- if (!base::CopyFile(icon_src, icon_dst)) {
- fprintf(stdout, "Couldn't copy application icon to '%s'\n",
- icon_dst.value().c_str());
- return false;
- }
-
- FileDeleter icon_cleaner(icon_dst, false);
-
- base::FilePath xml_src(xmlpath);
- base::FilePath xml_dst = kXmlDir.Append(
- kServicePrefix + std::string(appid) + ".xml");
- if (!base::CopyFile(xml_src, xml_dst)) {
- fprintf(stdout, "Couldn't copy application XML metadata to '%s'\n",
- xml_dst.value().c_str());
- return false;
- }
-
- FileDeleter xml_cleaner(xml_dst, false);
-
- if (pkgmgr_parser_parse_manifest_for_installation(xmlpath, NULL)) {
- fprintf(stdout, "Couldn't parse manifest XML '%s'\n", xmlpath);
- return false;
- }
-
- icon_cleaner.Dismiss();
- xml_cleaner.Dismiss();
-
- return true;
-}
-
-bool UninstallApplication(const char* appid) {
- bool result = true;
-
- // FIXME(vcgomes): Add support for more icon types
- base::FilePath icon_dst = kIconDir.Append(
- kServicePrefix + std::string(appid) + ".png");
- if (!base::DeleteFile(icon_dst, false)) {
- fprintf(stdout, "Couldn't delete '%s'\n", icon_dst.value().c_str());
- result = false;
- }
-
- base::FilePath xmlpath(kXmlDir);
- xmlpath = xmlpath.Append(kServicePrefix + std::string(appid) + ".xml");
-
- int ret = pkgmgr_parser_parse_manifest_for_uninstallation(
- xmlpath.value().c_str(), NULL);
- if (ret) {
- fprintf(stdout, "Couldn't parse manifest XML '%s'\n",
- xmlpath.value().c_str());
- result = false;
- }
-
- if (!base::DeleteFile(xmlpath, false)) {
- fprintf(stdout, "Couldn't delete '%s'\n", xmlpath.value().c_str());
- result = false;
- }
-
- return result;
-}
-
int usage(const char* program) {
fprintf(stdout, "%s - Crosswalk Tizen Application Installation helper\n\n",
basename(program));
return 1;;
}
+ PkgInstaller installer(argv[2]);
if (!strcmp(argv[1], "--install")) {
if (argc != 5)
return usage(argv[0]);
- result = InstallApplication(argv[2], argv[3], argv[4]);
+ result = installer.InstallApplication(argv[3], argv[4]);
} else if (!strcmp(argv[1], "--uninstall")) {
if (argc != 3)
return usage(argv[0]);
- result = UninstallApplication(argv[2]);
+ result = installer.UninstallApplication();
} else {
return usage(argv[0]);
}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/tools/tizen/xwalk_pkg_installer.h"
+
+#include <assert.h>
+#include <stdio.h>
+#if defined(OS_TIZEN)
+#include <pkgmgr/pkgmgr_parser.h>
+#endif
+
+#undef LOG
+#include <string>
+#include "base/files/file_path.h"
+#include "base/file_util.h"
+
+namespace {
+
+typedef int (*PkgParser)(const char*, char* const*);
+
+const base::FilePath kIconDir("/opt/share/icons/default/small/");
+const base::FilePath kXmlDir("/opt/share/packages/");
+const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
+const std::string kServicePrefix("xwalk-service.");
+
+// Package type sent in every signal.
+const char PKGMGR_PKG_TYPE[] = "rpm";
+
+// Notification about operation start.
+const char PKGMGR_START_KEY[] = "start";
+
+// Value for new installation.
+const char PKGMGR_START_INSTALL[] = "install";
+
+// Value for uninstallation.
+const char PKGMGR_START_UNINSTALL[] = "uninstall";
+
+// Notification about end of installation with status.
+const char PKGMGR_END_KEY[] = "end";
+
+// Success value of end of installation.
+const char PKGMGR_END_SUCCESS[] = "ok";
+
+// Failure value of end of installation.
+const char PKGMGR_END_FAILURE[] = "fail";
+
+const std::string kAppIdPrefix("xwalk.");
+
+class FileDeleter {
+ public:
+ FileDeleter(const base::FilePath& path, bool recursive)
+ : path_(path),
+ recursive_(recursive) {}
+
+ ~FileDeleter() {
+ if (path_.empty())
+ return;
+
+ base::DeleteFile(path_, recursive_);
+ }
+
+ void Dismiss() {
+ path_.clear();
+ }
+
+ private:
+ base::FilePath path_;
+ bool recursive_;
+};
+
+} // namespace
+
+PkgInstaller::PkgInstaller(const std::string& appid)
+ : appid_(appid) {
+ if (appid_.empty())
+ fprintf(stdout, "Invalid app id is provided for pkg installer.\n");
+
+#if defined(OS_TIZEN)
+ handle_ = pkgmgr_installer_new();
+ if (!handle_)
+ fprintf(stdout, "Fail to get package manager installer handle.\n");
+#endif
+}
+
+PkgInstaller::~PkgInstaller() {
+#if defined(OS_TIZEN)
+ if (handle_)
+ pkgmgr_installer_free(handle_);
+#endif
+}
+
+bool PkgInstaller::InstallApplication(const std::string& xmlpath,
+ const std::string& iconpath) {
+ if (xmlpath.empty() || iconpath.empty()) {
+ fprintf(stdout, "Invalid xml path or icon path for installation\n");
+ }
+
+ base::FilePath icon_src(iconpath);
+ // icon_dst == /opt/share/icons/default/small/xwalk-service.<appid>.png
+ // FIXME(vcgomes): Add support for more icon types
+ base::FilePath icon_dst = kIconDir.Append(
+ kServicePrefix + std::string(appid_) + ".png");
+ if (!base::CopyFile(icon_src, icon_dst)) {
+ fprintf(stdout, "Couldn't copy application icon to '%s'\n",
+ icon_dst.value().c_str());
+ return false;
+ }
+
+ FileDeleter icon_cleaner(icon_dst, false);
+
+ base::FilePath xml_src(xmlpath);
+ base::FilePath xml_dst = kXmlDir.Append(
+ kServicePrefix + std::string(appid_) + ".xml");
+ if (!base::CopyFile(xml_src, xml_dst)) {
+ fprintf(stdout, "Couldn't copy application XML metadata to '%s'\n",
+ xml_dst.value().c_str());
+ return false;
+ }
+
+#if defined(OS_TIZEN)
+ if (!ParseManifest(PkgInstaller::INSTALL, xmlpath)) {
+ fprintf(stdout, "Couldn't install %s'\n", appid_.c_str());
+ return false;
+ }
+#endif
+
+ FileDeleter xml_cleaner(xml_dst, false);
+ icon_cleaner.Dismiss();
+ xml_cleaner.Dismiss();
+
+ return true;
+}
+
+bool PkgInstaller::UninstallApplication() {
+ bool result = true;
+
+ // FIXME(vcgomes): Add support for more icon types
+ base::FilePath icon_dst = kIconDir.Append(
+ kServicePrefix + appid_ + ".png");
+ if (!base::DeleteFile(icon_dst, false)) {
+ fprintf(stdout, "Couldn't delete '%s'\n", icon_dst.value().c_str());
+ result = false;
+ }
+
+ base::FilePath xmlpath(kXmlDir);
+ xmlpath = xmlpath.Append(kServicePrefix + std::string(appid_) + ".xml");
+
+#if defined(OS_TIZEN)
+ if (!ParseManifest(PkgInstaller::UNINSTALL, xmlpath.MaybeAsASCII())) {
+ fprintf(stdout, "Couldn't uninstall %s'\n", appid_.c_str());
+ result = false;
+ }
+#endif
+
+ if (!base::DeleteFile(xmlpath, false)) {
+ fprintf(stdout, "Couldn't delete '%s'\n", xmlpath.value().c_str());
+ result = false;
+ }
+
+ return result;
+}
+
+#if defined(OS_TIZEN)
+bool PkgInstaller::ParseManifest(PkgInstaller::RequestType type,
+ const std::string& xmlpath) {
+ std::string pkgmgr_cmd;
+ PkgParser parser;
+ switch (type) {
+ case PkgInstaller::INSTALL:
+ pkgmgr_cmd = PKGMGR_START_INSTALL;
+ parser = pkgmgr_parser_parse_manifest_for_installation;
+ break;
+
+ case PkgInstaller::UNINSTALL:
+ pkgmgr_cmd = PKGMGR_START_UNINSTALL;
+ parser = pkgmgr_parser_parse_manifest_for_uninstallation;
+ break;
+
+ default:
+ assert(false);
+ fprintf(stdout, "Setting unknown command for package manager.");
+ return false;
+ }
+
+ SendSignal(PKGMGR_START_KEY, pkgmgr_cmd);
+
+ bool result = parser(xmlpath.c_str(), NULL);
+
+ if (result) {
+ fprintf(stdout, "Couldn't parse manifest XML '%s'\n", xmlpath.c_str());
+ SendSignal(PKGMGR_END_KEY, PKGMGR_END_FAILURE);
+ return false;
+ } else {
+ SendSignal(PKGMGR_END_KEY, PKGMGR_END_SUCCESS);
+ }
+
+ return true;
+}
+
+bool PkgInstaller::SendSignal(
+ const std::string& key,
+ const std::string& value) {
+ if (!handle_) {
+ fprintf(stdout, "The package install manager is not initialized.\n");
+ return false;
+ }
+
+ if (key.empty() || value.empty()) {
+ fprintf(stdout, " Fail to send signal, key/value is empty.\n");
+ return false;
+ }
+
+ if (pkgmgr_installer_send_signal(
+ handle_, PKGMGR_PKG_TYPE, appid_.c_str(),
+ key.c_str(), value.c_str())) {
+ fprintf(stdout, "Fail to send package manager signal.\n");
+ }
+
+ return true;
+}
+#endif
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_APPLICATION_TOOLS_TIZEN_XWALK_PKG_INSTALLER_H_
+#define XWALK_APPLICATION_TOOLS_TIZEN_XWALK_PKG_INSTALLER_H_
+
+#if defined(OS_TIZEN)
+#include <pkgmgr_installer.h>
+#endif
+
+#include <string>
+
+class PkgInstaller {
+ public:
+ explicit PkgInstaller(const std::string& appid);
+ ~PkgInstaller();
+ bool InstallApplication(const std::string& xmlpath,
+ const std::string& iconpath);
+ bool UninstallApplication();
+
+ private:
+#if defined(OS_TIZEN)
+ enum RequestType {
+ INSTALL,
+ UNINSTALL
+ };
+ bool ParseManifest(RequestType type, const std::string& xmlpath);
+ bool SendSignal(const std::string& key, const std::string& value);
+
+ pkgmgr_installer* handle_;
+#endif
+
+ std::string appid_;
+};
+
+#endif // XWALK_APPLICATION_TOOLS_TIZEN_XWALK_PKG_INSTALLER_H_
],
'sources': [
'xwalk_pkg_helper.cc',
+ 'xwalk_pkg_installer.cc',
+ 'xwalk_pkg_installer.h',
],
},
],
'common/permission_policy_manager.cc',
'common/permission_policy_manager.h',
'common/permission_types.h',
+ 'common/security_policy.cc',
+ 'common/security_policy.h',
'extension/application_event_extension.cc',
'extension/application_event_extension.h',
'common/manifest_handlers/navigation_handler.h',
'common/manifest_handlers/tizen_application_handler.cc',
'common/manifest_handlers/tizen_application_handler.h',
+ 'common/manifest_handlers/tizen_metadata_handler.cc',
+ 'common/manifest_handlers/tizen_metadata_handler.h',
'common/manifest_handlers/tizen_setting_handler.cc',
'common/manifest_handlers/tizen_setting_handler.h',
],
. ${SCRIPT_DIR}/../../../build/android/envsetup.sh "$@"
-unset CHROMIUM_GYP_FILE
-
export PATH=$PATH:${CHROME_SRC}/xwalk/build/android
+# The purpose of this function is to do the same as android_gyp(), but calling
+# gyp_xwalk instead.
xwalk_android_gyp() {
- echo "GYP_GENERATORS set to '$GYP_GENERATORS'"
- (
- "${CHROME_SRC}/xwalk/gyp_xwalk" --check "$@"
- )
+ "${CHROME_SRC}/xwalk/gyp_xwalk" --check "$@"
}
os.path.join(target_dir, 'scripts/ant')),
(os.path.join(tools_src_dir, 'compress_js_and_css.py'), target_dir),
(os.path.join(tools_src_dir, 'customize.py'), target_dir),
+ (os.path.join(tools_src_dir, 'customize_launch_screen.py'), target_dir),
(os.path.join(tools_src_dir, 'handle_permissions.py'), target_dir),
(os.path.join(tools_src_dir, 'handle_xml.py'), target_dir),
(os.path.join(tools_src_dir, 'make_apk.py'), target_dir),
shutil.copy2(source_file, target_file)
-def CopyJavaSources(project_source, out_dir):
- """cp <path>/java/src/<package>
- out/Release/xwalk_core_library/src/<package>
- """
-
- print 'Copying Java sources...'
- target_source_dir = os.path.join(
- out_dir, LIBRARY_PROJECT_NAME, 'src')
- if not os.path.exists(target_source_dir):
- os.makedirs(target_source_dir)
-
- # FIXME(wang16): There is an assumption here the package names listed
- # here are all beginned with "org". If the assumption is broken in
- # future, the logic needs to be adjusted accordingly.
- java_srcs_to_copy = [
- # Chromium java sources.
- 'base/android/java/src/org/chromium/base',
- 'content/public/android/java/src/org/chromium/content',
- 'content/public/android/java/src/org/chromium/content_public',
- 'media/base/android/java/src/org/chromium/media',
- 'net/android/java/src/org/chromium/net',
- 'ui/android/java/src/org/chromium/ui',
- 'components/navigation_interception/android/java/'
- 'src/org/chromium/components/navigation_interception',
- 'components/web_contents_delegate_android/android/java/'
- 'src/org/chromium/components/web_contents_delegate_android',
-
- # R.javas
- 'content/public/android/java/resource_map/org/chromium/content/R.java',
- 'ui/android/java/resource_map/org/chromium/ui/R.java',
-
- # XWalk java sources.
- 'xwalk/runtime/android/core/src/org/xwalk/core',
- 'xwalk/extensions/android/java/src/org/xwalk/core/extensions',
- ]
-
- for source in java_srcs_to_copy:
- # find the src/org in the path
- slash_org_pos = source.find(r'/org/')
- if slash_org_pos < 0:
- raise Exception('Invalid java source path: %s' % source)
- source_path = os.path.join(project_source, source)
- package_path = source[slash_org_pos+1:]
- target_path = os.path.join(target_source_dir, package_path)
- if os.path.isfile(source_path):
- if not os.path.isdir(os.path.dirname(target_path)):
- os.makedirs(os.path.dirname(target_path))
- shutil.copyfile(source_path, target_path)
- else:
- shutil.copytree(source_path, target_path)
-
-
-def CopyGeneratedSources(out_dir):
- """cp out/Release/gen/templates/<path>
- out/Release/xwalk_core_library/src/<path>
- cp out/Release/xwalk_core_shell_apk/
- native_libraries_java/NativeLibraries.java
- out/Release/xwalk_core_library/src/org/
- chromium/base/library_loader/NativeLibraries.java
- """
-
- print 'Copying generated source files...'
- generated_srcs_to_copy = [
- 'org/chromium/base/ApplicationState.java',
- 'org/chromium/base/MemoryPressureLevelList.java',
- 'org/chromium/base/library_loader/NativeLibraries.java',
- 'org/chromium/content/browser/GestureEventType.java',
- 'org/chromium/content/browser/input/PopupItemType.java',
- 'org/chromium/content/browser/PageTransitionTypes.java',
- 'org/chromium/content/browser/SpeechRecognitionError.java',
- 'org/chromium/content/common/ResultCodes.java',
- 'org/chromium/content/common/ScreenOrientationValues.java',
- 'org/chromium/content/common/TopControlsState.java',
- 'org/chromium/media/ImageFormat.java',
- 'org/chromium/net/CertificateMimeType.java',
- 'org/chromium/net/CertVerifyStatusAndroid.java',
- 'org/chromium/net/NetError.java',
- 'org/chromium/net/PrivateKeyType.java',
- 'org/chromium/ui/gfx/BitmapFormat.java',
- 'org/chromium/ui/WindowOpenDisposition.java'
- ]
-
- for source in generated_srcs_to_copy:
- source_file = os.path.join(out_dir, 'gen', 'templates', source)
- target_file = os.path.join(
- out_dir, LIBRARY_PROJECT_NAME, 'src', source)
- shutil.copyfile(source_file, target_file)
-
- source_file = os.path.join(out_dir, XWALK_CORE_SHELL_APK,
- 'native_libraries_java',
- 'NativeLibraries.java')
- target_file = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'src', 'org',
- 'chromium', 'base', 'library_loader',
- 'NativeLibraries.java')
- shutil.copyfile(source_file, target_file)
-
def CopyJSBindingFiles(project_source, out_dir):
print 'Copying js binding files...'
jsapi_dir = os.path.join(out_dir,
os.mkdir(libs_dir)
libs_to_copy = [
- 'eyesfree_java.jar',
- 'guava_javalib.jar',
- 'jsr_305_javalib.jar',
+ 'xwalk_core_library_java.jar',
]
for lib in libs_to_copy:
# Copy Eclipse project files of library project.
CopyProjectFiles(options.source, out_dir)
- # Copy Java sources of chromium and xwalk.
- CopyJavaSources(options.source, out_dir)
- CopyGeneratedSources(out_dir)
# Copy binaries and resuorces.
CopyResources(options.source, out_dir)
CopyBinaries(out_dir)
mode = os.path.basename(os.path.normpath(out_dir))
RemoveUnusedFilesInReleaseMode(mode,
os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'libs'))
+ # Create empty src directory
+ src_dir = os.path.join(out_project_dir, 'src')
+ if not os.path.isdir(src_dir):
+ os.mkdir(src_dir)
print 'Your Android library project has been created at %s' % (
out_project_dir)
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright (c) 2014 Intel Corporation. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import fnmatch
+import optparse
+import os
+import sys
+import shutil
+import subprocess
+
+
+def GetCommandOutput(command, cwd=None):
+ proc = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, bufsize=1,
+ cwd=cwd)
+ output = proc.communicate()[0]
+ result = proc.returncode
+ if result:
+ raise Exception('%s: %s' % (subprocess.list2cmdline(command), output))
+ return output
+
+
+def UnpackJar(jar, classes_dir):
+ jar_cmd = ['jar', 'xvf', os.path.abspath(jar)]
+ GetCommandOutput(jar_cmd, classes_dir)
+
+
+def FindInDirectory(directory, filename_filter):
+ files = []
+ for root, _dirnames, filenames in os.walk(directory):
+ matched_files = fnmatch.filter(filenames, filename_filter)
+ files.extend((os.path.join(root, f) for f in matched_files))
+ return files
+
+
+def DoJar(classes_dir, jar_path):
+ class_files = FindInDirectory(classes_dir, '*.class')
+
+ jar_path = os.path.abspath(jar_path)
+
+ class_files_rel = [os.path.relpath(f, classes_dir) for f in class_files]
+ jar_cmd = ['jar', 'cf0', jar_path] + class_files_rel
+
+ GetCommandOutput(jar_cmd, classes_dir)
+
+
+def main():
+ parser = optparse.OptionParser()
+ info = ('The folder to place unzipped classes')
+ parser.add_option('--classes-dir', help=info)
+ info = ('The jars to merge')
+ parser.add_option('--jars', help=info)
+ info = ('The output merged jar file')
+ parser.add_option('--jar-path', help=info)
+ options, _ = parser.parse_args()
+
+ if os.path.isdir(options.classes_dir):
+ shutil.rmtree(options.classes_dir)
+ os.makedirs(options.classes_dir)
+
+ for jar in options.jars.split(' '):
+ UnpackJar(eval(jar), options.classes_dir)
+
+ DoJar(options.classes_dir, options.jar_path)
+
+if __name__ == '__main__':
+ sys.exit(main())
'variables': {
'packages': [
'capi-location-manager',
+ 'vconf',
],
},
'direct_dependent_settings': {
'type': 'none',
'variables': {
'packages': [
+ 'dlog',
'pkgmgr-parser',
'pkgmgr-info',
+ 'pkgmgr-installer',
],
},
'direct_dependent_settings': {
@JNINamespace("xwalk::extensions")
public abstract class XWalkExtensionAndroid {
private final static String TAG = "XWalkExtensionAndroid";
- private int mXWalkExtension;
+ private long mXWalkExtension;
public XWalkExtensionAndroid(String name, String jsApi) {
mXWalkExtension = nativeGetOrCreateExtension(name, jsApi, null);
@CalledByNative
public abstract String handleSyncMessage(int instanceID, String message);
- private native int nativeGetOrCreateExtension(String name, String jsApi, String[] entryPoints);
- private native void nativePostMessage(int nativeXWalkExtensionAndroid, int instanceID, String message);
- private native void nativeBroadcastMessage(int nativeXWalkExtensionAndroid, String message);
- private native void nativeDestroyExtension(int nativeXWalkExtensionAndroid);
+ private native long nativeGetOrCreateExtension(String name, String jsApi, String[] entryPoints);
+ private native void nativePostMessage(long nativeXWalkExtensionAndroid, int instanceID, String message);
+ private native void nativeBroadcastMessage(long nativeXWalkExtensionAndroid, String message);
+ private native void nativeDestroyExtension(long nativeXWalkExtensionAndroid);
}
explicit ExtensionSandboxedProcessLauncherDelegate(
content::ChildProcessHost* host)
#if defined(OS_POSIX)
- : ipc_fd_(host->TakeClientFileDescriptor()) {}
+ : ipc_fd_(host->TakeClientFileDescriptor())
#endif
+ {}
virtual ~ExtensionSandboxedProcessLauncherDelegate() {}
#if defined(OS_WIN)
- virtual void ShouldSandbox(bool* in_sandbox) OVERRIDE {
- *in_sandbox = false;
+ virtual bool ShouldSandbox() OVERRIDE {
+ return false;
}
#elif defined(OS_POSIX)
virtual int GetIpcFd() OVERRIDE {
}
void XWalkExtensionProcessHost::StopProcess() {
- if (process_);
+ if (process_)
process_.reset();
if (channel_)
channel_.reset();
SendSyncReplyToJS(scoped_ptr<base::Value>(ret_val));
}
-static jint GetOrCreateExtension(JNIEnv* env, jobject obj, jstring name,
+static jlong GetOrCreateExtension(JNIEnv* env, jobject obj, jstring name,
jstring js_api, jobjectArray js_entry_points) {
xwalk::XWalkBrowserMainPartsAndroid* main_parts =
ToAndroidMainParts(XWalkContentBrowserClient::Get()->main_parts());
static_cast<XWalkExtensionAndroid*>(extension)->BindToJavaObject(env, obj);
}
- return reinterpret_cast<jint>(extension);
+ return reinterpret_cast<intptr_t>(extension);
}
bool RegisterXWalkExtensionAndroid(JNIEnv* env) {
%bcond_with wayland
Name: crosswalk
-Version: 6.35.121.0
+Version: 6.35.131.0
Release: 0
Summary: Crosswalk is an app runtime based on Chromium
License: (BSD-3-Clause and LGPL-2.1+)
BuildRequires: pkgconfig(libxslt)
BuildRequires: pkgconfig(pango)
BuildRequires: pkgconfig(pkgmgr-info)
+BuildRequires: pkgconfig(pkgmgr-installer)
BuildRequires: pkgconfig(pkgmgr-parser)
BuildRequires: pkgconfig(nspr)
BuildRequires: pkgconfig(nss)
fi
%if %{with wayland}
-GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ozone=1 -Denable_ozone_wayland_vkb=1"
+GYP_EXTRA_FLAGS="${GYP_EXTRA_FLAGS} -Duse_ozone=1 -Denable_ozone_wayland_vkb=1 -Denable_xdg_shell=1"
%endif
# --no-parallel is added because chroot does not mount a /dev/shm, this will
}
}
+ static String getUrlContent(Context context, String url) throws IOException {
+ InputStream stream = open(context, url);
+ if (stream == null) {
+ throw new RuntimeException("Failed to open the url: " + url);
+ }
+
+ String content = "";
+ try {
+ final int bufferSize = 1024;
+ byte[] buffer = new byte[bufferSize];
+ int actualSize = 0;
+ while ((actualSize = stream.read(buffer, 0, bufferSize)) > 0) {
+ content += new String(buffer, 0, actualSize);
+ }
+ } finally {
+ stream.close();
+ }
+ return content;
+ }
+
private static int getFieldId(Context context, String assetType, String assetName)
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> d = context.getClassLoader()
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core;
+
+import org.chromium.net.NetError;
+
+/**
+ * This is a helper class to map native error code about loading a page to Android specific ones.
+ */
+class ErrorCodeConversionHelper {
+ static int convertErrorCode(int netError) {
+ // Note: many NetError.Error constants don't have an obvious mapping.
+ // These will be handled by the default case, ERROR_UNKNOWN.
+ switch (netError) {
+ case NetError.ERR_UNSUPPORTED_AUTH_SCHEME:
+ return XWalkResourceClient.ERROR_UNSUPPORTED_AUTH_SCHEME;
+
+ case NetError.ERR_INVALID_AUTH_CREDENTIALS:
+ case NetError.ERR_MISSING_AUTH_CREDENTIALS:
+ case NetError.ERR_MISCONFIGURED_AUTH_ENVIRONMENT:
+ return XWalkResourceClient.ERROR_AUTHENTICATION;
+
+ case NetError.ERR_TOO_MANY_REDIRECTS:
+ return XWalkResourceClient.ERROR_REDIRECT_LOOP;
+
+ case NetError.ERR_UPLOAD_FILE_CHANGED:
+ return XWalkResourceClient.ERROR_FILE_NOT_FOUND;
+
+ case NetError.ERR_INVALID_URL:
+ return XWalkResourceClient.ERROR_BAD_URL;
+
+ case NetError.ERR_DISALLOWED_URL_SCHEME:
+ case NetError.ERR_UNKNOWN_URL_SCHEME:
+ return XWalkResourceClient.ERROR_UNSUPPORTED_SCHEME;
+
+ case NetError.ERR_IO_PENDING:
+ case NetError.ERR_NETWORK_IO_SUSPENDED:
+ return XWalkResourceClient.ERROR_IO;
+
+ case NetError.ERR_CONNECTION_TIMED_OUT:
+ case NetError.ERR_TIMED_OUT:
+ return XWalkResourceClient.ERROR_TIMEOUT;
+
+ case NetError.ERR_FILE_TOO_BIG:
+ return XWalkResourceClient.ERROR_FILE;
+
+ case NetError.ERR_HOST_RESOLVER_QUEUE_TOO_LARGE:
+ case NetError.ERR_INSUFFICIENT_RESOURCES:
+ case NetError.ERR_OUT_OF_MEMORY:
+ return XWalkResourceClient.ERROR_TOO_MANY_REQUESTS;
+
+ case NetError.ERR_CONNECTION_CLOSED:
+ case NetError.ERR_CONNECTION_RESET:
+ case NetError.ERR_CONNECTION_REFUSED:
+ case NetError.ERR_CONNECTION_ABORTED:
+ case NetError.ERR_CONNECTION_FAILED:
+ case NetError.ERR_SOCKET_NOT_CONNECTED:
+ return XWalkResourceClient.ERROR_CONNECT;
+
+ case NetError.ERR_INTERNET_DISCONNECTED:
+ case NetError.ERR_ADDRESS_INVALID:
+ case NetError.ERR_ADDRESS_UNREACHABLE:
+ case NetError.ERR_NAME_NOT_RESOLVED:
+ case NetError.ERR_NAME_RESOLUTION_FAILED:
+ return XWalkResourceClient.ERROR_HOST_LOOKUP;
+
+ case NetError.ERR_SSL_PROTOCOL_ERROR:
+ case NetError.ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
+ case NetError.ERR_TUNNEL_CONNECTION_FAILED:
+ case NetError.ERR_NO_SSL_VERSIONS_ENABLED:
+ case NetError.ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
+ case NetError.ERR_SSL_RENEGOTIATION_REQUESTED:
+ case NetError.ERR_CERT_ERROR_IN_SSL_RENEGOTIATION:
+ case NetError.ERR_BAD_SSL_CLIENT_AUTH_CERT:
+ case NetError.ERR_SSL_NO_RENEGOTIATION:
+ case NetError.ERR_SSL_DECOMPRESSION_FAILURE_ALERT:
+ case NetError.ERR_SSL_BAD_RECORD_MAC_ALERT:
+ case NetError.ERR_SSL_UNSAFE_NEGOTIATION:
+ case NetError.ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
+ case NetError.ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
+ case NetError.ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
+ return XWalkResourceClient.ERROR_FAILED_SSL_HANDSHAKE;
+
+ case NetError.ERR_PROXY_AUTH_UNSUPPORTED:
+ case NetError.ERR_PROXY_AUTH_REQUESTED:
+ case NetError.ERR_PROXY_CONNECTION_FAILED:
+ case NetError.ERR_UNEXPECTED_PROXY_AUTH:
+ return XWalkResourceClient.ERROR_PROXY_AUTHENTICATION;
+
+ // The certificate errors are handled by onReceivedSslError
+ // and don't need to be reported here.
+ case NetError.ERR_CERT_COMMON_NAME_INVALID:
+ case NetError.ERR_CERT_DATE_INVALID:
+ case NetError.ERR_CERT_AUTHORITY_INVALID:
+ case NetError.ERR_CERT_CONTAINS_ERRORS:
+ case NetError.ERR_CERT_NO_REVOCATION_MECHANISM:
+ case NetError.ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
+ case NetError.ERR_CERT_REVOKED:
+ case NetError.ERR_CERT_INVALID:
+ case NetError.ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
+ case NetError.ERR_CERT_NON_UNIQUE_NAME:
+ return XWalkResourceClient.ERROR_OK;
+
+ default:
+ return XWalkResourceClient.ERROR_UNKNOWN;
+ }
+ }
+}
--- /dev/null
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a method as being able to be exposed to JavaScript. This is used for
+ * safety purposes so that only explicitly marked methods get exposed instead
+ * of every method in a class.
+ * See the explanation for {@link XWalkView#addJavascriptInterface(Object, String)}
+ * about the usage.
+ */
+@SuppressWarnings("javadoc")
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface JavascriptInterface {
+}
/**
* It's the Internal class to handle legacy resource related callbacks not
* handled by XWalkResourceClient.
+ *
+ * @hide
*/
public class XWalkClient {
private AlertDialog mDialog;
private XWalkView mXWalkView;
- public XWalkClient(Context context, XWalkView view) {
- mContext = context;
+ public XWalkClient(XWalkView view) {
+ mContext = view.getContext();
mXWalkView = view;
}
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.ViewGroup;
import android.webkit.ValueCallback;
import android.webkit.WebResourceResponse;
import android.widget.FrameLayout;
+import java.io.IOException;
+import java.io.InputStream;
+
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.ThreadUtils;
import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
-import org.chromium.content.browser.ContentVideoView;
import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.ContentViewRenderView;
* This class is the implementation class for XWalkView by calling internal
* various classes.
*/
-public class XWalkContent extends FrameLayout implements XWalkPreferences.KeyValueChangeListener {
+class XWalkContent extends FrameLayout implements XWalkPreferences.KeyValueChangeListener {
+ private static String TAG = "XWalkContent";
private ContentViewCore mContentViewCore;
private ContentView mContentView;
private ContentViewRenderView mContentViewRenderView;
private XWalkGeolocationPermissions mGeolocationPermissions;
private XWalkLaunchScreenManager mLaunchScreenManager;
- int mXWalkContent;
- int mWebContents;
+ long mXWalkContent;
+ long mWebContents;
boolean mReadyToLoad = false;
String mPendingUrl = null;
+ String mPendingData = null;
public XWalkContent(Context context, AttributeSet attrs, XWalkView xwView) {
super(context, attrs);
mContentViewRenderView = new ContentViewRenderView(context, mWindow) {
protected void onReadyToRender() {
if (mPendingUrl != null) {
- doLoadUrl(mPendingUrl);
+ doLoadUrl(mPendingUrl, mPendingData);
mPendingUrl = null;
+ mPendingData = null;
}
mReadyToLoad = true;
XWalkPreferences.load(this);
}
- void doLoadUrl(String url) {
- //TODO(Xingnan): Configure appropriate parameters here.
+ void doLoadUrl(String url, String content) {
// Handle the same url loading by parameters.
- if (TextUtils.equals(url, mContentView.getUrl())) {
+ if (url != null && !url.isEmpty() &&
+ TextUtils.equals(url, mContentView.getUrl())) {
mContentView.getContentViewCore().reload(true);
} else {
- LoadUrlParams params = new LoadUrlParams(url);
+ LoadUrlParams params = null;
+ if (content == null || content.isEmpty()) {
+ params = new LoadUrlParams(url);
+ } else {
+ params = LoadUrlParams.createLoadDataParamsWithBaseUrl(
+ content, "text/html", false, url, null);
+ }
params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
mContentView.loadUrl(params);
}
mContentView.requestFocus();
}
- public void loadUrl(String url) {
- if (url == null)
+ public void loadUrl(String url, String data) {
+ if ((url == null || url.isEmpty()) &&
+ (data == null || data.isEmpty())) {
return;
+ }
- if (mReadyToLoad)
- doLoadUrl(url);
- else
+ if (mReadyToLoad) {
+ doLoadUrl(url, data);
+ } else {
mPendingUrl = url;
+ mPendingData = data;
+ }
}
- public void reload() {
+ public void reload(int mode) {
if (mReadyToLoad) {
- mContentView.getContentViewCore().reload(true);
+ switch (mode) {
+ case XWalkView.RELOAD_IGNORE_CACHE:
+ mContentView.getContentViewCore().reloadIgnoringCache(true);
+ break;
+ case XWalkView.RELOAD_NORMAL:
+ default:
+ mContentView.getContentViewCore().reload(true);
+
+ }
}
}
}
public void addJavascriptInterface(Object object, String name) {
- mContentViewCore.addJavascriptInterface(object, name);
+ mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name,
+ JavascriptInterface.class);
}
public void evaluateJavascript(String script, ValueCallback<String> callback) {
return mSettings;
}
- public void loadAppFromManifest(String path, String manifest) {
- if (path == null || manifest == null || mXWalkContent == 0) {
+ public void loadAppFromManifest(String url, String data) {
+ if (mXWalkContent == 0 ||
+ ((url == null || url.isEmpty()) &&
+ (data == null || data.isEmpty()))) {
return;
}
- if (!nativeSetManifest(mXWalkContent, path, manifest)) {
- throw new RuntimeException("Failed to parse the manifest file.");
+ String content = data;
+ // If the data of manifest.json is not set, try to load it.
+ if (data == null || data.isEmpty()) {
+ try {
+ content = AndroidProtocolHandler.getUrlContent(mXWalkView.getActivity(), url);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to read the manifest: " + url);
+ }
+ }
+
+ // Calculate the base url of manifestUrl. Used by native side.
+ // TODO(yongsheng): It's from runtime side. Need to find a better way
+ // to get base url.
+ String baseUrl = url;
+ int position = url.lastIndexOf("/");
+ if (position != -1) {
+ baseUrl = url.substring(0, position + 1);
+ } else {
+ Log.w(TAG, "The url of manifest.json is probably not set correctly.");
+ }
+
+ if (!nativeSetManifest(mXWalkContent, baseUrl, content)) {
+ throw new RuntimeException("Failed to parse the manifest file: " + url);
}
}
@CalledByNative
public void onGetUrlFromManifest(String url) {
if (url != null && !url.isEmpty()) {
- loadUrl(url);
+ loadUrl(url, null);
}
}
@CalledByNative
- public void onGetUrlAndLaunchScreenFromManifest(String url, String readyWhen) {
+ public void onGetUrlAndLaunchScreenFromManifest(String url, String readyWhen, String imageBorder) {
if (url == null || url.isEmpty()) return;
- mLaunchScreenManager.displayLaunchScreen(readyWhen);
+ mLaunchScreenManager.displayLaunchScreen(readyWhen, imageBorder);
mContentsClientBridge.registerPageLoadListener(mLaunchScreenManager);
- loadUrl(url);
+ loadUrl(url, null);
}
@CalledByNative
mContentsClientBridge.getCallbackHelper().postOnLoadResource(url);
} else {
if (isMainFrame && webResourceResponse.getData() == null) {
- mContentsClientBridge.getCallbackHelper().postOnReceivedError(-1, null, url);
+ mContentsClientBridge.getCallbackHelper().postOnReceivedError(
+ XWalkResourceClient.ERROR_UNKNOWN, null, url);
}
interceptedRequestData = new InterceptedRequestData(webResourceResponse.getMimeType(),
webResourceResponse.getEncoding(),
}
}
- private native int nativeInit(XWalkWebContentsDelegate webViewContentsDelegate,
+ public void setOverlayVideoMode(boolean enabled) {
+ if (mContentViewRenderView != null) {
+ mContentViewRenderView.setOverlayVideoMode(enabled);
+ }
+ }
+
+ private native long nativeInit(XWalkWebContentsDelegate webViewContentsDelegate,
XWalkContentsClientBridge bridge);
- private static native void nativeDestroy(int nativeXWalkContent);
- private native int nativeGetWebContents(int nativeXWalkContent,
+ private static native void nativeDestroy(long nativeXWalkContent);
+ private native long nativeGetWebContents(long nativeXWalkContent,
XWalkContentsIoThreadClient ioThreadClient,
InterceptNavigationDelegate delegate);
- private native void nativeClearCache(int nativeXWalkContent, boolean includeDiskFiles);
- private native String nativeDevToolsAgentId(int nativeXWalkContent);
- private native String nativeGetVersion(int nativeXWalkContent);
- private native void nativeSetJsOnlineProperty(int nativeXWalkContent, boolean networkUp);
- private native boolean nativeSetManifest(int nativeXWalkContent, String path, String manifest);
- private native int nativeGetRoutingID(int nativeXWalkContent);
+ private native void nativeClearCache(long nativeXWalkContent, boolean includeDiskFiles);
+ private native String nativeDevToolsAgentId(long nativeXWalkContent);
+ private native String nativeGetVersion(long nativeXWalkContent);
+ private native void nativeSetJsOnlineProperty(long nativeXWalkContent, boolean networkUp);
+ private native boolean nativeSetManifest(long nativeXWalkContent, String path, String manifest);
+ private native int nativeGetRoutingID(long nativeXWalkContent);
private native void nativeInvokeGeolocationCallback(
- int nativeXWalkContent, boolean value, String requestingFrame);
- private native byte[] nativeGetState(int nativeXWalkContent);
- private native boolean nativeSetState(int nativeXWalkContent, byte[] state);
+ long nativeXWalkContent, boolean value, String requestingFrame);
+ private native byte[] nativeGetState(long nativeXWalkContent);
+ private native boolean nativeSetState(long nativeXWalkContent, byte[] state);
}
import android.view.View;
import android.view.WindowManager;
+import org.chromium.base.CommandLine;
import org.chromium.content.browser.ContentVideoViewClient;
+import org.chromium.content.common.ContentSwitches;
import org.xwalk.core.XWalkWebChromeClient.CustomViewCallback;
class XWalkContentVideoViewClient implements ContentVideoViewClient {
private XWalkContentsClient mContentsClient;
private Activity mActivity;
+ private XWalkView mView;
- public XWalkContentVideoViewClient(XWalkContentsClient client, Activity activity) {
+ public XWalkContentVideoViewClient(XWalkContentsClient client, Activity activity, XWalkView view) {
mContentsClient = client;
mActivity = activity;
+ mView = view;
}
@Override
public void onShowCustomView(View view) {
+ if (!CommandLine.getInstance().hasSwitch(
+ ContentSwitches.DISABLE_OVERLAY_FULLSCREEN_VIDEO_SUBTITLE)) {
+ mView.setOverlayVideoMode(true);
+ }
+
CustomViewCallback cb = new CustomViewCallback() {
@Override
public void onCustomViewHidden() {
@Override
public void onDestroyContentVideoView() {
+ if (!CommandLine.getInstance().hasSwitch(
+ ContentSwitches.DISABLE_OVERLAY_FULLSCREEN_VIDEO_SUBTITLE)) {
+ mView.setOverlayVideoMode(false);
+ }
mContentsClient.onHideCustomView();
}
* new abstract methods that the our own client must implement.
* i.e.: all methods in this class should either be final, or abstract.
*/
-// TODO(yongsheng): remove public modifier.
-public abstract class XWalkContentsClient extends ContentViewClient {
+abstract class XWalkContentsClient extends ContentViewClient {
private static final String TAG = "XWalkContentsClient";
private final XWalkContentsClientCallbackHelper mCallbackHelper =
// the XWalkView does not notify the embedder of sub-frame failures.
return;
}
- onReceivedError(errorCode, description, failingUrl);
+ onReceivedError(ErrorCodeConversionHelper.convertErrorCode(errorCode),
+ description, failingUrl);
}
@Override
public abstract boolean hasEnteredFullscreen();
+ public abstract boolean shouldOverrideRunFileChooser(
+ int processId, int renderId, int mode, String acceptTypes, boolean capture);
+
// TODO (michaelbai): Remove this method once the same method remove from
// XWalkContentsClientAdapter.
public void onShowCustomView(View view,
package org.xwalk.core;
+import android.content.ContentResolver;
import android.content.Intent;
+import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Picture;
+import android.net.Uri;
import android.net.http.SslCertificate;
import android.net.http.SslError;
import android.os.Message;
+import android.provider.MediaStore;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
private boolean mIsFullscreen = false;
// The native peer of the object
- private int mNativeContentsClientBridge;
+ private long mNativeContentsClientBridge;
private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
private XWalkContentsClient mContentsClient;
mXWalkUIClient = client;
return;
}
- mXWalkUIClient = new XWalkUIClientImpl(mXWalkView.getContext(), mXWalkView);
+ mXWalkUIClient = new XWalkUIClient(mXWalkView);
}
public void setResourceClient(XWalkResourceClient client) {
mXWalkResourceClient = client;
return;
}
- mXWalkResourceClient = new XWalkResourceClientImpl(mXWalkView.getContext(), mXWalkView);
+ mXWalkResourceClient = new XWalkResourceClient(mXWalkView);
}
return mInterceptNavigationDelegate;
}
+ private boolean isOwnerActivityRunning() {
+ if (mXWalkView != null && mXWalkView.isOwnerActivityRunning()) {
+ return true;
+ }
+ return false;
+ }
+
// TODO(Xingnan): All the empty functions need to be implemented.
@Override
public boolean shouldOverrideUrlLoading(String url) {
@Override
public void onProgressChanged(int progress) {
- mXWalkResourceClient.onProgressChanged(mXWalkView, progress);
+ if (isOwnerActivityRunning()) {
+ mXWalkResourceClient.onProgressChanged(mXWalkView, progress);
+ }
}
@Override
public WebResourceResponse shouldInterceptRequest(String url) {
- return mXWalkResourceClient.shouldInterceptLoadRequest(mXWalkView, url);
+ if (isOwnerActivityRunning()) {
+ return mXWalkResourceClient.shouldInterceptLoadRequest(mXWalkView, url);
+ }
+ return null;
}
public void onResourceLoadStarted(String url) {
- mXWalkResourceClient.onLoadStarted(mXWalkView, url);
+ if (isOwnerActivityRunning()) {
+ mXWalkResourceClient.onLoadStarted(mXWalkView, url);
+ }
}
public void onResourceLoadFinished(String url) {
- // TODO(yongsheng): this method is never called. Where should it be hooked?
- mXWalkResourceClient.onLoadFinished(mXWalkView, url);
+ if (isOwnerActivityRunning()) {
+ mXWalkResourceClient.onLoadFinished(mXWalkView, url);
+ }
}
@Override
public void onLoadResource(String url) {
- if (mXWalkClient != null && mXWalkView != null) {
+ if (mXWalkClient != null && isOwnerActivityRunning()) {
mXWalkClient.onLoadResource(mXWalkView, url);
}
}
@CalledByNative
public void onReceivedHttpAuthRequest(XWalkHttpAuthHandler handler, String host, String realm) {
- if (mXWalkClient != null && mXWalkView != null) {
+ if (mXWalkClient != null && isOwnerActivityRunning()) {
mXWalkClient.onReceivedHttpAuthRequest(mXWalkView, handler, host, realm);
}
}
@Override
public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
- if (mXWalkClient != null && mXWalkView != null) {
+ if (mXWalkClient != null && isOwnerActivityRunning()) {
mXWalkClient.onReceivedSslError(mXWalkView, callback, error);
}
}
@Override
public void onGeolocationPermissionsShowPrompt(String origin,
XWalkGeolocationPermissions.Callback callback) {
- if (mXWalkWebChromeClient != null) {
+ if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
mXWalkWebChromeClient.onGeolocationPermissionsShowPrompt(origin, callback);
}
}
@Override
public void onGeolocationPermissionsHidePrompt() {
- if (mXWalkWebChromeClient != null) {
+ if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
mXWalkWebChromeClient.onGeolocationPermissionsHidePrompt();
}
}
@Override
public void onPageStarted(String url) {
- if (mXWalkClient != null && mXWalkView != null) {
+ if (mXWalkClient != null && isOwnerActivityRunning()) {
mXWalkClient.onPageStarted(mXWalkView, url);
}
}
@Override
public void onPageFinished(String url) {
+ if (!isOwnerActivityRunning()) return;
if (mPageLoadListener != null) mPageLoadListener.onPageFinished(url);
- if (mXWalkClient != null && mXWalkView != null) {
+ if (mXWalkClient != null) {
mXWalkClient.onPageFinished(mXWalkView, url);
}
+
+ // This isn't the accurate point to notify a resource loading is finished,
+ // but it's a workable way. We could enhance this by extending Content
+ // API in future if we have the demand.
+ onResourceLoadFinished(url);
}
@Override
public void onReceivedError(int errorCode, String description, String failingUrl) {
- mXWalkResourceClient.onReceivedLoadError(mXWalkView, errorCode, description, failingUrl);
+ if (isOwnerActivityRunning()) {
+ mXWalkResourceClient.onReceivedLoadError(mXWalkView, errorCode, description, failingUrl);
+ }
}
@Override
public void onRendererUnresponsive() {
- if (mXWalkClient != null && mXWalkView != null) {
+ if (mXWalkClient != null && isOwnerActivityRunning()) {
mXWalkClient.onRendererUnresponsive(mXWalkView);
}
}
@Override
public void onRendererResponsive() {
- if (mXWalkClient != null && mXWalkView != null) {
+ if (mXWalkClient != null && isOwnerActivityRunning()) {
mXWalkClient.onRendererResponsive(mXWalkView);
}
}
@Override
public void onRequestFocus() {
- mXWalkUIClient.onRequestFocus(mXWalkView);
+ if (isOwnerActivityRunning()) {
+ mXWalkUIClient.onRequestFocus(mXWalkView);
+ }
}
@Override
public void onCloseWindow() {
- mXWalkUIClient.onJavascriptCloseWindow(mXWalkView);
+ if (isOwnerActivityRunning()) {
+ mXWalkUIClient.onJavascriptCloseWindow(mXWalkView);
+ }
}
@Override
@Override
public void onShowCustomView(View view, XWalkWebChromeClient.CustomViewCallback callback) {
- if (mXWalkWebChromeClient != null) {
+ if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
mXWalkWebChromeClient.onShowCustomView(view, callback);
}
}
@Override
public void onHideCustomView() {
- if (mXWalkWebChromeClient != null) {
+ if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
mXWalkWebChromeClient.onHideCustomView();
}
}
@Override
public void onScaleChangedScaled(float oldScale, float newScale) {
- mXWalkUIClient.onScaleChanged(mXWalkView, oldScale, newScale);
+ if (isOwnerActivityRunning()) {
+ mXWalkUIClient.onScaleChanged(mXWalkView, oldScale, newScale);
+ }
}
@Override
@Override
public void onTitleChanged(String title) {
- if (mXWalkWebChromeClient != null && mXWalkView != null) {
+ if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
mXWalkWebChromeClient.onReceivedTitle(mXWalkView, title);
}
}
@Override
public void onToggleFullscreen(boolean enterFullscreen) {
- mIsFullscreen = enterFullscreen;
- mXWalkUIClient.onFullscreenToggled(mXWalkView, enterFullscreen);
+ if (isOwnerActivityRunning()) {
+ mIsFullscreen = enterFullscreen;
+ mXWalkUIClient.onFullscreenToggled(mXWalkView, enterFullscreen);
+ }
}
@Override
}
@Override
+ public boolean shouldOverrideRunFileChooser(
+ final int processId, final int renderId, final int modeFlags,
+ String acceptTypes, boolean capture) {
+ if (!isOwnerActivityRunning()) return false;
+ abstract class UriCallback implements ValueCallback<Uri> {
+ boolean syncNullReceived = false;
+ boolean syncCallFinished = false;
+ protected String resolveFileName(Uri uri, ContentResolver contentResolver) {
+ if (contentResolver == null || uri == null) return "";
+ Cursor cursor = null;
+ try {
+ cursor = contentResolver.query(uri, null, null, null, null);
+
+ if (cursor != null && cursor.getCount() >= 1) {
+ cursor.moveToFirst();
+ int index = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
+ if (index > -1) return cursor.getString(index);
+ }
+ } catch (NullPointerException e) {
+ // Some android models don't handle the provider call correctly.
+ // see crbug.com/345393
+ return "";
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ return "";
+ }
+ }
+ UriCallback uploadFile = new UriCallback() {
+ boolean completed = false;
+ @Override
+ public void onReceiveValue(Uri value) {
+ if (completed) {
+ throw new IllegalStateException("Duplicate openFileChooser result");
+ }
+ completed = true;
+ if (value == null && !syncCallFinished) {
+ syncNullReceived = true;
+ return;
+ }
+ if (value == null) {
+ nativeOnFilesNotSelected(mNativeContentsClientBridge,
+ processId, renderId, modeFlags);
+ } else {
+ String result = "";
+ String displayName = null;
+ if (ContentResolver.SCHEME_FILE.equals(value.getScheme())) {
+ result = value.getSchemeSpecificPart();
+ displayName = value.getLastPathSegment();
+ } else if (ContentResolver.SCHEME_CONTENT.equals(value.getScheme())) {
+ result = value.toString();
+ displayName = resolveFileName(
+ value, mXWalkView.getActivity().getContentResolver());
+ } else {
+ result = value.getPath();
+ displayName = value.getLastPathSegment();
+ }
+ if (displayName == null || displayName.isEmpty()) displayName = result;
+ nativeOnFilesSelected(mNativeContentsClientBridge,
+ processId, renderId, modeFlags, result, displayName);
+ }
+ }
+ };
+ mXWalkUIClient.openFileChooser(
+ mXWalkView, uploadFile, acceptTypes, Boolean.toString(capture));
+ uploadFile.syncCallFinished = true;
+ // File chooser requires user interaction, valid derives should handle it in async process.
+ // If the ValueCallback receive a sync result with null value, it is considered the
+ // file chooser is not overridden.
+ return !uploadFile.syncNullReceived;
+ }
+
+ @Override
public ContentVideoViewClient getContentVideoViewClient() {
- return new XWalkContentVideoViewClient(this, mXWalkView.getActivity());
+ return new XWalkContentVideoViewClient(this, mXWalkView.getActivity(), mXWalkView);
}
// Used by the native peer to set/reset a weak ref to the native peer.
@CalledByNative
- private void setNativeContentsClientBridge(int nativeContentsClientBridge) {
+ private void setNativeContentsClientBridge(long nativeContentsClientBridge) {
mNativeContentsClientBridge = nativeContentsClientBridge;
}
@CalledByNative
private void handleJsAlert(String url, String message, int id) {
- XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
- mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
- XWalkUIClient.JavascriptMessageType.JAVASCRIPT_ALERT, url, message, "", result);
+ if (isOwnerActivityRunning()) {
+ XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
+ mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
+ XWalkUIClient.JavascriptMessageType.JAVASCRIPT_ALERT, url, message, "", result);
+ }
}
@CalledByNative
private void handleJsConfirm(String url, String message, int id) {
- XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
- mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
- XWalkUIClient.JavascriptMessageType.JAVASCRIPT_CONFIRM, url, message, "", result);
+ if (isOwnerActivityRunning()) {
+ XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
+ mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
+ XWalkUIClient.JavascriptMessageType.JAVASCRIPT_CONFIRM, url, message, "", result);
+ }
}
@CalledByNative
private void handleJsPrompt(String url, String message, String defaultValue, int id) {
- XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
- mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
- XWalkUIClient.JavascriptMessageType.JAVASCRIPT_PROMPT, url, message, defaultValue,
- result);
+ if (isOwnerActivityRunning()) {
+ XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
+ mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
+ XWalkUIClient.JavascriptMessageType.JAVASCRIPT_PROMPT, url, message, defaultValue,
+ result);
+ }
}
@CalledByNative
private void handleJsBeforeUnload(String url, String message, int id) {
- XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
- mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
- XWalkUIClient.JavascriptMessageType.JAVASCRIPT_BEFOREUNLOAD, url, message, "",
- result);
- }
-
- // @CalledByNative
- // TODO(yongsheng): Native side should call file chooser.
- public void runFileChooser(final int processId, final int renderId, final int mode_flags,
- String acceptTypes, String title, String defaultFilename, boolean capture) {
- // TODO(yongsheng): Implement it.
- // mXWalkUIClient.openFileChooser(mXWalkView, ...);
- // See https://crosswalk-project.org/jira/browse/XWALK-1241.
+ if (isOwnerActivityRunning()) {
+ XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
+ mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
+ XWalkUIClient.JavascriptMessageType.JAVASCRIPT_BEFOREUNLOAD, url, message, "",
+ result);
+ }
}
@CalledByNative
nativeCancelJsResult(mNativeContentsClientBridge, id);
}
- void exitFullscreen(int nativeWebContents) {
+ void exitFullscreen(long nativeWebContents) {
if (mNativeContentsClientBridge == 0) return;
nativeExitFullscreen(mNativeContentsClientBridge, nativeWebContents);
}
//--------------------------------------------------------------------------------------------
// Native methods
//--------------------------------------------------------------------------------------------
- private native void nativeProceedSslError(int nativeXWalkContentsClientBridge,
+ private native void nativeProceedSslError(long nativeXWalkContentsClientBridge,
boolean proceed, int id);
- private native void nativeConfirmJsResult(int nativeXWalkContentsClientBridge, int id,
+ private native void nativeConfirmJsResult(long nativeXWalkContentsClientBridge, int id,
String prompt);
- private native void nativeCancelJsResult(int nativeXWalkContentsClientBridge, int id);
- private native void nativeExitFullscreen(int nativeXWalkContentsClientBridge, int nativeWebContents);
- private native void nativeNotificationDisplayed(int nativeXWalkContentsClientBridge, int id,
+ private native void nativeCancelJsResult(long nativeXWalkContentsClientBridge, int id);
+ private native void nativeExitFullscreen(long nativeXWalkContentsClientBridge, long nativeWebContents);
+ private native void nativeNotificationDisplayed(long nativeXWalkContentsClientBridge, int id,
int processId, int routeId);
- private native void nativeNotificationError(int nativeXWalkContentsClientBridge, int id,
+ private native void nativeNotificationError(long nativeXWalkContentsClientBridge, int id,
String error, int processId, int routeId);
- private native void nativeNotificationClicked(int nativeXWalkContentsClientBridge, int id,
+ private native void nativeNotificationClicked(long nativeXWalkContentsClientBridge, int id,
int processId, int routeId);
- private native void nativeNotificationClosed(int nativeXWalkContentsClientBridge, int id,
+ private native void nativeNotificationClosed(long nativeXWalkContentsClientBridge, int id,
boolean byUser, int processId, int routeId);
+ private native void nativeOnFilesSelected(long nativeXWalkContentsClientBridge,
+ int processId, int renderId, int mode_flags, String filepath, String displayName);
+ private native void nativeOnFilesNotSelected(long nativeXWalkContentsClientBridge,
+ int processId, int renderId, int mode_flags);
}
* XWalkCookieManager manages cookies according to RFC2109 spec.
*
* Methods in this class are thread safe.
+ *
+ * @hide
*/
@JNINamespace("xwalk")
-// TODO(yongsheng): remove public modifier.
public final class XWalkCookieManager {
/**
* Control whether cookie is enabled or disabled
@JNINamespace("xwalk")
class XWalkDevToolsServer {
- private int mNativeDevToolsServer = 0;
+ private long mNativeDevToolsServer = 0;
public XWalkDevToolsServer(String socketName) {
mNativeDevToolsServer = nativeInitRemoteDebugging(socketName);
nativeAllowConnectionFromUid(mNativeDevToolsServer, uid);
}
- private native int nativeInitRemoteDebugging(String socketName);
- private native void nativeDestroyRemoteDebugging(int devToolsServer);
- private native boolean nativeIsRemoteDebuggingEnabled(int devToolsServer);
- private native void nativeSetRemoteDebuggingEnabled(int devToolsServer, boolean enabled);
- private native void nativeAllowConnectionFromUid(int devToolsServer, int uid);
+ private native long nativeInitRemoteDebugging(String socketName);
+ private native void nativeDestroyRemoteDebugging(long devToolsServer);
+ private native boolean nativeIsRemoteDebuggingEnabled(long devToolsServer);
+ private native void nativeSetRemoteDebuggingEnabled(long devToolsServer, boolean enabled);
+ private native void nativeAllowConnectionFromUid(long devToolsServer, int uid);
}
* This class is used to manage permissions for the WebView's Geolocation JavaScript API.
*
* Callbacks are posted on the UI thread.
- * TODO(yongsheng): remove public modifier.
+ * @hide
*/
public final class XWalkGeolocationPermissions {
/**
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
+/**
+ * It's for http auth handling.
+ * @hide
+ */
@JNINamespace("xwalk")
-// TODO(yongsheng): remove public modifier.
public class XWalkHttpAuthHandler {
- private int mNativeXWalkHttpAuthHandler;
+ private long mNativeXWalkHttpAuthHandler;
private final boolean mFirstAttempt;
public void proceed(String username, String password) {
}
@CalledByNative
- public static XWalkHttpAuthHandler create(int nativeXWalkAuthHandler, boolean firstAttempt) {
+ public static XWalkHttpAuthHandler create(long nativeXWalkAuthHandler, boolean firstAttempt) {
return new XWalkHttpAuthHandler(nativeXWalkAuthHandler, firstAttempt);
}
- private XWalkHttpAuthHandler(int nativeXWalkHttpAuthHandler, boolean firstAttempt) {
+ private XWalkHttpAuthHandler(long nativeXWalkHttpAuthHandler, boolean firstAttempt) {
mNativeXWalkHttpAuthHandler = nativeXWalkHttpAuthHandler;
mFirstAttempt = firstAttempt;
}
mNativeXWalkHttpAuthHandler = 0;
}
- private native void nativeProceed(int nativeXWalkHttpAuthHandler,
+ private native void nativeProceed(long nativeXWalkHttpAuthHandler,
String username, String password);
- private native void nativeCancel(int nativeXWalkHttpAuthHandler);
+ private native void nativeCancel(long nativeXWalkHttpAuthHandler);
}
package org.xwalk.core;
import java.lang.Runnable;
+import java.util.ArrayList;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Shader.TileMode;
+import android.hardware.SensorManager;
import android.os.Bundle;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
+import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.OrientationEventListener;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import org.chromium.content.browser.ContentViewRenderView.FirstRenderedFrameListener;
-// Provisionally set it as public due to the use of launch screen extension.
-// TODO(yongsheng): remove public modifier.
+/**
+ * Provisionally set it as public due to the use of launch screen extension.
+ * @hide
+ */
public class XWalkLaunchScreenManager
- implements FirstRenderedFrameListener, DialogInterface.OnShowListener, PageLoadListener {
+ implements FirstRenderedFrameListener, DialogInterface.OnShowListener,
+ DialogInterface.OnDismissListener, PageLoadListener {
// This string will be initialized before extension initialized,
// and used by LaunchScreenExtension.
private static String mIntentFilterStr;
+ private final static String BORDER_MODE_REPEAT = "repeat";
+ private final static String BORDER_MODE_STRETCH = "stretch";
+ private final static String BORDER_MODE_ROUND = "round";
+
private XWalkView mXWalkView;
private Activity mActivity;
private Context mLibContext;
private boolean mFirstFrameReceived;
private BroadcastReceiver mLaunchScreenReadyWhenReceiver;
private boolean mCustomHideLaunchScreen;
+ private int mCurrentOrientation;
+ private OrientationEventListener mOrientationListener;
private enum ReadyWhenType {
FIRST_PAINT,
CUSTOM
}
+ private enum BorderModeType {
+ REPEAT,
+ STRETCH,
+ ROUND,
+ NONE
+ }
+
public XWalkLaunchScreenManager(Context context, XWalkView xwView) {
mXWalkView = xwView;
mLibContext = context;
mIntentFilterStr = mActivity.getPackageName() + ".hideLaunchScreen";
}
- public void displayLaunchScreen(String readyWhen) {
+ public void displayLaunchScreen(String readyWhen, final String imageBorderList) {
if (mXWalkView == null) return;
setReadyWhen(readyWhen);
Runnable runnable = new Runnable() {
- public void run(){
- int resId = mActivity.getResources().getIdentifier(
- "launchscreen", "drawable", mActivity.getPackageName());
- if (resId == 0) return;
-
- // Can not use the drawable directly in shared mode, need to decode it and create a new drawable.
- Bitmap bitmap = BitmapFactory.decodeResource(mActivity.getResources(), resId);
- Drawable finalDrawable = new BitmapDrawable(mActivity.getResources(), bitmap);
-
- mLaunchScreenDialog = new Dialog(mLibContext, android.R.style.Theme_Holo_Light_NoActionBar);
- if ((mActivity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
- mLaunchScreenDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ public void run() {
+ int bgResId = mActivity.getResources().getIdentifier(
+ "launchscreen_bg", "drawable", mActivity.getPackageName());
+ if (bgResId == 0) return;
+ Drawable bgDrawable = mActivity.getResources().getDrawable(bgResId);
+ if (bgDrawable == null) return;
+
+ mLaunchScreenDialog = new Dialog(mLibContext,
+ android.R.style.Theme_Holo_Light_NoActionBar);
+ if ((mActivity.getWindow().getAttributes().flags &
+ WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
+ mLaunchScreenDialog.getWindow().setFlags(
+ WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
- mLaunchScreenDialog.getWindow().setBackgroundDrawable(finalDrawable);
mLaunchScreenDialog.setOnKeyListener(new Dialog.OnKeyListener() {
@Override
public boolean onKey(DialogInterface arg0, int keyCode,
KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
- mLaunchScreenDialog.dismiss();
+ performHideLaunchScreen();
mActivity.onBackPressed();
}
return true;
}
});
mLaunchScreenDialog.setOnShowListener(XWalkLaunchScreenManager.this);
+ mLaunchScreenDialog.setOnDismissListener(XWalkLaunchScreenManager.this);
+ // Set background
+ mLaunchScreenDialog.getWindow().setBackgroundDrawable(bgDrawable);
+ // Set foreground image
+ RelativeLayout root = getLaunchScreenLayout(imageBorderList);
+ if (root == null) return;
+ mLaunchScreenDialog.setContentView(root);
mLaunchScreenDialog.show();
+
+ // Change the layout depends on the orientation change.
+ mOrientationListener = new OrientationEventListener(mActivity,
+ SensorManager.SENSOR_DELAY_NORMAL) {
+ public void onOrientationChanged(int ori) {
+ if (mLaunchScreenDialog == null || !mLaunchScreenDialog.isShowing()) {
+ return;
+ }
+ int orientation = getScreenOrientation();
+ if (orientation != mCurrentOrientation) {
+ RelativeLayout root = getLaunchScreenLayout(imageBorderList);
+ if (root == null) return;
+ mLaunchScreenDialog.setContentView(root);
+ }
+ }
+ };
+ mOrientationListener.enable();
if (mReadyWhen == ReadyWhenType.CUSTOM) registerBroadcastReceiver();
}
};
}
@Override
+ public void onDismiss(DialogInterface dialog) {
+ mOrientationListener.disable();
+ mOrientationListener = null;
+ }
+
+ @Override
public void onPageFinished(String url) {
mPageLoadFinished = true;
hideLaunchScreenWhenReady();
return mIntentFilterStr;
}
+ public int getScreenOrientation() {
+ // getResources().getConfiguration().orientation returns wrong value in some devices.
+ // Below is another way to calculate screen orientation.
+ Display display = mActivity.getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ int orientation;
+ if (size.x < size.y) {
+ orientation = Configuration.ORIENTATION_PORTRAIT;
+ } else {
+ orientation = Configuration.ORIENTATION_LANDSCAPE;
+ }
+ return orientation;
+ }
+
+ private RelativeLayout getLaunchScreenLayout(String imageBorderList) {
+ // Parse the borders depends on orientation.
+ // imageBorderList format:"[default];[landscape];[portrait]"
+ String[] borders = imageBorderList.split(";");
+ // When there is no borders defined, display with no borders.
+ if (borders.length < 1) return parseImageBorder("");
+ int orientation = getScreenOrientation();
+ mCurrentOrientation = orientation;
+ if (borders.length >= 2 && orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ if (borders[1].equals("empty")) {
+ // Has launch_screen.landscape configured, but no image_border set.
+ // Display the iamge with no borders.
+ return parseImageBorder("");
+ } else if (borders[1].isEmpty()) {
+ // No launch_screen.landscape configured.
+ // Use launch_screen.default.
+ return parseImageBorder(borders[0]);
+ } else {
+ return parseImageBorder(borders[1]);
+ }
+ } else if (borders.length == 3 && orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (borders[2].equals("empty")) {
+ // Has launch_screen.portrait configured, but no image_border set.
+ // Display the iamge with no borders.
+ return parseImageBorder("");
+ } else if (borders[2].isEmpty()) {
+ // No launch_screen.portrait configured.
+ // Use launch_screen.default.
+ return parseImageBorder(borders[0]);
+ } else {
+ return parseImageBorder(borders[2]);
+ }
+ }
+
+ return parseImageBorder(borders[0]);
+ }
+
+ private int getSuitableSize(int maxSize, int divider) {
+ int finalSize = divider;
+ float minMod = divider;
+ for (; divider > 1; divider--) {
+ int mod = maxSize % divider;
+ // Found the suitable size.
+ if (mod == 0) {
+ finalSize = divider;
+ break;
+ }
+ // Record the best suitable one.
+ // If there is no mod==0 found, return the divider which min(mod).
+ if (mod < minMod) {
+ minMod = mod;
+ finalSize = divider;
+ }
+ }
+ return finalSize;
+ }
+
+ /**
+ * Get each section from 9-piece format image depends on the spec defined
+ * @param img The foreground image.
+ * @param x The position where the section start.
+ * @param y The position where the section start.
+ * @param width The width of the section.
+ * @param height The height of the section.
+ * @param mode The border type for this section.
+ * @param maxWidth When mode == ROUND, this will be used.
+ * @param maxHeight When mode == ROUND, this will be used.
+ * @return The ImageView for this section.
+ */
+ private ImageView getSubImageView(Bitmap img, int x, int y, int width, int height,
+ BorderModeType mode, int maxWidth, int maxHeight) {
+ if (img == null) return null;
+
+ if (width <= 0 || height <= 0) return null;
+
+ // Check whether the section is inside the foreground image.
+ Rect imgRect = new Rect(0, 0, img.getWidth(), img.getHeight());
+ Rect subRect = new Rect(x, y, x + width, y + height);
+ if (!imgRect.contains(subRect)) return null;
+
+ Bitmap subImage = Bitmap.createBitmap(img, x, y, width, height);
+ ImageView subImageView = new ImageView(mActivity);
+ BitmapDrawable drawable;
+ if (mode == BorderModeType.ROUND) {
+ int originW = subImage.getWidth();
+ int originH = subImage.getHeight();
+ int newW = originW;
+ int newH = originH;
+ // Scale down the sub image to let the last image not cropped when it's repeated.
+ if (maxWidth > 0) newW = getSuitableSize(maxWidth, originW);
+ if (maxHeight > 0) newH = getSuitableSize(maxHeight, originH);
+ // recreate the new scaled bitmap.
+ Bitmap resizedBitmap = Bitmap.createScaledBitmap(subImage, newW, newH, true);
+ // Treat as repeat mode.
+ subImage = resizedBitmap;
+ mode = BorderModeType.REPEAT;
+ }
+ if (mode == BorderModeType.REPEAT) {
+ drawable = new BitmapDrawable(mActivity.getResources(), subImage);
+ drawable.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
+ subImageView.setImageDrawable(drawable);
+ subImageView.setScaleType(ScaleType.FIT_XY);
+ } else if (mode == BorderModeType.STRETCH) {
+ subImageView.setImageBitmap(subImage);
+ subImageView.setScaleType(ScaleType.FIT_XY);
+ } else {
+ subImageView.setImageBitmap(subImage);
+ }
+
+ return subImageView;
+ }
+
+ private int getStatusBarHeight() {
+ int resourceId = mActivity.getResources().getIdentifier(
+ "status_bar_height", "dimen", "android");
+ if (resourceId > 0) {
+ return mActivity.getResources().getDimensionPixelSize(resourceId);
+ }
+ // If not found, return default one.
+ return 25;
+ }
+
+ private RelativeLayout parseImageBorder(String imageBorder) {
+ int topBorder = 0;
+ int rightBorder = 0;
+ int leftBorder = 0;
+ int bottomBorder = 0;
+ BorderModeType horizontalMode = BorderModeType.STRETCH;
+ BorderModeType verticalMode = BorderModeType.STRETCH;
+
+ if (imageBorder.equals("empty")) imageBorder = "";
+
+ // Parse the value of image_border.
+ String[] items = imageBorder.split(" ");
+ ArrayList<String> borders = new ArrayList<String>();
+ ArrayList<BorderModeType> modes = new ArrayList<BorderModeType>();
+ for (int i = 0; i < items.length; i++) {
+ String item = items[i];
+ if (item.endsWith("px")) {
+ borders.add(item.replaceAll("px", ""));
+ } else if (item.equals(BORDER_MODE_REPEAT)) {
+ modes.add(BorderModeType.REPEAT);
+ } else if (item.equals(BORDER_MODE_STRETCH)) {
+ modes.add(BorderModeType.STRETCH);
+ } else if (item.equals(BORDER_MODE_ROUND)) {
+ modes.add(BorderModeType.ROUND);
+ }
+ }
+ // Parse borders as defined by the spec.
+ try {
+ if (borders.size() == 1) {
+ topBorder = rightBorder = leftBorder = bottomBorder =
+ Integer.valueOf(borders.get(0));
+ } else if (borders.size() == 2) {
+ topBorder = bottomBorder = Integer.valueOf(borders.get(0));
+ rightBorder = leftBorder = Integer.valueOf(borders.get(1));
+ } else if (borders.size() == 3) {
+ rightBorder = leftBorder = Integer.valueOf(borders.get(1));
+ topBorder = Integer.valueOf(borders.get(0));
+ bottomBorder = Integer.valueOf(borders.get(2));
+ } else if (borders.size() == 4) {
+ topBorder = Integer.valueOf(borders.get(0));
+ rightBorder = Integer.valueOf(borders.get(1));
+ leftBorder = Integer.valueOf(borders.get(2));
+ bottomBorder = Integer.valueOf(borders.get(3));
+ }
+ } catch (NumberFormatException e) {
+ topBorder = rightBorder = leftBorder = bottomBorder = 0;
+ }
+
+ // The border values are dpi from manifest.json, need to translate to px.
+ DisplayMetrics matrix = mActivity.getResources().getDisplayMetrics();
+ topBorder = (int)TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, topBorder, matrix);
+ rightBorder = (int)TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, rightBorder, matrix);
+ leftBorder = (int)TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, leftBorder, matrix);
+ bottomBorder = (int)TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, bottomBorder, matrix);
+
+ // Parse border mode as spec defined.
+ if (modes.size() == 1) {
+ horizontalMode = verticalMode = modes.get(0);
+ } else if (modes.size() == 2) {
+ horizontalMode = modes.get(0);
+ verticalMode = modes.get(1);
+ }
+
+ // Get foreground image
+ int imgResId = mActivity.getResources().getIdentifier(
+ "launchscreen_img", "drawable", mActivity.getPackageName());
+ if (imgResId == 0) return null;
+ Bitmap img = BitmapFactory.decodeResource(mActivity.getResources(), imgResId);
+ if (img == null) return null;
+
+ // Create the 9-piece layout as spec defined.
+ RelativeLayout root = new RelativeLayout(mActivity);
+ root.setLayoutParams(new RelativeLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ RelativeLayout.LayoutParams params;
+ ImageView subImageView;
+
+ // Get Screen width and height.
+ Display display = mActivity.getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+
+ // For non fullscreen, the height should substract status bar height
+ if ((mActivity.getWindow().getAttributes().flags &
+ WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0) {
+ size.y -= getStatusBarHeight();
+ }
+
+ // Image section-1 top left
+ subImageView = getSubImageView(img, 0, 0, leftBorder, topBorder, BorderModeType.NONE, 0, 0);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
+ root.addView(subImageView, params);
+ }
+
+ // Image section-2 top
+ subImageView = getSubImageView(img, leftBorder, 0, img.getWidth() - leftBorder
+ - rightBorder, topBorder, horizontalMode, size.x - leftBorder - rightBorder, 0);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
+ params.leftMargin = leftBorder;
+ params.rightMargin = rightBorder;
+ root.addView(subImageView, params);
+ }
+
+ // Image section-3 top right
+ subImageView = getSubImageView(img, img.getWidth() - rightBorder, 0,
+ rightBorder, topBorder, BorderModeType.NONE, 0, 0);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
+ root.addView(subImageView, params);
+ }
+
+ // Image section-4 left
+ subImageView = getSubImageView(img, 0, topBorder, leftBorder, img.getHeight()
+ - topBorder - bottomBorder, verticalMode, 0, size.y - topBorder - bottomBorder);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.MATCH_PARENT);
+ params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+ params.topMargin = topBorder;
+ params.bottomMargin = bottomBorder;
+ root.addView(subImageView, params);
+ }
+
+ // Image section-5 middle
+ subImageView = getSubImageView(img, leftBorder, topBorder, img.getWidth() - leftBorder - rightBorder,
+ img.getHeight() - topBorder - bottomBorder, BorderModeType.NONE, 0, 0);
+ if (subImageView != null) {
+ subImageView.setScaleType(ScaleType.FIT_XY);
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.MATCH_PARENT);
+ params.leftMargin = leftBorder;
+ params.topMargin = topBorder;
+ params.rightMargin = rightBorder;
+ params.bottomMargin = bottomBorder;
+ root.addView(subImageView, params);
+ }
+
+ // Image section-6 right
+ subImageView = getSubImageView(img, img.getWidth() - rightBorder, topBorder, rightBorder,
+ img.getHeight() - topBorder - bottomBorder, verticalMode, 0,
+ size.y - topBorder - bottomBorder);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.MATCH_PARENT);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
+ params.topMargin = topBorder;
+ params.bottomMargin = bottomBorder;
+ root.addView(subImageView, params);
+ }
+
+ // Image section-7 bottom left
+ subImageView = getSubImageView(img, 0, img.getHeight() - bottomBorder,
+ leftBorder, bottomBorder, BorderModeType.NONE, 0, 0);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
+ root.addView(subImageView, params);
+ }
+
+ // Image section-8 bottom
+ subImageView = getSubImageView(img, leftBorder, img.getHeight() - bottomBorder,
+ img.getWidth() - leftBorder - rightBorder, bottomBorder, horizontalMode,
+ size.x - leftBorder - rightBorder, 0);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
+ params.leftMargin = leftBorder;
+ params.rightMargin = rightBorder;
+ root.addView(subImageView, params);
+ }
+
+ // Image section-9 bottom right
+ subImageView = getSubImageView(img, img.getWidth() - rightBorder,
+ img.getHeight() - bottomBorder, rightBorder, bottomBorder,
+ BorderModeType.NONE, 0, 0);
+ if (subImageView != null) {
+ params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
+ params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
+ root.addView(subImageView, params);
+ }
+ return root;
+ }
+
private void registerBroadcastReceiver() {
IntentFilter intentFilter = new IntentFilter(mIntentFilterStr);
mLaunchScreenReadyWhenReceiver = new BroadcastReceiver() {
import org.xwalk.core.XWalkNavigationHandler;
-// TODO(yongsheng): remove public modifier.
+/**
+ * @hide
+ */
public class XWalkNavigationHandlerImpl implements XWalkNavigationHandler {
private static final String TAG = "XWalkNavigationHandlerImpl";
}
/**
- * The direction for navigation.
+ * The direction for web page navigation.
*/
public enum Direction {
+ /** the backward direction for web page navigation. */
BACKWARD,
+ /** the forward direction for web page navigation. */
FORWARD
}
switch(direction) {
case FORWARD:
mXWalkView.navigateTo(steps);
+ break;
case BACKWARD:
mXWalkView.navigateTo(-steps);
+ break;
default:
break;
}
import org.chromium.content.browser.NavigationEntry;
/**
- * Represent a navigation item and managed in XWalkNavigationHistory.
+ * This class represents a navigation item and is managed in XWalkNavigationHistory.
*/
public final class XWalkNavigationItem implements Cloneable {
private NavigationEntry mEntry;
import org.xwalk.core.XWalkNotificationService;
import org.xwalk.core.XWalkView;
-// TODO(yongsheng): remove public modifier.
+/**
+ * @hide
+ */
public class XWalkNotificationServiceImpl implements XWalkNotificationService {
private static final String TAG = "XWalkNotificationServiceImpl";
import java.util.Map;
/**
- * This class is not thread-safe and must be called on the UI thread.
+ * This class represents the preferences and could be set by callers.
+ * It is not thread-safe and must be called on the UI thread.
* Afterwards, the preference could be read from all threads and can impact
* all XWalkView instances.
*/
}
/**
- * Get a preference value into Crosswalk. An exception will be thrown if
+ * Get a preference value from Crosswalk. An exception will be thrown if
* the key for the preference is not valid.
* @param key the string name of the key.
* @return true if it's enabled.
package org.xwalk.core;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.view.View;
import android.webkit.WebResourceResponse;
/**
- * This interface notifies the embedder resource events/callbacks.
+ * This class notifies the embedder resource events/callbacks.
*/
public class XWalkResourceClient {
+ /** Success */
+ public static final int ERROR_OK = 0;
+ /** Generic error */
+ public static final int ERROR_UNKNOWN = -1;
+ /** Server or proxy hostname lookup failed */
+ public static final int ERROR_HOST_LOOKUP = -2;
+ /** Unsupported authentication scheme (not basic or digest) */
+ public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3;
+ /** User authentication failed on server */
+ public static final int ERROR_AUTHENTICATION = -4;
+ /** User authentication failed on proxy */
+ public static final int ERROR_PROXY_AUTHENTICATION = -5;
+ /** Failed to connect to the server */
+ public static final int ERROR_CONNECT = -6;
+ /** Failed to read or write to the server */
+ public static final int ERROR_IO = -7;
+ /** Connection timed out */
+ public static final int ERROR_TIMEOUT = -8;
+ /** Too many redirects */
+ public static final int ERROR_REDIRECT_LOOP = -9;
+ /** Unsupported URI scheme */
+ public static final int ERROR_UNSUPPORTED_SCHEME = -10;
+ /** Failed to perform SSL handshake */
+ public static final int ERROR_FAILED_SSL_HANDSHAKE = -11;
+ /** Malformed URL */
+ public static final int ERROR_BAD_URL = -12;
+ /** Generic file error */
+ public static final int ERROR_FILE = -13;
+ /** File not found */
+ public static final int ERROR_FILE_NOT_FOUND = -14;
+ /** Too many requests during this load */
+ public static final int ERROR_TOO_MANY_REQUESTS = -15;
+
+ /**
+ * Constructor.
+ * @param view the owner XWalkView instance.
+ */
+ public XWalkResourceClient(XWalkView view) {
+ // Keep the above parameter for future use.
+ }
+
/**
* Notify the client that the XWalkView will load the resource specified
* by the given url.
/**
* Notify the client the progress info of loading a specific url.
* @param view the owner XWalkView instance.
- * @param url the loading process in percent.
+ * @param progressInPercent the loading process in percent.
*/
public void onProgressChanged(XWalkView view, int progressInPercent) {
}
*/
public void onReceivedLoadError(XWalkView view, int errorCode, String description,
String failingUrl) {
- // TODO(yongsheng): Need to define errorCode.
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(view.getContext());
+ dialogBuilder.setTitle(android.R.string.dialog_alert_title)
+ .setMessage(description)
+ .setCancelable(false)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ AlertDialog dialog = dialogBuilder.create();
+ dialog.show();
}
}
+++ /dev/null
-// Copyright (c) 2014 Intel Corporation. All rights reserved
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.xwalk.core;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.view.View;
-
-/**
- * It's the default implementation class for XWalkResourceClient.
- */
-public class XWalkResourceClientImpl extends XWalkResourceClient {
- private Context mContext;
- private AlertDialog mDialog;
- private XWalkView mXWalkView;
-
- public XWalkResourceClientImpl(Context context, XWalkView view) {
- mContext = context;
- mXWalkView = view;
- }
-
- @Override
- public void onReceivedLoadError(XWalkView view, int errorCode,
- String description, String failingUrl) {
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
- dialogBuilder.setTitle(android.R.string.dialog_alert_title)
- .setMessage(description)
- .setCancelable(false)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- });
- mDialog = dialogBuilder.create();
- mDialog.show();
- }
-}
import org.chromium.base.JNINamespace;
import org.chromium.base.ThreadUtils;
+/**
+ * @hide
+ */
@JNINamespace("xwalk")
public class XWalkSettings {
private static boolean sAppCachePathIsSet = false;
// The native side of this object.
- private int mNativeXWalkSettings = 0;
+ private long mNativeXWalkSettings = 0;
// A flag to avoid sending superfluous synchronization messages.
private boolean mIsUpdateWebkitPrefsMessagePending = false;
}
}
- public XWalkSettings(Context context, int nativeWebContents,
+ public XWalkSettings(Context context, long nativeWebContents,
boolean isAccessFromFileURLsGrantedByDefault) {
ThreadUtils.assertOnUiThread();
mContext = context;
setWebContents(nativeWebContents);
}
- void setWebContents(int nativeWebContents) {
+ void setWebContents(long nativeWebContents) {
synchronized (mXWalkSettingsLock) {
if (mNativeXWalkSettings != 0) {
nativeDestroy(mNativeXWalkSettings);
}
@CalledByNative
- private void nativeXWalkSettingsGone(int nativeXWalkSettings) {
+ private void nativeXWalkSettingsGone(long nativeXWalkSettings) {
assert mNativeXWalkSettings != 0 && mNativeXWalkSettings == nativeXWalkSettings;
mNativeXWalkSettings = 0;
}
}
/**
- * @returns the default User-Agent used by each ContentViewCore instance, i.e. unless
+ * @return returns the default User-Agent used by each ContentViewCore instance, i.e. unless
* overridden by {@link #setUserAgentString()}
*/
public static String getDefaultUserAgent() {
}
}
- private native int nativeInit(int webContentsPtr);
+ private native long nativeInit(long webContentsPtr);
- private native void nativeDestroy(int nativeXWalkSettings);
+ private native void nativeDestroy(long nativeXWalkSettings);
private static native String nativeGetDefaultUserAgent();
- private native void nativeUpdateEverythingLocked(int nativeXWalkSettings);
+ private native void nativeUpdateEverythingLocked(long nativeXWalkSettings);
- private native void nativeUpdateUserAgent(int nativeXWalkSettings);
+ private native void nativeUpdateUserAgent(long nativeXWalkSettings);
- private native void nativeUpdateWebkitPreferences(int nativeXWalkSettings);
+ private native void nativeUpdateWebkitPreferences(long nativeXWalkSettings);
}
package org.xwalk.core;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
import android.net.Uri;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
import android.webkit.ValueCallback;
+import android.widget.EditText;
/**
* This class notifies the embedder UI events/callbacks.
*/
public class XWalkUIClient {
+
+ // Strings for displaying Dialog.
+ private static String mJSAlertTitle;
+ private static String mJSConfirmTitle;
+ private static String mJSPromptTitle;
+ private static String mOKButton;
+ private static String mCancelButton;
+
+ private Context mContext;
+ private AlertDialog mDialog;
+ private EditText mPromptText;
+ private int mSystemUiFlag;
+ private View mDecorView;
+ private XWalkView mXWalkView;
+ private boolean mOriginalFullscreen;
+
+ /**
+ * Constructor.
+ * @param view the owner XWalkView instance.
+ */
+ public XWalkUIClient(XWalkView view) {
+ mContext = view.getContext();
+ mDecorView = view.getActivity().getWindow().getDecorView();
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ mSystemUiFlag = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ }
+ mXWalkView = view;
+ initResources();
+ }
+
+ private void initResources() {
+ if (mJSAlertTitle != null) return;
+ mJSAlertTitle = mContext.getString(R.string.js_alert_title);
+ mJSConfirmTitle = mContext.getString(R.string.js_confirm_title);
+ mJSPromptTitle = mContext.getString(R.string.js_prompt_title);
+ mOKButton = mContext.getString(android.R.string.ok);
+ mCancelButton = mContext.getString(android.R.string.cancel);
+ }
+
/**
* Request display and focus for this XWalkView.
* @param view the owner XWalkView instance.
* @param view the owner XWalkView instance.
*/
public void onJavascriptCloseWindow(XWalkView view) {
+ if (view != null && view.getActivity() != null) {
+ view.getActivity().finish();
+ }
}
/**
* The type of JavaScript modal dialog.
*/
public enum JavascriptMessageType {
+ /** JavaScript alert dialog. */
JAVASCRIPT_ALERT,
+ /** JavaScript confirm dialog. */
JAVASCRIPT_CONFIRM,
+ /** JavaScript prompt dialog. */
JAVASCRIPT_PROMPT,
+ /** JavaScript dialog for a window-before-unload notification. */
JAVASCRIPT_BEFOREUNLOAD
}
*/
public boolean onJavascriptModalDialog(XWalkView view, JavascriptMessageType type, String url,
String message, String defaultValue, XWalkJavascriptResult result) {
+ switch(type) {
+ case JAVASCRIPT_ALERT:
+ return onJsAlert(view, url, message, result);
+ case JAVASCRIPT_CONFIRM:
+ return onJsConfirm(view, url, message, result);
+ case JAVASCRIPT_PROMPT:
+ return onJsPrompt(view, url, message, defaultValue, result);
+ case JAVASCRIPT_BEFOREUNLOAD:
+ // Reuse onJsConfirm to show the dialog.
+ return onJsConfirm(view, url, message, result);
+ default:
+ break;
+ }
+ assert(false);
return false;
}
* @param enterFullscreen true if it has entered fullscreen mode.
*/
public void onFullscreenToggled(XWalkView view, boolean enterFullscreen) {
+ Activity activity = view.getActivity();
+ if (enterFullscreen) {
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ mSystemUiFlag = mDecorView.getSystemUiVisibility();
+ mDecorView.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ } else {
+ if ((activity.getWindow().getAttributes().flags &
+ WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
+ mOriginalFullscreen = true;
+ } else {
+ mOriginalFullscreen = false;
+ }
+ if (!mOriginalFullscreen) {
+ activity.getWindow().setFlags(
+ WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
+ }
+ } else {
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
+ mDecorView.setSystemUiVisibility(mSystemUiFlag);
+ } else {
+ // Clear the activity fullscreen flag.
+ if (!mOriginalFullscreen) {
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
+ }
+ }
}
/**
* Tell the client to open a file chooser.
* @param view the owner XWalkView instance.
- * @param uploadFile the callback class to handle the result from caller.
+ * @param uploadFile the callback class to handle the result from caller. It MUST
+ * be invoked in all cases. Leave it not invoked will block all following
+ * requests to open file chooser.
+ * @param acceptType value of the 'accept' attribute of the input tag associated
+ * with this file picker.
+ * @param capture value of the 'capture' attribute of the input tag associated
+ * with this file picker
*/
public void openFileChooser(XWalkView view, ValueCallback<Uri> uploadFile,
String acceptType, String capture) {
*/
public void onScaleChanged(XWalkView view, float oldScale, float newScale) {
}
+
+ private boolean onJsAlert(XWalkView view, String url, String message,
+ XWalkJavascriptResult result) {
+ final XWalkJavascriptResult fResult = result;
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ dialogBuilder.setTitle(mJSAlertTitle)
+ .setMessage(message)
+ .setCancelable(true)
+ .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ fResult.confirm();
+ dialog.dismiss();
+ }
+ }).setOnKeyListener(new DialogInterface.OnKeyListener() {
+ @Override
+ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ fResult.confirm();
+ return false;
+ } else {
+ return true;
+ }
+ }
+ });
+ mDialog = dialogBuilder.create();
+ mDialog.show();
+ return false;
+ }
+
+ private boolean onJsConfirm(XWalkView view, String url, String message,
+ XWalkJavascriptResult result) {
+ final XWalkJavascriptResult fResult = result;
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ dialogBuilder.setTitle(mJSConfirmTitle)
+ .setMessage(message)
+ .setCancelable(true)
+ .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ fResult.confirm();
+ dialog.dismiss();
+ }
+ })
+ .setNegativeButton(mCancelButton, null)
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ fResult.cancel();
+ }
+ }).setOnKeyListener(new DialogInterface.OnKeyListener() {
+ @Override
+ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ fResult.confirm();
+ return false;
+ } else {
+ return true;
+ }
+ }
+ });
+ mDialog = dialogBuilder.create();
+ mDialog.show();
+ return false;
+ }
+
+ private boolean onJsPrompt(XWalkView view, String url, String message,
+ String defaultValue, XWalkJavascriptResult result) {
+ final XWalkJavascriptResult fResult = result;
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ dialogBuilder.setTitle(mJSPromptTitle)
+ .setMessage(message)
+ .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ fResult.confirmWithResult(mPromptText.getText().toString());
+ dialog.dismiss();
+ }
+ })
+ .setNegativeButton(mCancelButton, null)
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ fResult.cancel();
+ }
+ });
+ mPromptText = new EditText(mContext);
+ mPromptText.setVisibility(View.VISIBLE);
+ mPromptText.setText(defaultValue);
+ mPromptText.selectAll();
+
+ dialogBuilder.setView(mPromptText);
+ mDialog = dialogBuilder.create();
+ mDialog.show();
+ return false;
+ }
}
+++ /dev/null
-// Copyright (c) 2013 Intel Corporation. All rights reserved
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.xwalk.core;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.webkit.ValueCallback;
-import android.widget.EditText;
-
-/**
- * This is the implementation of XWalkUIClient if callers don't specify one.
- */
-public class XWalkUIClientImpl extends XWalkUIClient {
-
- // Strings for displaying Dialog.
- private static String mJSAlertTitle;
- private static String mJSConfirmTitle;
- private static String mJSPromptTitle;
- private static String mOKButton;
- private static String mCancelButton;
-
- private Context mContext;
- private AlertDialog mDialog;
- private EditText mPromptText;
- private int mSystemUiFlag;
- private View mDecorView;
- private XWalkView mXWalkView;
- private boolean mOriginalFullscreen;
-
- public XWalkUIClientImpl(Context context, XWalkView view) {
- mContext = context;
- mDecorView = view.getActivity().getWindow().getDecorView();
- if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- mSystemUiFlag = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- }
- mXWalkView = view;
- initResources(context);
- }
-
- private static void initResources(Context context) {
- if (mJSAlertTitle != null) return;
- mJSAlertTitle = context.getString(R.string.js_alert_title);
- mJSConfirmTitle = context.getString(R.string.js_confirm_title);
- mJSPromptTitle = context.getString(R.string.js_prompt_title);
- mOKButton = context.getString(android.R.string.ok);
- mCancelButton = context.getString(android.R.string.cancel);
- }
-
- @Override
- public void onJavascriptCloseWindow(XWalkView view) {
- if (view != null && view.getActivity() != null) {
- view.getActivity().finish();
- }
- }
-
- @Override
- public boolean onJavascriptModalDialog(XWalkView view, JavascriptMessageType type, String url,
- String message, String defaultValue, XWalkJavascriptResult result) {
- switch(type) {
- case JAVASCRIPT_ALERT:
- return onJsAlert(view, url, message, result);
- case JAVASCRIPT_CONFIRM:
- return onJsConfirm(view, url, message, result);
- case JAVASCRIPT_PROMPT:
- return onJsPrompt(view, url, message, defaultValue, result);
- case JAVASCRIPT_BEFOREUNLOAD:
- // Reuse onJsConfirm to show the dialog.
- return onJsConfirm(view, url, message, result);
- default:
- break;
- }
- assert(false);
- return false;
- }
-
- private boolean onJsAlert(XWalkView view, String url, String message,
- XWalkJavascriptResult result) {
- final XWalkJavascriptResult fResult = result;
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
- dialogBuilder.setTitle(mJSAlertTitle)
- .setMessage(message)
- .setCancelable(true)
- .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- fResult.confirm();
- dialog.dismiss();
- }
- }).setOnKeyListener(new DialogInterface.OnKeyListener() {
- @Override
- public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- fResult.confirm();
- return false;
- } else {
- return true;
- }
- }
- });
- mDialog = dialogBuilder.create();
- mDialog.show();
- return false;
- }
-
- private boolean onJsConfirm(XWalkView view, String url, String message,
- XWalkJavascriptResult result) {
- final XWalkJavascriptResult fResult = result;
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
- dialogBuilder.setTitle(mJSConfirmTitle)
- .setMessage(message)
- .setCancelable(true)
- .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- fResult.confirm();
- dialog.dismiss();
- }
- })
- .setNegativeButton(mCancelButton, null)
- .setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- fResult.cancel();
- }
- }).setOnKeyListener(new DialogInterface.OnKeyListener() {
- @Override
- public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- fResult.confirm();
- return false;
- } else {
- return true;
- }
- }
- });
- mDialog = dialogBuilder.create();
- mDialog.show();
- return false;
- }
-
- private boolean onJsPrompt(XWalkView view, String url, String message,
- String defaultValue, XWalkJavascriptResult result) {
- final XWalkJavascriptResult fResult = result;
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
- dialogBuilder.setTitle(mJSPromptTitle)
- .setMessage(message)
- .setPositiveButton(mOKButton, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- fResult.confirmWithResult(mPromptText.getText().toString());
- dialog.dismiss();
- }
- })
- .setNegativeButton(mCancelButton, null)
- .setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- fResult.cancel();
- }
- });
- mPromptText = new EditText(mContext);
- mPromptText.setVisibility(View.VISIBLE);
- mPromptText.setText(defaultValue);
- mPromptText.selectAll();
-
- dialogBuilder.setView(mPromptText);
- mDialog = dialogBuilder.create();
- mDialog.show();
- return false;
- }
-
- @Override
- public void onFullscreenToggled(XWalkView view, boolean enterFullscreen) {
- Activity activity = view.getActivity();
- if (enterFullscreen) {
- if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- mSystemUiFlag = mDecorView.getSystemUiVisibility();
- mDecorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- } else {
- if ((activity.getWindow().getAttributes().flags &
- WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
- mOriginalFullscreen = true;
- } else {
- mOriginalFullscreen = false;
- }
- if (!mOriginalFullscreen) {
- activity.getWindow().setFlags(
- WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- }
- }
- } else {
- if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
- mDecorView.setSystemUiVisibility(mSystemUiFlag);
- } else {
- // Clear the activity fullscreen flag.
- if (!mOriginalFullscreen) {
- activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- }
- }
- }
- }
-}
package org.xwalk.core;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ApplicationErrorReport;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.ViewGroup;
-import android.webkit.WebSettings;
import android.webkit.ValueCallback;
import android.widget.FrameLayout;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
+
import org.xwalk.core.extension.XWalkExtensionManager;
/**
* It already includes all newly created Web APIs from Crosswalk like Presentation,
* DeviceCapabilities, etc..
*/
-public class XWalkView extends FrameLayout {
+public class XWalkView extends android.widget.FrameLayout {
+
+ protected static final String PLAYSTORE_DETAIL_URI = "market://details?id=";
private XWalkContent mContent;
private Activity mActivity;
private Context mContext;
private XWalkExtensionManager mExtensionManager;
+ /** Normal reload mode as default. */
+ public static final int RELOAD_NORMAL = 0;
+ /** Reload mode with bypassing the cache. */
+ public static final int RELOAD_IGNORE_CACHE = 1;
+
/**
- * Constructors for inflating via XML.
+ * Constructor for inflating via XML.
* @param context a Context object used to access application assets.
* @param attrs an AttributeSet passed to our parent.
*/
}
/**
- * Constructors for Crosswalk runtime. In shared mode, context isi
+ * Constructor for Crosswalk runtime. In shared mode, context isi
* different from activity. In embedded mode, they're same.
* @param context a Context object used to access application assets
* @param activity the activity for this XWalkView.
/**
* Get the current activity passed from callers. It's never null.
* @return the activity instance passed from callers.
+ *
+ * @hide
*/
public Activity getActivity() {
if (mActivity != null) {
}
// TODO(yongsheng): we should remove this since we have getContext()?
+ /**
+ * @hide
+ */
public Context getViewContext() {
return mContext;
}
XWalkInternalResources.resetIds(context);
// Intialize library, paks and others.
- XWalkViewDelegate.init(this);
+ try {
+ XWalkViewDelegate.init(this);
+ } catch (UnsatisfiedLinkError e) {
+ final UnsatisfiedLinkError err = e;
+ final Activity activity = getActivity();
+ final String packageName = context.getPackageName();
+ String missingArch = XWalkViewDelegate.isRunningOnIA() ? "Intel" : "ARM";
+ final String message =
+ context.getString(R.string.cpu_arch_mismatch_message, missingArch);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.cpu_arch_mismatch_title)
+ .setMessage(message)
+ .setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ activity.finish();
+ }
+ }).setPositiveButton(R.string.goto_store_button_label,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW,
+ Uri.parse(PLAYSTORE_DETAIL_URI + packageName)));
+ activity.finish();
+ }
+ }).setNeutralButton(R.string.report_feedback_button_label,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ApplicationErrorReport report = new ApplicationErrorReport();
+ report.type = ApplicationErrorReport.TYPE_CRASH;
+ report.packageName = report.processName = packageName;
+
+ ApplicationErrorReport.CrashInfo crash =
+ new ApplicationErrorReport.CrashInfo();
+ crash.exceptionClassName = err.getClass().getSimpleName();
+ crash.exceptionMessage = "CPU architecture mismatch";
+ StringWriter writer = new StringWriter();
+ PrintWriter print = new PrintWriter(writer);
+ err.printStackTrace(print);
+ crash.stackTrace = writer.toString();
+ StackTraceElement stack = err.getStackTrace()[0];
+ crash.throwClassName = stack.getClassName();
+ crash.throwFileName = stack.getFileName();
+ crash.throwLineNumber = stack.getLineNumber();
+ crash.throwMethodName = stack.getMethodName();
+
+ report.crashInfo = crash;
+ report.systemApp = false;
+ report.time = System.currentTimeMillis();
+
+ Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+ intent.putExtra(Intent.EXTRA_BUG_REPORT, report);
+ activity.startActivity(intent);
+ activity.finish();
+ }
+ });
+ builder.create().show();
+ return;
+ }
initXWalkContent(context, attrs);
}
// Set default XWalkClientImpl.
- setXWalkClient(new XWalkClient(context, this));
+ setXWalkClient(new XWalkClient(this));
// Set default XWalkWebChromeClient and DownloadListener. The default actions
// are provided via the following clients if special actions are not needed.
- setXWalkWebChromeClient(new XWalkWebChromeClient(context, this));
+ setXWalkWebChromeClient(new XWalkWebChromeClient(this));
// Set with internal implementation. Could be overwritten by embedders'
// setting.
- setUIClient(new XWalkUIClientImpl(context, this));
- setResourceClient(new XWalkResourceClientImpl(context, this));
+ setUIClient(new XWalkUIClient(this));
+ setResourceClient(new XWalkResourceClient(this));
setDownloadListener(new XWalkDownloadListenerImpl(context));
setNavigationHandler(new XWalkNavigationHandlerImpl(context));
}
/**
- * Load a web page/app from a given base URL or a content. If content is
- * specified, load the web page/app from the content. If it's null, try to
- * load the content from the baseUrl.
- * @param baseUrl the base url for web page/app.
+ * Load a web page/app from a given base URL or a content.
+ * If url is null or empty and content is null or empty, then this function
+ * will do nothing.
+ * If content is not null, load the web page/app from the content.
+ * If content is not null and the url is not set, return "about:blank" ifi
+ * calling {@link XWalkView#getUrl()}.
+ * If content is null, try to load the content from the url.
+ *
+ * It supports URL schemes like 'http:', 'https:' and 'file:'.
+ * It can also load files from Android assets, e.g. 'file:///android_asset/'.
+ * @param url the url for web page/app.
* @param content the content for the web page/app. Could be empty.
*/
- public void load(String baseUrl, String content) {
+ public void load(String url, String content) {
+ if (mContent == null) return;
checkThreadSafety();
- // TODO(yongsheng): enable to use content.
- mContent.loadUrl(baseUrl);
+ mContent.loadUrl(url, content);
}
/**
- * Load a web app from a given manifest.json file. The content must not be
- * empty.
- * @param baseUrl the base url for manifest.json.
+ * Load a web app from a given manifest.json file. If content is not null,
+ * load the manifest.json from the content. If content is null, try to load
+ * the manifest.json from the url. Note that url should not be null if the
+ * launched path defined in manifest.json is relative.
+ *
+ * It supports URL schemes like 'http:', 'https:' and 'file:'.
+ * It can also load files from Android assets, e.g. 'file:///android_asset/'.
+ * @param url the url for manifest.json.
* @param content the content for manifest.json.
*/
- public void loadAppFromManifest(String baseUrl, String content) {
- mContent.loadAppFromManifest(baseUrl, content);
+ public void loadAppFromManifest(String url, String content) {
+ if (mContent == null) return;
+ checkThreadSafety();
+ mContent.loadAppFromManifest(url, content);
}
/**
- * Reload a web app with a given reload mode.
+ * Reload a web app with a given mode.
+ * @param mode the reload mode.
*/
- // TODO(yongsheng): add reload modes here.
- public void reload() {
+ public void reload(int mode) {
+ if (mContent == null) return;
checkThreadSafety();
- mContent.reload();
+ mContent.reload(mode);
}
/**
* Stop current loading progress.
*/
public void stopLoading() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.stopLoading();
}
* @return the url for current web page/app.
*/
public String getUrl() {
+ if (mContent == null) return null;
checkThreadSafety();
return mContent.getUrl();
}
* @return the title for current web page/app.
*/
public String getTitle() {
+ if (mContent == null) return null;
checkThreadSafety();
return mContent.getTitle();
}
* @return the original url.
*/
public String getOriginalUrl() {
+ if (mContent == null) return null;
checkThreadSafety();
return mContent.getOriginalUrl();
}
* @return the navigation history.
*/
public XWalkNavigationHistory getNavigationHistory() {
+ if (mContent == null) return null;
+ checkThreadSafety();
return mContent.getNavigationHistory();
}
/**
* Injects the supplied Java object into this XWalkView.
+ * Each method defined in the class of the object should be
+ * marked with {@link JavascriptInterface} if it's called by JavaScript.
* @param object the supplied Java object, called by JavaScript.
* @param name the name injected in JavaScript.
*/
public void addJavascriptInterface(Object object, String name) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.addJavascriptInterface(object, name);
}
* @param script the JavaScript string.
* @param callback the callback to handle the evaluated result.
*/
- void evaluateJavascript(String script, ValueCallback<String> callback) {
+ public void evaluateJavascript(String script, ValueCallback<String> callback) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.evaluateJavascript(script, callback);
}
* @param includeDiskFiles indicate whether to clear disk files for cache.
*/
public void clearCache(boolean includeDiskFiles) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.clearCache(includeDiskFiles);
}
* @return true if any HTML element is occupying the whole screen.
*/
public boolean hasEnteredFullscreen() {
+ if (mContent == null) return false;
checkThreadSafety();
return mContent.hasEnteredFullscreen();
}
* in fullscreen.
*/
public void leaveFullscreen() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.exitFullscreen();
}
* when the activity for this view is paused.
*/
public void pauseTimers() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.pauseTimers();
}
* when the activyt for this view is resumed.
*/
public void resumeTimers() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.resumeTimers();
}
* Typically it should be called when the activity for this view is paused.
*/
public void onHide() {
+ if (mContent == null) return;
mExtensionManager.onPause();
mContent.onPause();
}
* Typically it should be called when the activity for this view is resumed.
*/
public void onShow() {
+ if (mContent == null) return;
mExtensionManager.onResume();
mContent.onResume();
}
* @param data passed from android.app.Activity.onActivityResult().
*/
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (mContent == null) return;
mExtensionManager.onActivityResult(requestCode, resultCode, data);
mContent.onActivityResult(requestCode, resultCode, data);
}
* @param intent passed from android.app.Activity.onNewIntent().
*/
public boolean onNewIntent(Intent intent) {
+ if (mContent == null) return false;
return mContent.onNewIntent(intent);
}
* @param outState the saved state for restoring.
*/
public boolean saveState(Bundle outState) {
+ if (mContent == null) return false;
mContent.saveState(outState);
return true;
}
* @return true if it can restore the state.
*/
public boolean restoreState(Bundle inState) {
+ if (mContent == null) return false;
if (mContent.restoreState(inState) != null) return true;
return false;
}
*/
// TODO(yongsheng): make it static?
public String getXWalkVersion() {
+ if (mContent == null) return null;
return mContent.getXWalkVersion();
}
* @param client the XWalkUIClient defined by callers.
*/
public void setUIClient(XWalkUIClient client) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setUIClient(client);
}
* @param client the XWalkResourceClient defined by callers.
*/
public void setResourceClient(XWalkResourceClient client) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setResourceClient(client);
}
- @Override
/**
* Inherit from android.view.View. This class needs to handle some keys like
* 'BACK'.
* @param keyCode passed from android.view.View.onKeyUp().
* @param event passed from android.view.View.onKeyUp().
*/
+ @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// If there's navigation happens when app is fullscreen,
}
// TODO(yongsheng): this is not public.
+ /**
+ * @hide
+ */
public XWalkSettings getSettings() {
+ if (mContent == null) return null;
checkThreadSafety();
return mContent.getSettings();
}
- // TODO(yongsheng): remove this and related test cases?
+ /**
+ * This method is used by Cordova for hacking.
+ * TODO(yongsheng): remove this and related test cases?
+ *
+ * @hide
+ */
public void setNetworkAvailable(boolean networkUp) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setNetworkAvailable(networkUp);
}
- // Enables remote debugging and returns the URL at which the dev tools server is listening
- // for commands. The allowedUid argument can be used to specify the uid of the process that is
- // permitted to connect.
- // TODO(yongsheng): how to enable this in XWalkPreferences?
+ /**
+ * Enables remote debugging and returns the URL at which the dev tools server is listening
+ * for commands. The allowedUid argument can be used to specify the uid of the process that is
+ * permitted to connect.
+ * TODO(yongsheng): how to enable this in XWalkPreferences?
+ *
+ * @hide
+ */
public String enableRemoteDebugging(int allowedUid) {
+ if (mContent == null) return null;
checkThreadSafety();
return mContent.enableRemoteDebugging(allowedUid);
}
- // It's used by presentation API.
- // TODO(yongsheng): how to fix it?
+ /**
+ * It's used for Presentation API.
+ * @hide
+ */
public int getContentID() {
+ if (mContent == null) return -1;
return mContent.getRoutingID();
}
boolean canGoBack() {
+ if (mContent == null) return false;
checkThreadSafety();
return mContent.canGoBack();
}
void goBack() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.goBack();
}
boolean canGoForward() {
+ if (mContent == null) return false;
checkThreadSafety();
return mContent.canGoForward();
}
void goForward() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.goForward();
}
void clearHistory() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.clearHistory();
}
void destroy() {
+ if (mContent == null) return;
mExtensionManager.onDestroy();
mContent.destroy();
disableRemoteDebugging();
}
void disableRemoteDebugging() {
+ if (mContent == null) return;
checkThreadSafety();
mContent.disableRemoteDebugging();
}
}
}
+ boolean isOwnerActivityRunning() {
+ int status = ApplicationStatus.getStateForActivity(getActivity());
+ if (status == ActivityState.DESTROYED) return false;
+ return true;
+ }
+
void navigateTo(int offset) {
+ if (mContent == null) return;
mContent.navigateTo(offset);
}
+ void setOverlayVideoMode(boolean enabled) {
+ mContent.setOverlayVideoMode(enabled);
+ }
+
// Below methods are for test shell and instrumentation tests.
+ /**
+ * @hide
+ */
public void setXWalkClient(XWalkClient client) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setXWalkClient(client);
}
+ /**
+ * @hide
+ */
public void setXWalkWebChromeClient(XWalkWebChromeClient client) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setXWalkWebChromeClient(client);
}
- public XWalkContent getXWalkViewContentForTest() {
- checkThreadSafety();
- return mContent;
- }
-
+ /**
+ * @hide
+ */
public void setDownloadListener(DownloadListener listener) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setDownloadListener(listener);
}
+ /**
+ * @hide
+ */
public void setNavigationHandler(XWalkNavigationHandler handler) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setNavigationHandler(handler);
}
+ /**
+ * @hide
+ */
public void setNotificationService(XWalkNotificationService service) {
+ if (mContent == null) return;
checkThreadSafety();
mContent.setNotificationService(service);
}
import android.os.Build;
import android.util.Log;
-import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatusManager;
import org.chromium.base.CommandLine;
+import org.chromium.base.JNINamespace;
import org.chromium.base.PathUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.content.browser.DeviceUtils;
import org.chromium.content.browser.ResourceExtractor;
import org.chromium.content.browser.ResourceExtractor.ResourceIntercepter;
+import org.chromium.net.NetworkChangeNotifier;
+@JNINamespace("xwalk")
class XWalkViewDelegate {
private static boolean sInitialized = false;
+ private static boolean sRunningOnIA = true;
private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "xwalkcore";
private static final String[] MANDATORY_PAKS = {
"xwalk.pak",
}
}
- public static void init(XWalkView xwalkView) {
+ public static void init(XWalkView xwalkView) throws UnsatisfiedLinkError {
if (sInitialized) {
return;
}
// features such as location provider to listen to activity status.
ApplicationStatusManager.init(xwalkView.getActivity().getApplication());
+ // Auto detect network connectivity state.
+ // setAutoDetectConnectivityState() need to be called before activity started.
+ NetworkChangeNotifier.init(xwalkView.getActivity());
+ NetworkChangeNotifier.setAutoDetectConnectivityState(true);
+
// We will miss activity onCreate() status in ApplicationStatusManager,
// informActivityStarted() will simulate these callbacks.
ApplicationStatusManager.informActivityStarted(xwalkView.getActivity());
// libraries starting from 4.2 and load them automatically.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 &&
!context.getApplicationContext().getPackageName().equals(context.getPackageName())) {
- try {
- for (String library : MANDATORY_LIBRARIES) {
- System.load("/data/data/" + context.getPackageName() + "/lib/" + library);
- }
- } catch (UnsatisfiedLinkError e) {
- throw new RuntimeException("Cannot initialize Crosswalk Core", e);
+ for (String library : MANDATORY_LIBRARIES) {
+ System.load("/data/data/" + context.getPackageName() + "/lib/" + library);
}
}
loadLibrary(context);
DeviceUtils.addDeviceSpecificUserAgentSwitch(context);
+ if (sRunningOnIA && !nativeIsLibraryBuiltForIA()) {
+ throw new UnsatisfiedLinkError();
+ }
+
ResourceExtractor.setMandatoryPaksToExtract(MANDATORY_PAKS);
final int resourcesListResId = context.getResources().getIdentifier(
XWALK_RESOURCES_LIST_RES_NAME, "array", context.getPackageName());
}
});
}
+
+ public static boolean isRunningOnIA() {
+ return sRunningOnIA;
+ }
+
+ private static native boolean nativeIsLibraryBuiltForIA();
+
+ static {
+ sRunningOnIA = Build.CPU_ABI.equalsIgnoreCase("x86");
+ }
}
* It's an internal legacy class which is to handle kinds of ui related
* callback functions. It only handles those which are not exposed to
* external users compared to XWalkUIClient.
+ *
+ * @hide
*/
public class XWalkWebChromeClient {
private Context mContext;
private XWalkContentsClient mContentsClient = null;
private long XWALK_MAX_QUOTA = 1024 * 1024 * 100;
- public XWalkWebChromeClient(Context context, XWalkView view) {
- mContext = context;
+ public XWalkWebChromeClient(XWalkView view) {
+ mContext = view.getContext();
mXWalkView = view;
}
public abstract void rendererResponsive();
@CalledByNative
+ public abstract boolean shouldOverrideRunFileChooser(
+ int processId, int renderId, int mode,
+ String acceptTypes, boolean capture);
+
+ @CalledByNative
public void updatePreferredSize(int widthCss, int heightCss) {
}
return false;
}
+
+ @Override
+ public boolean shouldOverrideRunFileChooser(int processId, int renderId, int mode,
+ String acceptTypes, boolean capture) {
+ if (mXWalkContentsClient != null) {
+ return mXWalkContentsClient.shouldOverrideRunFileChooser(processId, renderId, mode,
+ acceptTypes, capture);
+ }
+ return false;
+ }
}
import android.os.Bundle;
import android.view.View;
-import org.xwalk.core.XWalkView;
-import org.xwalk.core.XWalkResourceClient;
+import org.xwalk.core.XWalkClient;
import org.xwalk.core.XWalkUIClient;
+import org.xwalk.core.XWalkView;
/**
* Represents the content to be presented on the secondary display.
private Activity mActivity;
private PresentationDelegate mDelegate;
- private final XWalkResourceClient mXWalkResourceClient = new XWalkResourceClient() {
- @Override
- public void onLoadFinished(XWalkView view, String url) {
- mPresentationId = mContentView.getContentID();
- onContentLoaded();
- }
- };
-
- private final XWalkUIClient mXWalkUIClient = new XWalkUIClient() {
- @Override
- public void onJavascriptCloseWindow(XWalkView view) {
- // The content was closed already. Web need to invalidate the
- // presentation id now.
- mPresentationId = INVALID_PRESENTATION_ID;
- onContentClosed();
- }
- };
public XWalkPresentationContent(Context context, Activity activity, PresentationDelegate delegate) {
mContext = context;
public void load(final String url) {
if (mContentView == null) {
mContentView = new XWalkView(mContext, mActivity);
- mContentView.setResourceClient(mXWalkResourceClient);
+ final XWalkClient xWalkClient = new XWalkClient(mContentView) {
+ @Override
+ public void onPageFinished(XWalkView view, String url) {
+ mPresentationId = mContentView.getContentID();
+ onContentLoaded();
+ }
+ };
+ mContentView.setXWalkClient(xWalkClient);
+
+ final XWalkUIClient xWalkUIClient = new XWalkUIClient(mContentView) {
+ @Override
+ public void onJavascriptCloseWindow(XWalkView view) {
+ // The content was closed already. Web need to invalidate the
+ // presentation id now.
+ mPresentationId = INVALID_PRESENTATION_ID;
+ onContentClosed();
+ }
+ };
+ mContentView.setUIClient(xWalkUIClient);
}
mContentView.load(url, null);
}
--- /dev/null
+<html>
+ <body>
+ <p>Provides an embedding API for browsing web and running web applications.
+ <p>For more information about building apps with Crosswalk embedding API, see the
+ <a href="https://crosswalk-project.org/">Crosswalk project</a>.
+ </body>
+</html>
<message desc="Prompt for the http authentication login [CHAR-LIMIT=32]" name="IDS_HTTP_AUTH_LOG_IN">
Log In
</message>
+ <message desc="Title for the CPU architecture mismatch dialog [CHAR-LIMIT=50]" name="IDS_CPU_ARCH_MISMATCH_TITLE">
+ Mismatch of CPU architecture for Crosswalk
+ </message>
+ <message desc="Message for the CPU architecture mismatch dialog [CHAR-LIMIT=150]" name="IDS_CPU_ARCH_MISMATCH_MESSAGE">
+ Unfortunately this application was not created for %1$s based devices, please take a moment to notify the developer about it. Thanks.
+ </message>
+ <message desc="Label of the button for going to Google Play Store [CHAR-LIMIT=32]" name="IDS_GOTO_STORE_BUTTON_LABEL">
+ Go to Google Play Store
+ </message>
+ <message desc="Label of the button for reporting to developer [CHAR-LIMIT=32]" name="IDS_REPORT_FEEDBACK_BUTTON_LABEL">
+ Report to developer
+ </message>
</messages>
</release>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (c) 2013-2014 Intel Corporation. All rights reserved.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.xwalk.core.library.empty">
+
+ <application android:name="android.app.Application"
+ android:label="XWalkCoreLibraryEmpty" android:hardwareAccelerated="true">
+ </application>
+
+ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
+</manifest>
--- /dev/null
+# Source folder for xwalk_core_library_empty_apk
+## Why it's empty
+The "xwalk_core_library_empty_apk" is an apk target which
+only depends on xwalk_core_java. The purpose of it is to
+get all the classes compiled from the code chromium generated
+for each apk.
+So there is no java src here.
+## Why put me here
+To make git keep the folder, the src directory is needed to
+build an apk.
+
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
import org.chromium.content.browser.TracingControllerAndroid;
import org.xwalk.core.XWalkNavigationHistory;
import org.xwalk.core.XWalkPreferences;
-import org.xwalk.core.XWalkResourceClientImpl;
+import org.xwalk.core.XWalkResourceClient;
import org.xwalk.core.XWalkView;
import org.xwalk.core.XWalkWebChromeClient;
getTracingController().unregisterReceiver(this);
} catch (SecurityException e) {
Log.w(TAG, "failed to unregister tracing receiver: " + e.getMessage());
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "failed to unregister tracing receiver: " + e.getMessage());
}
}
mReloadButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- if (mActiveView != null) mActiveView.reload();
+ if (mActiveView != null) mActiveView.reload(XWalkView.RELOAD_NORMAL);
}
});
}
private void initializeXWalkViewClients(XWalkView xwalkView) {
- xwalkView.setResourceClient(new XWalkResourceClientImpl(this, xwalkView) {
+ xwalkView.setResourceClient(new XWalkResourceClient(xwalkView) {
@Override
public void onProgressChanged(XWalkView view, int newProgress) {
if (view != mActiveView) return;
}
});
- xwalkView.setXWalkWebChromeClient(new XWalkWebChromeClient(this, xwalkView) {
+ xwalkView.setXWalkWebChromeClient(new XWalkWebChromeClient(xwalkView) {
@Override
public void onReceivedTitle(XWalkView view, String title) {
mSectionsPagerAdapter.setPageTitle(view, title);
@Override
public Object getSystemService(String name) {
+ if (name.equals(Context.LAYOUT_INFLATER_SERVICE)) {
+ return super.getSystemService(name);
+ }
return mActivityCtx.getSystemService(name);
}
}
@Override
public void loadAppFromManifest(String manifestUrl) {
- XWalkManifestReader manifestReader = new XWalkManifestReader(mActivity);
- String manifest = manifestReader.read(manifestUrl);
- int position = manifestUrl.lastIndexOf("/");
- if (position == -1) {
- throw new RuntimeException("The URL of manifest file is invalid.");
- }
-
- String path = manifestUrl.substring(0, position + 1);
- mXWalkView.loadAppFromManifest(path, manifest);
+ mXWalkView.loadAppFromManifest(manifestUrl, null);
}
@Override
@Override
public void loadDataForTest(String data, String mimeType, boolean isBase64Encoded) {
- mXWalkView.getXWalkViewContentForTest().getContentViewCoreForTest(
- ).loadUrl(LoadUrlParams.createLoadDataParams(
- data, mimeType, isBase64Encoded));
+ mXWalkView.load("", data);
}
@Override
+++ /dev/null
-// Copyright (c) 2013 Intel Corporation. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.xwalk.runtime;
-
-import android.app.Activity;
-import android.content.res.AssetManager;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-/**
- * This internal class parses manifest.json of current app.
- */
-class XWalkManifestReader {
- private final static String TAG = "XWalkManifestReader";
- private final static String ASSETS_FILE_PATH = "file:///android_asset/";
- private final static String WWW_FOLDER = "www";
- private final static String APP_SCHEME = "app";
-
- private Activity mActivity;
-
- public XWalkManifestReader(Activity activity) {
- mActivity = activity;
- }
-
- public String read(String manifestPath) {
- manifestPath = getAssetsPath(manifestPath);
-
- String manifestString = null;
- try {
- manifestString = getAssetsFileContent(mActivity.getAssets(), manifestPath);
- } catch (IOException e) {
- throw new RuntimeException("Failed to read manifest.json", e);
- }
- return manifestString;
- }
-
- private String getAssetsFileContent(AssetManager assetManager, String fileName) throws IOException {
- String result = "";
- InputStream inputStream = null;
- try {
- inputStream = assetManager.open(fileName);
- int size = inputStream.available();
- byte[] buffer = new byte[size];
- inputStream.read(buffer);
- result = new String(buffer);
- } finally {
- if (inputStream != null) {
- inputStream.close();
- }
- }
- return result;
- }
-
- private String getAssetsPath(String path) {
- if (path == null || path.isEmpty()) {
- return null;
- }
-
- String assetsPath;
- URI uri = null;
- try {
- uri = new URI(path);
- } catch (URISyntaxException e) {
- Log.e(TAG, "Invalid manifest URI: " + path, e);
- }
-
- if (uri.getScheme().equals(APP_SCHEME)) {
- assetsPath = WWW_FOLDER + uri.getPath();
- } else if (path.startsWith(ASSETS_FILE_PATH)) {
- assetsPath = path.substring(ASSETS_FILE_PATH.length());
- } else {
- assetsPath = null;
- }
-
- return assetsPath;
- }
-}
import org.xwalk.core.XWalkClient;
import org.xwalk.core.XWalkResourceClient;
-import org.xwalk.core.XWalkResourceClientImpl;
import org.xwalk.core.XWalkWebChromeClient;
import org.xwalk.core.XWalkView;
class XWalkRuntimeTestHelper {
- class TestXWalkResourceClient extends XWalkResourceClientImpl {
+ class TestXWalkResourceClient extends XWalkResourceClient {
TestXWalkResourceClient(Context context, XWalkView view) {
- super(context, view);
+ super(view);
}
@Override
class TestXWalkClient extends XWalkClient {
TestXWalkClient(Context context, XWalkView view) {
- super(context, view);
+ super(view);
}
@Override
class TestXWalkWebChromeClient extends XWalkWebChromeClient {
TestXWalkWebChromeClient(Context context, XWalkView view) {
- super(context, view);
+ super(view);
}
@Override
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2014 Intel Corporation. All rights reserved.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.xwalk.core.sample"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="14"
+ android:targetSdkVersion="19" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <application
+ android:name="android.app.Application"
+ android:hardwareAccelerated="true"
+ android:icon="@drawable/crosswalk"
+ android:label="CrosswalkSample" >
+ <activity
+ android:name="org.xwalk.core.sample.XWalkEmbeddingAPISample"
+ android:label="Crosswalk Sample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.XWalkViewWithLayoutActivity"
+ android:label="XWalkView UI Inflation"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.MultiXWalkViewActivity"
+ android:label="Multiple XWalkView Instances"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.LoadAppFromManifestActivity"
+ android:label="Manifest"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.ResourceAndUIClientsActivity"
+ android:label="XWalkResourceClient and XWalkUIClient"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.XWalkPreferencesActivity"
+ android:label="Preferences"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.XWalkNavigationActivity"
+ android:label="Page Navigation"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.PauseTimersActivity"
+ android:label="Pause/Resume JavaScript Timers"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="org.xwalk.core.sample.OnHideOnShowActivity"
+ android:label="Visibility Change"
+ android:parentActivityName="org.xwalk.core.sample.XWalkEmbeddingAPISample" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
--- /dev/null
+<html>
+ <body>
+ Hello World.
+ <script>alert('Hello World!')</script>
+ </body>
+</html>
--- /dev/null
+{
+ "name": "ManifestTest",
+ "start_url": "index.html",
+ "app": {
+ "launch": {
+ "local_path": "index.html"
+ }
+ },
+ "description": "Manifest test",
+ "version": "1.0.0"
+}
--- /dev/null
+<!DOCTYPE html>
+<html>
+<body>
+
+<p>A script on this page starts this clock:</p>
+<p id="demo"></p>
+
+<script>
+ var myVar = setInterval(function(){ myTimer(); }, 1000);
+
+ function myTimer()
+ {
+ var d = new Date();
+ var t = d.toLocaleTimeString();
+ document.getElementById("demo").innerHTML = t;
+ }
+</script>
+
+</body>
+</html>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2014 Intel Corporation. All rights reserved.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="2"
+ android:orientation="vertical" >
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2014 Intel Corporation. All rights reserved.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <ImageButton
+ android:id="@+id/prev"
+ android:layout_width="38dp"
+ android:layout_height="38dp"
+ android:scaleType="center"
+ android:src="@android:drawable/ic_media_previous" />
+
+ <ImageButton
+ android:id="@+id/next"
+ android:layout_width="38dp"
+ android:layout_height="38dp"
+ android:scaleType="center"
+ android:src="@android:drawable/ic_media_next" />
+ </LinearLayout>
+
+ <org.xwalk.core.XWalkView
+ android:id="@+id/xwalkview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ </org.xwalk.core.XWalkView>
+
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2014 Intel Corporation. All rights reserved.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <ImageButton
+ android:id="@+id/pause"
+ android:layout_width="38dp"
+ android:layout_height="38dp"
+ android:scaleType="center"
+ android:src="@android:drawable/ic_media_pause" />
+ </LinearLayout>
+
+ <org.xwalk.core.XWalkView
+ android:id="@+id/xwalkview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ </org.xwalk.core.XWalkView>
+
+</LinearLayout>
--- /dev/null
+<!--
+ Copyright (c) 2014 Intel Corporation. All rights reserved.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<org.xwalk.core.XWalkView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/xwalkview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+</org.xwalk.core.XWalkView>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+Copyright (c) 2013-2014 Intel Corporation. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<resources>
+
+</resources>
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkView;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class LoadAppFromManifestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.xwview_layout);
+ XWalkView xwalkView = (XWalkView) findViewById(R.id.xwalkview);
+
+ // The manifest definition, please refer to the link:
+ // https://crosswalk-project.org/#wiki/Crosswalk-manifest
+ xwalkView.loadAppFromManifest("file:///android_asset/manifest.json", null);
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkView;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+
+public class MultiXWalkViewActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.container);
+ LinearLayout parent = (LinearLayout) findViewById(R.id.container);
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT);
+ params.weight = 1;
+
+ XWalkView view1 = new XWalkView(this, this);
+ parent.addView(view1, params);
+
+ XWalkView view2 = new XWalkView(this, this);
+ parent.addView(view2, params);
+
+ view1.load("http://www.intel.com", null);
+ view2.load("http://www.baidu.com", null);
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkView;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class OnHideOnShowActivity extends Activity {
+
+ private XWalkView mXWalkView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.xwview_layout);
+ mXWalkView = (XWalkView) findViewById(R.id.xwalkview);
+
+ mXWalkView.load("http://www.w3.org/2010/05/video/mediaevents.html", null);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ // It will pause the video, when the app in background.
+ mXWalkView.onHide();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Need to call onShow() when onHide() was called.
+ mXWalkView.onShow();
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkView;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+
+public class PauseTimersActivity extends Activity {
+
+ private ImageButton mButton;
+ private boolean isPaused;
+ XWalkView mXWalkView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.pause_timers_layout);
+ mXWalkView = (XWalkView) findViewById(R.id.xwalkview);
+
+ isPaused = false;
+ mButton = (ImageButton) findViewById(R.id.pause);
+ mButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mXWalkView != null) {
+ if (!isPaused) {
+ // Pause JS timer
+ mXWalkView.pauseTimers();
+ isPaused = true;
+ mButton.setImageResource(android.R.drawable.ic_media_play);
+ } else {
+ // Resume JS timer
+ mXWalkView.resumeTimers();
+ isPaused = false;
+ mButton.setImageResource(android.R.drawable.ic_media_pause);
+ }
+ }
+ }
+ });
+ mXWalkView.load("file:///android_asset/pause_timers.html", null);
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkJavascriptResult;
+import org.xwalk.core.XWalkResourceClient;
+import org.xwalk.core.XWalkUIClient;
+import org.xwalk.core.XWalkView;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.webkit.ValueCallback;
+import android.webkit.WebResourceResponse;
+
+public class ResourceAndUIClientsActivity extends Activity {
+
+ private static final String TAG = ResourceAndUIClientsActivity.class.getName();
+
+ class ResourceCLient extends XWalkResourceClient {
+
+ public ResourceCLient(XWalkView xwalkView) {
+ super(xwalkView);
+ }
+
+ public void onLoadStarted(XWalkView view, String url) {
+ super.onLoadStarted(view, url);
+ Log.d(TAG, "Load Started:" + url);
+ }
+
+ public void onLoadFinished(XWalkView view, String url) {
+ super.onLoadFinished(view, url);
+ Log.d(TAG, "Load Finished:" + url);
+ }
+
+ public void onProgressChanged(XWalkView view, int progressInPercent) {
+ super.onProgressChanged(view, progressInPercent);
+ Log.d(TAG, "Loading Progress:" + progressInPercent);
+ }
+
+ public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) {
+ Log.d(TAG, "Intercept load request");
+ return super.shouldInterceptLoadRequest(view, url);
+ }
+
+ public void onReceivedLoadError(XWalkView view, int errorCode, String description,
+ String failingUrl) {
+ Log.d(TAG, "Load Failed:" + description);
+ super.onReceivedLoadError(view, errorCode, description, failingUrl);
+ }
+ }
+
+ class UIClient extends XWalkUIClient {
+
+ public UIClient(XWalkView xwalkView) {
+ super(xwalkView);
+ }
+
+ public void onJavascriptCloseWindow(XWalkView view) {
+ super.onJavascriptCloseWindow(view);
+ Log.d(TAG, "Window closed.");
+ }
+
+ public boolean onJavascriptModalDialog(XWalkView view, JavascriptMessageType type,
+ String url,
+ String message, String defaultValue, XWalkJavascriptResult result) {
+ Log.d(TAG, "Show JS dialog.");
+ return super.onJavascriptModalDialog(view, type, url, message, defaultValue, result);
+ }
+
+ public void onFullscreenToggled(XWalkView view, boolean enterFullscreen) {
+ super.onFullscreenToggled(view, enterFullscreen);
+ if (enterFullscreen) {
+ Log.d(TAG, "Entered fullscreen.");
+ } else {
+ Log.d(TAG, "Exited fullscreen.");
+ }
+ }
+
+ public void openFileChooser(XWalkView view, ValueCallback<Uri> uploadFile,
+ String acceptType, String capture) {
+ super.openFileChooser(view, uploadFile, acceptType, capture);
+ Log.d(TAG, "Opened file chooser.");
+ }
+
+ public void onScaleChanged(XWalkView view, float oldScale, float newScale) {
+ super.onScaleChanged(view, oldScale, newScale);
+ Log.d(TAG, "Scale changed.");
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.xwview_layout);
+ XWalkView xwalkView = (XWalkView) findViewById(R.id.xwalkview);
+ xwalkView.setResourceClient(new ResourceCLient(xwalkView));
+ xwalkView.setUIClient(new UIClient(xwalkView));
+ xwalkView.load("http://www.baidu.com", null);
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class XWalkEmbeddingAPISample extends ListActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setListAdapter(new SampleAdapter());
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onListItemClick(ListView lv, View v, int pos, long id) {
+ SampleInfo info = (SampleInfo) getListAdapter().getItem(pos);
+ startActivity(info.intent);
+ }
+
+ static class SampleInfo {
+ String name;
+ Intent intent;
+
+ SampleInfo(String name, Intent intent) {
+ this.name = name;
+ this.intent = intent;
+ }
+ }
+
+ class SampleAdapter extends BaseAdapter {
+ private ArrayList<SampleInfo> mItems;
+
+ public SampleAdapter() {
+ Intent intent = new Intent(Intent.ACTION_MAIN, null);
+ intent.setPackage(getPackageName());
+ intent.addCategory(Intent.CATEGORY_SAMPLE_CODE);
+
+ PackageManager pm = getPackageManager();
+ List<ResolveInfo> infos = pm.queryIntentActivities(intent, 0);
+
+ mItems = new ArrayList<SampleInfo>();
+
+ final int count = infos.size();
+ for (int i = 0; i < count; i++) {
+ final ResolveInfo info = infos.get(i);
+ final CharSequence labelSeq = info.loadLabel(pm);
+ String label = labelSeq != null ? labelSeq.toString() : info.activityInfo.name;
+
+ Intent target = new Intent();
+ target.setClassName(info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ SampleInfo sample = new SampleInfo(label, target);
+ mItems.add(sample);
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return mItems.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mItems.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(android.R.layout.simple_list_item_1,
+ parent, false);
+ }
+ TextView tv = (TextView) convertView.findViewById(android.R.id.text1);
+ SampleInfo info = mItems.get(position);
+ tv.setText(info.name);
+ return convertView;
+ }
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkView;
+import org.xwalk.core.XWalkNavigationHistory;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+
+public class XWalkNavigationActivity extends Activity {
+
+ private ImageButton mNextButton;
+ private ImageButton mPrevButton;
+ private XWalkView mXWalkView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.navigation_layout);
+ mPrevButton = (ImageButton) findViewById(R.id.prev);
+ mNextButton = (ImageButton) findViewById(R.id.next);
+ mXWalkView = (XWalkView) findViewById(R.id.xwalkview);
+
+ mPrevButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Go backward
+ if (mXWalkView != null &&
+ mXWalkView.getNavigationHistory().canGoBack()) {
+ mXWalkView.getNavigationHistory().navigate(
+ XWalkNavigationHistory.Direction.BACKWARD, 1);
+ }
+ }
+ });
+
+ mNextButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Go forward
+ if (mXWalkView != null &&
+ mXWalkView.getNavigationHistory().canGoForward()) {
+ mXWalkView.getNavigationHistory().navigate(
+ XWalkNavigationHistory.Direction.FORWARD, 1);
+ }
+ }
+ });
+
+ mXWalkView.load("http://www.baidu.com/", null);
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkPreferences;
+import org.xwalk.core.XWalkView;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class XWalkPreferencesActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.xwview_layout);
+ XWalkView xwalkView = (XWalkView) findViewById(R.id.xwalkview);
+
+ // Enable remote debugging.
+ // You can debug the web content via PC chrome.
+ XWalkPreferences.setValue(XWalkPreferences.REMOTE_DEBUGGING, true);
+
+ xwalkView.load("http://www.baidu.com/", null);
+ }
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.core.sample;
+
+import org.xwalk.core.XWalkView;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class XWalkViewWithLayoutActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.xwview_layout);
+ XWalkView xwalkView = (XWalkView) findViewById(R.id.xwalkview);
+ xwalkView.load("http://www.baidu.com/", null);
+ }
+}
#include "xwalk/runtime/browser/android/xwalk_dev_tools_server.h"
#include "xwalk/runtime/browser/android/xwalk_http_auth_handler.h"
#include "xwalk/runtime/browser/android/xwalk_settings.h"
+#include "xwalk/runtime/browser/android/xwalk_view_delegate.h"
#include "xwalk/runtime/browser/android/xwalk_web_contents_delegate.h"
namespace xwalk {
{ "XWalkExtensionAndroid", extensions::RegisterXWalkExtensionAndroid },
{ "XWalkHttpAuthHandler", RegisterXWalkHttpAuthHandler },
{ "XWalkSettings", RegisterXWalkSettings },
+ { "XWalkViewDelegate", RegisterXWalkViewDelegate },
{ "XWalkWebContentsDelegate", RegisterXWalkWebContentsDelegate },
};
XWalkRenderViewHostExt::XWalkRenderViewHostExt(content::WebContents* contents)
: content::WebContentsObserver(contents),
- has_new_hit_test_data_(false) {
+ has_new_hit_test_data_(false),
+ is_render_view_created_(false) {
}
XWalkRenderViewHostExt::~XWalkRenderViewHostExt() {}
page_scale_factor));
}
+void XWalkRenderViewHostExt::RenderViewCreated(
+ content::RenderViewHost* render_view_host) {
+ if (!pending_base_url_.empty()) {
+ Send(new XWalkViewMsg_SetOriginAccessWhitelist(
+ pending_base_url_, pending_match_patterns_));
+ }
+ is_render_view_created_ = true;
+}
+
void XWalkRenderViewHostExt::SetJsOnlineProperty(bool network_up) {
Send(new XWalkViewMsg_SetJsOnlineProperty(network_up));
}
has_new_hit_test_data_ = true;
}
+void XWalkRenderViewHostExt::SetOriginAccessWhitelist(
+ const std::string& base_url,
+ const std::string& match_patterns) {
+ DCHECK(CalledOnValidThread());
+ pending_base_url_ = base_url;
+ pending_match_patterns_ = match_patterns;
+
+ if (is_render_view_created_) {
+ Send(new XWalkViewMsg_SetOriginAccessWhitelist(
+ pending_base_url_, pending_match_patterns_));
+ }
+}
+
} // namespace xwalk
#define XWALK_RUNTIME_BROWSER_ANDROID_RENDERER_HOST_XWALK_RENDER_VIEW_HOST_EXT_H_
#include <map>
+#include <string>
#include "base/callback_forward.h"
#include "base/threading/non_thread_safe.h"
void SetInitialPageScale(double page_scale_factor);
void SetJsOnlineProperty(bool network_up);
+ // Sets the white list for Cross-Origin access.
+ void SetOriginAccessWhitelist(const std::string& base_url,
+ const std::string& permissions);
+
private:
// content::WebContentsObserver implementation.
+ virtual void RenderViewCreated(
+ content::RenderViewHost* render_view_host) OVERRIDE;
virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
virtual void DidNavigateAnyFrame(
const content::LoadCommittedDetails& details,
bool has_new_hit_test_data_;
+ std::string pending_base_url_;
+ std::string pending_match_patterns_;
+ bool is_render_view_created_;
+
DISALLOW_COPY_AND_ASSIGN(XWalkRenderViewHostExt);
};
#include "base/android/jni_string.h"
#include "base/base_paths_android.h"
#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "content/public/browser/browser_context.h"
using navigation_interception::InterceptNavigationDelegate;
using xwalk::application_manifest_keys::kDisplay;
+namespace keys = xwalk::application_manifest_keys;
+
namespace xwalk {
namespace {
return XWalkContentUserData::GetContents(web_contents);
}
-jint XWalkContent::GetWebContents(
+jlong XWalkContent::GetWebContents(
JNIEnv* env, jobject obj, jobject io_thread_client,
jobject intercept_navigation_delegate) {
if (!web_contents_) {
render_view_host_ext_.reset(
new XWalkRenderViewHostExt(web_contents_.get()));
}
- return reinterpret_cast<jint>(web_contents_.get());
+ return reinterpret_cast<intptr_t>(web_contents_.get());
}
content::WebContents* XWalkContent::CreateWebContents(
manifest_dictionary_ptr.Pass());
std::string url;
- if (manifest.GetString(
- xwalk::application_manifest_keys::kLaunchLocalPathKey, &url)) {
+ if (manifest.GetString(keys::kLaunchLocalPathKey, &url)) {
// According to original proposal for "app:launch:local_path", the "http"
// and "https" schemes are supported. So |url| should do nothing when it
// already has "http" or "https" scheme.
if (scheme != content::kHttpScheme && scheme != content::kHttpsScheme)
url = path_str + url;
} else {
- manifest.GetString(
- xwalk::application_manifest_keys::kLaunchWebURLKey, &url);
+ manifest.GetString(keys::kLaunchWebURLKey, &url);
+ }
+
+ std::string match_patterns;
+ const base::ListValue* xwalk_hosts = NULL;
+ if (manifest.GetList(
+ xwalk::application_manifest_keys::kXWalkHostsKey, &xwalk_hosts)) {
+ base::JSONWriter::Write(xwalk_hosts, &match_patterns);
}
+ render_view_host_ext_->SetOriginAccessWhitelist(url, match_patterns);
std::string csp;
- manifest.GetString(
- xwalk::application_manifest_keys::kCSPKey, &csp);
+ manifest.GetString(keys::kCSPKey, &csp);
RuntimeContext* runtime_context =
XWalkRunner::GetInstance()->runtime_context();
CHECK(runtime_context);
}
// Check whether need to display launch screen. (Read from manifest.json)
- if (manifest.HasPath(
- xwalk::application_manifest_keys::kLaunchScreen)) {
+ if (manifest.HasPath(keys::kLaunchScreen)) {
std::string ready_when;
- // Get the value of 'ready_when' from manifest.json and callback
- // to Java side.
- manifest.GetString(
- xwalk::application_manifest_keys::kLaunchScreenReadyWhen, &ready_when);
+ // Get the value of 'ready_when' from manifest.json
+ manifest.GetString(keys::kLaunchScreenReadyWhen, &ready_when);
ScopedJavaLocalRef<jstring> ready_when_buffer =
base::android::ConvertUTF8ToJavaString(env, ready_when);
+
+ // Get the value of 'image_border'
+ // 1. When 'launch_screen.[orientation]' was defined, but no 'image_border'
+ // The value of 'image_border' will be set as 'empty'.
+ // 2. Otherwise, there is no 'launch_screen.[orientation]' defined,
+ // The value of 'image_border' will be empty.
+ const char empty[] = "empty";
+ std::string image_border_default;
+ manifest.GetString(keys::kLaunchScreenImageBorderDefault,
+ &image_border_default);
+ if (image_border_default.empty() && manifest.HasPath(
+ keys::kLaunchScreenDefault)) {
+ image_border_default = empty;
+ }
+
+ std::string image_border_landscape;
+ manifest.GetString(keys::kLaunchScreenImageBorderLandscape,
+ &image_border_landscape);
+ if (image_border_landscape.empty() && manifest.HasPath(
+ keys::kLaunchScreenLandscape)) {
+ image_border_landscape = empty;
+ }
+
+ std::string image_border_portrait;
+ manifest.GetString(keys::kLaunchScreenImageBorderPortrait,
+ &image_border_portrait);
+ if (image_border_portrait.empty() && manifest.HasPath(
+ keys::kLaunchScreenPortrait)) {
+ image_border_portrait = empty;
+ }
+
+ std::string image_border = image_border_default + ';' +
+ image_border_landscape + ';' + image_border_portrait;
+ ScopedJavaLocalRef<jstring> image_border_buffer =
+ base::android::ConvertUTF8ToJavaString(env, image_border);
+
Java_XWalkContent_onGetUrlAndLaunchScreenFromManifest(
- env, obj, url_buffer.obj(), ready_when_buffer.obj());
+ env, obj, url_buffer.obj(), ready_when_buffer.obj(),
+ image_border_buffer.obj());
} else {
// No need to display launch screen, load the url directly.
Java_XWalkContent_onGetUrlFromManifest(env, obj, url_buffer.obj());
return RestoreFromPickle(&iterator, web_contents_.get());
}
-static jint Init(JNIEnv* env, jobject obj, jobject web_contents_delegate,
+static jlong Init(JNIEnv* env, jobject obj, jobject web_contents_delegate,
jobject contents_client_bridge) {
XWalkContent* xwalk_core_content =
new XWalkContent(env, obj, web_contents_delegate, contents_client_bridge);
- return reinterpret_cast<jint>(xwalk_core_content);
+ return reinterpret_cast<intptr_t>(xwalk_core_content);
}
bool RegisterXWalkContent(JNIEnv* env) {
void XWalkContent::ShowGeolocationPrompt(
const GURL& requesting_frame,
- const base::Callback<void(bool)>& callback) {
+ const base::Callback<void(bool)>& callback) { // NOLINT
GURL origin = requesting_frame.GetOrigin();
bool show_prompt = pending_geolocation_prompts_.empty();
pending_geolocation_prompts_.push_back(OriginCallback(origin, callback));
static XWalkContent* FromID(int render_process_id, int render_view_id);
static XWalkContent* FromWebContents(content::WebContents* web_contents);
- jint GetWebContents(JNIEnv* env, jobject obj, jobject io_thread_client,
+ jlong GetWebContents(JNIEnv* env, jobject obj, jobject io_thread_client,
jobject delegate);
void ClearCache(JNIEnv* env, jobject obj, jboolean include_disk_files);
ScopedJavaLocalRef<jstring> DevToolsAgentId(JNIEnv* env, jobject obj);
// Geolocation API support
void ShowGeolocationPrompt(const GURL& origin,
- const base::Callback<void(bool)>& callback);
+ const base::Callback<void(bool)>& callback); // NOLINT
void HideGeolocationPrompt(const GURL& origin);
void InvokeGeolocationCallback(JNIEnv* env,
jobject obj,
// GURL is supplied by the content layer as requesting frame.
// Callback is supplied by the content layer, and is invoked with the result
// from the permission prompt.
- typedef std::pair<const GURL, const base::Callback<void(bool)> > \
+ typedef std::pair<const GURL, const base::Callback<void(bool)> > /* NOLINT */ \
OriginCallback;
// The first element in the list is always the currently pending request.
std::list<OriginCallback> pending_geolocation_prompts_;
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/file_chooser_params.h"
#include "content/public/common/show_desktop_notification_params.h"
#include "jni/XWalkContentsClientBridge_jni.h"
#include "net/cert/x509_certificate.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "url/gurl.h"
#include "ui/gfx/android/java_bitmap.h"
+#include "ui/shell_dialogs/selected_file_info.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
using content::BrowserThread;
+using content::FileChooserParams;
using content::RenderViewHost;
using content::WebContents;
: java_ref_(env, obj) {
DCHECK(obj);
Java_XWalkContentsClientBridge_setNativeContentsClientBridge(
- env, obj, reinterpret_cast<jint>(this));
+ env, obj, reinterpret_cast<intptr_t>(this));
}
XWalkContentsClientBridge::~XWalkContentsClientBridge() {
int cert_error,
net::X509Certificate* cert,
const GURL& request_url,
- const base::Callback<void(bool)>& callback,
+ const base::Callback<void(bool)>& callback, // NOLINT
bool* cancel_request) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
void XWalkContentsClientBridge::ExitFullscreen(
- JNIEnv*, jobject, jint j_web_contents) {
+ JNIEnv*, jobject, jlong j_web_contents) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
WebContents* web_contents = reinterpret_cast<WebContents*>(j_web_contents);
if (web_contents) {
rvh->DesktopNotificationPostClose(id, by_user);
}
+void XWalkContentsClientBridge::OnFilesSelected(
+ JNIEnv* env, jobject, int process_id, int render_id,
+ int mode, jstring filepath, jstring display_name) {
+ content::RenderViewHost* rvh =
+ content::RenderViewHost::FromID(process_id, render_id);
+ if (!rvh)
+ return;
+
+ std::string path = base::android::ConvertJavaStringToUTF8(env, filepath);
+ std::string file_name =
+ base::android::ConvertJavaStringToUTF8(env, display_name);
+ base::FilePath file_path = base::FilePath(path);
+ ui::SelectedFileInfo file_info;
+ file_info.file_path = file_path;
+ file_info.local_path = file_path;
+ if (!file_name.empty())
+ file_info.display_name = file_name;
+ std::vector<ui::SelectedFileInfo> files;
+ files.push_back(file_info);
+
+ rvh->FilesSelectedInChooser(
+ files, static_cast<content::FileChooserParams::Mode>(mode));
+}
+
+void XWalkContentsClientBridge::OnFilesNotSelected(
+ JNIEnv* env, jobject, int process_id, int render_id, int mode) {
+ content::RenderViewHost* rvh =
+ content::RenderViewHost::FromID(process_id, render_id);
+ if (!rvh)
+ return;
+
+ std::vector<ui::SelectedFileInfo> files;
+
+ rvh->FilesSelectedInChooser(
+ files, static_cast<content::FileChooserParams::Mode>(mode));
+}
+
bool RegisterXWalkContentsClientBridge(JNIEnv* env) {
return RegisterNativesImpl(env) >= 0;
}
virtual void AllowCertificateError(int cert_error,
net::X509Certificate* cert,
const GURL& request_url,
- const base::Callback<void(bool)>& callback,
+ const base::Callback<void(bool)>& callback, // NOLINT
bool* cancel_request) OVERRIDE;
virtual void RunJavaScriptDialog(
void ProceedSslError(JNIEnv* env, jobject obj, jboolean proceed, jint id);
void ConfirmJsResult(JNIEnv*, jobject, int id, jstring prompt);
void CancelJsResult(JNIEnv*, jobject, int id);
- void ExitFullscreen(JNIEnv*, jobject, jint web_contents);
+ void ExitFullscreen(JNIEnv*, jobject, jlong web_contents);
void NotificationDisplayed(
JNIEnv*, jobject, int id, int process_id, int route_id);
void NotificationError(
JNIEnv*, jobject, int id, int process_id, int route_id);
void NotificationClosed(
JNIEnv*, jobject, int id, bool by_user, int process_id, int route_id);
+ void OnFilesSelected(
+ JNIEnv*, jobject, int process_id, int render_id,
+ int mode, jstring filepath, jstring display_name);
+ void OnFilesNotSelected(
+ JNIEnv*, jobject, int process_id, int render_id, int mode);
private:
JavaObjectWeakGlobalRef java_ref_;
- typedef const base::Callback<void(bool)> CertErrorCallback;
+ typedef const base::Callback<void(bool)> CertErrorCallback; // NOLINT
IDMap<CertErrorCallback, IDMapOwnPointer> pending_cert_error_callbacks_;
IDMap<content::JavaScriptDialogManager::DialogClosedCallback, IDMapOwnPointer>
pending_js_dialog_callbacks_;
return RegisterNativesImpl(env);
}
-static jint InitRemoteDebugging(JNIEnv* env,
+static jlong InitRemoteDebugging(JNIEnv* env,
jobject obj,
jstring socketName) {
XWalkDevToolsServer* server = new XWalkDevToolsServer(
base::android::ConvertJavaStringToUTF8(env, socketName));
- return reinterpret_cast<jint>(server);
+ return reinterpret_cast<intptr_t>(server);
}
-static void DestroyRemoteDebugging(JNIEnv* env, jobject obj, jint server) {
+static void DestroyRemoteDebugging(JNIEnv* env, jobject obj, jlong server) {
delete reinterpret_cast<XWalkDevToolsServer*>(server);
}
static jboolean IsRemoteDebuggingEnabled(JNIEnv* env,
jobject obj,
- jint server) {
+ jlong server) {
return reinterpret_cast<XWalkDevToolsServer*>(server)->IsStarted();
}
static void SetRemoteDebuggingEnabled(JNIEnv* env,
jobject obj,
- jint server,
+ jlong server,
jboolean enabled) {
XWalkDevToolsServer* devtools_server =
reinterpret_cast<XWalkDevToolsServer*>(server);
static void AllowConnectionFromUid(JNIEnv* env,
jobject obj,
- jint server,
+ jlong server,
jint uid) {
XWalkDevToolsServer* devtools_server =
reinterpret_cast<XWalkDevToolsServer*>(server);
JNIEnv* env = base::android::AttachCurrentThread();
http_auth_handler_.Reset(
Java_XWalkHttpAuthHandler_create(
- env, reinterpret_cast<jint>(this), first_auth_attempt));
+ env, reinterpret_cast<intptr_t>(this), first_auth_attempt));
}
XWalkHttpAuthHandler:: ~XWalkHttpAuthHandler() {
jfieldID default_video_poster_url;
};
-XWalkSettings::XWalkSettings(JNIEnv* env, jobject obj, jint web_contents)
+XWalkSettings::XWalkSettings(JNIEnv* env, jobject obj, jlong web_contents)
: WebContentsObserver(
reinterpret_cast<content::WebContents*>(web_contents)),
xwalk_settings_(env, obj) {
ScopedJavaLocalRef<jobject> scoped_obj = xwalk_settings_.get(env);
jobject obj = scoped_obj.obj();
if (!obj) return;
- Java_XWalkSettings_nativeXWalkSettingsGone(env, obj,
- reinterpret_cast<jint>(this));
+ Java_XWalkSettings_nativeXWalkSettingsGone(
+ env, obj, reinterpret_cast<intptr_t>(this));
}
void XWalkSettings::Destroy(JNIEnv* env, jobject obj) {
UpdateEverything();
}
-static jint Init(JNIEnv* env,
+static jlong Init(JNIEnv* env,
jobject obj,
- jint web_contents) {
+ jlong web_contents) {
XWalkSettings* settings = new XWalkSettings(env, obj, web_contents);
- return reinterpret_cast<jint>(settings);
+ return reinterpret_cast<intptr_t>(settings);
}
static jstring GetDefaultUserAgent(JNIEnv* env, jclass clazz) {
class XWalkSettings : public content::WebContentsObserver {
public:
- XWalkSettings(JNIEnv* env, jobject obj, jint web_contents);
+ XWalkSettings(JNIEnv* env, jobject obj, jlong web_contents);
virtual ~XWalkSettings();
// Called from Java.
--- /dev/null
+// Copyright (c) 2014 Intel Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/runtime/browser/android/xwalk_view_delegate.h"
+
+#include "base/android/jni_android.h"
+#include "jni/XWalkViewDelegate_jni.h"
+
+namespace xwalk {
+
+jboolean IsLibraryBuiltForIA(JNIEnv* env, jclass jcaller) {
+#if defined(ARCH_CPU_X86)
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+bool RegisterXWalkViewDelegate(JNIEnv* env) {
+ return RegisterNativesImpl(env) >= 0;
+}
+
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_RUNTIME_BROWSER_ANDROID_XWALK_VIEW_DELEGATE_H_
+#define XWALK_RUNTIME_BROWSER_ANDROID_XWALK_VIEW_DELEGATE_H_
+
+#include <jni.h>
+
+namespace xwalk {
+
+bool RegisterXWalkViewDelegate(JNIEnv* env);
+
+} // namespace xwalk
+
+#endif // XWALK_RUNTIME_BROWSER_ANDROID_XWALK_VIEW_DELEGATE_H_
#include "xwalk/runtime/browser/android/xwalk_web_contents_delegate.h"
+#include <vector>
+
+#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/common/file_chooser_params.h"
#include "jni/XWalkWebContentsDelegate_jni.h"
#include "xwalk/runtime/browser/media/media_capture_devices_dispatcher.h"
#include "xwalk/runtime/browser/runtime_file_select_helper.h"
#include "xwalk/runtime/browser/runtime_javascript_dialog_manager.h"
+#include "ui/shell_dialogs/selected_file_info.h"
using base::android::AttachCurrentThread;
+using base::android::ConvertUTF16ToJavaString;
using base::android::ScopedJavaLocalRef;
+using content::FileChooserParams;
using content::WebContents;
namespace xwalk {
void XWalkWebContentsDelegate::RunFileChooser(
content::WebContents* web_contents,
const content::FileChooserParams& params) {
- RuntimeFileSelectHelper::RunFileChooser(web_contents, params);
+ JNIEnv* env = AttachCurrentThread();
+
+ ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
+ if (!java_delegate.obj())
+ return;
+
+ if (params.mode == FileChooserParams::Save) {
+ // Save not supported, so cancel it.
+ web_contents->GetRenderViewHost()->FilesSelectedInChooser(
+ std::vector<ui::SelectedFileInfo>(),
+ params.mode);
+ return;
+ }
+ int mode = static_cast<int>(params.mode);
+ jboolean overridden =
+ Java_XWalkWebContentsDelegate_shouldOverrideRunFileChooser(env,
+ java_delegate.obj(),
+ web_contents->GetRenderProcessHost()->GetID(),
+ web_contents->GetRenderViewHost()->GetRoutingID(),
+ mode,
+ ConvertUTF16ToJavaString(env,
+ JoinString(params.accept_types, ',')).obj(),
+ params.capture);
+ if (overridden == JNI_FALSE)
+ RuntimeFileSelectHelper::RunFileChooser(web_contents, params);
}
content::JavaScriptDialogManager*
int valid_type_count = 0;
int description_id = 0;
for (size_t i = 0; i < accept_types.size(); ++i) {
- std::string ascii_type = UTF16ToASCII(accept_types[i]);
+ std::string ascii_type = base::UTF16ToASCII(accept_types[i]);
if (!IsAcceptTypeValid(ascii_type))
continue;
#include "xwalk/runtime/browser/runtime_platform_util.h"
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "url/gurl.h"
namespace platform_util {
+namespace {
+// The system default web browser path.
+// In some Tizen releases, there exists a system browser called 'MiniBrowser',
+// which we can use to open an external link from a web app.
+const char kWebBrowserPath[] = "/usr/bin/MiniBrowser";
+} // namespace
void OpenExternal(const GURL& url) {
if (url.SchemeIsHTTPOrHTTPS()) {
- LOG(INFO) << "Open in MiniBrowser.";
+ LOG(INFO) << "Open in WebBrowser.";
std::vector<std::string> argv;
- argv.push_back("MiniBrowser");
+ if (base::PathExists(base::FilePath(kWebBrowserPath)))
+ argv.push_back(kWebBrowserPath);
+ else
+ argv.push_back("xwalk");
argv.push_back(url.spec());
base::ProcessHandle handle;
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/runtime/browser/tizen/tizen_locale_listener.h"
+
+#include <vconf.h>
+#include <algorithm>
+
+#include "base/logging.h"
+#include "content/public/browser/browser_thread.h"
+#include "xwalk/runtime/browser/xwalk_runner_tizen.h"
+#include "xwalk/application/browser/application_system.h"
+#include "xwalk/application/browser/application_service.h"
+
+namespace xwalk {
+namespace {
+const char kTizenDefaultLocale[] = "en-GB";
+const char kTizenLocaleListenerThreadName[] = "TizenLocaleListener";
+
+bool TizenLocaleToBCP47Locale(const std::string& tizen_locale,
+ std::string* out_BCP47_locale) {
+ if (tizen_locale.empty())
+ return false;
+
+ // Tizen locale format [language[_territory][.codeset][@modifier]] .
+ // Conver to BCP47 format language[-territory] .
+ *out_BCP47_locale = tizen_locale.substr(0, tizen_locale.find_first_of("."));
+ std::replace(out_BCP47_locale->begin(), out_BCP47_locale->end(), '_', '-');
+ return true;
+}
+
+void OnVconfLangSetChanged(keynode_t *key, void *user_data) {
+ if (vconf_keynode_get_type(key) != VCONF_TYPE_STRING)
+ return;
+ TizenLocaleListener* tizen_locale_listener =
+ static_cast<TizenLocaleListener*>(user_data);
+
+ std::string locale;
+ if (TizenLocaleToBCP47Locale(vconf_keynode_get_str(key), &locale)) {
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&TizenLocaleListener::SetLocale,
+ base::Unretained(tizen_locale_listener),
+ locale));
+ }
+}
+
+std::string GetSystemLocale() {
+ std::string tizen_locale;
+ char* langset = vconf_get_str(VCONFKEY_LANGSET);
+ if (langset) {
+ tizen_locale = langset;
+ } else {
+ LOG(ERROR) << "Can not get VCONFKEY_LANGSET from vconf or "
+ << "VCONFKEY_LANGSET vlaue is not a string value";
+ }
+ free(langset);
+
+ // Tizen take en-GB as default.
+ std::string BCP47_locale(kTizenDefaultLocale);
+ TizenLocaleToBCP47Locale(tizen_locale, &BCP47_locale);
+ return BCP47_locale;
+}
+
+} // namespace
+
+TizenLocaleListener::TizenLocaleListener()
+ : SimpleThread(kTizenLocaleListenerThreadName),
+ locale_(GetSystemLocale()) {
+ vconf_notify_key_changed(VCONFKEY_LANGSET, OnVconfLangSetChanged, this);
+ main_loop_ = g_main_loop_new(NULL, FALSE);
+ Start();
+}
+
+TizenLocaleListener::~TizenLocaleListener() {
+ g_main_loop_quit(main_loop_);
+ g_main_loop_unref(main_loop_);
+ SimpleThread::Join();
+ vconf_ignore_key_changed(VCONFKEY_LANGSET, OnVconfLangSetChanged);
+}
+
+void TizenLocaleListener::Run() {
+ g_main_loop_run(main_loop_);
+}
+
+std::string TizenLocaleListener::GetLocale() const {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Note: we can only get locale from main thread for thread safe.
+ return locale_;
+}
+
+void TizenLocaleListener::SetLocale(const std::string& locale) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // Note: we can only set locale from main thread for thread safe.
+ // If you need set locale from other thread, please PostTask to main thread.
+ if (locale_ == locale)
+ return;
+
+ LOG(INFO) << "Locale change from " << locale_ << " to " << locale;
+ locale_ = locale;
+
+ application::ApplicationSystem* application_system_ =
+ XWalkRunnerTizen::GetInstance()->app_system();
+ if (application_system_)
+ application_system_->application_service()->ChangeLocale(locale);
+}
+
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_RUNTIME_BROWSER_TIZEN_TIZEN_LOCALE_LISTENER_H_
+#define XWALK_RUNTIME_BROWSER_TIZEN_TIZEN_LOCALE_LISTENER_H_
+
+#include <glib.h>
+#include <string>
+
+#include "base/threading/simple_thread.h"
+
+namespace xwalk {
+
+class TizenLocaleListener : public base::SimpleThread {
+ public:
+ TizenLocaleListener();
+ virtual ~TizenLocaleListener();
+
+ virtual void Run() OVERRIDE;
+
+ // Get the latest application locale from system.
+ // locale is a langtag defined in [BCP47]
+ std::string GetLocale() const;
+ // Set the locale and apply this locale to all applications.
+ // Locale is a langtag defined in [BCP47].
+ // This function will called by TizenLocaleListener when locale is changed.
+ void SetLocale(const std::string& locale);
+
+ private:
+ GMainLoop* main_loop_;
+ // The locale is a langtag defined in [BCP47]
+ std::string locale_;
+};
+
+} // namespace xwalk
+
+#endif // XWALK_RUNTIME_BROWSER_TIZEN_TIZEN_LOCALE_LISTENER_H_
// This method assumed a fixed portrait device. As everything
// is calculated from the fixed position we do not update the
// display bounds after rotation change.
+ // FIXME : Add proper support for landscape devices.
gfx::Transform rotate;
float one_pixel = 1.0f / display_.device_scale_factor();
switch (display_.rotation()) {
namespace {
-// Rotates a binary mask of 4 positions to the left.
-unsigned rotl4(unsigned value, int shift) {
- unsigned res = (value << shift);
- if (res > (1 << 4) - 1)
- res = res >> 4;
- return res;
+#if defined(OS_TIZEN_MOBILE)
+Orientation ToOrientation(const gfx::Display::Rotation& rotation) {
+ switch (rotation) {
+ case gfx::Display::ROTATE_0:
+ return PORTRAIT_PRIMARY;
+ case gfx::Display::ROTATE_90:
+ return LANDSCAPE_PRIMARY;
+ case gfx::Display::ROTATE_180:
+ return PORTRAIT_SECONDARY;
+ case gfx::Display::ROTATE_270:
+ return LANDSCAPE_SECONDARY;
+ default:
+ NOTREACHED();
+ }
+ return PORTRAIT_PRIMARY;
+}
+#else
+Orientation ToOrientation(const gfx::Display::Rotation& rotation) {
+ switch (rotation) {
+ case gfx::Display::ROTATE_0:
+ return LANDSCAPE_PRIMARY;
+ case gfx::Display::ROTATE_90:
+ return PORTRAIT_PRIMARY;
+ case gfx::Display::ROTATE_180:
+ return LANDSCAPE_SECONDARY;
+ case gfx::Display::ROTATE_270:
+ return PORTRAIT_SECONDARY;
+ default:
+ NOTREACHED();
+ }
+ return LANDSCAPE_PRIMARY;
+}
+#endif
+
+inline gfx::Display::Rotation ToRotation(unsigned rotation) {
+ return static_cast<gfx::Display::Rotation>(rotation % 4);
}
bool IsLandscapeOrientation(const gfx::Display::Rotation& rotation) {
- return rotation == gfx::Display::ROTATE_90 ||
- rotation == gfx::Display::ROTATE_270;
+ return ToOrientation(rotation) & LANDSCAPE;
}
} // namespace.
gfx::Display::Rotation NativeAppWindowTizen::GetClosestAllowedRotation(
gfx::Display::Rotation rotation) const {
- unsigned result = PORTRAIT_PRIMARY;
- // gfx::Display::Rotation starts at portrait-primary and
- // belongs to the set [0:3].
- result = rotl4(result, rotation);
-
// Test current orientation
- if (allowed_orientations_ & result)
+ if (allowed_orientations_ & ToOrientation(rotation))
return rotation;
// Test orientation right of current one.
- if (allowed_orientations_ & rotl4(result, 1))
- return static_cast<gfx::Display::Rotation>((rotation + 1) % 4);
+ if (allowed_orientations_ & ToOrientation(ToRotation(rotation + 1)))
+ return ToRotation(rotation + 1);
// Test orientation left of current one.
- if (allowed_orientations_ & rotl4(result, 3))
- return static_cast<gfx::Display::Rotation>((rotation + 3) % 4);
+ if (allowed_orientations_ & ToOrientation(ToRotation(rotation + 3)))
+ return ToRotation(rotation + 3);
// Test orientation opposite of current one.
- if (allowed_orientations_ & rotl4(result, 2))
- return static_cast<gfx::Display::Rotation>((rotation + 2) % 4);
+ if (allowed_orientations_ & ToOrientation(ToRotation(rotation + 1)))
+ return ToRotation(rotation + 1);
NOTREACHED();
return rotation;
}
Orientation NativeAppWindowTizen::GetCurrentOrientation() const {
- switch (display_.rotation()) {
- case gfx::Display::ROTATE_0:
- return PORTRAIT_PRIMARY;
- case gfx::Display::ROTATE_90:
- return LANDSCAPE_PRIMARY;
- case gfx::Display::ROTATE_180:
- return PORTRAIT_SECONDARY;
- case gfx::Display::ROTATE_270:
- return LANDSCAPE_SECONDARY;
- default:
- NOTREACHED();
- return PORTRAIT_PRIMARY;
- }
+ return ToOrientation(display_.rotation());
}
void NativeAppWindowTizen::OnAllowedOrientationsChanged(
#include "xwalk/runtime/browser/runtime_resource_dispatcher_host_delegate_android.h"
#include "xwalk/runtime/browser/xwalk_browser_main_parts_android.h"
#include "xwalk/runtime/common/android/xwalk_globals_android.h"
+#else
+#include "xwalk/application/browser/application_system.h"
+#include "xwalk/application/browser/application_service.h"
+#include "xwalk/application/browser/application.h"
#endif
#if defined(OS_MACOSX)
#endif
#if defined(OS_TIZEN)
-#include "xwalk/application/browser/application_system.h"
-#include "xwalk/application/browser/application_service.h"
-#include "xwalk/application/browser/application.h"
#include "xwalk/application/common/application_manifest_constants.h"
#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
#include "xwalk/application/common/constants.h"
return new xwalk::XWalkSpeechRecognitionManagerDelegate();
}
-#if defined(OS_TIZEN)
-bool XWalkContentBrowserClient::CanCommitURL(
- content::RenderProcessHost* process_host, const GURL& url) {
+#if !defined(OS_ANDROID)
+bool XWalkContentBrowserClient::CanCreateWindow(const GURL& opener_url,
+ const GURL& opener_top_level_frame_url,
+ const GURL& source_origin,
+ WindowContainerType container_type,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ WindowOpenDisposition disposition,
+ const blink::WebWindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ content::ResourceContext* context,
+ int render_process_id,
+ bool is_guest,
+ int opener_id,
+ bool* no_javascript_access) {
+ *no_javascript_access = false;
application::Application* app = xwalk_runner_->app_system()->
- application_service()->GetApplicationByRenderHostID(
- process_host->GetID());
- DCHECK(app);
- const application::ApplicationData* app_data =app->data();
- if (!app_data->HasCSPDefined() ||
- (url.SchemeIs(application::kApplicationScheme) &&
- url.host() == app_data->ID()))
+ application_service()->GetApplicationByRenderHostID(render_process_id);
+ if (!app)
+ // If it's not a request from an application, always enable this action.
return true;
- application::NavigationInfo* info = static_cast<application::NavigationInfo*>(
- app_data->GetManifestData(application_widget_keys::kAllowNavigationKey));
- if (!info || !url.SchemeIsHTTPOrHTTPS()) {
- LOG(INFO) << "[Block] Navigation link: " << url.spec();
- // FIXME: Blocked navigation link should be opened in system web browser,
- // add corresponding code like this:
- // platform_util::OpenExternal(url);
- return false;
+ if (app->CanRequestURL(target_url)) {
+ LOG(INFO) << "[ALLOW] CreateWindow: " << target_url.spec();
+ return true;
}
- // Check whether the navigation url domain is listed in WGT <allow-navigation>
- // element, if yes, display it in web application, otherwise block the
- // request.
- const std::vector<std::string>& allowed_list = info->GetAllowedDomains();
- for (std::vector<std::string>::const_iterator it = allowed_list.begin();
- it != allowed_list.end(); ++it) {
- if ((*it).find("*.") == 0 &&
- url.DomainIs((*it).substr(2).c_str())) {
- LOG(INFO) << "[Allow] Navigation link: " << url.spec();
- return true;
- }
-
- if (url.host() == *it) {
- LOG(INFO) << "[Allow] Navigation link: " << url.spec();
- return true;
- }
- }
- LOG(INFO) << "[Block] navigation link: " << url.spec();
- // FIXME: Should open blocked link in system web browser, need to add:
- // platform_util::OpenExternal(url);
+ LOG(INFO) << "[BlOCK] CreateWindow: " << target_url.spec();
+#if defined(OS_TIZEN)
+ platform_util::OpenExternal(target_url);
+#endif
return false;
}
#endif
int render_process_id,
int render_view_id,
int notification_id) OVERRIDE;
-#if defined(OS_TIZEN)
- virtual bool CanCommitURL(
- content::RenderProcessHost* process_host, const GURL& url) OVERRIDE;
+#if !defined(OS_ANDROID)
+ virtual bool CanCreateWindow(const GURL& opener_url,
+ const GURL& opener_top_level_frame_url,
+ const GURL& source_origin,
+ WindowContainerType container_type,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ WindowOpenDisposition disposition,
+ const blink::WebWindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ content::ResourceContext* context,
+ int render_process_id,
+ bool is_guest,
+ int opener_id,
+ bool* no_javascript_access) OVERRIDE;
#endif
#if defined(OS_ANDROID)
const IPC::Message& message,
bool* message_was_ok) {
bool handled = true;
+#if !defined(OS_WIN)
IPC_BEGIN_MESSAGE_MAP_EX(XWalkRenderMessageFilter, message, *message_was_ok)
#if defined(OS_TIZEN)
IPC_MESSAGE_HANDLER(ViewMsg_OpenLinkExternal, OnOpenLinkExternal)
#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
+#else
+ handled = false;
+#endif
return handled;
}
namespace {
+const char kDefaultLocale[] = "en-US";
XWalkRunner* g_xwalk_runner = NULL;
} // namespace
runtime_context_.reset();
}
+std::string XWalkRunner::GetLocale() const {
+ return kDefaultLocale;
+}
+
void XWalkRunner::CreateComponents() {
scoped_ptr<ApplicationComponent> app_component(CreateAppComponent());
// Keep a reference as some code still needs to call
#ifndef XWALK_RUNTIME_BROWSER_XWALK_RUNNER_H_
#define XWALK_RUNTIME_BROWSER_XWALK_RUNNER_H_
+#include <string>
+
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/values.h"
void PreMainMessageLoopRun();
void PostMainMessageLoopRun();
+ // Get the latest application locale from system.
+ // locale is a langtag defined in [BCP47]
+ virtual std::string GetLocale() const;
+
protected:
XWalkRunner();
return static_cast<XWalkRunnerTizen*>(XWalkRunner::GetInstance());
}
+std::string XWalkRunnerTizen::GetLocale() const {
+ return tizen_locale_listener_.GetLocale();
+}
+
} // namespace xwalk
#ifndef XWALK_RUNTIME_BROWSER_XWALK_RUNNER_TIZEN_H_
#define XWALK_RUNTIME_BROWSER_XWALK_RUNNER_TIZEN_H_
+#include <string>
+
#include "xwalk/runtime/browser/xwalk_runner.h"
+#include "xwalk/runtime/browser/tizen/tizen_locale_listener.h"
namespace xwalk {
virtual ~XWalkRunnerTizen();
+ // Get the latest application locale from system.
+ // locale is a langtag defined in [BCP47]
+ virtual std::string GetLocale() const OVERRIDE;
+
private:
friend class XWalkRunner;
XWalkRunnerTizen();
+
+ TizenLocaleListener tizen_locale_listener_;
};
} // namespace xwalk
// found in the LICENSE file.
// Multiply-included file, no traditional include guard.
+#include <string>
+
#include "xwalk/runtime/common/android/xwalk_hit_test_data.h"
#include "content/public/common/common_param_traits.h"
#include "ipc/ipc_channel_handle.h"
// These are messages sent from the browser to the renderer process.
// Tells the renderer to drop all WebCore memory cache.
-IPC_MESSAGE_CONTROL0(XWalkViewMsg_ClearCache)
+IPC_MESSAGE_CONTROL0(XWalkViewMsg_ClearCache) // NOLINT(*)
// Request for the renderer to determine if the document contains any image
// elements. The id should be passed in the response message so the response
// can be associated with the request.
-IPC_MESSAGE_ROUTED1(XWalkViewMsg_DocumentHasImages,
+IPC_MESSAGE_ROUTED1(XWalkViewMsg_DocumentHasImages, // NOLINT(*)
int /* id */)
// Do hit test at the given webview coordinate. "Webview" coordinates are
// physical pixel values with the 0,0 at the top left of the current displayed
// view (ie 0,0 is not the top left of the page if the page is scrolled).
-IPC_MESSAGE_ROUTED2(XWalkViewMsg_DoHitTest,
+IPC_MESSAGE_ROUTED2(XWalkViewMsg_DoHitTest, // NOLINT(*)
int /* view_x */,
int /* view_y */)
// Enables receiving pictures from the renderer on every new frame.
-IPC_MESSAGE_ROUTED1(XWalkViewMsg_EnableCapturePictureCallback,
+IPC_MESSAGE_ROUTED1(XWalkViewMsg_EnableCapturePictureCallback, // NOLINT(*)
bool /* enable */)
// Requests a new picture with the latest renderer contents synchronously.
// This message blocks the browser process on the renderer until complete.
-IPC_SYNC_MESSAGE_ROUTED0_0(XWalkViewMsg_CapturePictureSync)
+IPC_SYNC_MESSAGE_ROUTED0_0(XWalkViewMsg_CapturePictureSync) // NOLINT(*)
// Sets the zoom level for text only. Used in layout modes other than
// Text Autosizing.
-IPC_MESSAGE_ROUTED1(XWalkViewMsg_SetTextZoomLevel,
+IPC_MESSAGE_ROUTED1(XWalkViewMsg_SetTextZoomLevel, // NOLINT(*)
double /* zoom_level */)
// Resets WebKit WebView scrolling and scale state. We need to send this
// message whenever we want to guarantee that page's scale will be
// recalculated by WebKit.
-IPC_MESSAGE_ROUTED0(XWalkViewMsg_ResetScrollAndScaleState)
+IPC_MESSAGE_ROUTED0(XWalkViewMsg_ResetScrollAndScaleState) // NOLINT(*)
// Sets the initial page scale. This overrides initial scale set by
// the meta viewport tag.
-IPC_MESSAGE_ROUTED1(XWalkViewMsg_SetInitialPageScale,
+IPC_MESSAGE_ROUTED1(XWalkViewMsg_SetInitialPageScale, // NOLINT(*)
double /* page_scale_factor */)
// Set the Javascript online property for network availability change.
-IPC_MESSAGE_CONTROL1(XWalkViewMsg_SetJsOnlineProperty, bool /* network_up */)
+IPC_MESSAGE_CONTROL1(XWalkViewMsg_SetJsOnlineProperty, bool /* network_up */) // NOLINT(*)
+
+// Set the white list for Cross-Origin access.
+IPC_MESSAGE_CONTROL2(XWalkViewMsg_SetOriginAccessWhitelist, // NOLINT(*)
+ std::string /* base url */,
+ std::string /* match pattern content*/)
//-----------------------------------------------------------------------------
// RenderView messages
// These are messages sent from the renderer to the browser process.
// Response to XWalkViewMsg_DocumentHasImages request.
-IPC_MESSAGE_ROUTED2(XWalkViewHostMsg_DocumentHasImagesResponse,
+IPC_MESSAGE_ROUTED2(XWalkViewHostMsg_DocumentHasImagesResponse, // NOLINT(*)
int, /* id */
bool /* has_images */)
// Response to XWalkViewMsg_DoHitTest.
-IPC_MESSAGE_ROUTED1(XWalkViewHostMsg_UpdateHitTestData,
+IPC_MESSAGE_ROUTED1(XWalkViewHostMsg_UpdateHitTestData, // NOLINT(*)
xwalk::XWalkHitTestData)
// Sent whenever the page scale factor (as seen by RenderView) is changed.
-IPC_MESSAGE_ROUTED1(XWalkViewHostMsg_PageScaleFactorChanged,
+IPC_MESSAGE_ROUTED1(XWalkViewHostMsg_PageScaleFactorChanged, // NOLINT(*)
float /* page_scale_factor */)
// Notification that a new picture becomes available. It is only sent if
// XWalkViewMsg_EnableCapturePictureCallback was previously enabled.
-IPC_MESSAGE_ROUTED0(XWalkViewHostMsg_PictureUpdated)
+IPC_MESSAGE_ROUTED0(XWalkViewHostMsg_PictureUpdated) // NOLINT(*)
// Sent by the renderer when accelerated compositing is enabled, allowing the
// browser to perform synchronous input event filtering.
-IPC_MESSAGE_ROUTED1(XWalkViewHostMsg_DidActivateAcceleratedCompositing,
+IPC_MESSAGE_ROUTED1(XWalkViewHostMsg_DidActivateAcceleratedCompositing, // NOLINT(*)
int /* input_handler_id */)
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_platform_file.h"
#include "url/gurl.h"
+#include "xwalk/application/common/security_policy.h"
// Singly-included section for enums and custom IPC traits.
#ifndef XWALK_RUNTIME_COMMON_XWALK_COMMON_MESSAGES_H_
#define IPC_MESSAGE_START ViewMsgStart
+IPC_ENUM_TRAITS(xwalk::application::SecurityPolicy::SecurityMode)
//-----------------------------------------------------------------------------
// RenderView messages
// These are messages sent from the browser to the renderer process.
GURL /* dest */,
bool /* allow_subdomains */)
-IPC_MESSAGE_CONTROL1(ViewMsg_EnableWarpMode, // NOLINT
- GURL /* application url */)
+IPC_MESSAGE_CONTROL2(ViewMsg_EnableSecurityMode, // NOLINT
+ GURL /* application url */,
+ xwalk::application::SecurityPolicy::SecurityMode
+ /* security mode */)
+
+IPC_MESSAGE_ROUTED1(ViewMsg_HWKeyPressed, int /*keycode*/) // NOLINT
// These are messages sent from the renderer to the browser process.
#if defined(OS_TIZEN)
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/runtime/common/xwalk_localized_error.h"
+
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/net/net_error_info.h"
+#include "grit/xwalk_resources.h"
+#include "net/base/escape.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "third_party/WebKit/public/platform/WebURLError.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/webui/web_ui_util.h"
+#include "url/gurl.h"
+
+using blink::WebURLError;
+
+namespace {
+
+struct LocalizedErrorMap {
+ int error_code;
+ unsigned int details_resource_id;
+};
+
+const LocalizedErrorMap net_error_options[] = {
+ { net::ERR_TIMED_OUT,
+ IDS_ERRORPAGES_DETAILS_TIMED_OUT,
+ },
+ { net::ERR_CONNECTION_TIMED_OUT,
+ IDS_ERRORPAGES_DETAILS_TIMED_OUT,
+ },
+ { net::ERR_CONNECTION_CLOSED,
+ IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED,
+ },
+ { net::ERR_CONNECTION_RESET,
+ IDS_ERRORPAGES_DETAILS_CONNECTION_RESET,
+ },
+ { net::ERR_CONNECTION_REFUSED,
+ IDS_ERRORPAGES_DETAILS_CONNECTION_REFUSED,
+ },
+ { net::ERR_CONNECTION_FAILED,
+ IDS_ERRORPAGES_DETAILS_CONNECTION_FAILED,
+ },
+ { net::ERR_NAME_NOT_RESOLVED,
+ IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED,
+ },
+ { net::ERR_ADDRESS_UNREACHABLE,
+ IDS_ERRORPAGES_DETAILS_ADDRESS_UNREACHABLE,
+ },
+ { net::ERR_NETWORK_ACCESS_DENIED,
+ IDS_ERRORPAGES_DETAILS_NETWORK_ACCESS_DENIED,
+ },
+ { net::ERR_PROXY_CONNECTION_FAILED,
+ IDS_ERRORPAGES_DETAILS_PROXY_CONNECTION_FAILED,
+ },
+ { net::ERR_INTERNET_DISCONNECTED,
+ IDS_ERRORPAGES_DETAILS_INTERNET_DISCONNECTED,
+ },
+ { net::ERR_FILE_NOT_FOUND,
+ IDS_ERRORPAGES_DETAILS_FILE_NOT_FOUND,
+ },
+ { net::ERR_CACHE_MISS,
+ IDS_ERRORPAGES_DETAILS_CACHE_MISS,
+ },
+ { net::ERR_CACHE_READ_FAILURE,
+ IDS_ERRORPAGES_DETAILS_CACHE_READ_FAILURE,
+ },
+ { net::ERR_NETWORK_IO_SUSPENDED,
+ IDS_ERRORPAGES_DETAILS_NETWORK_IO_SUSPENDED,
+ },
+ { net::ERR_TOO_MANY_REDIRECTS,
+ IDS_ERRORPAGES_DETAILS_TOO_MANY_REDIRECTS,
+ },
+ { net::ERR_EMPTY_RESPONSE,
+ IDS_ERRORPAGES_DETAILS_EMPTY_RESPONSE,
+ },
+ { net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH,
+ IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH,
+ },
+ { net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION,
+ IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION,
+ },
+ { net::ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION,
+ IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_LOCATION,
+ },
+ { net::ERR_CONTENT_LENGTH_MISMATCH,
+ IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED,
+ },
+ { net::ERR_INCOMPLETE_CHUNKED_ENCODING,
+ IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED,
+ },
+ { net::ERR_SSL_PROTOCOL_ERROR,
+ IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR,
+ },
+ { net::ERR_SSL_UNSAFE_NEGOTIATION,
+ IDS_ERRORPAGES_DETAILS_SSL_UNSAFE_NEGOTIATION,
+ },
+ { net::ERR_BAD_SSL_CLIENT_AUTH_CERT,
+ IDS_ERRORPAGES_DETAILS_BAD_SSL_CLIENT_AUTH_CERT,
+ },
+ { net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY,
+ IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR,
+ },
+ { net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN,
+ IDS_ERRORPAGES_DETAILS_PINNING_FAILURE,
+ },
+ { net::ERR_TEMPORARILY_THROTTLED,
+ IDS_ERRORPAGES_DETAILS_TEMPORARILY_THROTTLED,
+ },
+ { net::ERR_BLOCKED_BY_CLIENT,
+ IDS_ERRORPAGES_DETAILS_BLOCKED,
+ },
+ { net::ERR_NETWORK_CHANGED,
+ IDS_ERRORPAGES_DETAILS_NETWORK_CHANGED,
+ },
+ { net::ERR_BLOCKED_BY_ADMINISTRATOR,
+ IDS_ERRORPAGES_DETAILS_BLOCKED_BY_ADMINISTRATOR,
+ },
+};
+
+// Special error page to be used in the case of navigating back to a page
+// generated by a POST. LocalizedError::HasStrings expects this net error code
+// to also appear in the array above.
+
+const LocalizedErrorMap repost_error = {
+ net::ERR_CACHE_MISS,
+ IDS_ERRORPAGES_DETAILS_CACHE_MISS,
+};
+
+const LocalizedErrorMap http_error_options[] = {
+ { 403,
+ IDS_ERRORPAGES_DETAILS_FORBIDDEN,
+ },
+ { 410,
+ IDS_ERRORPAGES_DETAILS_GONE,
+ },
+
+ { 500,
+ IDS_ERRORPAGES_DETAILS_INTERNAL_SERVER_ERROR,
+ },
+ { 501,
+ IDS_ERRORPAGES_DETAILS_NOT_IMPLEMENTED,
+ },
+ { 502,
+ IDS_ERRORPAGES_DETAILS_BAD_GATEWAY,
+ },
+ { 503,
+ IDS_ERRORPAGES_DETAILS_SERVICE_UNAVAILABLE,
+ },
+ { 504,
+ IDS_ERRORPAGES_DETAILS_GATEWAY_TIMEOUT,
+ },
+ { 505,
+ IDS_ERRORPAGES_DETAILS_HTTP_VERSION_NOT_SUPPORTED,
+ },
+};
+
+const LocalizedErrorMap dns_probe_error_options[] = {
+ { chrome_common_net::DNS_PROBE_POSSIBLE,
+ IDS_ERRORPAGES_DETAILS_DNS_PROBE_RUNNING,
+ },
+
+ // DNS_PROBE_NOT_RUN is not here; NetErrorHelper will restore the original
+ // error, which might be one of several DNS-related errors.
+
+ { chrome_common_net::DNS_PROBE_STARTED,
+ IDS_ERRORPAGES_DETAILS_DNS_PROBE_RUNNING,
+ },
+
+ // DNS_PROBE_FINISHED_UNKNOWN is not here; NetErrorHelper will restore the
+ // original error, which might be one of several DNS-related errors.
+
+ { chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET,
+ IDS_ERRORPAGES_DETAILS_INTERNET_DISCONNECTED,
+ },
+ { chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG,
+ IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED,
+ },
+ { chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN,
+ IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED,
+ },
+};
+
+const LocalizedErrorMap* FindErrorMapInArray(const LocalizedErrorMap* maps,
+ size_t num_maps,
+ int error_code) {
+ for (size_t i = 0; i < num_maps; ++i) {
+ if (maps[i].error_code == error_code)
+ return &maps[i];
+ }
+ return NULL;
+}
+
+const LocalizedErrorMap* LookupErrorMap(const std::string& error_domain,
+ int error_code, bool is_post) {
+ if (error_domain == net::kErrorDomain) {
+ // Display a different page in the special case of navigating through the
+ // history to an uncached page created by a POST.
+ if (is_post && error_code == net::ERR_CACHE_MISS)
+ return &repost_error;
+ return FindErrorMapInArray(net_error_options,
+ arraysize(net_error_options),
+ error_code);
+ } else if (error_domain == LocalizedError::kHttpErrorDomain) {
+ return FindErrorMapInArray(http_error_options,
+ arraysize(http_error_options),
+ error_code);
+ } else if (error_domain == LocalizedError::kDnsProbeErrorDomain) {
+ const LocalizedErrorMap* map =
+ FindErrorMapInArray(dns_probe_error_options,
+ arraysize(dns_probe_error_options),
+ error_code);
+ DCHECK(map);
+ return map;
+ } else {
+ NOTREACHED();
+ return NULL;
+ }
+}
+} // namespace
+
+const char LocalizedError::kHttpErrorDomain[] = "http";
+const char LocalizedError::kDnsProbeErrorDomain[] = "dnsprobe";
+
+base::string16 LocalizedError::GetErrorDetails(const blink::WebURLError& error,
+ bool is_post) {
+ const LocalizedErrorMap* error_map =
+ LookupErrorMap(error.domain.utf8(), error.reason, is_post);
+ if (error_map)
+ return l10n_util::GetStringUTF16(error_map->details_resource_id);
+ else
+ return l10n_util::GetStringUTF16(IDS_ERRORPAGES_DETAILS_UNKNOWN);
+}
--- /dev/null
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_RUNTIME_COMMON_XWALK_LOCALIZED_ERROR_H_
+#define XWALK_RUNTIME_COMMON_XWALK_LOCALIZED_ERROR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+
+class GURL;
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace blink {
+struct WebURLError;
+}
+
+class LocalizedError {
+ public:
+ // Returns a description of the encountered error.
+ static base::string16 GetErrorDetails(const blink::WebURLError& error,
+ bool is_post);
+
+ static const char kHttpErrorDomain[];
+ static const char kDnsProbeErrorDomain[];
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(LocalizedError);
+};
+
+#endif // XWALK_RUNTIME_COMMON_XWALK_LOCALIZED_ERROR_H_
#include "xwalk/runtime/renderer/android/xwalk_render_process_observer.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/url_pattern.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebCache.h"
#include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
+#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "xwalk/runtime/browser/android/net/url_constants.h"
#include "xwalk/runtime/common/android/xwalk_render_view_messages.h"
namespace xwalk {
IPC_BEGIN_MESSAGE_MAP(XWalkRenderProcessObserver, message)
IPC_MESSAGE_HANDLER(XWalkViewMsg_SetJsOnlineProperty, OnSetJsOnlineProperty)
IPC_MESSAGE_HANDLER(XWalkViewMsg_ClearCache, OnClearCache);
+ IPC_MESSAGE_HANDLER(XWalkViewMsg_SetOriginAccessWhitelist,
+ OnSetOriginAccessWhitelist)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
blink::WebCache::clear();
}
+void XWalkRenderProcessObserver::OnSetOriginAccessWhitelist(
+ std::string base_url,
+ std::string match_patterns) {
+ blink::WebSecurityPolicy::resetOriginAccessWhitelists();
+
+ DCHECK(!base_url.empty());
+ if (base_url.empty() || match_patterns.empty())
+ return;
+
+ base::Value* patterns = base::JSONReader::Read(match_patterns);
+ if (!patterns)
+ return;
+
+ base::ListValue* match_pattern_list = NULL;
+ if (!patterns->GetAsList(&match_pattern_list))
+ return;
+
+ const char* schemes[] = {
+ content::kHttpScheme,
+ content::kHttpsScheme,
+ content::kFileScheme,
+ xwalk::kAppScheme,
+ };
+ size_t size = match_pattern_list->GetSize();
+ for (size_t i = 0; i < size; i ++) {
+ std::string match_pattern;
+ if (!match_pattern_list->GetString(i, &match_pattern))
+ continue;
+
+ URLPattern allowedUrl(URLPattern::SCHEME_ALL);
+ if (allowedUrl.Parse(match_pattern) != URLPattern::PARSE_SUCCESS)
+ continue;
+
+ for (size_t j = 0; j < arraysize(schemes); ++j) {
+ if (allowedUrl.MatchesScheme(schemes[j])) {
+ blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(
+ blink::WebURL(GURL(base_url)),
+ blink::WebString::fromUTF8(schemes[j]),
+ blink::WebString::fromUTF8(allowedUrl.host()),
+ allowedUrl.match_subdomains());
+ }
+ }
+ }
+}
+
} // namespace xwalk
#ifndef XWALK_RUNTIME_RENDERER_ANDROID_XWALK_RENDER_PROCESS_OBSERVER_H_
#define XWALK_RUNTIME_RENDERER_ANDROID_XWALK_RENDER_PROCESS_OBSERVER_H_
+#include <string>
+
#include "content/public/renderer/render_process_observer.h"
#include "base/compiler_specific.h"
private:
void OnSetJsOnlineProperty(bool network_up);
void OnClearCache();
+ void OnSetOriginAccessWhitelist(std::string base_url,
+ std::string match_patterns);
bool webkit_initialized_;
};
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/runtime/renderer/tizen/xwalk_render_view_ext_tizen.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_view.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
+#include "xwalk/runtime/common/xwalk_common_messages.h"
+
+namespace {
+std::string GenerateEventJs(const std::string& name) {
+ std::string result;
+ std::string defineJs =
+ "var event = new Event('tizenhwkey');"
+ "function defineProps(val) {"
+ " Object.defineProperty(event, 'keyName', {"
+ " enumerable: false,"
+ " configurable: false,"
+ " writable: false,"
+ " value: val"
+ " });"
+ "}";
+ std::string nameJs = "defineProps('" + name + "');";
+ std::string dispatchJs = "document.dispatchEvent(event);";
+ result += defineJs;
+ result += nameJs;
+ result += dispatchJs;
+
+ return result;
+}
+} // namespace
+
+namespace xwalk {
+
+XWalkRenderViewExtTizen::XWalkRenderViewExtTizen(
+ content::RenderView* render_view)
+ : content::RenderViewObserver(render_view) {
+ render_view_ = render_view;
+ DCHECK(render_view_);
+}
+
+XWalkRenderViewExtTizen::~XWalkRenderViewExtTizen() {
+}
+
+// static
+void XWalkRenderViewExtTizen::RenderViewCreated(
+ content::RenderView* render_view) {
+ new XWalkRenderViewExtTizen(render_view); // |render_view| takes ownership.
+}
+
+bool XWalkRenderViewExtTizen::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(XWalkRenderViewExtTizen, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_HWKeyPressed,
+ OnHWKeyPressed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void XWalkRenderViewExtTizen::OnHWKeyPressed(int keycode) {
+ std::string event_name;
+ if (keycode == ui::VKEY_BACK) {
+ event_name = "back";
+ } else if (keycode == ui::VKEY_HOME) {
+ event_name = "menu";
+ } else {
+ LOG(INFO) << "Unknown input key code, only support 'back' & 'menu'"
+ "at present.";
+ return;
+ }
+
+ content::RenderFrame* render_frame = render_view_->GetMainRenderFrame();
+ blink::WebFrame* web_frame = render_frame->GetWebFrame();
+ blink::WebScriptSource source =
+ blink::WebScriptSource(base::ASCIIToUTF16(GenerateEventJs(event_name)));
+ web_frame->executeScript(source);
+}
+
+} // namespace xwalk
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_RUNTIME_RENDERER_TIZEN_XWALK_RENDER_VIEW_EXT_TIZEN_H_
+#define XWALK_RUNTIME_RENDERER_TIZEN_XWALK_RENDER_VIEW_EXT_TIZEN_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/public/renderer/render_view_observer.h"
+
+namespace xwalk {
+
+class XWalkRenderViewExtTizen : public content::RenderViewObserver {
+ public:
+ static void RenderViewCreated(content::RenderView* render_view);
+
+ private:
+ explicit XWalkRenderViewExtTizen(content::RenderView* render_view);
+ virtual ~XWalkRenderViewExtTizen();
+
+ // RenderView::Observer:
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ void OnHWKeyPressed(int keycode);
+
+ content::RenderView* render_view_;
+ DISALLOW_COPY_AND_ASSIGN(XWalkRenderViewExtTizen);
+};
+
+} // namespace xwalk
+
+#endif // XWALK_RUNTIME_RENDERER_TIZEN_XWALK_RENDER_VIEW_EXT_TIZEN_H_
#include "grit/xwalk_application_resources.h"
#include "grit/xwalk_sysapps_resources.h"
#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "xwalk/application/common/constants.h"
#include "xwalk/application/renderer/application_native_module.h"
#include "xwalk/extensions/renderer/xwalk_js_module.h"
+#include "xwalk/runtime/common/xwalk_localized_error.h"
#if defined(OS_ANDROID)
#include "xwalk/runtime/renderer/android/xwalk_permission_client.h"
#include "xwalk/runtime/renderer/tizen/xwalk_content_renderer_client_tizen.h"
#endif
+#if defined(OS_TIZEN)
+#include "xwalk/runtime/renderer/tizen/xwalk_render_view_ext_tizen.h"
+#endif
+
namespace xwalk {
namespace {
content::RenderView* render_view) {
#if defined(OS_ANDROID)
XWalkRenderViewExt::RenderViewCreated(render_view);
+#elif defined(OS_TIZEN)
+ XWalkRenderViewExtTizen::RenderViewCreated(render_view);
#endif
}
#if defined(OS_ANDROID)
return false;
#else
- if (!xwalk_render_process_observer_->IsWarpMode())
+ if (!xwalk_render_process_observer_->IsWarpMode()
+#if defined(OS_TIZEN)
+ && !xwalk_render_process_observer_->IsCSPMode()
+#endif
+ )
return false;
GURL origin_url(frame->document().url());
GURL app_url(xwalk_render_process_observer_->app_url());
- if ((url.scheme() == app_url.scheme() &&
- url.host() == app_url.host()) ||
+#if defined(OS_TIZEN)
+ // if under CSP mode.
+ if (xwalk_render_process_observer_->IsCSPMode()) {
+ if (url.GetOrigin() != app_url.GetOrigin() &&
+ origin_url != first_party_for_cookies &&
+ first_party_for_cookies.GetOrigin() != app_url.GetOrigin() &&
+ !frame->document().securityOrigin().canRequest(url)) {
+ LOG(INFO) << "[BLOCK] allow-navigation: " << url.spec();
+ content::RenderThread::Get()->Send(new ViewMsg_OpenLinkExternal(url));
+ *new_url = GURL();
+ return true;
+ }
+ return false;
+ }
+#endif
+ // if under WARP mode.
+ if (url.GetOrigin() == app_url.GetOrigin() ||
frame->document().securityOrigin().canRequest(url)) {
LOG(INFO) << "[PASS] " << origin_url.spec() << " request " << url.spec();
return false;
}
LOG(INFO) << "[BLOCK] " << origin_url.spec() << " request " << url.spec();
-
#if defined(OS_TIZEN)
- if (origin_url.spec().empty())
+ if (url.GetOrigin() != app_url.GetOrigin() &&
+ origin_url != first_party_for_cookies &&
+ first_party_for_cookies.GetOrigin() != app_url.GetOrigin())
content::RenderThread::Get()->Send(new ViewMsg_OpenLinkExternal(url));
#endif
return true;
#endif
}
+
+void XWalkContentRendererClient::GetNavigationErrorStrings(
+ content::RenderView* render_view,
+ blink::WebFrame* frame,
+ const blink::WebURLRequest& failed_request,
+ const blink::WebURLError& error,
+ std::string* error_html,
+ base::string16* error_description) {
+ bool is_post = EqualsASCII(failed_request.httpMethod(), "POST");
+
+ // TODO(guangzhen): Check whether error_html is needed in xwalk runtime.
+
+ if (error_description) {
+ *error_description = LocalizedError::GetErrorDetails(error, is_post);
+ }
+}
+
} // namespace xwalk
#ifndef XWALK_RUNTIME_RENDERER_XWALK_CONTENT_RENDERER_CLIENT_H_
#define XWALK_RUNTIME_RENDERER_XWALK_CONTENT_RENDERER_CLIENT_H_
+#include <string>
+
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/platform_file.h"
+#include "base/strings/string16.h"
#include "content/public/common/page_transition_types.h"
#include "content/public/renderer/content_renderer_client.h"
#include "xwalk/extensions/renderer/xwalk_extension_renderer_controller.h"
scoped_ptr<visitedlink::VisitedLinkSlave> visited_link_slave_;
#endif
+ void GetNavigationErrorStrings(
+ content::RenderView* render_view,
+ blink::WebFrame* frame,
+ const blink::WebURLRequest& failed_request,
+ const blink::WebURLError& error,
+ std::string* error_html,
+ base::string16* error_description) OVERRIDE;
+
DISALLOW_COPY_AND_ASSIGN(XWalkContentRendererClient);
};
XWalkRenderProcessObserver::XWalkRenderProcessObserver()
: is_webkit_initialized_(false),
- is_warp_mode_(false) {
+ security_mode_(application::SecurityPolicy::NoSecurity) {
}
XWalkRenderProcessObserver::~XWalkRenderProcessObserver() {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(XWalkRenderProcessObserver, message)
IPC_MESSAGE_HANDLER(ViewMsg_SetAccessWhiteList, OnSetAccessWhiteList)
- IPC_MESSAGE_HANDLER(ViewMsg_EnableWarpMode, OnEnableWarpMode)
+ IPC_MESSAGE_HANDLER(ViewMsg_EnableSecurityMode, OnEnableSecurityMode)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
AccessWhitelistItem(source, dest, allow_subdomains));
}
-void XWalkRenderProcessObserver::OnEnableWarpMode(const GURL& url) {
+void XWalkRenderProcessObserver::OnEnableSecurityMode(
+ const GURL& url, application::SecurityPolicy::SecurityMode mode) {
app_url_ = url;
- is_warp_mode_ = true;
+ security_mode_ = mode;
}
} // namespace xwalk
#include "content/public/renderer/render_process_observer.h"
#include "url/gurl.h"
#include "v8/include/v8.h"
+#include "xwalk/application/common/security_policy.h"
namespace blink {
class WebFrame;
virtual void WebKitInitialized() OVERRIDE;
virtual void OnRenderProcessShutdown() OVERRIDE;
- bool IsWarpMode() const { return is_warp_mode_; }
+ bool IsWarpMode() const {
+ return security_mode_ == application::SecurityPolicy::WARP;
+ }
+ bool IsCSPMode() const {
+ return security_mode_ == application::SecurityPolicy::CSP;
+ }
+
const GURL& app_url() const { return app_url_; }
private:
void OnSetAccessWhiteList(
const GURL& source, const GURL& dest, bool allow_subdomains);
- void OnEnableWarpMode(const GURL& url);
+ void OnEnableSecurityMode(
+ const GURL& url, application::SecurityPolicy::SecurityMode mode);
bool is_webkit_initialized_;
- bool is_warp_mode_;
+ application::SecurityPolicy::SecurityMode security_mode_;
GURL app_url_;
};
} // namespace xwalk
<message name="IDS_SELECT_COLOR_DIALOG_TITLE" desc="The default title for the Select Color color chooser dialog.">
Select Color
</message>
+ <!-- error messages for network errors -->
+ <message name="IDS_ERRORPAGES_DETAILS_TIMED_OUT" desc="The error message displayed when a page takes too long to load.">
+ The operation timed out.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED" desc="The error message displayed when the server unexpectedly closes a connection.">
+ The server unexpectedly closed the connection.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_CONNECTION_RESET" desc="The error message displayed when a connection was reset.">
+ The connection was reset.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_CONNECTION_REFUSED" desc="The error message displayed when we try and connect to a server, but the server doesn't let us.">
+ The server refused the connection.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_CONNECTION_FAILED" desc="The error message displayed when we can not reach the website.">
+ The attempt to connect to the server failed.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_NETWORK_CHANGED" desc="The error message displayed when a connection is interrupted because the network changed.">
+ A network change was detected.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED" desc="The error message displayed when a dns look up fails.">
+ Unable to resolve the server's DNS address.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_ADDRESS_UNREACHABLE" desc="The error message displayed when we can't reach a server.">
+ Unable to reach the server.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_NETWORK_ACCESS_DENIED" desc="The error message displayed when we're not being allowed to access the network.">
+ Unable to access the network.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_FILE_ACCESS_DENIED" desc="The error message displayed when we're not being allowed to access a file.">
+ Unable to access the file.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_PROXY_CONNECTION_FAILED" desc="The error message displayed when the proxy server connection failed.">
+ Proxy server connection failed.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_INTERNET_DISCONNECTED" desc="The error message displayed when we have no Internet access.">
+ The Internet connection has been lost.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_CACHE_READ_FAILURE" desc="The error message displayed when we encountered an error reading from the cache. Generally this happens when the disk cache is corrupted from improper shutdown.">
+ Error reading data from cache.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_CACHE_MISS" desc="The error message displayed when we couldn't find a resource in the cache, and cannot fall back to the network.">
+ The requested entry was not found in the cache.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_NETWORK_IO_SUSPENDED" desc="The error message displayed when a page load failed due to the computer entering sleep/suspend mode.">
+ Network IO suspended.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_FILE_NOT_FOUND" desc="The error message displayed when a local file can not be found.">
+ The file or directory could not be found.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_TOO_MANY_REDIRECTS" desc="The error message displayed when there are too many redirects.">
+ There were too many redirects.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_EMPTY_RESPONSE" desc="The error message displayed when no data is received.">
+ The server closed the connection without sending any data.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH" desc="The error message displayed when we received multiple 'Content-Length' header fields in an http response.">
+ Multiple distinct Content-Length headers received. This is disallowed
+ to protect against HTTP response splitting attacks.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION" desc="The error message displayed when we received multiple 'Content-Disposition' header fields in an http response.">
+ Multiple distinct Content-Disposition headers received. This is disallowed to
+ protect against HTTP response splitting attacks.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_LOCATION" desc="The error message displayed when we received multiple 'Location' header fields in an http response.">
+ Multiple distinct Location headers received. This is disallowed to protect
+ against HTTP response splitting attacks.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_DNS_PROBE_RUNNING" desc="The error message displayed when we are waiting to see whether we will run a DNS probe.">
+ Waiting for DNS probe.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_UNKNOWN" desc="The default error message displayed if we don't have a more specific error message.">
+ Unknown error.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR" desc="The error message displayed for SSL protocol errors.">
+ SSL protocol error.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_SSL_UNSAFE_NEGOTIATION" desc="The error message displayed when the SSL renegotiation extension is missing.">
+ The SSL renegotiation extension was missing from the secure handshake. For some sites, which are known to support the renegotiation extension, Chrome requires a more secure handshake to prevent a class of known attacks. The omission of this extension suggests that your connection was intercepted and manipulated in transit.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_BAD_SSL_CLIENT_AUTH_CERT" desc="The error message for SSL client certificate authentication failure.">
+ Bad SSL client authentication certificate.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_TEMPORARILY_THROTTLED" desc="The error message displayed when we temporarily stop sending requests to a server in order to avoid DDoS.">
+ Extension requests to this URL have been temporarily throttled.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_PINNING_FAILURE" desc="Description of the error page for a certificate which doesn't match the built-in pins for that name">
+ The server's certificate appears to be a forgery.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_BLOCKED" desc="The error message displayed when an extension blocks a request.">
+ Requests to the server have been blocked by an extension.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_BLOCKED_BY_ADMINISTRATOR" desc="The error message displayed when a policy blocks a request.">
+ Requests to the server have been blocked by a policy.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_FORBIDDEN" desc="Details in the error page when a server returns a 403.">
+ The server refused to fulfill the request.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_GONE" desc="Details in the error page when a server returns a 410.">
+ The requested resource no longer exists, and there is no forwarding address. This is expected to be a permanent condition.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_INTERNAL_SERVER_ERROR" desc="The error message displayed when the server returns a 500.">
+ An unexpected condition was encountered while the server was attempting to fulfill the request.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_NOT_IMPLEMENTED" desc="The error message displayed when the server returns a 501.">
+ The server does not support the functionality required to fulfill the request.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_BAD_GATEWAY" desc="The error message displayed when the server returns a 502.">
+ The gateway or proxy server received an invalid response from an upstream server.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_SERVICE_UNAVAILABLE" desc="The error message displayed when the server returns a 503.">
+ The server is currently unable to handle the request. This code indicates this is a temporary condition, and the server will be up again after a delay.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_GATEWAY_TIMEOUT" desc="The error message displayed when the server returns a 504.">
+ The gateway or proxy server timed out while waiting for a response from an upstream server.
+ </message>
+ <message name="IDS_ERRORPAGES_DETAILS_HTTP_VERSION_NOT_SUPPORTED" desc="The error message displayed when the server returns a 505.">
+ The server does not support the HTTP version used in the request.
+ </message>
</messages>
</release>
<translations />
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>
import org.xwalk.core.XWalkCookieManager;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
import org.xwalk.core.XWalkView;
/**
public void testGeolocationPermissionShowPrompt() throws Throwable {
class TestWebChromeClient extends XWalkWebChromeClient {
public TestWebChromeClient() {
- super(getXWalkView().getContext(), getXWalkView());
+ super(getXWalkView());
}
private int mCalledCount = 0;
+
@Override
public void onGeolocationPermissionsShowPrompt(String origin,
XWalkGeolocationPermissions.Callback callback) {
public void testGeolocationPermissionHidePrompt() throws Throwable {
class TestWebChromeClient extends XWalkWebChromeClient {
public TestWebChromeClient() {
- super(getXWalkView().getContext(), getXWalkView());
+ super(getXWalkView());
}
@Override
import android.content.Intent;
import android.graphics.Bitmap;
import android.test.suitebuilder.annotation.SmallTest;
+
import org.chromium.base.test.util.Feature;
import org.xwalk.core.XWalkView;
import org.xwalk.core.XWalkClient;
import android.graphics.Bitmap;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
-import org.xwalk.core.XWalkView;
-import org.xwalk.core.XWalkClient;
/**
* Test suite for loadUrl().
+++ /dev/null
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.xwalk.core.xwview.test;
-
-import android.graphics.Bitmap;
-import android.graphics.Picture;
-import android.net.http.SslError;
-import android.os.Message;
-import android.view.KeyEvent;
-import android.view.View;
-import android.webkit.ConsoleMessage;
-import android.webkit.ValueCallback;
-import android.webkit.WebResourceResponse;
-
-import org.xwalk.core.XWalkJavascriptResult;
-import org.xwalk.core.XWalkJavascriptResult;
-import org.xwalk.core.XWalkContentsClient;
-import org.xwalk.core.XWalkGeolocationPermissions;
-import org.xwalk.core.XWalkHttpAuthHandler;
-import org.xwalk.core.XWalkWebChromeClient;
-
-/**
- * As a convience for tests that only care about specefic callbacks, this class provides
- * empty implementations of all abstract methods.
- */
-public class NullContentsClient extends XWalkContentsClient {
- @Override
- public void onUnhandledKeyEvent(KeyEvent event) {
- }
-
- @Override
- public void getVisitedHistory(ValueCallback<String[]> callback) {
- }
-
- @Override
- public void doUpdateVisitedHistory(String url, boolean isReload) {
- }
-
- @Override
- public void onProgressChanged(int progress) {
- }
-
- @Override
- public WebResourceResponse shouldInterceptRequest(String url) {
- return null;
- }
-
- @Override
- public void onLoadResource(String url) {
- }
-
- @Override
- public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
- return false;
- }
-
- @Override
- public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
- }
-
- @Override
- public void onReceivedLoginRequest(String realm, String account, String args) {
- }
-
- @Override
- public void onGeolocationPermissionsShowPrompt(String origin,
- XWalkGeolocationPermissions.Callback callback) {
- }
-
- @Override
- public void onGeolocationPermissionsHidePrompt() {
- }
-
-
- @Override
- public boolean hasEnteredFullscreen() {
- return false;
- }
-
- @Override
- public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
- boolean isDoneCounting) {
- }
-
- @Override
- public void onNewPicture(Picture picture) {
- }
-
- @Override
- public void onPageStarted(String url) {
- }
-
- @Override
- public void onPageFinished(String url) {
- }
-
- @Override
- public void onReceivedError(int errorCode, String description, String failingUrl) {
- }
-
- @Override
- public void onFormResubmission(Message dontResend, Message resend) {
- dontResend.sendToTarget();
- }
-
- @Override
- public void onDownloadStart(String url,
- String userAgent,
- String contentDisposition,
- String mimeType,
- long contentLength) {
- }
-
- @Override
- public boolean onCreateWindow(boolean isDialog, boolean isUserGesture) {
- return false;
- }
-
- @Override
- public void onCloseWindow() {
- }
-
- @Override
- public void onRequestFocus() {
- }
-
- @Override
- public void onReceivedTouchIconUrl(String url, boolean precomposed) {
- }
-
- @Override
- public void onReceivedIcon(Bitmap bitmap) {
- }
-
- @Override
- public void onShowCustomView(View view, XWalkWebChromeClient.CustomViewCallback callback) {
- }
-
- @Override
- public void onHideCustomView() {
- }
-
- @Override
- public void onScaleChangedScaled(float oldScale, float newScale) {
- }
-
- @Override
- protected View getVideoLoadingProgressView() {
- return null;
- }
-
- @Override
- public Bitmap getDefaultVideoPoster() {
- return null;
- }
-
- @Override
- public void didFinishLoad(String url) {
- }
-
- @Override
- public void onReceivedHttpAuthRequest(XWalkHttpAuthHandler handler, String host, String realm) {
- }
-
- @Override
- public boolean shouldOverrideUrlLoading(String url) {
- return false;
- }
-
- @Override
- public void onTitleChanged(String title) {
- }
-
- @Override
- public void onToggleFullscreen(boolean enterFullscreen) {
- }
-
- @Override
- public void onRendererResponsive() {
- }
-
- @Override
- public void onRendererUnresponsive() {
- }
-}
import org.chromium.net.test.util.TestWebServer;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
import org.xwalk.core.XWalkView;
import java.util.concurrent.TimeUnit;
String html = "<html><body>Simple page.</body></html>";
int currentCallCount = onPageFinishedHelper.getCallCount();
- loadDataAsync(html, "text/html", false);
+ loadDataAsync(null, html, "text/html", false);
onPageFinishedHelper.waitForCallback(currentCallCount);
- assertEquals("data:text/html," + html, onPageFinishedHelper.getUrl());
+ assertEquals("about:blank", onPageFinishedHelper.getUrl());
}
@MediumTest
assertEquals(0, onPageFinishedHelper.getCallCount());
final int pageWithSubresourcesCallCount = onPageFinishedHelper.getCallCount();
- loadDataAsync("<html><iframe src=\"" + testUrl + "\" /></html>",
+ loadDataAsync(null, "<html><iframe src=\"" + testUrl + "\" /></html>",
"text/html",
false);
int currentCallCount = onPageFinishedHelper.getCallCount();
assertEquals(0, currentCallCount);
- loadDataAsync(html, "text/html", false);
+ loadDataAsync(null, html, "text/html", false);
loadJavaScriptUrl("javascript: try { console.log('foo'); } catch(e) {};");
onPageFinishedHelper.waitForCallback(currentCallCount);
- assertEquals("data:text/html," + html, onPageFinishedHelper.getUrl());
+ assertEquals("about:blank", onPageFinishedHelper.getUrl());
// onPageFinished won't be called for javascript: url.
assertEquals(1, onPageFinishedHelper.getCallCount());
}
String url = mWebServer.setResponse("/reload.html", html1, null);
loadUrlSync(url);
mWebServer.setResponse("/reload.html", html2, null);
- reloadSync();
+ reloadSync(XWalkView.RELOAD_IGNORE_CACHE);
//TODO(guangzhen) When reload finished, immediately call getTitle will get wrong title.
Thread.sleep(1000);
assertEquals(title2, getTitleOnUiThread());
import org.chromium.content.browser.ContentViewCore;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
import org.xwalk.core.XWalkView;
/**
@DisabledTest
public void testRendererUnresponsive() throws Throwable {
setXWalkClient(new XWalkViewTestBase.TestXWalkClient());
- getXWalkView().setXWalkClient(new XWalkClient(getXWalkView().getContext(),
- getXWalkView()) {
+ getXWalkView().setXWalkClient(new XWalkClient(getXWalkView()) {
@Override
public void onRendererUnresponsive(XWalkView view) {
unresponsiveHelper.notifyCalled(view);
loadAssetFile("renderHung.html");
int currentCallCount = unresponsiveHelper.getCallCount();
-
- XWalkContent content = getXWalkView().getXWalkViewContentForTest();
- content.getContentViewCoreForTest().evaluateJavaScript("deadLoopForever();", null);
+ getXWalkView().evaluateJavascript("deadLoopForever();", null);
/**
* Send an input event to xwalk view. Internally, if no ACK message is received
@DisabledTest
public void testRendererResponsiveAgain() throws Throwable {
setXWalkClient(new XWalkViewTestBase.TestXWalkClient());
- getXWalkView().setXWalkClient(new XWalkClient(getXWalkView().getContext(),
- getXWalkView()) {
+ getXWalkView().setXWalkClient(new XWalkClient(getXWalkView()) {
/**
* Called once the renderer become responsive again.
*/
loadAssetFile("renderHung.html");
int currentCallCount = responsiveHelper.getCallCount();
- XWalkContent content = getXWalkView().getXWalkViewContentForTest();
- content.getContentViewCoreForTest().evaluateJavaScript("deadLoopFor40secs();", null);
+ getXWalkView().evaluateJavascript("deadLoopFor40secs();", null);
/**
* Send an input event to start the hung monitor.
import org.chromium.content.browser.NavigationEntry;
import org.chromium.content.browser.NavigationHistory;
import org.chromium.net.test.util.TestWebServer;
-import org.xwalk.core.xwview.test.util.CommonResources;
+
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
+import org.xwalk.core.XWalkNavigationHistory;
import org.xwalk.core.XWalkView;
+import org.xwalk.core.xwview.test.util.CommonResources;
import java.util.concurrent.Callable;
private String mUrls[];
private XWalkView mXWalkView;
private XWalkView mRestoreXWalkView;
- private XWalkContent mXWalkContent;
@Override
public void setUp() throws Exception {
mXWalkView = getXWalkView();
mRestoreXWalkView = new XWalkView(activity, activity);
mXWalkView.setXWalkClient(new XWalkViewTestBase.TestXWalkClient());
- mXWalkContent = mXWalkView.getXWalkViewContentForTest();
}
});
}
}
- private NavigationHistory getNavigationHistoryOnUiThread(
- final XWalkContent content) throws Throwable{
- return runTestOnUiThreadAndGetResult(new Callable<NavigationHistory>() {
+ private XWalkNavigationHistory getNavigationHistoryOnUiThread(
+ final XWalkView content) throws Throwable{
+ return runTestOnUiThreadAndGetResult(new Callable<XWalkNavigationHistory>() {
@Override
- public NavigationHistory call() throws Exception {
- return content.getContentViewCoreForTest().getNavigationHistory();
+ public XWalkNavigationHistory call() throws Exception {
+ return content.getNavigationHistory();
}
});
}
- private void checkHistoryItemList(XWalkContent content) throws Throwable {
- NavigationHistory history = getNavigationHistoryOnUiThread(content);
- assertEquals(NUM_NAVIGATIONS, history.getEntryCount());
- assertEquals(NUM_NAVIGATIONS - 1, history.getCurrentEntryIndex());
+ private void checkHistoryItemList(XWalkView content) throws Throwable {
+ XWalkNavigationHistory history = getNavigationHistoryOnUiThread(content);
+ assertEquals(NUM_NAVIGATIONS, history.size());
+ assertEquals(NUM_NAVIGATIONS - 1, history.getCurrentIndex());
// Note this is not meant to be a thorough test of NavigationHistory,
// but is only meant to test enough to make sure state is restored.
// See NavigationHistoryTest for more thorough tests.
for (int i = 0; i < NUM_NAVIGATIONS; ++i) {
- assertEquals(mUrls[i], history.getEntryAtIndex(i).getOriginalUrl());
- assertEquals(mUrls[i], history.getEntryAtIndex(i).getUrl());
- assertEquals(TITLES[i], history.getEntryAtIndex(i).getTitle());
+ assertEquals(mUrls[i], history.getItemAt(i).getOriginalUrl());
+ assertEquals(mUrls[i], history.getItemAt(i).getUrl());
+ assertEquals(TITLES[i], history.getItemAt(i).getTitle());
}
}
@Override
public Boolean call() throws Exception {
// TODO(hengzhi): add the judge about updated title.
- return TITLES[0].equals(mXWalkContent.getContentViewCoreForTest().getTitle());
+ return TITLES[0].equals(mXWalkView.getTitle());
}
}));
}
public void testSaveRestoreStateWithHistoryItemList() throws Throwable {
setServerResponseAndLoad(NUM_NAVIGATIONS);
saveAndRestoreStateOnUiThread();
- checkHistoryItemList(mRestoreXWalkView.getXWalkViewContentForTest());
+ checkHistoryItemList(mRestoreXWalkView);
}
@SmallTest
@Feature({"SaveRestoreState"})
public void testRestoreFromInvalidStateFails() throws Throwable {
final Bundle invalidState = new Bundle();
- invalidState.putByteArray(mXWalkContent.SAVE_RESTORE_STATE_KEY,
+ // TODO(yongsheng): how to share this with
+ // XWalkContent.SAVE_RESTORE_STATE_KEY?
+ invalidState.putByteArray("XWALKVIEW_STATE",
"invalid state".getBytes());
boolean result = runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
@Override
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.net.test.util.TestWebServer;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
import org.xwalk.core.XWalkSettings;
import org.xwalk.core.XWalkView;
import org.xwalk.core.XWalkWebChromeClient;
createXWalkViewContainerOnMainSync(getActivity(), client,
resourceClient, chromeClient);
- final XWalkContent xWalkContent = getXWalkContentOnMainSync(xWalkView);
final XWalkSettings settings = getXWalkSettings(xWalkView);
settings.setJavaScriptEnabled(true);
settings.setAppCacheEnabled(false);
ManifestTestHelper helper = new ManifestTestHelper(
webServer, "testAppCache.html", "appcache.manifest");
loadUrlSyncByContent(
- xWalkContent,
+ xWalkView,
mContentClient,
helper.getHtmlUrl());
helper.waitUntilHtmlIsRequested(0);
// Enables AppCache. Use the default path if app cache path isn't set.
settings.setAppCacheEnabled(true);
loadUrlSyncByContent(
- xWalkContent,
+ xWalkView,
mContentClient,
helper.getHtmlUrl());
helper.waitUntilManifestIsRequested(0);
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.UrlUtils;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
import org.xwalk.core.XWalkSettings;
import org.xwalk.core.XWalkView;
import org.xwalk.core.XWalkWebChromeClient;
private static final boolean DISABLED = false;
abstract class XWalkViewSettingsTestHelper<T> {
- protected final XWalkContent mXWalkContent;
+ protected final XWalkView mXWalkView;
protected final XWalkSettings mXWalkSettings;
- XWalkViewSettingsTestHelper(XWalkContent xWalkContent,
+ XWalkViewSettingsTestHelper(XWalkView xWalkContent,
boolean requiresJsEnabled) throws Throwable {
- mXWalkContent = xWalkContent;
+ mXWalkView = xWalkContent;
mXWalkSettings = getXWalkSettingsOnUiThreadByContent(xWalkContent);
mXWalkSettings.setDomStorageEnabled(false);
if (requiresJsEnabled) {
TestHelperBridge mHelperBridge;
XWalkViewSettingsDomStorageEnabledTestHelper(
- XWalkContent xWalkContent,
+ XWalkView xWalkContent,
final TestHelperBridge helperBridge) throws Throwable {
super(xWalkContent, true);
mHelperBridge = helperBridge;
protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
// It is not permitted to access localStorage from data URLs in WebKit,
// that is why a standalone page must be used.
- loadUrlSyncByContent(mXWalkContent, mHelperBridge,
+ loadUrlSyncByContent(mXWalkView, mHelperBridge,
UrlUtils.getTestFileUrl("xwalkview/localStorage.html"));
assertEquals(
value == ENABLED ? HAS_LOCAL_STORAGE : NO_LOCAL_STORAGE,
import org.chromium.base.test.util.Feature;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
import org.xwalk.core.XWalkView;
/**
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
import org.chromium.net.test.util.TestWebServer;
-import org.xwalk.core.xwview.test.util.CommonResources;
import org.xwalk.core.XWalkView;
-import org.xwalk.core.XWalkResourceClient;
+import org.xwalk.core.xwview.test.TestContentProvider;
+import org.xwalk.core.xwview.test.util.CommonResources;
/**
* Test case for XWalkResourceClient.shouldInterceptRequest callback
package org.xwalk.core.xwview.test;
import android.util.Log;
+import android.webkit.ValueCallback;
import android.webkit.WebResourceResponse;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeoutException;
import org.chromium.content.browser.test.util.CallbackHelper;
-import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
+import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
+import org.xwalk.core.XWalkView;
+
class TestHelperBridge {
// Two new helper classes for testing new APIs.
}
}
+ class OnEvaluateJavaScriptResultHelper extends CallbackHelper {
+ private String mJsonResult;
+ public void evaluateJavascript(XWalkView xWalkView, String code) {
+ ValueCallback<String> callback =
+ new ValueCallback<String>() {
+ @Override
+ public void onReceiveValue(String jsonResult) {
+ notifyCalled(jsonResult);
+ }
+ };
+ xWalkView.evaluateJavascript(code, callback);
+ mJsonResult = null;
+ }
+
+ public boolean hasValue() {
+ return mJsonResult != null;
+ }
+
+ public boolean waitUntilHasValue() throws InterruptedException, TimeoutException {
+ waitUntilCriteria(getHasValueCriteria());
+ return hasValue();
+ }
+
+ public String getJsonResultAndClear() {
+ assert hasValue();
+ String result = mJsonResult;
+ mJsonResult = null;
+ return result;
+ }
+
+ public Criteria getHasValueCriteria() {
+ return new Criteria() {
+ @Override
+ public boolean isSatisfied() {
+ return hasValue();
+ }
+ };
+ }
+
+ public void notifyCalled(String jsonResult) {
+ assert !hasValue();
+ mJsonResult = jsonResult;
+ notifyCalled();
+ }
+ }
+
private String mChangedTitle;
private final OnPageStartedHelper mOnPageStartedHelper;
private final OnPageFinishedHelper mOnPageFinishedHelper;
private final OnReceivedErrorHelper mOnReceivedErrorHelper;
- // TODO(yongsheng): write test for this.
private final OnEvaluateJavaScriptResultHelper mOnEvaluateJavaScriptResultHelper;
private final OnTitleUpdatedHelper mOnTitleUpdatedHelper;
import org.chromium.base.test.util.Feature;
import org.chromium.net.test.util.TestWebServer;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
import org.xwalk.core.XWalkSettings;
import org.xwalk.core.XWalkView;
return runTestOnUiThreadAndGetResult(new Callable<XWalkSettings>() {
@Override
public XWalkSettings call() throws Exception {
- return getXWalkView().getXWalkViewContentForTest().getSettings();
+ return getXWalkView().getSettings();
}
});
}
import org.chromium.content.browser.test.util.CallbackHelper;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
import org.xwalk.core.XWalkClient;
-import org.xwalk.core.XWalkContent;
-import org.xwalk.core.XWalkContentsClient;
import org.xwalk.core.XWalkNavigationHistory;
import org.xwalk.core.XWalkResourceClient;
-import org.xwalk.core.XWalkResourceClientImpl;
import org.xwalk.core.XWalkSettings;
import org.xwalk.core.XWalkView;
import org.xwalk.core.XWalkWebChromeClient;
class TestXWalkClientBase extends XWalkClient {
TestHelperBridge mInnerContentsClient;
public TestXWalkClientBase(TestHelperBridge client) {
- super(getXWalkView().getContext(), getXWalkView());
+ super(getXWalkView());
mInnerContentsClient = client;
}
class TestXWalkWebChromeClientBase extends XWalkWebChromeClient {
TestHelperBridge mInnerContentsClient;
public TestXWalkWebChromeClientBase(TestHelperBridge client) {
- super(getXWalkView().getContext(), getXWalkView());
+ super(getXWalkView());
mInnerContentsClient = client;
}
class TestXWalkResourceClientBase extends XWalkResourceClient {
TestHelperBridge mInnerContentsClient;
public TestXWalkResourceClientBase(TestHelperBridge client) {
+ super(mXWalkView);
mInnerContentsClient = client;
}
}
static class ViewPair {
- private final XWalkContent content0;
+ private final XWalkView content0;
private final TestHelperBridge client0;
- private final XWalkContent content1;
+ private final XWalkView content1;
private final TestHelperBridge client1;
- ViewPair(XWalkContent content0, TestHelperBridge client0,
- XWalkContent content1, TestHelperBridge client1) {
+ ViewPair(XWalkView content0, TestHelperBridge client0,
+ XWalkView content1, TestHelperBridge client1) {
this.content0 = content0;
this.client0 = client0;
this.content1 = content1;
this.client1 = client1;
}
- XWalkContent getContent0() {
+ XWalkView getContent0() {
return content0;
}
return client0;
}
- XWalkContent getContent1() {
+ XWalkView getContent1() {
return content1;
}
});
}
- protected void loadDataSync(final String data, final String mimeType,
+ protected void loadDataSync(final String url, final String data, final String mimeType,
final boolean isBase64Encoded) throws Exception {
CallbackHelper pageFinishedHelper = mTestHelperBridge.getOnPageFinishedHelper();
int currentCallCount = pageFinishedHelper.getCallCount();
- loadDataAsync(data, mimeType, isBase64Encoded);
+ loadDataAsync(url, data, mimeType, isBase64Encoded);
pageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
TimeUnit.SECONDS);
}
- protected void loadDataAsync(final String data, final String mimeType,
+ protected void loadDataAsync(final String url, final String data, final String mimeType,
final boolean isBase64Encoded) throws Exception {
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- mXWalkView.getXWalkViewContentForTest().getContentViewCoreForTest(
- ).loadUrl(LoadUrlParams.createLoadDataParams(
- data, mimeType, isBase64Encoded));
+ mXWalkView.load(url, data);
}
});
}
- protected void loadUrlSyncByContent(final XWalkContent xWalkContent,
+ protected void loadUrlSyncByContent(final XWalkView xWalkContent,
final TestHelperBridge contentsClient,
final String url) throws Exception {
CallbackHelper pageFinishedHelper = contentsClient.getOnPageFinishedHelper();
TimeUnit.SECONDS);
}
- protected void loadUrlAsyncByContent(final XWalkContent xWalkContent,
+ protected void loadUrlAsyncByContent(final XWalkView xWalkContent,
final String url) throws Exception {
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- xWalkContent.loadUrl(url);
+ xWalkContent.load(url, null);
}
});
}
}
}
- protected String getTitleOnUiThreadByContent(final XWalkContent xWalkContent) throws Exception {
+ protected String getTitleOnUiThreadByContent(final XWalkView xWalkContent) throws Exception {
return runTestOnUiThreadAndGetResult(new Callable<String>() {
@Override
public String call() throws Exception {
- String title = xWalkContent.getContentViewCoreForTest().getTitle();
+ String title = xWalkContent.getTitle();
return title;
}
});
}
protected XWalkSettings getXWalkSettingsOnUiThreadByContent(
- final XWalkContent xwalkContent) throws Exception {
+ final XWalkView xwalkContent) throws Exception {
return runTestOnUiThreadAndGetResult(new Callable<XWalkSettings>() {
@Override
public XWalkSettings call() throws Exception {
return xWalkViewContainer.get();
}
- protected XWalkContent getXWalkContentOnMainSync(final XWalkView view) throws Exception {
- final AtomicReference<XWalkContent> xWalkContent =
- new AtomicReference<XWalkContent>();
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- xWalkContent.set(view.getXWalkViewContentForTest());
- }
- });
-
- return xWalkContent.get();
- }
-
protected ViewPair createViewsOnMainSync(final TestHelperBridge helperBridge0,
final TestHelperBridge helperBridge1,
final XWalkClient client0,
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- XWalkContent content0 = walkView0.getXWalkViewContentForTest();
- XWalkContent content1 = walkView1.getXWalkViewContentForTest();
- viewPair.set(new ViewPair(content0, helperBridge0, content1, helperBridge1));
+ viewPair.set(new ViewPair(walkView0, helperBridge0, walkView1, helperBridge1));
}
});
protected void loadAssetFile(String fileName) throws Exception {
String fileContent = getFileContent(fileName);
- loadDataSync(fileContent, "text/html", false);
+ loadDataSync(fileName, fileContent, "text/html", false);
}
public void loadAssetFileAndWaitForTitle(String fileName) throws Exception {
int currentCallCount = getTitleHelper.getCallCount();
String fileContent = getFileContent(fileName);
- loadDataSync(fileContent, "text/html", false);
+ loadDataSync(fileName, fileContent, "text/html", false);
getTitleHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
TimeUnit.SECONDS);
TimeUnit.SECONDS);
}
- protected void reloadSync() throws Exception {
+ protected void reloadSync(final int mode) throws Exception {
runTestWaitPageFinished(new Runnable(){
@Override
public void run() {
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- mXWalkView.reload();
+ mXWalkView.reload(mode);
}
});
}
}
protected String executeJavaScriptAndWaitForResult(final String code) throws Exception {
- final OnEvaluateJavaScriptResultHelper helper =
+
+ final TestHelperBridge.OnEvaluateJavaScriptResultHelper helper =
mTestHelperBridge.getOnEvaluateJavaScriptResultHelper();
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- XWalkContent content = mXWalkView.getXWalkViewContentForTest();
- helper.evaluateJavaScript(content.getContentViewCoreForTest(), code);
+ helper.evaluateJavascript(mXWalkView, code);
}
});
helper.waitUntilHasValue();
--- /dev/null
+<html>
+<head>
+<title>Original Title</title>
+<script>
+window.onload = function() {
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState==4 && xhr.status==200) {
+ // The response text from test server should be "Cross-Origin XHR".
+ document.title = xhr.responseText;
+ }
+ };
+ xhr.open("GET", 'http://localhost:4444/cross_origin_xhr_test.html', true);
+ xhr.send();
+}
+</script>
+</head>
+<body>
+<h1>Test Page for Cross-Origin XHR.</hi>
+</body>
+</html>
--- /dev/null
+{
+ "name": "Cross Origin XHR Test",
+ "version": "1.0.0",
+ "description": "Test for Cross-Origin XHR without xwalk_hosts",
+ "app": {
+ "launch": {
+ "local_path": "cross_origin.html"
+ }
+ }
+}
--- /dev/null
+{
+ "name": "Cross Origin XHR Test",
+ "version": "1.0.0",
+ "description": "Test for Cross-Origin XHR",
+ "app": {
+ "launch": {
+ "local_path": "cross_origin.html"
+ }
+ },
+ "xwalk_hosts": [
+ "http://localhost:4444/*"
+ ]
+}
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.runtime.client.test;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import org.chromium.base.test.util.Feature;
+import org.xwalk.runtime.client.shell.XWalkRuntimeClientShellActivity;
+import org.xwalk.test.util.RuntimeClientApiTestBase;
+
+/**
+ * Test suite for CrossOriginXhr.
+ */
+public class CrossOriginXhrTest extends XWalkRuntimeClientTestBase {
+
+ @SmallTest
+ @Feature({"CrossOriginXhr"})
+ public void testCrossOriginXhr() throws Throwable {
+ RuntimeClientApiTestBase<XWalkRuntimeClientShellActivity> helper =
+ new RuntimeClientApiTestBase<XWalkRuntimeClientShellActivity>(
+ getTestUtil(), this);
+ helper.testCrossOriginXhr();
+ }
+}
<uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
--- /dev/null
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.xwalk.runtime.client.embedded.test;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import org.chromium.base.test.util.Feature;
+import org.xwalk.runtime.client.embedded.shell.XWalkRuntimeClientEmbeddedShellActivity;
+import org.xwalk.test.util.RuntimeClientApiTestBase;
+
+/**
+ * Test suite for CrossOriginXhr.
+ */
+public class CrossOriginXhrTest extends XWalkRuntimeClientTestBase {
+
+ @SmallTest
+ @Feature({"CrossOriginXhr"})
+ public void testCrossOriginXhr() throws Throwable {
+ RuntimeClientApiTestBase<XWalkRuntimeClientEmbeddedShellActivity> helper =
+ new RuntimeClientApiTestBase<XWalkRuntimeClientEmbeddedShellActivity>(
+ getTestUtil(), this);
+ helper.testCrossOriginXhr();
+ }
+}
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.net.test.util.TestWebServer;
/**
* Test helper for Runtime client APIs.
*/
});
}
- // For testCSP.
+ // For testCSP.
public void testCSP() throws Throwable {
final String originalTitle = "Original Title";
final String newTitle = "New Title";
});
}
+ // For Cross-Origin XHR.
+ public void testCrossOriginXhr() throws Throwable {
+ TestWebServer webServer = null;
+ try {
+ // The server will be accessed by XMLHttpRequest from js.
+ webServer = new TestWebServer(false);
+ final String path = "/cross_origin_xhr_test.html";
+ final String responseStr = "Cross-Origin XHR";
+ final String url = webServer.setResponse(path, responseStr, null);
+ mTestCase.assertEquals("http://localhost:4444/cross_origin_xhr_test.html", url);
+
+ // The original title of the cross_origin.html.
+ final String originalTitle = "Original Title";
+
+ // Test without the xwalk_hosts member.
+ mTestUtil.loadManifestSync("file:///android_asset/www/manifest_without_xwalk_hosts.json");
+ Thread.sleep(1000);
+ mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ String title = mTestUtil.getTestedView().getTitleForTest();
+ // XHR in page should be failed, and the title should be "Original Title".
+ mTestCase.assertEquals(originalTitle, title);
+ }
+ });
+
+ // Test with the manifest which has a xwalk_host member.
+ mTestUtil.loadManifestSync("file:///android_asset/www/manifest_xwalk_hosts.json");
+ Thread.sleep(1000);
+ mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ String title = mTestUtil.getTestedView().getTitleForTest();
+ // XHR in page should be success, and the title should be "Cross-Origin XHR".
+ mTestCase.assertEquals(responseStr, title);
+ }
+ });
+
+ // Retry with app:// scheme.
+ final String host = mTestCase.getActivity().getPackageName();
+ mTestUtil.loadManifestSync("app://" + host + "/manifest_without_xwalk_hosts.json");
+ Thread.sleep(1000);
+ mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ String title = mTestUtil.getTestedView().getTitleForTest();
+ mTestCase.assertEquals(originalTitle, title);
+ }
+ });
+
+ mTestUtil.loadManifestSync("app://" + host + "/manifest_xwalk_hosts.json");
+ Thread.sleep(1000);
+ mTestCase.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ String title = mTestUtil.getTestedView().getTitleForTest();
+ mTestCase.assertEquals(responseStr, title);
+ }
+ });
+ } finally {
+ if (webServer != null) webServer.shutdown();
+ }
+ }
+
// For internal extension implementation of Contacts.
public void testContacts() throws Throwable {
String title = mTestUtil.loadAssetFileAndWaitForTitle("contacts.html");
'..',
],
'sources': [
+ '../extensions/common/constants.cc',
+ '../extensions/common/constants.h',
+ '../extensions/common/url_pattern.cc',
+ '../extensions/common/url_pattern.h',
'runtime/app/android/xwalk_main_delegate_android.cc',
'runtime/app/android/xwalk_main_delegate_android.h',
'runtime/app/xwalk_main_delegate.cc',
'runtime/browser/android/xwalk_request_interceptor.cc',
'runtime/browser/android/xwalk_request_interceptor.h',
'runtime/browser/android/xwalk_settings.cc',
+ 'runtime/browser/android/xwalk_view_delegate.cc',
+ 'runtime/browser/android/xwalk_view_delegate.h',
'runtime/browser/android/xwalk_web_contents_delegate.cc',
'runtime/browser/android/xwalk_web_contents_delegate.h',
'runtime/browser/android/xwalk_web_contents_view_delegate.cc',
'runtime/common/xwalk_common_message_generator.h',
'runtime/common/xwalk_content_client.cc',
'runtime/common/xwalk_content_client.h',
+ 'runtime/common/xwalk_localized_error.cc',
+ 'runtime/common/xwalk_localized_error.h',
'runtime/common/xwalk_paths.cc',
'runtime/common/xwalk_paths.h',
'runtime/common/xwalk_runtime_features.cc',
'runtime/renderer/android/xwalk_render_view_ext.h',
'runtime/renderer/tizen/xwalk_content_renderer_client_tizen.cc',
'runtime/renderer/tizen/xwalk_content_renderer_client_tizen.h',
+ 'runtime/renderer/tizen/xwalk_render_view_ext_tizen.cc',
+ 'runtime/renderer/tizen/xwalk_render_view_ext_tizen.h',
'runtime/renderer/xwalk_content_renderer_client.cc',
'runtime/renderer/xwalk_content_renderer_client.h',
'runtime/renderer/xwalk_render_process_observer_generic.cc',
'runtime/browser/ui/screen_orientation.h',
'runtime/extension/screen_orientation_extension.cc',
'runtime/extension/screen_orientation_extension.h',
+ 'runtime/browser/tizen/tizen_locale_listener.cc',
+ 'runtime/browser/tizen/tizen_locale_listener.h',
],
'sources!':[
'runtime/browser/runtime_platform_util_linux.cc',
'type': 'none',
'variables': {
'jni_gen_package': 'xwalk',
- 'jni_generator_ptr_type': 'int',
},
'sources': [
'runtime/android/core/src/org/xwalk/core/AndroidProtocolHandler.java',
'runtime/android/core/src/org/xwalk/core/XWalkCookieManager.java',
'runtime/android/core/src/org/xwalk/core/XWalkDevToolsServer.java',
'runtime/android/core/src/org/xwalk/core/XWalkSettings.java',
+ 'runtime/android/core/src/org/xwalk/core/XWalkViewDelegate.java',
'runtime/android/core/src/org/xwalk/core/XWalkWebContentsDelegate.java',
],
'includes': ['../build/jni_generator.gypi'],
'type': 'none',
'variables': {
'jni_gen_package': 'xwalk',
- 'jni_generator_ptr_type': 'int',
},
'sources': [
'extensions/android/java/src/org/xwalk/core/extensions/XWalkExtensionAndroid.java',
'type': 'none',
'dependencies': [
'../content/content_shell_and_tests.gyp:content_java_test_support',
+ '../net/net.gyp:net_java_test_support',
],
'variables': {
'java_in_dir': 'test/android/util',
'<(PRODUCT_DIR)/runtime_client_shell/assets/sampapp-icon-helloworld.png',
'<(PRODUCT_DIR)/runtime_client_shell/assets/www/manifest_self.json',
'<(PRODUCT_DIR)/runtime_client_shell/assets/www/manifest_inline_script.json',
+ '<(PRODUCT_DIR)/runtime_client_shell/assets/www/cross_origin.html',
'<(PRODUCT_DIR)/runtime_client_shell/assets/www/csp.html',
+ '<(PRODUCT_DIR)/runtime_client_shell/assets/www/manifest_without_xwalk_hosts.json',
+ '<(PRODUCT_DIR)/runtime_client_shell/assets/www/manifest_xwalk_hosts.json',
],
'asset_location': '<(PRODUCT_DIR)/runtime_client_shell/assets',
},
'files': [
'test/android/data/www/manifest_self.json',
'test/android/data/www/manifest_inline_script.json',
+ 'test/android/data/www/cross_origin.html',
'test/android/data/www/csp.html',
+ 'test/android/data/www/manifest_without_xwalk_hosts.json',
+ 'test/android/data/www/manifest_xwalk_hosts.json',
],
},
],
'<(PRODUCT_DIR)/runtime_client_embedded_shell/assets/xwalk.pak',
'<(PRODUCT_DIR)/runtime_client_embedded_shell/assets/www/manifest_self.json',
'<(PRODUCT_DIR)/runtime_client_embedded_shell/assets/www/manifest_inline_script.json',
+ '<(PRODUCT_DIR)/runtime_client_embedded_shell/assets/www/cross_origin.html',
'<(PRODUCT_DIR)/runtime_client_embedded_shell/assets/www/csp.html',
+ '<(PRODUCT_DIR)/runtime_client_embedded_shell/assets/www/manifest_without_xwalk_hosts.json',
+ '<(PRODUCT_DIR)/runtime_client_embedded_shell/assets/www/manifest_xwalk_hosts.json',
],
'conditions': [
['icu_use_data_file_flag==1', {
'files': [
'test/android/data/www/manifest_self.json',
'test/android/data/www/manifest_inline_script.json',
+ 'test/android/data/www/cross_origin.html',
'test/android/data/www/csp.html',
+ 'test/android/data/www/manifest_without_xwalk_hosts.json',
+ 'test/android/data/www/manifest_xwalk_hosts.json',
],
},
],
],
'includes': [ '../build/java_apk.gypi' ],
},
+ {
+ 'target_name': 'xwalk_core_sample_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'libxwalkcore',
+ 'xwalk_core_extensions_java',
+ 'xwalk_core_java',
+ 'xwalk_core_shell_apk_pak',
+ ],
+ 'variables': {
+ 'apk_name': 'CrosswalkSample',
+ 'java_in_dir': 'runtime/android/sample',
+ 'resource_dir': 'runtime/android/sample/res',
+ 'native_lib_target': 'libxwalkcore',
+ 'additional_input_paths': [
+ '<(PRODUCT_DIR)/sample/assets/index.html',
+ '<(PRODUCT_DIR)/sample/assets/manifest.json',
+ '<(PRODUCT_DIR)/sample/assets/pause_timers.html',
+ '<(PRODUCT_DIR)/sample/assets/xwalk.pak',
+ ],
+ 'conditions': [
+ ['icu_use_data_file_flag==1', {
+ 'additional_input_paths': [
+ '<(PRODUCT_DIR)/sample/assets/icudtl.dat',
+ ],
+ }],
+ ],
+ 'asset_location': '<(PRODUCT_DIR)/sample/assets',
+ },
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/sample/assets',
+ 'files': [
+ 'runtime/android/sample/assets/index.html',
+ 'runtime/android/sample/assets/manifest.json',
+ 'runtime/android/sample/assets/pause_timers.html',
+ '<(PRODUCT_DIR)/xwalk.pak',
+ ],
+ 'conditions': [
+ ['icu_use_data_file_flag==1', {
+ 'files': [
+ '<(PRODUCT_DIR)/icudtl.dat',
+ ],
+ }],
+ ],
+ },
+ ],
+ 'includes': [ '../build/java_apk.gypi' ],
+ },
],
}
# found in the LICENSE file.
{
+ 'variables': {
+ 'core_library_empty_embedder_apk_name': 'XWalkCoreLibraryEmptyEmbedder',
+ },
'targets': [
{
'target_name': 'pack_xwalk_core_library',
],
},
{
+ 'target_name': 'xwalk_core_library_empty_embedder_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'libxwalkcore',
+ 'xwalk_core_java',
+ ],
+ 'variables': {
+ 'apk_name': '<(core_library_empty_embedder_apk_name)',
+ 'java_in_dir': 'runtime/android/core_library_empty',
+ 'native_lib_target': 'libxwalkcore',
+ 'is_test_apk': 1,
+ 'additional_src_dirs': [
+ '<(DEPTH)/ui/android/java/resource_map',
+ '<(DEPTH)/content/public/android/java/resource_map',
+ ],
+ },
+ 'includes': [ '../build/java_apk.gypi' ],
+ },
+ {
+ # pack classes compiled from the java files chromium generated into a
+ # jar file.
+ 'target_name': 'chromium_generated_java',
+ 'type': 'none',
+ 'dependencies': [
+ 'xwalk_core_library_empty_embedder_apk',
+ ],
+ 'variables': {
+ 'jar_name': '<(_target_name).jar',
+ 'jar_final_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
+ 'jar_excluded_classes': [
+ '*org/xwalk/*',
+ ],
+ },
+ 'actions': [
+ {
+ 'action_name': 'jar_<(_target_name)',
+ 'message': 'Creating <(_target_name) jar',
+ 'inputs': [
+ '<(DEPTH)/build/android/gyp/util/build_utils.py',
+ '<(DEPTH)/build/android/gyp/util/md5_check.py',
+ '<(DEPTH)/build/android/gyp/jar.py',
+ '<(PRODUCT_DIR)/apks/<(core_library_empty_embedder_apk_name).apk',
+ ],
+ 'outputs': [
+ '<(jar_final_path)',
+ ],
+ 'action': [
+ 'python', '<(DEPTH)/build/android/gyp/jar.py',
+ '--classes-dir=<(PRODUCT_DIR)/xwalk_core_library_empty_embedder_apk/classes',
+ '--jar-path=<(jar_final_path)',
+ '--excluded-classes=<(jar_excluded_classes)',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'xwalk_core_library_java',
+ 'type': 'none',
+ 'dependencies': [
+ 'xwalk_core_java',
+ 'chromium_generated_java',
+ ],
+ 'variables': {
+ 'classes_dir': '<(PRODUCT_DIR)/<(_target_name)/classes',
+ 'jar_name': '<(_target_name).jar',
+ 'jar_final_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
+ #TODO(wang16): figure out why the 'jar_final_path' defined in chromium_generated_java
+ # not added into following all_dependent_settings setting chain.
+ # BUG=https://crosswalk-project.org/jira/browse/XWALK-1575
+ 'input_jars_paths': ['<(PRODUCT_DIR)/lib.java/chromium_generated_java.jar'],
+ },
+ 'all_dependent_settings': {
+ 'variables': {
+ 'input_jars_paths': ['<(jar_final_path)'],
+ },
+ },
+ 'actions': [
+ {
+ 'action_name': 'jars_<(_target_name)',
+ 'message': 'Creating <(_target_name) jar',
+ 'inputs': [
+ 'build/android/merge_jars.py',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/pack_xwalk_core_library_java_intermediate/always_run',
+ ],
+ 'action': [
+ 'python', 'build/android/merge_jars.py',
+ '--classes-dir=<(classes_dir)',
+ '--jars=>(input_jars_paths)',
+ '--jar-path=<(jar_final_path)',
+ ],
+ },
+ ],
+ },
+ {
'target_name': 'xwalk_core_library',
'type': 'none',
'dependencies': [
- 'xwalk_core_shell_apk'
+ 'xwalk_core_shell_apk',
+ 'xwalk_core_library_java',
],
'actions': [
{