| // Copyright 2016 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 "android_webview/browser/aw_permission_manager.h" | 
 |  | 
 | #include <list> | 
 | #include <memory> | 
 |  | 
 | #include "android_webview/browser/aw_browser_permission_request_delegate.h" | 
 | #include "base/bind.h" | 
 | #include "base/bind_helpers.h" | 
 | #include "content/public/browser/permission_manager.h" | 
 | #include "content/public/browser/permission_type.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "url/gurl.h" | 
 |  | 
 | using blink::mojom::PermissionStatus; | 
 | using content::PermissionType; | 
 |  | 
 | namespace android_webview { | 
 |  | 
 | namespace { | 
 |  | 
 | int kNoPendingOperation = -1; | 
 |  | 
 | int kRenderProcessIDForTesting = 8; | 
 | int kRenderFrameIDForTesting = 19; | 
 | const char kEmbeddingOrigin[] = "https://www.google.com/"; | 
 | const char kRequestingOrigin1[] = "https://www.google.com/"; | 
 | const char kRequestingOrigin2[] = "https://www.chromium.org/"; | 
 |  | 
 | class AwBrowserPermissionRequestDelegateForTesting final | 
 |     : public AwBrowserPermissionRequestDelegate { | 
 |  public: | 
 |   void EnqueueResponse(const std::string& origin, | 
 |                        PermissionType type, | 
 |                        bool grant) { | 
 |     for (auto it = request_.begin(); it != request_.end(); ++it) { | 
 |       if ((*it)->type != type || (*it)->origin != origin) | 
 |         continue; | 
 |       const base::Callback<void(bool)> callback = (*it)->callback; | 
 |       request_.erase(it); | 
 |       callback.Run(grant); | 
 |       return; | 
 |     } | 
 |     response_.push_back(std::make_unique<Response>(origin, type, grant)); | 
 |   } | 
 |  | 
 |   // AwBrowserPermissionRequestDelegate: | 
 |   void RequestProtectedMediaIdentifierPermission( | 
 |       const GURL& origin, | 
 |       const base::Callback<void(bool)>& callback) override {} | 
 |  | 
 |   void CancelProtectedMediaIdentifierPermissionRequests( | 
 |       const GURL& origin) override {} | 
 |  | 
 |   void RequestGeolocationPermission( | 
 |       const GURL& origin, | 
 |       const base::Callback<void(bool)>& callback) override { | 
 |     RequestPermission(origin, PermissionType::GEOLOCATION, callback); | 
 |   } | 
 |  | 
 |   void CancelGeolocationPermissionRequests(const GURL& origin) override { | 
 |     CancelPermission(origin, PermissionType::GEOLOCATION); | 
 |   } | 
 |  | 
 |   void RequestMIDISysexPermission( | 
 |       const GURL& origin, | 
 |       const base::Callback<void(bool)>& callback) override { | 
 |     RequestPermission(origin, PermissionType::MIDI_SYSEX, callback); | 
 |   } | 
 |  | 
 |   void CancelMIDISysexPermissionRequests(const GURL& origin) override { | 
 |     CancelPermission(origin, PermissionType::MIDI_SYSEX); | 
 |   } | 
 |  | 
 |  private: | 
 |   void RequestPermission(const GURL& origin, | 
 |                          PermissionType type, | 
 |                          const base::Callback<void(bool)>& callback) { | 
 |     for (auto it = response_.begin(); it != response_.end(); ++it) { | 
 |       if ((*it)->type != type || (*it)->origin != origin) | 
 |         continue; | 
 |       bool grant = (*it)->grant; | 
 |       response_.erase(it); | 
 |       callback.Run(grant); | 
 |       return; | 
 |     } | 
 |     request_.push_back(std::make_unique<Request>(origin, type, callback)); | 
 |   } | 
 |  | 
 |   void CancelPermission(const GURL& origin, PermissionType type) { | 
 |     for (auto it = request_.begin(); it != request_.end(); ++it) { | 
 |       if ((*it)->type != type || (*it)->origin != origin) | 
 |         continue; | 
 |       request_.erase(it); | 
 |       return; | 
 |     } | 
 |     NOTREACHED(); | 
 |   } | 
 |  | 
 |  private: | 
 |   struct Request { | 
 |     GURL origin; | 
 |     PermissionType type; | 
 |     base::Callback<void(bool)> callback; | 
 |  | 
 |     Request(const GURL& origin, | 
 |             PermissionType type, | 
 |             const base::Callback<void(bool)>& callback) | 
 |         : origin(origin), type(type), callback(callback) {} | 
 |   }; | 
 |  | 
 |   struct Response { | 
 |     GURL origin; | 
 |     PermissionType type; | 
 |     bool grant; | 
 |  | 
 |     Response(const std::string& origin, PermissionType type, bool grant) | 
 |         : origin(GURL(origin)), type(type), grant(grant) {} | 
 |  | 
 |   }; | 
 |  | 
 |   std::list<std::unique_ptr<Response>> response_; | 
 |   std::list<std::unique_ptr<Request>> request_; | 
 | }; | 
 |  | 
 | class AwPermissionManagerForTesting : public AwPermissionManager { | 
 |  public: | 
 |   ~AwPermissionManagerForTesting() override { | 
 |     // Call CancelPermissionRequests() from here so that it calls virtual | 
 |     // methods correctly. | 
 |     CancelPermissionRequests(); | 
 |   } | 
 |  | 
 |   void EnqueuePermissionResponse(const std::string& origin, | 
 |                                  PermissionType type, | 
 |                                  bool grant) { | 
 |     delegate()->EnqueueResponse(origin, type, grant); | 
 |   } | 
 |  | 
 |  private: | 
 |   AwBrowserPermissionRequestDelegateForTesting* delegate() { | 
 |     if (!delegate_) | 
 |       delegate_.reset(new AwBrowserPermissionRequestDelegateForTesting); | 
 |     return delegate_.get(); | 
 |   } | 
 |  | 
 |   // AwPermissionManager: | 
 |   int GetRenderProcessID(content::RenderFrameHost* render_frame_host) override { | 
 |     return kRenderProcessIDForTesting; | 
 |   } | 
 |  | 
 |   int GetRenderFrameID(content::RenderFrameHost* render_frame_host) override { | 
 |     return kRenderFrameIDForTesting; | 
 |   } | 
 |  | 
 |   GURL LastCommittedOrigin( | 
 |       content::RenderFrameHost* render_frame_host) override { | 
 |     return GURL(kEmbeddingOrigin); | 
 |   } | 
 |  | 
 |   AwBrowserPermissionRequestDelegate* GetDelegate( | 
 |       int render_process_id, | 
 |       int render_frame_id) override { | 
 |     CHECK_EQ(kRenderProcessIDForTesting, render_process_id); | 
 |     CHECK_EQ(kRenderFrameIDForTesting, render_frame_id); | 
 |     return delegate(); | 
 |   } | 
 |  | 
 |   std::unique_ptr<AwBrowserPermissionRequestDelegateForTesting> delegate_; | 
 | }; | 
 |  | 
 | class AwPermissionManagerTest : public testing::Test { | 
 |  public: | 
 |   AwPermissionManagerTest() | 
 |       : render_frame_host(nullptr) {} | 
 |  | 
 |   void PermissionRequestResponse(int id, const PermissionStatus status) { | 
 |     resolved_permission_status.push_back(status); | 
 |     resolved_permission_request_id.push_back(id); | 
 |   } | 
 |  | 
 |   void PermissionsRequestResponse(int id, | 
 |                                   const std::vector<PermissionStatus>& status) { | 
 |     resolved_permission_status.insert(resolved_permission_status.end(), | 
 |                                       status.begin(), status.end()); | 
 |     for (size_t i = 0; i < status.size(); ++i) | 
 |       resolved_permission_request_id.push_back(id); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void SetUp() override { manager.reset(new AwPermissionManagerForTesting); } | 
 |   void TearDown() override { manager.reset(); } | 
 |  | 
 |   void EnqueuePermissionResponse(const std::string& origin, | 
 |                                  PermissionType type, | 
 |                                  bool grant) { | 
 |     CHECK(manager); | 
 |     manager->EnqueuePermissionResponse(origin, type, grant); | 
 |   } | 
 |  | 
 |   std::unique_ptr<AwPermissionManagerForTesting> manager; | 
 |  | 
 |   // Use nullptr for testing. AwPermissionManagerForTesting override all methods | 
 |   // that touch RenderFrameHost to work with nullptr. | 
 |   content::RenderFrameHost* render_frame_host; | 
 |  | 
 |   std::vector<PermissionStatus> resolved_permission_status; | 
 |   std::vector<int> resolved_permission_request_id; | 
 | }; | 
 |  | 
 | // The most simple test, PermissionType::MIDI is hard-coded to be granted. | 
 | TEST_F(AwPermissionManagerTest, MIDIPermissionIsGrantedSynchronously) { | 
 |   int request_id = manager->RequestPermission( | 
 |       PermissionType::MIDI, render_frame_host, GURL(kRequestingOrigin1), true, | 
 |       base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                  base::Unretained(this), 0)); | 
 |   EXPECT_EQ(kNoPendingOperation, request_id); | 
 |   ASSERT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 | } | 
 |  | 
 | // Test the case a delegate is called, and it resolves the permission | 
 | // synchronously. | 
 | TEST_F(AwPermissionManagerTest, SinglePermissionRequestIsGrantedSynchronously) { | 
 |   // Permission should be granted in this scenario. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   int request_id = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 0)); | 
 |   EXPECT_EQ(kNoPendingOperation, request_id); | 
 |   ASSERT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |  | 
 |   // Permission should not be granted in this scenario. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, false); | 
 |   request_id = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 0)); | 
 |   EXPECT_EQ(kNoPendingOperation, request_id); | 
 |   ASSERT_EQ(2u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]); | 
 | } | 
 |  | 
 | // Test the case a delegate is called, and it resolves the permission | 
 | // asynchronously. | 
 | TEST_F(AwPermissionManagerTest, | 
 |        SinglePermissionRequestIsGrantedAsynchronously) { | 
 |   int request_id = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 0)); | 
 |   EXPECT_NE(kNoPendingOperation, request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This will resolve the permission. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |  | 
 |   ASSERT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 | } | 
 |  | 
 | // Test the case a delegate is called, and the manager is deleted before the | 
 | // delegate callback is invoked. | 
 | TEST_F(AwPermissionManagerTest, ManagerIsDeletedWhileDelegateProcesses) { | 
 |   int request_id = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 0)); | 
 |  | 
 |   EXPECT_NE(kNoPendingOperation, request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // Delete the manager. | 
 |   manager.reset(); | 
 |  | 
 |   // All requests are cancelled internally. | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested for the same origin, and the | 
 | // second permission is also resolved when the first permission is resolved. | 
 | TEST_F(AwPermissionManagerTest, | 
 |        MultiplePermissionRequestsAreGrantedTogether) { | 
 |   int request_1 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 2)); | 
 |   EXPECT_NE(kNoPendingOperation, request_2); | 
 |  | 
 |   EXPECT_NE(request_1, request_2); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This will resolve the permission. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |  | 
 |   ASSERT_EQ(2u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested for different origins, and | 
 | // each permission is resolved respectively in the requested order. | 
 | TEST_F(AwPermissionManagerTest, | 
 |        MultiplePermissionRequestsAreGrantedRespectively) { | 
 |   int request_1 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin2), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 2)); | 
 |   EXPECT_NE(kNoPendingOperation, request_2); | 
 |  | 
 |   EXPECT_NE(request_1, request_2); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This will resolve the first request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |  | 
 |   ASSERT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[0]); | 
 |  | 
 |   // This will resolve the second request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin2, | 
 |                                      PermissionType::GEOLOCATION, false); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[1]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested through single | 
 | // RequestPermissions call, then resolved synchronously. | 
 | TEST_F(AwPermissionManagerTest, | 
 |        SinglePermissionsRequestIsGrantedSynchronously) { | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, false); | 
 |  | 
 |   std::vector<PermissionType> permissions = {PermissionType::MIDI, | 
 |                                              PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_id = manager->RequestPermissions( | 
 |       permissions, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 0)); | 
 |   EXPECT_EQ(kNoPendingOperation, request_id); | 
 |  | 
 |   ASSERT_EQ(2u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested through single | 
 | // RequestPermissions call, then one is resolved synchronously, the other is | 
 | // resolved asynchronously. | 
 | TEST_F(AwPermissionManagerTest, | 
 |        SinglePermissionsRequestIsGrantedAsynchronously) { | 
 |   std::vector<PermissionType> permissions = {PermissionType::MIDI, | 
 |                                              PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_id = manager->RequestPermissions( | 
 |       permissions, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 0)); | 
 |   EXPECT_NE(kNoPendingOperation, request_id); | 
 |  | 
 |   // PermissionType::MIDI is resolved synchronously, but all permissions result | 
 |   // are notified together when all permissions are resolved. | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, false); | 
 |  | 
 |   ASSERT_EQ(2u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested multiple times as follow. | 
 | //  1. Permission A and B are requested. | 
 | //  2. Permission A is resolved. | 
 | //  3. Permission A is requested for the same origin before the B is resolved. | 
 | TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario1) { | 
 |   // In the first case, the permission A is a type that does not call an | 
 |   // internal delegate method. | 
 |   std::vector<PermissionType> permissions_1 = {PermissionType::MIDI, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_1 = manager->RequestPermissions( | 
 |       permissions_1, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::MIDI, render_frame_host, GURL(kRequestingOrigin1), true, | 
 |       base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                  base::Unretained(this), 2)); | 
 |   EXPECT_EQ(kNoPendingOperation, request_2); | 
 |   ASSERT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[0]); | 
 |  | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |  | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[1]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[2]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[2]); | 
 |  | 
 |   // In the second case, the permission A is a type that calls an internal | 
 |   // delegate method. | 
 |   std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_3 = manager->RequestPermissions( | 
 |       permissions_2, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 3)); | 
 |   EXPECT_NE(kNoPendingOperation, request_3); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   // The permission A is resolved, but the first request isn't finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, false); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   int request_4 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 4)); | 
 |   // The second request is finished first by using the resolved result for the | 
 |   // first request. | 
 |   EXPECT_EQ(kNoPendingOperation, request_4); | 
 |   ASSERT_EQ(4u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[3]); | 
 |   EXPECT_EQ(4, resolved_permission_request_id[3]); | 
 |  | 
 |   // Then the first request is finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |  | 
 |   ASSERT_EQ(6u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[4]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[5]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[5]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested multiple times as follow. | 
 | //  1. Permission A and B are requested. | 
 | //  2. Permission A is resolved. | 
 | //  3. Permission A is requested for a different origin before the B is | 
 | //     resolved. | 
 | TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario2) { | 
 |   // In the first case, the permission A is a type that does not call an | 
 |   // internal delegate method. | 
 |   std::vector<PermissionType> permissions_1 = {PermissionType::MIDI, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_1 = manager->RequestPermissions( | 
 |       permissions_1, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::MIDI, render_frame_host, GURL(kRequestingOrigin2), true, | 
 |       base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                  base::Unretained(this), 2)); | 
 |   EXPECT_EQ(kNoPendingOperation, request_2); | 
 |   ASSERT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[0]); | 
 |  | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |  | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[1]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[2]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[2]); | 
 |  | 
 |   // In the second case, the permission A is a type that calls an internal | 
 |   // delegate method. | 
 |   std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_3 = manager->RequestPermissions( | 
 |       permissions_2, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 3)); | 
 |   EXPECT_NE(kNoPendingOperation, request_3); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   // The permission A is resolved, but the first request isn't finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, false); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   // The second request could be resolved synchronously even if the first | 
 |   // request isn't finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin2, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   int request_4 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin2), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 4)); | 
 |   EXPECT_EQ(kNoPendingOperation, request_4); | 
 |   ASSERT_EQ(4u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[3]); | 
 |   EXPECT_EQ(4, resolved_permission_request_id[3]); | 
 |  | 
 |   // The first request is finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |  | 
 |   ASSERT_EQ(6u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[4]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[5]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[5]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested multiple times as follow. | 
 | //  1. Permission A and B are requested. | 
 | //  2. Permission B is resolved. | 
 | //  3. Permission A is requested for the same origin before the A is resolved. | 
 | TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario3) { | 
 |   // In the first case, the permission A is a type that does not call an | 
 |   // internal delegate method. | 
 |   std::vector<PermissionType> permissions_1 = {PermissionType::MIDI, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_1 = manager->RequestPermissions( | 
 |       permissions_1, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 2)); | 
 |   EXPECT_NE(kNoPendingOperation, request_2); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // Resolving the first request results in both requests finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, false); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |   // Note: The result order in the same requiest is ensured, but each results | 
 |   // for a request can be swapped because the manager use IDMap to resolve | 
 |   // matched requests. | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[1]); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[2]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[2]); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[0]); | 
 |  | 
 |   // In the second case, the permission A is a type that calls an internal | 
 |   // delegate method. | 
 |   std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_3 = manager->RequestPermissions( | 
 |       permissions_2, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 3)); | 
 |   EXPECT_NE(kNoPendingOperation, request_3); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   // The permission B is resolved, but the first request isn't finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, false); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   int request_4 = manager->RequestPermission( | 
 |       PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 4)); | 
 |   EXPECT_NE(kNoPendingOperation, request_4); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   // Resolving the first request results in both requests finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |   ASSERT_EQ(6u, resolved_permission_status.size()); | 
 |   // Order can be swapped. See Note in ComplicatedRequestScenario1. | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[4]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[5]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[5]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[3]); | 
 |   EXPECT_EQ(4, resolved_permission_request_id[3]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested multiple times as follow. | 
 | //  1. Permission A and B are requested. | 
 | //  2. Permission B is resolved. | 
 | //  3. Permission A is requested for a different origin before the A is | 
 | //     resolved. | 
 | TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario4) { | 
 |   // In the first case, the permission A is a type that does not call an | 
 |   // internal delegate method. | 
 |   std::vector<PermissionType> permissions_1 = {PermissionType::MIDI, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_1 = manager->RequestPermissions( | 
 |       permissions_1, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin2), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 2)); | 
 |   EXPECT_NE(kNoPendingOperation, request_2); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // The second request could be resolved synchronously even if the first | 
 |   // request isn't finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin2, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |   ASSERT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[0]); | 
 |  | 
 |   // The first request is finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, false); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[1]); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[2]); | 
 |   EXPECT_EQ(1, resolved_permission_request_id[2]); | 
 |  | 
 |   // In the second case, the permission A is a type that calls an internal | 
 |   // delegate method. | 
 |   std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_3 = manager->RequestPermissions( | 
 |       permissions_2, | 
 |       render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                        base::Unretained(this), 3)); | 
 |   EXPECT_NE(kNoPendingOperation, request_3); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   // The permission B is resolved, but the first request isn't finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, false); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   int request_4 = manager->RequestPermission( | 
 |       PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin2), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 4)); | 
 |   EXPECT_NE(kNoPendingOperation, request_4); | 
 |   ASSERT_EQ(3u, resolved_permission_status.size()); | 
 |  | 
 |   // The second request could be resolved synchronously even if the first | 
 |   // request isn't finished. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin2, | 
 |                                      PermissionType::MIDI_SYSEX, false); | 
 |   ASSERT_EQ(4u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[3]); | 
 |   EXPECT_EQ(4, resolved_permission_request_id[3]); | 
 |  | 
 |   // Resolving the first request results in resuming the second request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, false); | 
 |   ASSERT_EQ(6u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[4]); | 
 |   EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[5]); | 
 |   EXPECT_EQ(3, resolved_permission_request_id[5]); | 
 | } | 
 |  | 
 | // Test the case CancelPermissionRequest is called for an invalid request. | 
 | TEST_F(AwPermissionManagerTest, InvalidRequestIsCancelled) { | 
 |   manager->CancelPermissionRequest(0); | 
 | } | 
 |  | 
 | // Test the case a delegate is called, and cancelled. | 
 | TEST_F(AwPermissionManagerTest, SinglePermissionRequestIsCancelled) { | 
 |   int request_id = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 0)); | 
 |   EXPECT_NE(kNoPendingOperation, request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   manager->CancelPermissionRequest(request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This should not resolve the permission. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested through single call, and | 
 | // cancelled. | 
 | TEST_F(AwPermissionManagerTest, SinglePermissionsRequestIsCancelled) { | 
 |   std::vector<PermissionType> permissions_1 = {PermissionType::MIDI, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_id = manager->RequestPermissions( | 
 |       permissions_1, render_frame_host, GURL(kRequestingOrigin1), true, | 
 |       base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                  base::Unretained(this), 0)); | 
 |   EXPECT_NE(kNoPendingOperation, request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   manager->CancelPermissionRequest(request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION, | 
 |                                                PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   request_id = manager->RequestPermissions( | 
 |       permissions_2, render_frame_host, GURL(kRequestingOrigin1), true, | 
 |       base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                  base::Unretained(this), 0)); | 
 |   EXPECT_NE(kNoPendingOperation, request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   manager->CancelPermissionRequest(request_id); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This should not resolve the permission. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested, and cancelled as follow. | 
 | //  1. Permission A is requested. | 
 | //  2. Permission A is requested for the same origin again. | 
 | //  3. The first request is cancelled. | 
 | TEST_F(AwPermissionManagerTest, ComplicatedCancelScenario1) { | 
 |   int request_1 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 2)); | 
 |   EXPECT_NE(kNoPendingOperation, request_2); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   EXPECT_NE(request_1, request_2); | 
 |  | 
 |   manager->CancelPermissionRequest(request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This should resolve the second request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   EXPECT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[0]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested, and cancelled as follow. | 
 | //  1. Permission A is requested. | 
 | //  2. Permission A is requested for a different origin. | 
 | //  3. The first request is cancelled. | 
 | TEST_F(AwPermissionManagerTest, ComplicatedCancelScenario2) { | 
 |   int request_1 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   int request_2 = manager->RequestPermission( | 
 |       PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin2), | 
 |       true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse, | 
 |                        base::Unretained(this), 2)); | 
 |   EXPECT_NE(kNoPendingOperation, request_2); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   EXPECT_NE(request_1, request_2); | 
 |  | 
 |   manager->CancelPermissionRequest(request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This should not resolve the first request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This should resolve the second request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin2, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   EXPECT_EQ(1u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[0]); | 
 | } | 
 |  | 
 | // Test the case multiple permissions are requested, and cancelled as follow. | 
 | //  1. Permission A and B are requested. | 
 | //  2. Permission A and B are requested for a different origin. | 
 | //  3. Permission A for the second request is resolved. | 
 | //  4. The second request is cancelled. | 
 | TEST_F(AwPermissionManagerTest, ComplicatedCancelScenario3) { | 
 |   std::vector<PermissionType> permissions = {PermissionType::GEOLOCATION, | 
 |                                              PermissionType::MIDI_SYSEX}; | 
 |  | 
 |   int request_1 = manager->RequestPermissions( | 
 |       permissions, render_frame_host, GURL(kRequestingOrigin1), true, | 
 |       base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                  base::Unretained(this), 1)); | 
 |   EXPECT_NE(kNoPendingOperation, request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   int request_2 = manager->RequestPermissions( | 
 |       permissions, render_frame_host, GURL(kRequestingOrigin2), true, | 
 |       base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse, | 
 |                  base::Unretained(this), 2)); | 
 |   EXPECT_NE(kNoPendingOperation, request_2); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   EXPECT_NE(request_1, request_2); | 
 |  | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin2, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |  | 
 |   manager->CancelPermissionRequest(request_1); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This should not resolve the first request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::GEOLOCATION, true); | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin1, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |   EXPECT_EQ(0u, resolved_permission_status.size()); | 
 |  | 
 |   // This should resolve the second request. | 
 |   manager->EnqueuePermissionResponse(kRequestingOrigin2, | 
 |                                      PermissionType::MIDI_SYSEX, true); | 
 |   EXPECT_EQ(2u, resolved_permission_status.size()); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[0]); | 
 |   EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]); | 
 |   EXPECT_EQ(2, resolved_permission_request_id[1]); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | }  // namespace android_webview |