All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.android.utils.SdkUtils Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 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 com.android.utils;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableList;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Properties;

import static com.android.SdkConstants.DOT_WEBP;
import static com.android.SdkConstants.DOT_PNG;
import static com.android.SdkConstants.DOT_GIF;
import static com.android.SdkConstants.DOT_9PNG;
import static com.android.SdkConstants.DOT_JPEG;
import static com.android.SdkConstants.DOT_JPG;
import static com.android.SdkConstants.DOT_BMP;

/** Miscellaneous utilities used by the Android SDK tools */
public class SdkUtils {
    /**
     * Returns true if the given string ends with the given suffix, using a
     * case-insensitive comparison.
     *
     * @param string the full string to be checked
     * @param suffix the suffix to be checked for
     * @return true if the string case-insensitively ends with the given suffix
     */
    public static boolean endsWithIgnoreCase(@NonNull String string, @NonNull String suffix) {
        return string.regionMatches(true /* ignoreCase */, string.length() - suffix.length(),
                suffix, 0, suffix.length());
    }

    /**
     * Returns true if the given sequence ends with the given suffix (case
     * sensitive).
     *
     * @param sequence the character sequence to be checked
     * @param suffix the suffix to look for
     * @return true if the given sequence ends with the given suffix
     */
    public static boolean endsWith(@NonNull CharSequence sequence, @NonNull CharSequence suffix) {
        return endsWith(sequence, sequence.length(), suffix);
    }

    /**
     * Returns true if the given sequence ends at the given offset with the given suffix (case
     * sensitive)
     *
     * @param sequence the character sequence to be checked
     * @param endOffset the offset at which the sequence is considered to end
     * @param suffix the suffix to look for
     * @return true if the given sequence ends with the given suffix
     */
    public static boolean endsWith(@NonNull CharSequence sequence, int endOffset,
            @NonNull CharSequence suffix) {
        if (endOffset < suffix.length()) {
            return false;
        }

        for (int i = endOffset - 1, j = suffix.length() - 1; j >= 0; i--, j--) {
            if (sequence.charAt(i) != suffix.charAt(j)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Returns true if the given string starts with the given prefix, using a
     * case-insensitive comparison.
     *
     * @param string the full string to be checked
     * @param prefix the prefix to be checked for
     * @return true if the string case-insensitively starts with the given prefix
     */
    public static boolean startsWithIgnoreCase(@NonNull String string, @NonNull String prefix) {
        return string.regionMatches(true /* ignoreCase */, 0, prefix, 0, prefix.length());
    }

    /** For use by {@link #getLineSeparator()} */
    private static String sLineSeparator;

    /**
     * Returns the default line separator to use.
     * 

* NOTE: If you have an associated IDocument (Eclipse), it is better to call * TextUtilities#getDefaultLineDelimiter(IDocument) since that will * allow (for example) editing a \r\n-delimited document on a \n-delimited * platform and keep a consistent usage of delimiters in the file. * * @return the delimiter string to use */ @NonNull public static String getLineSeparator() { if (sLineSeparator == null) { // This is guaranteed to exist: sLineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$ } return sLineSeparator; } /** * Wraps the given text at the given line width, with an optional hanging * indent. * * @param text the text to be wrapped * @param lineWidth the number of characters to wrap the text to * @param hangingIndent the hanging indent (to be used for the second and * subsequent lines in each paragraph, or null if not known * @return the string, wrapped */ @NonNull public static String wrap( @NonNull String text, int lineWidth, @Nullable String hangingIndent) { if (hangingIndent == null) { hangingIndent = ""; } int explanationLength = text.length(); StringBuilder sb = new StringBuilder(explanationLength * 2); int index = 0; while (index < explanationLength) { int lineEnd = text.indexOf('\n', index); int next; if (lineEnd != -1 && (lineEnd - index) < lineWidth) { next = lineEnd + 1; } else { // Line is longer than available width; grab as much as we can lineEnd = Math.min(index + lineWidth, explanationLength); if (lineEnd - index < lineWidth) { next = explanationLength; } else { // then back up to the last space int lastSpace = text.lastIndexOf(' ', lineEnd); if (lastSpace > index) { lineEnd = lastSpace; next = lastSpace + 1; } else { // No space anywhere on the line: it contains something wider than // can fit (like a long URL) so just hard break it next = lineEnd + 1; } } } if (sb.length() > 0) { sb.append(hangingIndent); } else { lineWidth -= hangingIndent.length(); } sb.append(text.substring(index, lineEnd)); sb.append('\n'); index = next; } return sb.toString(); } /** * Returns the corresponding {@link File} for the given file:// url * * @param url the URL string, e.g. file://foo/bar * @return the corresponding {@link File} (which may or may not exist) * @throws MalformedURLException if the URL string is malformed or is not a file: URL */ @NonNull public static File urlToFile(@NonNull String url) throws MalformedURLException { return urlToFile(new URL(url)); } @NonNull public static File urlToFile(@NonNull URL url) throws MalformedURLException { try { return new File(url.toURI()); } catch (IllegalArgumentException e) { MalformedURLException ex = new MalformedURLException(e.getLocalizedMessage()); ex.initCause(e); throw ex; } catch (URISyntaxException e) { return new File(url.getPath()); } } /** * Returns the corresponding URL string for the given {@link File} * * @param file the file to look up the URL for * @return the corresponding URL * @throws MalformedURLException in very unexpected cases */ public static String fileToUrlString(@NonNull File file) throws MalformedURLException { String url = fileToUrl(file).toExternalForm(); // Use three slashes, which is the form most widely recognized by terminal emulators. if (!url.startsWith("file:///")) { url = url.replaceFirst("file:/", "file:///"); } return url; } /** * Returns the corresponding URL for the given {@link File} * * @param file the file to look up the URL for * @return the corresponding URL * @throws MalformedURLException in very unexpected cases */ public static URL fileToUrl(@NonNull File file) throws MalformedURLException { return file.toURI().toURL(); } /** Prefix in comments which mark the source locations for merge results */ public static final String FILENAME_PREFIX = "From: "; /** * Creates the path comment XML string. Note that it does not escape characters * such as & and <; those are expected to be escaped by the caller (for * example, handled by a call to {@link org.w3c.dom.Document#createComment(String)}) * * * @param file the file to create a path comment for * @param includePadding whether to include padding. The final comment recognized by * error recognizers expect padding between the {@code