更改安卓webkit默认的Not found page
2013 年 4 月 28 日 更改安卓webkit默认的Not found page有1条评论
更改后效果如下图所示:nodomain
显示部分由html完全实现,修改只需修改这部分即可。webkit显示该页面的具体实现过程为通过上层framework BrowserFrame.java找到resid,之后传给webkit中的FrameLoaderClientAndroid.cpp中处理文件内容,置换其中的%s字串为网址。附件中的nodomain.html文件放在framework/base/core/res/res/raw目录下,具有语言区分。图片资源放在res/assets/webkit目录下,本文附件中的html及相关代码如下所示:
<!--Add by tianyu-->
<html>
<head>
<meta name="viewport" content="target-densitydpi=320, initial-scale=1.0, user-scalable=no" />
<title>找不到网页</title>
<style type="text/css">
body { margin-top: 0px; padding-top: 0px; }
h2 { margin-top: 5px; padding-top: 50px; padding-left: 190px; color:#444444; font-size:42px;}
li, p1 { margin-top: 5px; padding-top: 10px; color:#7e7e7e; font-size:28px;}
a:link { text-decoration: underline;color: #ff8800}
a:active { text-decoration:blink}
a:hover { text-decoration:underline;color: red}
a:visited { text-decoration: underline;color: #ff8800}
.web{width:528px;margin:0 auto;}
.no_web{width:720px;margin:0 auto; color:#444444; font-size:42px; align:center}
.p0{ margin-top: 5px; padding-top: 40px; color:#444444; font-size:42px; align:center;}
.p1{ margin-top: 5px; padding-top: 0px; padding-bottom: 20px; color:#7e7e7e; font-size:28px;line-height:40px}
.p2{ color:#7e7e7e; font-size:28px; margin:-10px auto;}
</style>
<body style="background:#f2f2f2">
<div>
<div style="width:238px;margin:0 auto;margin-top:40px">
<img width="238" height="238" src="file:///android_asset/webkit/android-weberror-face.png" />
</div>
</div>
<div class="web">
<p class="p0" align="center">无法访问该网页!</p>
<p class="p1"><a href="%s">%s</a> 处的网页可能暂时出现故障,也可能已永久移至某个新的网络地址。</p>
<p class="p2">以下是几点建议:</p>
<ul>
<li>进行检查以确保您的设备具有信号和数据连接</li>
<li>稍后重新载入该网页。</li>
<li>查看 Google 提供的该网页的缓存副本</li>
</ul>
</div>
</body>
</head>
</html>
<html>
<head>
<meta name="viewport" content="target-densitydpi=320, initial-scale=1.0, user-scalable=no" />
<title>找不到网页</title>
<style type="text/css">
body { margin-top: 0px; padding-top: 0px; }
h2 { margin-top: 5px; padding-top: 50px; padding-left: 190px; color:#444444; font-size:42px;}
li, p1 { margin-top: 5px; padding-top: 10px; color:#7e7e7e; font-size:28px;}
a:link { text-decoration: underline;color: #ff8800}
a:active { text-decoration:blink}
a:hover { text-decoration:underline;color: red}
a:visited { text-decoration: underline;color: #ff8800}
.web{width:528px;margin:0 auto;}
.no_web{width:720px;margin:0 auto; color:#444444; font-size:42px; align:center}
.p0{ margin-top: 5px; padding-top: 40px; color:#444444; font-size:42px; align:center;}
.p1{ margin-top: 5px; padding-top: 0px; padding-bottom: 20px; color:#7e7e7e; font-size:28px;line-height:40px}
.p2{ color:#7e7e7e; font-size:28px; margin:-10px auto;}
</style>
<body style="background:#f2f2f2">
<div>
<div style="width:238px;margin:0 auto;margin-top:40px">
<img width="238" height="238" src="file:///android_asset/webkit/android-weberror-face.png" />
</div>
</div>
<div class="web">
<p class="p0" align="center">无法访问该网页!</p>
<p class="p1"><a href="%s">%s</a> 处的网页可能暂时出现故障,也可能已永久移至某个新的网络地址。</p>
<p class="p2">以下是几点建议:</p>
<ul>
<li>进行检查以确保您的设备具有信号和数据连接</li>
<li>稍后重新载入该网页。</li>
<li>查看 Google 提供的该网页的缓存副本</li>
</ul>
</div>
</body>
</head>
</html>
/* package */ static String getRawResFilename(int id, Context context) {
int resid;
switch (id) {
case NODOMAIN:
resid = com.android.internal.R.raw.nodomain;
break;
case LOADERROR:
resid = com.android.internal.R.raw.loaderror;
break;
case DRAWABLEDIR:
// use one known resource to find the drawable directory
resid = com.android.internal.R.drawable.btn_check_off;
break;
case FILE_UPLOAD_LABEL:
return context.getResources().getString(
com.android.internal.R.string.upload_file);
case RESET_LABEL:
return context.getResources().getString(
com.android.internal.R.string.reset);
case SUBMIT_LABEL:
return context.getResources().getString(
com.android.internal.R.string.submit);
case FILE_UPLOAD_NO_FILE_CHOSEN:
return context.getResources().getString(
com.android.internal.R.string.no_file_chosen);
default:
Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
return "";
}
TypedValue value = new TypedValue();
context.getResources().getValue(resid, value, true);
if (id == DRAWABLEDIR) {
String path = value.string.toString();
int index = path.lastIndexOf('/');
if (index < 0) {
Log.e(LOGTAG, "Can't find drawable directory.");
return "";
}
return path.substring(0, index + 1);
}
return value.string.toString();
}
int resid;
switch (id) {
case NODOMAIN:
resid = com.android.internal.R.raw.nodomain;
break;
case LOADERROR:
resid = com.android.internal.R.raw.loaderror;
break;
case DRAWABLEDIR:
// use one known resource to find the drawable directory
resid = com.android.internal.R.drawable.btn_check_off;
break;
case FILE_UPLOAD_LABEL:
return context.getResources().getString(
com.android.internal.R.string.upload_file);
case RESET_LABEL:
return context.getResources().getString(
com.android.internal.R.string.reset);
case SUBMIT_LABEL:
return context.getResources().getString(
com.android.internal.R.string.submit);
case FILE_UPLOAD_NO_FILE_CHOSEN:
return context.getResources().getString(
com.android.internal.R.string.no_file_chosen);
default:
Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
return "";
}
TypedValue value = new TypedValue();
context.getResources().getValue(resid, value, true);
if (id == DRAWABLEDIR) {
String path = value.string.toString();
int index = path.lastIndexOf('/');
if (index < 0) {
Log.e(LOGTAG, "Can't find drawable directory.");
return "";
}
return path.substring(0, index + 1);
}
return value.string.toString();
}
void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
ASSERT(m_frame);
// Ignore ErrorInterrupted since it is due to a policy interruption. This
// is caused by a decision to download the main resource rather than
// display it.
if (error.errorCode() == InternalErrorInterrupted
|| error.errorCode() == InternalErrorCancelled) {
// If we decided to download the main resource or if the user cancelled
// it, make sure we report that the load is done.
didFinishLoad();
return;
}
AssetManager* am = globalAssetManager();
// Check to see if the error code was not generated internally
WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain;
if ((error.errorCode() == ErrorFile ||
error.errorCode() == ErrorFileNotFound) &&
(!error.localizedDescription().isEmpty())) {
id = WebCore::PlatformBridge::LoadError;
}
String filename = m_webFrame->getRawResourceFilename(id);
if (filename.isEmpty())
return;
// Grab the error page from the asset manager
Asset* a = am->openNonAsset(
filename.utf8().data(), Asset::ACCESS_BUFFER);
if (!a)
return;
// Take the failing url and encode html entities so javascript urls are not
// executed.
CString failingUrl = error.failingURL().utf8();
WTF::Vector<char> url;
int len = failingUrl.length();
const char* data = failingUrl.data();
for (int i = 0; i < len; i++) {
char c = data[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9'))
url.append(c);
else {
char buf[16];
int res = sprintf(buf, "&#%d;", c);
buf[res] = 0;
url.append(buf, res);
}
}
// Vector sets up its data buffer lazilly, so if failingUrl is the empty
// string, the data buffer will be null. This will result in sanitizedUrl
// being null, and the string substitution below will be a no-op.
// FIXME: Ideally we'd always have a non-empty URL, or at least improve the
// wording of the error page in this case. See http://b/5293782.
String sanitizedUrl = url.data() ? String(url.data(), url.size()) : "";
// Replace all occurances of %s with the failing url.
String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
s = s.replace("%s", sanitizedUrl);
// Replace all occurances of %e with the error text
s = s.replace("%e", error.localizedDescription());
// Create the request and the substitute data and tell the FrameLoader to
// load with the replacement data.
// use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
// invalidate URL string.
loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s);
// Delete the asset.
delete a;
// Report that the load is finished, since it failed.
didFinishLoad();
}
ASSERT(m_frame);
// Ignore ErrorInterrupted since it is due to a policy interruption. This
// is caused by a decision to download the main resource rather than
// display it.
if (error.errorCode() == InternalErrorInterrupted
|| error.errorCode() == InternalErrorCancelled) {
// If we decided to download the main resource or if the user cancelled
// it, make sure we report that the load is done.
didFinishLoad();
return;
}
AssetManager* am = globalAssetManager();
// Check to see if the error code was not generated internally
WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain;
if ((error.errorCode() == ErrorFile ||
error.errorCode() == ErrorFileNotFound) &&
(!error.localizedDescription().isEmpty())) {
id = WebCore::PlatformBridge::LoadError;
}
String filename = m_webFrame->getRawResourceFilename(id);
if (filename.isEmpty())
return;
// Grab the error page from the asset manager
Asset* a = am->openNonAsset(
filename.utf8().data(), Asset::ACCESS_BUFFER);
if (!a)
return;
// Take the failing url and encode html entities so javascript urls are not
// executed.
CString failingUrl = error.failingURL().utf8();
WTF::Vector<char> url;
int len = failingUrl.length();
const char* data = failingUrl.data();
for (int i = 0; i < len; i++) {
char c = data[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9'))
url.append(c);
else {
char buf[16];
int res = sprintf(buf, "&#%d;", c);
buf[res] = 0;
url.append(buf, res);
}
}
// Vector sets up its data buffer lazilly, so if failingUrl is the empty
// string, the data buffer will be null. This will result in sanitizedUrl
// being null, and the string substitution below will be a no-op.
// FIXME: Ideally we'd always have a non-empty URL, or at least improve the
// wording of the error page in this case. See http://b/5293782.
String sanitizedUrl = url.data() ? String(url.data(), url.size()) : "";
// Replace all occurances of %s with the failing url.
String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
s = s.replace("%s", sanitizedUrl);
// Replace all occurances of %e with the error text
s = s.replace("%e", error.localizedDescription());
// Create the request and the substitute data and tell the FrameLoader to
// load with the replacement data.
// use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
// invalidate URL string.
loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s);
// Delete the asset.
delete a;
// Report that the load is finished, since it failed.
didFinishLoad();
}
评论:1