script-astra/Android/Sdk/sources/android-35/android/provider/E2eeContactKeysManager.java

1166 lines
46 KiB
Java
Raw Normal View History

2025-01-20 15:15:20 +00:00
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.provider;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* E2eeContactKeysManager provides access to the provider of end-to-end encryption contact keys.
* It manages two types of keys - {@link E2eeContactKey} and {@link E2eeSelfKey}.
* <ul>
* <li>
* A {@link E2eeContactKey} is a public key associated with a contact. It's used to end-to-end
* encrypt the communications between a user and the contact. This API allows operations on
* {@link E2eeContactKey}s to insert/update, remove, change the verification state, and retrieving
* keys (either created by or visible to the caller app).
* </li>
* <li>
* A {@link E2eeSelfKey} is a key for this device, so the key represents the owner of the device.
* This API allows operations on {@link E2eeSelfKey}s to insert/update, remove, and retrieving
* self keys (either created by or visible to the caller app).
* </li>
* </ul>
* Keys are uniquely identified by:
* <ul>
* <li>
* ownerPackageName - package name of an app that the key belongs to.
* </li>
* <li>
* deviceId - an app-specified identifier for the device, defined by the app. Within that app,
* the deviceID should be unique among devices belonging to that user.
* </li>
* <li>
* accountId - the app-specified identifier for the account for which the contact key can be used.
* Using different account IDs allows for multiple key entries representing the same user.
* For most apps this would be a phone number.
* </li>
* </ul>
* Contact keys also use lookupKey which is an opaque value used to identify a contact in
* ContactsProvider.
*/
@FlaggedApi(Flags.FLAG_USER_KEYS)
public final class E2eeContactKeysManager {
/**
* The authority for the end-to-end encryption contact keys provider.
*
* @hide
*/
public static final String AUTHORITY = "com.android.contactkeys.contactkeysprovider";
/**
* A content:// style uri to the authority for the end-to-end encryption contact keys provider.
*
* @hide
*/
@NonNull
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
/**
* Maximum size of an end-to-end encryption contact key.
*/
private static final int MAX_KEY_SIZE_BYTES = 5000;
/**
* Special value to distinguish a null array in a parcelable object.
*/
private static final int ARRAY_IS_NULL = -1;
@NonNull
private final ContentResolver mContentResolver;
/** @hide */
public E2eeContactKeysManager(@NonNull Context context) {
Objects.requireNonNull(context);
mContentResolver = context.getContentResolver();
}
/**
* Inserts a new entry into the end-to-end encryption contact keys table or updates one if it
* already exists.
* The inserted/updated end-to-end encryption contact key is owned by the caller app.
*
* @param lookupKey value that references the contact
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
*/
@RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
public void updateOrInsertE2eeContactKey(@NonNull String lookupKey,
@NonNull String deviceId,
@NonNull String accountId,
@NonNull byte[] keyValue) {
validateKeyLength(keyValue);
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras);
}
/**
* Retrieves an end-to-end encryption contact key entry given the lookup key, device ID,
* accountId and inferred caller package name.
*
* @param lookupKey the value that references the contact
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @return a {@link E2eeContactKey} object containing the contact key information,
* or null if no contact key is found.
*/
@RequiresPermission(android.Manifest.permission.READ_CONTACTS)
@Nullable
public E2eeContactKey getE2eeContactKey(
@NonNull String lookupKey,
@NonNull String deviceId,
@NonNull String accountId) {
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.GET_CONTACT_KEY_METHOD, extras);
if (response == null) {
return null;
}
return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeContactKey.class);
}
/**
* Retrieves all end-to-end encryption contact key entries that belong to apps visible to
* the caller.
* The keys will be stripped of deviceId, timeUpdated and keyValue data.
*
* @param lookupKey the value that references the contact
* @return a list of {@link E2eeContactKey} objects containing the contact key
* information, or an empty list if no keys are found.
*/
@RequiresPermission(android.Manifest.permission.READ_CONTACTS)
@NonNull
public List<E2eeContactKey> getAllE2eeContactKeys(@NonNull String lookupKey) {
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras);
if (response == null) {
return new ArrayList<>();
}
List<E2eeContactKey> value = response.getParcelableArrayList(
E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class);
if (value == null) {
return new ArrayList<>();
}
return value;
}
/**
* Retrieves all end-to-end encryption contact key entries for a given lookupKey that belong to
* the caller app.
*
* @param lookupKey the value that references the contact
* @return a list of {@link E2eeContactKey} objects containing the end-to-end encryption
* contact key information, or an empty list if no keys are found.
*/
@RequiresPermission(android.Manifest.permission.READ_CONTACTS)
@NonNull
public List<E2eeContactKey> getOwnerE2eeContactKeys(@NonNull String lookupKey) {
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras);
if (response == null) {
return new ArrayList<>();
}
List<E2eeContactKey> value = response.getParcelableArrayList(
E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class);
if (value == null) {
return new ArrayList<>();
}
return value;
}
/**
* Updates an end-to-end encryption contact key entry's local verification state that belongs
* to the caller app.
*
* @param lookupKey the value that references the contact
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param localVerificationState the new local verification state
* @return true if the entry was updated, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey,
@NonNull String deviceId,
@NonNull String accountId,
@VerificationState int localVerificationState) {
validateVerificationState(localVerificationState);
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
/**
* Updates an end-to-end encryption contact key entry's local verification state that belongs
* to the app identified by ownerPackageName.
*
* @param lookupKey the value that references the contact
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param ownerPackageName the package name of the app that owns the key
* @param localVerificationState the new local verification state
* @return true if the entry was updated, false otherwise.
* @hide
*/
@SystemApi
@RequiresPermission(allOf = {
android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
android.Manifest.permission.WRITE_CONTACTS})
public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey,
@NonNull String deviceId,
@NonNull String accountId,
@NonNull String ownerPackageName,
@VerificationState int localVerificationState) {
validateVerificationState(localVerificationState);
final Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
Objects.requireNonNull(ownerPackageName));
extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
final Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
/**
* Updates an end-to-end encryption contact key entry's remote verification state that belongs
* to the caller app.
*
* @param lookupKey the value that references the contact
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param remoteVerificationState the new remote verification state
* @return true if the entry was updated, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey,
@NonNull String deviceId,
@NonNull String accountId,
@VerificationState int remoteVerificationState) {
validateVerificationState(remoteVerificationState);
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
/**
* Updates an end-to-end encryption contact key entry's remote verification state that belongs
* to the app identified by ownerPackageName.
*
* @param lookupKey the value that references the contact
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param ownerPackageName the package name of the app that owns the key
* @param remoteVerificationState the new remote verification state
* @return true if the entry was updated, false otherwise.
* @hide
*/
@SystemApi
@RequiresPermission(allOf = {
android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
android.Manifest.permission.WRITE_CONTACTS})
public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey,
@NonNull String deviceId,
@NonNull String accountId,
@NonNull String ownerPackageName,
@VerificationState int remoteVerificationState) {
validateVerificationState(remoteVerificationState);
final Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
Objects.requireNonNull(ownerPackageName));
extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
final Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
private static void validateVerificationState(int verificationState) {
if (verificationState != VERIFICATION_STATE_UNVERIFIED
&& verificationState != VERIFICATION_STATE_VERIFICATION_FAILED
&& verificationState != VERIFICATION_STATE_VERIFIED) {
throw new IllegalArgumentException("Verification state value "
+ verificationState + " is not supported");
}
}
/**
* Removes an end-to-end encryption contact key entry that belongs to the caller app.
*
* @param lookupKey the value that references the contact
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @return true if the entry was removed, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
public boolean removeE2eeContactKey(@NonNull String lookupKey,
@NonNull String deviceId,
@NonNull String accountId) {
final Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
final Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.REMOVE_CONTACT_KEY_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
/**
* Inserts a new entry into the end-to-end encryption self keys table or updates one if it
* already exists.
*
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
* @return true if the entry was added or updated, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
public boolean updateOrInsertE2eeSelfKey(@NonNull String deviceId,
@NonNull String accountId,
@NonNull byte[] keyValue) {
validateKeyLength(keyValue);
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
private static void validateKeyLength(byte[] keyValue) {
Objects.requireNonNull(keyValue);
if (keyValue.length == 0 || keyValue.length > getMaxKeySizeBytes()) {
throw new IllegalArgumentException("Key value length is " + keyValue.length + "."
+ " Should be more than 0 and less than " + getMaxKeySizeBytes());
}
}
/**
* Updates an end-to-end encryption self key entry's remote verification state.
*
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param remoteVerificationState the new remote verification state
* @return true if the entry was updated, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId,
@NonNull String accountId,
@VerificationState int remoteVerificationState) {
validateVerificationState(remoteVerificationState);
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
/**
* Updates an end-to-end encryption self key entry's remote verification state that belongs to
* the app identified by ownerPackageName.
*
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @param ownerPackageName the package name of the app that owns the key
* @param remoteVerificationState the new remote verification state
* @return true if the entry was updated, false otherwise.
* @hide
*/
@SystemApi
@RequiresPermission(allOf = {
android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
android.Manifest.permission.WRITE_CONTACTS})
public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId,
@NonNull String accountId,
@NonNull String ownerPackageName,
@VerificationState int remoteVerificationState) {
validateVerificationState(remoteVerificationState);
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
Objects.requireNonNull(ownerPackageName));
extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
/**
* Maximum size of an end-to-end encryption contact key.
*/
public static int getMaxKeySizeBytes() {
return MAX_KEY_SIZE_BYTES;
}
/**
* Returns an end-to-end encryption self key entry given the deviceId and the inferred package
* name of the caller.
*
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @return a {@link E2eeSelfKey} object containing the end-to-end encryption self key
* information, or null if no self key is found.
*/
@RequiresPermission(android.Manifest.permission.READ_CONTACTS)
@Nullable
public E2eeSelfKey getE2eeSelfKey(@NonNull String deviceId,
@NonNull String accountId) {
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.GET_SELF_KEY_METHOD, extras);
if (response == null) {
return null;
}
return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeSelfKey.class);
}
/**
* Returns all end-to-end encryption self key entries that belong to apps visible to the caller.
* The keys will be stripped of deviceId, timeUpdated and keyValue data.
*
* @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key
* information, or an empty list if no self keys are found.
*/
@RequiresPermission(android.Manifest.permission.READ_CONTACTS)
@NonNull
public List<E2eeSelfKey> getAllE2eeSelfKeys() {
Bundle extras = new Bundle();
Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_ALL_SELF_KEYS_METHOD,
extras);
if (response == null) {
return new ArrayList<>();
}
List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS,
E2eeSelfKey.class);
if (value == null) {
return new ArrayList<>();
}
return value;
}
/**
* Returns all end-to-end encryption self key entries that are owned by the caller app.
*
* @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key
* information, or an empty list if no self keys are found.
*/
@RequiresPermission(android.Manifest.permission.READ_CONTACTS)
@NonNull
public List<E2eeSelfKey> getOwnerE2eeSelfKeys() {
Bundle extras = new Bundle();
Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_OWNER_SELF_KEYS_METHOD,
extras);
if (response == null) {
return new ArrayList<>();
}
List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS,
E2eeSelfKey.class);
if (value == null) {
return new ArrayList<>();
}
return value;
}
/**
* Removes an end-to-end encryption self key entry given the deviceId and the inferred
* package name of the caller.
*
* @param deviceId an app-specified identifier for the device
* @param accountId an app-specified identifier for the account
* @return true if the entry was removed, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
public boolean removeE2eeSelfKey(@NonNull String deviceId,
@NonNull String accountId) {
Bundle extras = new Bundle();
extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
Bundle response = nullSafeCall(mContentResolver,
E2eeContactKeys.REMOVE_SELF_KEY_METHOD, extras);
return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
}
private Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull String method,
@Nullable Bundle extras) {
try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY_URI)) {
return client.call(method, null, extras);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Possible values of verification state.
*
* @hide
*/
@IntDef(prefix = {"VERIFICATION_STATE_"}, value = {
VERIFICATION_STATE_UNVERIFIED,
VERIFICATION_STATE_VERIFICATION_FAILED,
VERIFICATION_STATE_VERIFIED
})
@Retention(RetentionPolicy.SOURCE)
public @interface VerificationState {
}
/**
* Unverified state of a contact end to end encrypted key.
*/
public static final int VERIFICATION_STATE_UNVERIFIED = 0;
/**
* Failed verification state of a contact end to end encrypted key.
*/
public static final int VERIFICATION_STATE_VERIFICATION_FAILED = 1;
/**
* Verified state of a contact end to end encrypted key.
*/
public static final int VERIFICATION_STATE_VERIFIED = 2;
/** @hide */
public static final class E2eeContactKeys {
private E2eeContactKeys() {
}
/**
* <p>
* An opaque value that contains hints on how to find the contact if
* its row id changed as a result of a sync or aggregation.
* </p>
*/
public static final String LOOKUP_KEY = "lookup";
/**
* <p>
* An app-specified identifier for the device for which the end-to-end encryption
* contact key can be used.
* </p>
*/
public static final String DEVICE_ID = "device_id";
/**
* <p>
* An app-specified identifier for the account for which the end-to-end encryption
* contact key can be used.
* Usually a phone number.
* </p>
*/
public static final String ACCOUNT_ID = "account_id";
/**
* <p>
* The display name for the contact.
* </p>
*/
public static final String DISPLAY_NAME = "display_name";
/**
* <p>
* The phone number as the user entered it.
* </p>
*/
public static final String PHONE_NUMBER = "number";
/**
* <p>
* The email address.
* </p>
*/
public static final String EMAIL_ADDRESS = "address";
/**
* <p>
* Timestamp at which the key was updated.
* </p>
*/
public static final String TIME_UPDATED = "time_updated";
/**
* <p>
* The raw bytes for the key.
* </p>
*/
public static final String KEY_VALUE = "key_value";
/**
* <p>
* The package name of the package that created the key.
* </p>
*/
public static final String OWNER_PACKAGE_NAME = "owner_package_name";
/**
* <p>
* Describes the local verification state for the key, for instance QR-code based
* verification.
* </p>
*/
public static final String LOCAL_VERIFICATION_STATE = "local_verification_state";
/**
* <p>
* Describes the remote verification state for the key, for instance through a key
* transparency server.
* </p>
*/
public static final String REMOTE_VERIFICATION_STATE = "remote_verification_state";
/**
* The method to invoke in order to add a new key for a contact.
*/
public static final String UPDATE_OR_INSERT_CONTACT_KEY_METHOD = "updateOrInsertContactKey";
/**
* The method to invoke in order to retrieve key for a single contact.
*/
public static final String GET_CONTACT_KEY_METHOD = "getContactKey";
/**
* The method to invoke in order to retrieve all end-to-end encryption contact keys.
*/
public static final String GET_ALL_CONTACT_KEYS_METHOD = "getAllContactKeys";
/**
* The method to invoke in order to retrieve end-to-end encryption contact keys that belong
* to the caller.
*/
public static final String GET_OWNER_CONTACT_KEYS_METHOD = "getOwnerContactKeys";
/**
* The method to invoke in order to update an end-to-end encryption contact key local
* verification state.
*/
public static final String UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD =
"updateContactKeyLocalVerificationState";
/**
* The method to invoke in order to update an end-to-end encryption contact key remote
* verification state.
*/
public static final String UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD =
"updateContactKeyRemoteVerificationState";
/**
* The method to invoke in order to remove a end-to-end encryption contact key.
*/
public static final String REMOVE_CONTACT_KEY_METHOD = "removeContactKey";
/**
* The method to invoke in order to add a new self key.
*/
public static final String UPDATE_OR_INSERT_SELF_KEY_METHOD = "updateOrInsertSelfKey";
/**
* The method to invoke in order to update a self key remote verification state.
*/
public static final String UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD =
"updateSelfKeyRemoteVerificationState";
/**
* The method to invoke in order to retrieve a self key.
*/
public static final String GET_SELF_KEY_METHOD = "getSelfKey";
/**
* The method to invoke in order to retrieve all self keys.
*/
public static final String GET_ALL_SELF_KEYS_METHOD = "getAllSelfKeys";
/**
* The method to invoke in order to retrieve self keys that belong to the caller.
*/
public static final String GET_OWNER_SELF_KEYS_METHOD = "getOwnerSelfKeys";
/**
* The method to invoke in order to remove a new self key.
*/
public static final String REMOVE_SELF_KEY_METHOD = "removeSelfKey";
/**
* Key in the incoming Bundle for all the end-to-end encryption contact keys.
*/
public static final String KEY_CONTACT_KEYS = "key_contact_keys";
/**
* Key in the incoming Bundle for a single end-to-end encryption contact key.
*/
public static final String KEY_CONTACT_KEY = "key_contact_key";
/**
* Key in the incoming Bundle for a number of modified rows.
*/
public static final String KEY_UPDATED_ROWS = "key_updated_rows";
}
/**
* A parcelable class encapsulating other users' end to end encrypted contact key.
*/
public static final class E2eeContactKey extends E2eeBaseKey implements Parcelable {
/**
* Describes the local verification state for the key, for instance QR-code based
* verification.
*/
private final int mLocalVerificationState;
/**
* The display name for the contact.
*/
private final String mDisplayName;
/**
* The phone number as the user entered it.
*/
private final String mPhoneNumber;
/**
* The email address.
*/
private final String mEmailAddress;
/**
* @hide
*/
public E2eeContactKey(@Nullable String deviceId, @NonNull String accountId,
@NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
@VerificationState int localVerificationState,
@VerificationState int remoteVerificationState,
@Nullable String displayName,
@Nullable String phoneNumber, @Nullable String emailAddress) {
super(deviceId, accountId, ownerPackageName, timeUpdated, keyValue,
remoteVerificationState);
this.mLocalVerificationState = localVerificationState;
this.mDisplayName = displayName;
this.mPhoneNumber = phoneNumber;
this.mEmailAddress = emailAddress;
}
/**
* Gets the local verification state for the key, for instance QR-code based verification.
*
* @return The local verification state for the key.
*/
public @VerificationState int getLocalVerificationState() {
return mLocalVerificationState;
}
/**
* Gets the display name for the contact.
*
* @return The display name for the contact.
*/
@Nullable
public String getDisplayName() {
return mDisplayName;
}
/**
* Gets the phone number as the user entered it.
*
* @return The phone number as the user entered it.
*/
@Nullable
public String getPhoneNumber() {
return mPhoneNumber;
}
/**
* Gets the email address.
*
* @return The email address.
*/
@Nullable
public String getEmailAddress() {
return mEmailAddress;
}
@Override
public int hashCode() {
return Objects.hash(mDeviceId, mAccountId, mOwnerPackageName, mTimeUpdated,
Arrays.hashCode(mKeyValue), mLocalVerificationState, mRemoteVerificationState,
mDisplayName, mPhoneNumber, mEmailAddress);
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (!(obj instanceof E2eeContactKey toCompare)) {
return false;
}
return Objects.equals(mDeviceId, toCompare.mDeviceId)
&& Objects.equals(mAccountId, toCompare.mAccountId)
&& Objects.equals(mOwnerPackageName, toCompare.mOwnerPackageName)
&& mTimeUpdated == toCompare.mTimeUpdated
&& Arrays.equals(mKeyValue, toCompare.mKeyValue)
&& mLocalVerificationState == toCompare.mLocalVerificationState
&& mRemoteVerificationState == toCompare.mRemoteVerificationState
&& Objects.equals(mDisplayName, toCompare.mDisplayName)
&& Objects.equals(mPhoneNumber, toCompare.mPhoneNumber)
&& Objects.equals(mEmailAddress, toCompare.mEmailAddress);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mDeviceId);
dest.writeString8(mAccountId);
dest.writeString8(mOwnerPackageName);
dest.writeLong(mTimeUpdated);
dest.writeInt(mKeyValue != null ? mKeyValue.length : ARRAY_IS_NULL);
if (mKeyValue != null) {
dest.writeByteArray(mKeyValue);
}
dest.writeInt(mLocalVerificationState);
dest.writeInt(mRemoteVerificationState);
dest.writeString8(mDisplayName);
dest.writeString8(mPhoneNumber);
dest.writeString8(mEmailAddress);
}
@Override
public int describeContents() {
return 0;
}
@NonNull
public static final Creator<E2eeContactKey> CREATOR =
new Creator<>() {
@Override
public E2eeContactKey createFromParcel(Parcel source) {
String deviceId = source.readString8();
String accountId = source.readString8();
String ownerPackageName = source.readString8();
long timeUpdated = source.readLong();
int keyValueLength = source.readInt();
byte[] keyValue;
if (keyValueLength > 0) {
keyValue = new byte[keyValueLength];
source.readByteArray(keyValue);
} else {
keyValue = null;
}
int localVerificationState = source.readInt();
int remoteVerificationState = source.readInt();
String displayName = source.readString8();
String number = source.readString8();
String address = source.readString8();
return new E2eeContactKey(deviceId, accountId, ownerPackageName,
timeUpdated, keyValue, localVerificationState,
remoteVerificationState, displayName, number, address);
}
@Override
public E2eeContactKey[] newArray(int size) {
return new E2eeContactKey[size];
}
};
}
/**
* A parcelable class encapsulating self end to end encrypted contact key.
*/
public static final class E2eeSelfKey extends E2eeBaseKey implements Parcelable {
/**
* @hide
*/
public E2eeSelfKey(@Nullable String deviceId, @NonNull String accountId,
@NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
@VerificationState int remoteVerificationState) {
super(deviceId, accountId, ownerPackageName, timeUpdated, keyValue,
remoteVerificationState);
}
@Override
public int hashCode() {
return Objects.hash(mDeviceId, mAccountId, mOwnerPackageName, mTimeUpdated,
Arrays.hashCode(mKeyValue), mRemoteVerificationState);
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (!(obj instanceof E2eeSelfKey toCompare)) {
return false;
}
return Objects.equals(mDeviceId, toCompare.mDeviceId)
&& Objects.equals(mAccountId, toCompare.mAccountId)
&& Objects.equals(mOwnerPackageName, toCompare.mOwnerPackageName)
&& mTimeUpdated == toCompare.mTimeUpdated
&& Arrays.equals(mKeyValue, toCompare.mKeyValue)
&& mRemoteVerificationState == toCompare.mRemoteVerificationState;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mDeviceId);
dest.writeString8(mAccountId);
dest.writeString8(mOwnerPackageName);
dest.writeLong(mTimeUpdated);
dest.writeInt(mKeyValue != null ? mKeyValue.length : ARRAY_IS_NULL);
if (mKeyValue != null) {
dest.writeByteArray(mKeyValue);
}
dest.writeInt(mRemoteVerificationState);
}
@Override
public int describeContents() {
return 0;
}
@NonNull
public static final Creator<E2eeSelfKey> CREATOR =
new Creator<>() {
@Override
public E2eeSelfKey createFromParcel(Parcel source) {
String deviceId = source.readString8();
String accountId = source.readString8();
String ownerPackageName = source.readString8();
long timeUpdated = source.readLong();
int keyValueLength = source.readInt();
byte[] keyValue;
if (keyValueLength > 0) {
keyValue = new byte[keyValueLength];
source.readByteArray(keyValue);
} else {
keyValue = null;
}
int remoteVerificationState = source.readInt();
return new E2eeSelfKey(deviceId, accountId, ownerPackageName,
timeUpdated, keyValue, remoteVerificationState);
}
@Override
public E2eeSelfKey[] newArray(int size) {
return new E2eeSelfKey[size];
}
};
}
/**
* An abstract class that's extended by self and contact key classes.
*
* @hide
*/
abstract static class E2eeBaseKey {
/**
* An app-specified identifier for the device for which the key can be used.
*/
protected final String mDeviceId;
/**
* An app-specified identifier for the account for which the key can be used.
* Usually a phone number.
*/
protected final String mAccountId;
/**
* Owner application package name.
*/
protected final String mOwnerPackageName;
/**
* Timestamp at which the key was updated.
*/
protected final long mTimeUpdated;
/**
* The raw bytes for the key.
*/
protected final byte[] mKeyValue;
/**
* Describes the remote verification state for the end-to-end encryption key, for instance
* through a key transparency server.
*/
protected final int mRemoteVerificationState;
protected E2eeBaseKey(@Nullable String deviceId, @NonNull String accountId,
@NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
@VerificationState int remoteVerificationState) {
this.mDeviceId = deviceId;
this.mAccountId = accountId;
this.mOwnerPackageName = ownerPackageName;
this.mTimeUpdated = timeUpdated;
this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
this.mRemoteVerificationState = remoteVerificationState;
}
/**
* Gets the app-specified identifier for the device for which the end-to-end encryption
* key can be used.
* Returns null if the app doesn't have the required visibility into
* the end-to-end encryption key.
*
* @return An app-specified identifier for the device.
*/
@Nullable
public String getDeviceId() {
return mDeviceId;
}
/**
* Gets the app-specified identifier for the account for which the end-to-end encryption
* key can be used.
* Usually a phone number.
*
* @return An app-specified identifier for the account.
*/
@NonNull
public String getAccountId() {
return mAccountId;
}
/**
* Gets the owner application package name.
*
* @return The owner application package name.
*/
@NonNull
public String getOwnerPackageName() {
return mOwnerPackageName;
}
/**
* Gets the timestamp at which the end-to-end encryption key was updated. Returns -1 if
* the app doesn't have the required visibility into the key.
*
* @return The timestamp at which the key was updated in the System.currentTimeMillis()
* base.
*/
public long getTimeUpdated() {
return mTimeUpdated;
}
/**
* Gets the raw bytes for the end-to-end encryption key.
* Returns null if the app doesn't have the required visibility into
* the end-to-end encryption key.
*
* @return A copy of the raw bytes for the end-to-end encryption key.
*/
@Nullable
public byte[] getKeyValue() {
return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
}
/**
* Gets the remote verification state for the end-to-end encryption key, for instance
* through a key transparency server.
*
* @return The remote verification state for the end-to-end encryption key.
*/
public @VerificationState int getRemoteVerificationState() {
return mRemoteVerificationState;
}
}
}