1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "android_webview/native/state_serializer.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/pickle.h"
11 #include "base/time.h"
12 #include "content/public/browser/navigation_controller.h"
13 #include "content/public/browser/navigation_entry.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/page_state.h"
17 // Reasons for not re-using TabNavigation under chrome/ as of 20121116:
18 // * Android WebView has different requirements for fields to store since
19 // we are the only ones using values like BaseURLForDataURL.
20 // * TabNavigation does unnecessary copying of data, which in Android
21 // WebView case, is undesired since save/restore is called in Android
23 // * TabNavigation is tightly integrated with the rest of chrome session
24 // restore and sync code, and has other purpose in addition to serializing
29 namespace android_webview
{
33 // Sanity check value that we are restoring from a valid pickle.
34 // This can potentially used as an actual serialization version number in the
35 // future if we ever decide to support restoring from older versions.
36 const uint32 AW_STATE_VERSION
= 20121126;
40 bool WriteToPickle(const content::WebContents
& web_contents
,
44 if (!internal::WriteHeaderToPickle(pickle
))
47 const content::NavigationController
& controller
=
48 web_contents
.GetController();
49 const int entry_count
= controller
.GetEntryCount();
50 const int selected_entry
= controller
.GetCurrentEntryIndex();
51 DCHECK(entry_count
>= 0);
52 DCHECK(selected_entry
>= -1); // -1 is valid
53 DCHECK(selected_entry
< entry_count
);
55 if (!pickle
->WriteInt(entry_count
))
58 if (!pickle
->WriteInt(selected_entry
))
61 for (int i
= 0; i
< entry_count
; ++i
) {
62 if (!internal::WriteNavigationEntryToPickle(*controller
.GetEntryAtIndex(i
),
67 // Please update AW_STATE_VERSION if serialization format is changed.
72 bool RestoreFromPickle(PickleIterator
* iterator
,
73 content::WebContents
* web_contents
) {
77 if (!internal::RestoreHeaderFromPickle(iterator
))
81 int selected_entry
= -2; // -1 is a valid value
83 if (!iterator
->ReadInt(&entry_count
))
86 if (!iterator
->ReadInt(&selected_entry
))
91 if (selected_entry
< -1)
93 if (selected_entry
>= entry_count
)
96 ScopedVector
<content::NavigationEntry
> restored_entries
;
97 for (int i
= 0; i
< entry_count
; ++i
) {
98 restored_entries
.push_back(content::NavigationEntry::Create());
99 if (!internal::RestoreNavigationEntryFromPickle(iterator
,
100 restored_entries
[i
]))
103 restored_entries
[i
]->SetPageID(i
);
106 // |web_contents| takes ownership of these entries after this call.
107 web_contents
->GetController().Restore(
109 content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
110 &restored_entries
.get());
111 DCHECK_EQ(0u, restored_entries
.size());
118 bool WriteHeaderToPickle(Pickle
* pickle
) {
119 return pickle
->WriteUInt32(AW_STATE_VERSION
);
122 bool RestoreHeaderFromPickle(PickleIterator
* iterator
) {
123 uint32 state_version
= -1;
124 if (!iterator
->ReadUInt32(&state_version
))
127 if (AW_STATE_VERSION
!= state_version
)
133 bool WriteNavigationEntryToPickle(const content::NavigationEntry
& entry
,
135 if (!pickle
->WriteString(entry
.GetURL().spec()))
138 if (!pickle
->WriteString(entry
.GetVirtualURL().spec()))
141 const content::Referrer
& referrer
= entry
.GetReferrer();
142 if (!pickle
->WriteString(referrer
.url
.spec()))
144 if (!pickle
->WriteInt(static_cast<int>(referrer
.policy
)))
147 if (!pickle
->WriteString16(entry
.GetTitle()))
150 if (!pickle
->WriteString(entry
.GetPageState().ToEncodedData()))
153 if (!pickle
->WriteBool(static_cast<int>(entry
.GetHasPostData())))
156 if (!pickle
->WriteString(entry
.GetOriginalRequestURL().spec()))
159 if (!pickle
->WriteString(entry
.GetBaseURLForDataURL().spec()))
162 if (!pickle
->WriteBool(static_cast<int>(entry
.GetIsOverridingUserAgent())))
165 if (!pickle
->WriteInt64(entry
.GetTimestamp().ToInternalValue()))
168 // Please update AW_STATE_VERSION if serialization format is changed.
173 bool RestoreNavigationEntryFromPickle(PickleIterator
* iterator
,
174 content::NavigationEntry
* entry
) {
177 if (!iterator
->ReadString(&url
))
179 entry
->SetURL(GURL(url
));
184 if (!iterator
->ReadString(&virtual_url
))
186 entry
->SetVirtualURL(GURL(virtual_url
));
190 content::Referrer referrer
;
194 if (!iterator
->ReadString(&referrer_url
))
196 if (!iterator
->ReadInt(&policy
))
199 referrer
.url
= GURL(referrer_url
);
200 referrer
.policy
= static_cast<WebKit::WebReferrerPolicy
>(policy
);
201 entry
->SetReferrer(referrer
);
206 if (!iterator
->ReadString16(&title
))
208 entry
->SetTitle(title
);
212 string content_state
;
213 if (!iterator
->ReadString(&content_state
))
216 content::PageState::CreateFromEncodedData(content_state
));
221 if (!iterator
->ReadBool(&has_post_data
))
223 entry
->SetHasPostData(has_post_data
);
227 string original_request_url
;
228 if (!iterator
->ReadString(&original_request_url
))
230 entry
->SetOriginalRequestURL(GURL(original_request_url
));
234 string base_url_for_data_url
;
235 if (!iterator
->ReadString(&base_url_for_data_url
))
237 entry
->SetBaseURLForDataURL(GURL(base_url_for_data_url
));
241 bool is_overriding_user_agent
;
242 if (!iterator
->ReadBool(&is_overriding_user_agent
))
244 entry
->SetIsOverridingUserAgent(is_overriding_user_agent
);
249 if (!iterator
->ReadInt64(×tamp
))
251 entry
->SetTimestamp(base::Time::FromInternalValue(timestamp
));
257 } // namespace internal
259 } // namespace android_webview