| /* |
| * Copyright 2022 Google LLC |
| * |
| * 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 com.google.android.libraries.mobiledatadownload.file.backends; |
| |
| import android.accounts.Account; |
| import com.google.android.libraries.mobiledatadownload.file.common.internal.Preconditions; |
| |
| /** Helper for Uri classes to serialize Android accounts. */ |
| public final class AccountSerialization { |
| |
| private static final String SHARED_ACCOUNT_STR = "shared"; |
| |
| /** A common {@link Account} with no associated user; it appears as "shared" on the filesystem. */ |
| public static final Account SHARED_ACCOUNT = new Account(SHARED_ACCOUNT_STR, "mobstore"); |
| |
| /** |
| * Validates and serializes an {@link Account} into a string representation "<type>:<name>", with |
| * the exception of {@link #SHARED_ACCOUNT} which is serialized as {@link #SHARED_ACCOUNT_STR}. |
| * |
| * <p>The account will be URL encoded in its URI representation (so, eg, "<internal>@gmail.com" |
| * will appear as "you%40gmail.com"), but not in the file path representation used to access disk. |
| * {@link #SHARED_ACCOUNT} shows up as "shared" on the filesystem. |
| * |
| * <p>This method performs some account validation. Android Account itself requires that both the |
| * type and name fields be present. In addition to this requirement, this method requires that the |
| * type contain no colons (as these are the delimiter used internally for the account |
| * serialization), and that neither the type nor the name include any slashes (as these are file |
| * separators). |
| * |
| * <p>Note the Linux filesystem accepts filenames composed of any bytes except "/" and NULL. |
| * |
| * @throws IllegalArgumentException if the account does not conform to the specifications above |
| */ |
| public static String serialize(Account account) { |
| validate(account); |
| if (isSharedAccount(account)) { |
| return SHARED_ACCOUNT_STR; |
| } |
| return account.type + ":" + account.name; |
| } |
| |
| /** |
| * Parses an account string generated by {@link #serialize} back into an {@link Account}, or |
| * throws {@link IllegalArgumentException} if {@code accountStr} has an unrecognized format. |
| */ |
| public static Account deserialize(String accountStr) { |
| if (isSharedAccount(accountStr)) { |
| return SHARED_ACCOUNT; |
| } |
| int colonIdx = accountStr.indexOf(':'); |
| Preconditions.checkArgument(colonIdx > -1, "Malformed account"); |
| String type = accountStr.substring(0, colonIdx); |
| String name = accountStr.substring(colonIdx + 1); |
| return new Account(name, type); |
| } |
| |
| static boolean isSharedAccount(String accountStr) { |
| return SHARED_ACCOUNT_STR.equals(accountStr); |
| } |
| |
| static boolean isSharedAccount(Account account) { |
| return SHARED_ACCOUNT.equals(account); |
| } |
| |
| private static void validate(Account account) { |
| // Android Account already validates that name and type are not empty. |
| Preconditions.checkArgument(account.type.indexOf(':') == -1, "Account type contains ':'."); |
| Preconditions.checkArgument(account.type.indexOf('/') == -1, "Account type contains '/'."); |
| Preconditions.checkArgument(account.name.indexOf('/') == -1, "Account name contains '/'."); |
| } |
| |
| private AccountSerialization() {} |
| } |