blob: e2bc0764dae18edcf3520db19cfdaf06c14891f5 [file] [log] [blame]
// Copyright 2013 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.chrome.browser.profiles;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.CheckDiscard;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.browser.cookies.CookiesFetcher;
import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
import org.chromium.components.profile_metrics.BrowserProfileType;
import org.chromium.content_public.browser.WebContents;
/**
* Wrapper that allows passing a Profile reference around in the Java layer.
*/
public class Profile implements BrowserContextHandle {
private static Profile sLastUsedProfileForTesting;
/** Holds OTRProfileID for OffTheRecord profiles. Is null for regular profiles. */
@Nullable
private final OTRProfileID mOTRProfileID;
/** Pointer to the Native-side ProfileAndroid. */
private long mNativeProfileAndroid;
private Profile(long nativeProfileAndroid) {
mNativeProfileAndroid = nativeProfileAndroid;
if (ProfileJni.get().isOffTheRecord(mNativeProfileAndroid, Profile.this)) {
mOTRProfileID = ProfileJni.get().getOTRProfileID(mNativeProfileAndroid, Profile.this);
} else {
mOTRProfileID = null;
}
}
/**
* Returns the regular (i.e., not off-the-record) profile.
*
* Note: The function name uses the "last used" terminology for consistency with
* profile_manager.cc which supports multiple regular profiles.
*/
public static Profile getLastUsedRegularProfile() {
if (sLastUsedProfileForTesting != null) {
return sLastUsedProfileForTesting;
}
ThreadUtils.assertOnUiThread();
// TODO(crbug.com/704025): turn this into an assert once the bug is fixed
if (!ProfileManager.isInitialized()) {
throw new IllegalStateException("Browser hasn't finished initialization yet!");
}
return (Profile) ProfileJni.get().getLastUsedRegularProfile();
}
/**
* @param webContents {@link WebContents} object.
* @return {@link Profile} object associated with the given WebContents.
*/
public static Profile fromWebContents(WebContents webContents) {
return (Profile) ProfileJni.get().fromWebContents(webContents);
}
/**
* Handles type conversion of Java side {@link BrowserContextHandle} to {@link Profile}.
* @param browserContextHandle Java reference to native BrowserContext.
* @return A strongly typed reference the {@link Profile}.
*/
public static Profile fromBrowserContextHandle(BrowserContextHandle browserContextHandle) {
return (Profile) browserContextHandle;
}
/**
* Returns the {@link BrowserProfileType} for the corresponding profile.
*
* Please note {@link BrowserProfileType} is generated from native so, it also contains other
* types of Profile like Guest, System, EphemeralGuest that we don't support in Android.
*/
public static @BrowserProfileType int getBrowserProfileTypeFromProfile(Profile profile) {
assert profile != null;
if (!profile.isOffTheRecord()) return BrowserProfileType.REGULAR;
if (profile.isPrimaryOTRProfile()) return BrowserProfileType.INCOGNITO;
return BrowserProfileType.OTHER_OFF_THE_RECORD_PROFILE;
}
/**
* Destroys the Profile. Destruction is delayed until all associated
* renderers have been killed, so the profile might not be destroyed upon returning from
* this call.
*/
public void destroyWhenAppropriate() {
ProfileJni.get().destroyWhenAppropriate(mNativeProfileAndroid, Profile.this);
}
public Profile getOriginalProfile() {
return (Profile) ProfileJni.get().getOriginalProfile(mNativeProfileAndroid, Profile.this);
}
/**
* Returns the OffTheRecord profile with given OTRProfileiD. If the profile
* does not exist and createIfNeeded is true, a new profile is created,
* otherwise returns null.
*
* @param profileID {@link OTRProfileID} object.
* @param createIfNeeded Boolean indicating the profile should be created if doesn't exist.
*/
public Profile getOffTheRecordProfile(OTRProfileID profileID, boolean createIfNeeded) {
assert profileID != null;
return (Profile) ProfileJni.get().getOffTheRecordProfile(
mNativeProfileAndroid, Profile.this, profileID, createIfNeeded);
}
/**
* Returns the OffTheRecord profile for incognito tabs. If the profile
* does not exist and createIfNeeded is true, a new profile is created,
* otherwise returns null.
*
* @param createIfNeeded Boolean indicating the profile should be created if doesn't exist.
*/
public Profile getPrimaryOTRProfile(boolean createIfNeeded) {
return (Profile) ProfileJni.get().getPrimaryOTRProfile(
mNativeProfileAndroid, Profile.this, createIfNeeded);
}
/**
* Returns the OffTheRecord profile id for OffTheRecord profiles, and null for regular profiles.
*/
@Nullable
public OTRProfileID getOTRProfileID() {
return mOTRProfileID;
}
/**
* Returns if OffTheRecord profile with given OTRProfileID exists.
*
* @param profileID {@link OTRProfileID} object.
*/
public boolean hasOffTheRecordProfile(OTRProfileID profileID) {
assert profileID != null;
return ProfileJni.get().hasOffTheRecordProfile(
mNativeProfileAndroid, Profile.this, profileID);
}
/**
* Returns if primary OffTheRecord profile exists.
*/
public boolean hasPrimaryOTRProfile() {
return ProfileJni.get().hasPrimaryOTRProfile(mNativeProfileAndroid, Profile.this);
}
/**
* Returns if the profile is a primary OTR Profile.
*/
public boolean isPrimaryOTRProfile() {
return ProfileJni.get().isPrimaryOTRProfile(mNativeProfileAndroid, Profile.this);
}
public ProfileKey getProfileKey() {
return (ProfileKey) ProfileJni.get().getProfileKey(mNativeProfileAndroid, Profile.this);
}
public boolean isOffTheRecord() {
return mOTRProfileID != null;
}
/**
* @return Whether the profile is signed in to a child account.
*/
public boolean isChild() {
return ProfileJni.get().isChild(mNativeProfileAndroid, Profile.this);
}
/**
* Wipes all data for this profile.
*/
public void wipe() {
ProfileJni.get().wipe(mNativeProfileAndroid, Profile.this);
}
/**
* @return Whether or not the native side profile exists.
*/
@VisibleForTesting
public boolean isNativeInitialized() {
return mNativeProfileAndroid != 0;
}
@Override
public long getNativeBrowserContextPointer() {
return ProfileJni.get().getBrowserContextPointer(mNativeProfileAndroid);
}
@CalledByNative
private static Profile create(long nativeProfileAndroid) {
return new Profile(nativeProfileAndroid);
}
@CalledByNative
private void onNativeDestroyed() {
mNativeProfileAndroid = 0;
if (mOTRProfileID != null) {
CookiesFetcher.deleteCookiesIfNecessary();
}
ProfileManager.onProfileDestroyed(this);
}
@CalledByNative
private long getNativePointer() {
return mNativeProfileAndroid;
}
/**
* Sets for testing the profile to be returned by {@link #getLastUsedRegularProfile()}.
*/
@CheckDiscard("Test-only setter.")
@VisibleForTesting
public static void setLastUsedProfileForTesting(Profile profile) {
sLastUsedProfileForTesting = profile;
}
@NativeMethods
public interface Natives {
Object getLastUsedRegularProfile();
Object fromWebContents(WebContents webContents);
void destroyWhenAppropriate(long nativeProfileAndroid, Profile caller);
Object getOriginalProfile(long nativeProfileAndroid, Profile caller);
Object getOffTheRecordProfile(long nativeProfileAndroid, Profile caller,
OTRProfileID otrProfileID, boolean createIfNeeded);
Object getPrimaryOTRProfile(
long nativeProfileAndroid, Profile caller, boolean createIfNeeded);
boolean hasOffTheRecordProfile(
long nativeProfileAndroid, Profile caller, OTRProfileID otrProfileID);
boolean hasPrimaryOTRProfile(long nativeProfileAndroid, Profile caller);
boolean isOffTheRecord(long nativeProfileAndroid, Profile caller);
boolean isPrimaryOTRProfile(long nativeProfileAndroid, Profile caller);
boolean isChild(long nativeProfileAndroid, Profile caller);
void wipe(long nativeProfileAndroid, Profile caller);
Object getProfileKey(long nativeProfileAndroid, Profile caller);
long getBrowserContextPointer(long nativeProfileAndroid);
OTRProfileID getOTRProfileID(long nativeProfileAndroid, Profile caller);
}
}