Commit 3b7ed9d0 authored by Pavel Shmakov's avatar Pavel Shmakov Committed by Commit Bot

Implement Profile#clearBrowsingData

Change-Id: I8cb125cf9ee2d2f72ba22f498248dd5fa6fd5c4d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1865334
Commit-Queue: Pavel Shmakov <pshmakov@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709853}
parent 4caa96fb
...@@ -4,17 +4,25 @@ ...@@ -4,17 +4,25 @@
package org.chromium.weblayer_private; package org.chromium.weblayer_private;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.weblayer_private.aidl.IObjectWrapper;
import org.chromium.weblayer_private.aidl.IProfile; import org.chromium.weblayer_private.aidl.IProfile;
import org.chromium.weblayer_private.aidl.ObjectWrapper;
import java.util.ArrayList;
import java.util.List;
@JNINamespace("weblayer") @JNINamespace("weblayer")
public final class ProfileImpl extends IProfile.Stub { public final class ProfileImpl extends IProfile.Stub {
private final List<Runnable> mCurrentClearDataCallbacks = new ArrayList<>();
private final List<Runnable> mPendingClearDataCallbacks = new ArrayList<>();
private long mNativeProfile; private long mNativeProfile;
private Runnable mOnDestroyCallback; private Runnable mOnDestroyCallback;
ProfileImpl(String path, Runnable onDestroyCallback) { ProfileImpl(String path, Runnable onDestroyCallback) {
mNativeProfile = ProfileImplJni.get().createProfile(path); mNativeProfile = ProfileImplJni.get().createProfile(this, path);
mOnDestroyCallback = onDestroyCallback; mOnDestroyCallback = onDestroyCallback;
} }
...@@ -27,17 +35,38 @@ public final class ProfileImpl extends IProfile.Stub { ...@@ -27,17 +35,38 @@ public final class ProfileImpl extends IProfile.Stub {
} }
@Override @Override
public void clearBrowsingData() { public void clearBrowsingData(IObjectWrapper completionCallback) {
Runnable callback = ObjectWrapper.unwrap(completionCallback, Runnable.class);
if (!mCurrentClearDataCallbacks.isEmpty()) {
// Already running a clear data job. Will have to re-run the job once it's completed,
// because new data may have been stored.
mPendingClearDataCallbacks.add(callback);
return;
}
mCurrentClearDataCallbacks.add(callback);
ProfileImplJni.get().clearBrowsingData(mNativeProfile); ProfileImplJni.get().clearBrowsingData(mNativeProfile);
} }
@CalledByNative
private void onBrowsingDataCleared() {
for (Runnable callback : mCurrentClearDataCallbacks) {
callback.run();
}
mCurrentClearDataCallbacks.clear();
if (!mPendingClearDataCallbacks.isEmpty()) {
mCurrentClearDataCallbacks.addAll(mPendingClearDataCallbacks);
mPendingClearDataCallbacks.clear();
ProfileImplJni.get().clearBrowsingData(mNativeProfile);
}
}
long getNativeProfile() { long getNativeProfile() {
return mNativeProfile; return mNativeProfile;
} }
@NativeMethods @NativeMethods
interface Natives { interface Natives {
long createProfile(String path); long createProfile(ProfileImpl caller, String path);
void deleteProfile(long profile); void deleteProfile(long profile);
void clearBrowsingData(long nativeProfileImpl); void clearBrowsingData(long nativeProfileImpl);
} }
......
...@@ -7,5 +7,5 @@ package org.chromium.weblayer_private.aidl; ...@@ -7,5 +7,5 @@ package org.chromium.weblayer_private.aidl;
interface IProfile { interface IProfile {
void destroy() = 0; void destroy() = 0;
void clearBrowsingData() = 1; void clearBrowsingData(in IObjectWrapper completionCallback) = 1;
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/download_manager_delegate.h" #include "content/public/browser/download_manager_delegate.h"
#include "content/public/browser/resource_context.h" #include "content/public/browser/resource_context.h"
#include "weblayer/browser/browser_controller_impl.h" #include "weblayer/browser/browser_controller_impl.h"
...@@ -16,6 +17,10 @@ ...@@ -16,6 +17,10 @@
#include "weblayer/browser/java/jni/ProfileImpl_jni.h" #include "weblayer/browser/java/jni/ProfileImpl_jni.h"
#endif #endif
#if defined(OS_ANDROID)
using base::android::AttachCurrentThread;
#endif
namespace weblayer { namespace weblayer {
namespace { namespace {
...@@ -148,6 +153,36 @@ class ProfileImpl::BrowserContextImpl : public content::BrowserContext { ...@@ -148,6 +153,36 @@ class ProfileImpl::BrowserContextImpl : public content::BrowserContext {
DISALLOW_COPY_AND_ASSIGN(BrowserContextImpl); DISALLOW_COPY_AND_ASSIGN(BrowserContextImpl);
}; };
class ProfileImpl::DataClearer : public content::BrowsingDataRemover::Observer {
public:
DataClearer(content::BrowserContext* browser_context, ProfileImpl* profile)
: remover_(
content::BrowserContext::GetBrowsingDataRemover(browser_context)),
profile_(profile) {
remover_->AddObserver(this);
}
~DataClearer() override { remover_->RemoveObserver(this); }
void ClearData() {
int mask = content::BrowsingDataRemover::DATA_TYPE_COOKIES |
content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES;
int origin_types =
content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB;
remover_->RemoveAndReply(base::Time(), base::Time::Max(), mask,
origin_types, this);
}
void OnBrowsingDataRemoverDone() override {
profile_->OnBrowsingDataCleared();
}
private:
content::BrowsingDataRemover* const remover_;
ProfileImpl* const profile_;
};
ProfileImpl::ProfileImpl(const base::FilePath& path) : path_(path) { ProfileImpl::ProfileImpl(const base::FilePath& path) : path_(path) {
browser_context_ = std::make_unique<BrowserContextImpl>(path_); browser_context_ = std::make_unique<BrowserContextImpl>(path_);
} }
...@@ -158,8 +193,17 @@ content::BrowserContext* ProfileImpl::GetBrowserContext() { ...@@ -158,8 +193,17 @@ content::BrowserContext* ProfileImpl::GetBrowserContext() {
return browser_context_.get(); return browser_context_.get();
} }
void ProfileImpl::OnBrowsingDataCleared() {
#if defined(OS_ANDROID)
Java_ProfileImpl_onBrowsingDataCleared(AttachCurrentThread(), java_profile_);
#endif
}
void ProfileImpl::ClearBrowsingData() { void ProfileImpl::ClearBrowsingData() {
NOTIMPLEMENTED(); if (!data_clearer_) {
data_clearer_ = std::make_unique<DataClearer>(browser_context_.get(), this);
}
data_clearer_->ClearData();
} }
std::unique_ptr<Profile> Profile::Create(const base::FilePath& path) { std::unique_ptr<Profile> Profile::Create(const base::FilePath& path) {
...@@ -167,11 +211,20 @@ std::unique_ptr<Profile> Profile::Create(const base::FilePath& path) { ...@@ -167,11 +211,20 @@ std::unique_ptr<Profile> Profile::Create(const base::FilePath& path) {
} }
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
ProfileImpl::ProfileImpl(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& java_profile,
const base::android::JavaParamRef<jstring>& path)
: ProfileImpl(base::FilePath(ConvertJavaStringToUTF8(env, path))) {
java_profile_.Reset(env, java_profile);
}
static jlong JNI_ProfileImpl_CreateProfile( static jlong JNI_ProfileImpl_CreateProfile(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& java_profile,
const base::android::JavaParamRef<jstring>& path) { const base::android::JavaParamRef<jstring>& path) {
return reinterpret_cast<jlong>(new weblayer::ProfileImpl( return reinterpret_cast<jlong>(
base::FilePath(ConvertJavaStringToUTF8(env, path)))); new weblayer::ProfileImpl(env, java_profile, path));
} }
static void JNI_ProfileImpl_DeleteProfile(JNIEnv* env, jlong profile) { static void JNI_ProfileImpl_DeleteProfile(JNIEnv* env, jlong profile) {
......
...@@ -5,10 +5,12 @@ ...@@ -5,10 +5,12 @@
#ifndef WEBLAYER_BROWSER_PROFILE_IMPL_H_ #ifndef WEBLAYER_BROWSER_PROFILE_IMPL_H_
#define WEBLAYER_BROWSER_PROFILE_IMPL_H_ #define WEBLAYER_BROWSER_PROFILE_IMPL_H_
#include "build/build_config.h"
#include "weblayer/public/profile.h" #include "weblayer/public/profile.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include <jni.h> #include <jni.h>
#include "base/android/scoped_java_ref.h"
#endif #endif
namespace content { namespace content {
...@@ -28,14 +30,26 @@ class ProfileImpl : public Profile { ...@@ -28,14 +30,26 @@ class ProfileImpl : public Profile {
void ClearBrowsingData() override; void ClearBrowsingData() override;
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
ProfileImpl(JNIEnv* env,
const base::android::JavaParamRef<jobject>& java_profile,
const base::android::JavaParamRef<jstring>& path);
void ClearBrowsingData(JNIEnv* env) { ClearBrowsingData(); } void ClearBrowsingData(JNIEnv* env) { ClearBrowsingData(); }
#endif #endif
private: private:
class BrowserContextImpl; class BrowserContextImpl;
class DataClearer;
void OnBrowsingDataCleared();
base::FilePath path_; base::FilePath path_;
std::unique_ptr<BrowserContextImpl> browser_context_; std::unique_ptr<BrowserContextImpl> browser_context_;
std::unique_ptr<DataClearer> data_clearer_;
#if defined(OS_ANDROID)
base::android::ScopedJavaGlobalRef<jobject> java_profile_;
#endif
}; };
} // namespace weblayer } // namespace weblayer
......
...@@ -8,6 +8,7 @@ import android.os.RemoteException; ...@@ -8,6 +8,7 @@ import android.os.RemoteException;
import org.chromium.weblayer_private.aidl.APICallException; import org.chromium.weblayer_private.aidl.APICallException;
import org.chromium.weblayer_private.aidl.IProfile; import org.chromium.weblayer_private.aidl.IProfile;
import org.chromium.weblayer_private.aidl.ObjectWrapper;
/** /**
* Profile holds state (typically on disk) needed for browsing. Create a * Profile holds state (typically on disk) needed for browsing. Create a
...@@ -28,10 +29,12 @@ public final class Profile { ...@@ -28,10 +29,12 @@ public final class Profile {
// TODO(sky): figure out right assertion here if mImpl is non-null. // TODO(sky): figure out right assertion here if mImpl is non-null.
} }
public void clearBrowsingData() { public ListenableResult<Void> clearBrowsingData() {
ThreadCheck.ensureOnUiThread(); ThreadCheck.ensureOnUiThread();
try { try {
mImpl.clearBrowsingData(); ListenableResult<Void> result = new ListenableResult<>();
mImpl.clearBrowsingData(ObjectWrapper.wrap((Runnable) () -> result.supplyResult(null)));
return result;
} catch (RemoteException e) { } catch (RemoteException e) {
throw new APICallException(e); throw new APICallException(e);
} }
......
...@@ -214,6 +214,7 @@ instrumentation_test_apk("weblayer_instrumentation_test_apk") { ...@@ -214,6 +214,7 @@ instrumentation_test_apk("weblayer_instrumentation_test_apk") {
"javatests/src/org/chromium/weblayer/test/EventUtils.java", "javatests/src/org/chromium/weblayer/test/EventUtils.java",
"javatests/src/org/chromium/weblayer/test/FullscreenDelegateTest.java", "javatests/src/org/chromium/weblayer/test/FullscreenDelegateTest.java",
"javatests/src/org/chromium/weblayer/test/NavigationTest.java", "javatests/src/org/chromium/weblayer/test/NavigationTest.java",
"javatests/src/org/chromium/weblayer/test/DataClearingTest.java",
"javatests/src/org/chromium/weblayer/test/SmokeTest.java", "javatests/src/org/chromium/weblayer/test/SmokeTest.java",
"javatests/src/org/chromium/weblayer/test/EventUtils.java", "javatests/src/org/chromium/weblayer/test/EventUtils.java",
"javatests/src/org/chromium/weblayer/test/ExecuteScriptTest.java", "javatests/src/org/chromium/weblayer/test/ExecuteScriptTest.java",
......
// Copyright 2019 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.chromium.weblayer.test;
import static org.junit.Assert.assertTrue;
import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
import android.os.Bundle;
import android.support.test.filters.SmallTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.weblayer.Profile;
import org.chromium.weblayer.shell.WebLayerShellActivity;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Example test that just starts the weblayer shell.
*/
@RunWith(BaseJUnit4ClassRunner.class)
public class DataClearingTest {
@Rule
public WebLayerShellActivityTestRule mActivityTestRule = new WebLayerShellActivityTestRule();
@Test
@SmallTest
public void clearDataWithPersistedProfile_TriggersCallback() throws InterruptedException {
checkTriggersCallbackOnClearData("Profile");
}
@Test
@SmallTest
public void clearDataWithInMemoryProfile_TriggersCallback() throws InterruptedException {
checkTriggersCallbackOnClearData("");
}
// The tests below should rather be unit tests for ProfileImpl.
@Test
@SmallTest
public void twoSuccesiveRequestsTriggerCallbacks() throws InterruptedException {
WebLayerShellActivity activity = launchWithProfile("profile");
CountDownLatch latch = new CountDownLatch(2);
runOnUiThreadBlocking(() -> {
Profile profile = activity.getBrowserFragmentController().getProfile();
profile.clearBrowsingData().addCallback((ignored) -> latch.countDown());
profile.clearBrowsingData().addCallback((ignored) -> latch.countDown());
});
assertTrue(latch.await(3, TimeUnit.SECONDS));
}
@Test
@SmallTest
public void clearingAgainAfterClearFinished_TriggersCallback() throws InterruptedException {
WebLayerShellActivity activity = launchWithProfile("profile");
CountDownLatch latch = new CountDownLatch(1);
runOnUiThreadBlocking(() -> {
Profile profile = activity.getBrowserFragmentController().getProfile();
profile.clearBrowsingData().addCallback((v1) -> {
profile.clearBrowsingData().addCallback((v2) -> latch.countDown());
});
});
assertTrue(latch.await(3, TimeUnit.SECONDS));
}
@Test
@SmallTest
public void threeSuccesiveRequestsTriggerCallbacks() throws InterruptedException {
WebLayerShellActivity activity = launchWithProfile("profile");
CountDownLatch latch = new CountDownLatch(3);
runOnUiThreadBlocking(() -> {
Profile profile = activity.getBrowserFragmentController().getProfile();
profile.clearBrowsingData().addCallback((ignored) -> latch.countDown());
profile.clearBrowsingData().addCallback((ignored) -> latch.countDown());
profile.clearBrowsingData().addCallback((ignored) -> latch.countDown());
});
assertTrue(latch.await(3, TimeUnit.SECONDS));
}
private void checkTriggersCallbackOnClearData(String profileName) throws InterruptedException {
WebLayerShellActivity activity = launchWithProfile(profileName);
CountDownLatch latch = new CountDownLatch(1);
runOnUiThreadBlocking(() -> activity.getBrowserFragmentController().getProfile()
.clearBrowsingData().addCallback((ignored) -> latch.countDown()));
assertTrue(latch.await(3, TimeUnit.SECONDS));
}
private WebLayerShellActivity launchWithProfile(String profileName) {
Bundle extras = new Bundle();
extras.putString(WebLayerShellActivity.EXTRA_PROFILE_NAME, profileName);
String url = "data:text,foo";
WebLayerShellActivity activity = mActivityTestRule.launchShellWithUrl(url, extras);
return activity;
}
}
...@@ -11,6 +11,7 @@ import android.content.Intent; ...@@ -11,6 +11,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry; import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule; import android.support.test.rule.ActivityTestRule;
...@@ -103,11 +104,12 @@ public class WebLayerShellActivityTestRule extends ActivityTestRule<WebLayerShel ...@@ -103,11 +104,12 @@ public class WebLayerShellActivityTestRule extends ActivityTestRule<WebLayerShel
} }
/** /**
* Starts the WebLayer activity and completely loads the given URL (this calls * Starts the WebLayer activity with the given extras Bundle and completely loads the given URL
* navigateAndWait()). * (this calls navigateAndWait()).
*/ */
public WebLayerShellActivity launchShellWithUrl(String url) { public WebLayerShellActivity launchShellWithUrl(String url, Bundle extras) {
Intent intent = new Intent(Intent.ACTION_MAIN); Intent intent = new Intent(Intent.ACTION_MAIN);
intent.putExtras(extras);
intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Prevent URL from being loaded on start. // Prevent URL from being loaded on start.
...@@ -121,6 +123,14 @@ public class WebLayerShellActivityTestRule extends ActivityTestRule<WebLayerShel ...@@ -121,6 +123,14 @@ public class WebLayerShellActivityTestRule extends ActivityTestRule<WebLayerShel
return activity; return activity;
} }
/**
* Starts the WebLayer activity and completely loads the given URL (this calls
* navigateAndWait()).
*/
public WebLayerShellActivity launchShellWithUrl(String url) {
return launchShellWithUrl(url, new Bundle());
}
/** /**
* Loads the given URL in the shell. * Loads the given URL in the shell.
*/ */
......
...@@ -51,6 +51,8 @@ public class WebLayerShellActivity extends FragmentActivity { ...@@ -51,6 +51,8 @@ public class WebLayerShellActivity extends FragmentActivity {
private static final String TAG = "WebLayerShell"; private static final String TAG = "WebLayerShell";
private static final String KEY_MAIN_VIEW_ID = "mainViewId"; private static final String KEY_MAIN_VIEW_ID = "mainViewId";
public static final String EXTRA_PROFILE_NAME = "EXTRA_PROFILE_NAME";
private Profile mProfile; private Profile mProfile;
private BrowserFragmentController mBrowserFragmentController; private BrowserFragmentController mBrowserFragmentController;
private BrowserController mBrowserController; private BrowserController mBrowserController;
...@@ -255,8 +257,14 @@ public class WebLayerShellActivity extends FragmentActivity { ...@@ -255,8 +257,14 @@ public class WebLayerShellActivity extends FragmentActivity {
} }
} }
File profile = new File(getFilesDir(), "defaultProfile"); String profileName = getIntent().hasExtra(EXTRA_PROFILE_NAME)
BrowserFragment fragment = WebLayer.createBrowserFragment(profile.getPath()); ? getIntent().getStringExtra(EXTRA_PROFILE_NAME) : "DefaultProfile";
String profilePath = null;
if (!TextUtils.isEmpty(profileName)) {
profilePath = new File(getFilesDir(), profileName).getPath();
} // else create an in-memory Profile.
BrowserFragment fragment = WebLayer.createBrowserFragment(profilePath);
FragmentTransaction transaction = fragmentManager.beginTransaction(); FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(mMainViewId, fragment); transaction.add(mMainViewId, fragment);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment