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

com.android.sdklib.SdkManager Maven / Gradle / Ivy

/*
 * Copyright (C) 2008 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.sdklib;

import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.annotations.VisibleForTesting;
import com.android.annotations.VisibleForTesting.Visibility;
import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.internal.androidTarget.AddOnTarget;
import com.android.sdklib.internal.androidTarget.PlatformTarget;
import com.android.sdklib.repository.FullRevision;
import com.android.sdklib.repository.descriptors.IPkgDesc;
import com.android.sdklib.repository.descriptors.PkgType;
import com.android.sdklib.repository.local.LocalExtraPkgInfo;
import com.android.sdklib.repository.local.LocalPkgInfo;
import com.android.sdklib.repository.local.LocalSdk;
import com.android.utils.ILogger;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * The SDK manager parses the SDK folder and gives access to the content.
 * @see PlatformTarget
 * @see AddOnTarget
 */
public class SdkManager {

    @SuppressWarnings("unused")
    private static final boolean DEBUG = System.getenv("SDKMAN_DEBUG") != null;        //$NON-NLS-1$

    /** Preference file containing the usb ids for adb */
    private static final String ADB_INI_FILE = "adb_usb.ini";                          //$NON-NLS-1$
       //0--------90--------90--------90--------90--------90--------90--------90--------9
       private static final String ADB_INI_HEADER =
        "# ANDROID 3RD PARTY USB VENDOR ID LIST -- DO NOT EDIT.\n" +                   //$NON-NLS-1$
        "# USE 'android update adb' TO GENERATE.\n" +                                  //$NON-NLS-1$
        "# 1 USB VENDOR ID PER LINE.\n";                                               //$NON-NLS-1$

    /** Embedded reference to the new local SDK object. */
    private final LocalSdk mLocalSdk;

    /**
     * Create a new {@link SdkManager} instance.
     * External users should use {@link #createManager(String, ILogger)}.
     *
     * @param osSdkPath the location of the SDK.
     */
    @VisibleForTesting(visibility=Visibility.PRIVATE)
    protected SdkManager(@NonNull String osSdkPath) {
        mLocalSdk = new LocalSdk(new File(osSdkPath));
    }

    /**
     * Creates an @{linkplain SdkManager} for an existing @{link LocalSdk}.
     *
     * @param localSdk the SDK to use with the SDK manager
     */
    private SdkManager(@NonNull LocalSdk localSdk) {
        mLocalSdk = localSdk;
    }

    /**
     * Creates an {@link SdkManager} for a given sdk location.
     * @param osSdkPath the location of the SDK.
     * @param log the ILogger object receiving warning/error from the parsing.
     * @return the created {@link SdkManager} or null if the location is not valid.
     */
    @Nullable
    public static SdkManager createManager(
            @NonNull String osSdkPath,
            @NonNull ILogger log) {
        try {
            SdkManager manager = new SdkManager(osSdkPath);
            manager.reloadSdk(log);

            return manager;
        } catch (Throwable throwable) {
            log.error(throwable, "Error parsing the sdk.");
        }

        return null;
    }

    /**
     * Creates an @{linkplain SdkManager} for an existing @{link LocalSdk}.
     *
     * @param localSdk the SDK to use with the SDK manager
     */
    @NonNull
    public static SdkManager createManager(@NonNull LocalSdk localSdk) {
        return new SdkManager(localSdk);
    }

    @NonNull
    public LocalSdk getLocalSdk() {
        return mLocalSdk;
    }

    /**
     * Reloads the content of the SDK.
     *
     * @param log the ILogger object receiving warning/error from the parsing.
     */
    public void reloadSdk(@NonNull ILogger log) {
        mLocalSdk.clearLocalPkg(PkgType.PKG_ALL);
    }

    /**
     * Checks whether any of the SDK platforms/add-ons/build-tools have changed on-disk
     * since we last loaded the SDK. This does not reload the SDK nor does it
     * change the underlying targets.
     *
     * @return True if at least one directory or source.prop has changed.
     */
    public boolean hasChanged() {
        return hasChanged(null);
    }

    /**
     * Checks whether any of the SDK platforms/add-ons/build-tools have changed on-disk
     * since we last loaded the SDK. This does not reload the SDK nor does it
     * change the underlying targets.
     *
     * @param log An optional logger used to print verbose info on what changed. Can be null.
     * @return True if at least one directory or source.prop has changed.
     */
    public boolean hasChanged(@Nullable ILogger log) {
        return mLocalSdk.hasChanged(EnumSet.of(PkgType.PKG_PLATFORM,
                                               PkgType.PKG_ADDON,
                                               PkgType.PKG_BUILD_TOOLS));
    }

    /**
     * Returns the location of the SDK.
     */
    @NonNull
    public String getLocation() {
        File f = mLocalSdk.getLocation();
        // Our LocalSdk is created with a file path, so we know the location won't be null.
        assert f != null;
        return f.getPath();
    }

    /**
     * Returns the targets (platforms & addons) that are available in the SDK.
     * The target list is created on demand the first time then cached.
     * It will not refreshed unless {@link #reloadSdk(ILogger)} is called.
     * 

* The array can be empty but not null. */ @NonNull public IAndroidTarget[] getTargets() { return mLocalSdk.getTargets(); } /** * Returns an unmodifiable set of known build-tools revisions. Can be empty but not null. * Deprecated. I don't think anything uses this. */ @Deprecated @NonNull public Set getBuildTools() { LocalPkgInfo[] pkgs = mLocalSdk.getPkgsInfos(PkgType.PKG_BUILD_TOOLS); TreeSet bt = new TreeSet(); for (LocalPkgInfo pkg : pkgs) { IPkgDesc d = pkg.getDesc(); if (d.hasFullRevision()) { bt.add(d.getFullRevision()); } } return Collections.unmodifiableSet(bt); } /** * Returns the highest build-tool revision known. Can be null. * * @return The highest build-tool revision known, or null. */ @Nullable public BuildToolInfo getLatestBuildTool() { return mLocalSdk.getLatestBuildTool(); } /** * Returns the {@link BuildToolInfo} for the given revision. * * @param revision The requested revision. * @return A {@link BuildToolInfo}. Can be null if {@code revision} is null or is * not part of the known set returned by {@link #getBuildTools()}. */ @Nullable public BuildToolInfo getBuildTool(@Nullable FullRevision revision) { return mLocalSdk.getBuildTool(revision); } /** * Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}. * * @param hash the {@link IAndroidTarget} hash string. * @return The matching {@link IAndroidTarget} or null. */ @Nullable public IAndroidTarget getTargetFromHashString(@Nullable String hash) { return mLocalSdk.getTargetFromHashString(hash); } /** * Updates adb with the USB devices declared in the SDK add-ons. * @throws AndroidLocationException * @throws IOException */ public void updateAdb() throws AndroidLocationException, IOException { FileWriter writer = null; try { // get the android prefs location to know where to write the file. File adbIni = new File(AndroidLocation.getFolder(), ADB_INI_FILE); writer = new FileWriter(adbIni); // first, put all the vendor id in an HashSet to remove duplicate. HashSet set = new HashSet(); IAndroidTarget[] targets = getTargets(); for (IAndroidTarget target : targets) { if (target.getUsbVendorId() != IAndroidTarget.NO_USB_ID) { set.add(target.getUsbVendorId()); } } // write file header. writer.write(ADB_INI_HEADER); // now write the Id in a text file, one per line. for (Integer i : set) { writer.write(String.format("0x%04x\n", i)); //$NON-NLS-1$ } } finally { if (writer != null) { writer.close(); } } } /** * Returns the greatest {@link LayoutlibVersion} found amongst all platform * targets currently loaded in the SDK. *

* We only started recording Layoutlib Versions recently in the platform meta data * so it's possible to have an SDK with many platforms loaded but no layoutlib * version defined. * * @return The greatest {@link LayoutlibVersion} or null if none is found. * @deprecated This does NOT solve the right problem and will be changed later. */ @Deprecated @Nullable public LayoutlibVersion getMaxLayoutlibVersion() { LayoutlibVersion maxVersion = null; for (IAndroidTarget target : getTargets()) { if (target instanceof PlatformTarget) { LayoutlibVersion lv = ((PlatformTarget) target).getLayoutlibVersion(); if (lv != null) { if (maxVersion == null || lv.compareTo(maxVersion) > 0) { maxVersion = lv; } } } } return maxVersion; } /** * Returns a map of the root samples directories located in the SDK/extras packages. * No guarantee is made that the extras' samples directory actually contain any valid samples. * The only guarantee is that the root samples directory actually exists. * The map is { File: Samples root directory => String: Extra package display name. } * * @return A non-null possibly empty map of extra samples directories and their associated * extra package display name. */ @NonNull public Map getExtraSamples() { LocalPkgInfo[] pkgsInfos = mLocalSdk.getPkgsInfos(PkgType.PKG_EXTRA); Map samples = new HashMap(); for (LocalPkgInfo info : pkgsInfos) { assert info instanceof LocalExtraPkgInfo; File root = info.getLocalDir(); File path = new File(root, SdkConstants.FD_SAMPLES); if (path.isDirectory()) { samples.put(path, info.getListDescription()); continue; } // Some old-style extras simply have a single "sample" directory. // Accept it if it contains an AndroidManifest.xml. path = new File(root, SdkConstants.FD_SAMPLE); if (path.isDirectory() && new File(path, SdkConstants.FN_ANDROID_MANIFEST_XML).isFile()) { samples.put(path, info.getListDescription()); } } return samples; } /** * Returns a map of all the extras found in the local SDK with their major revision. *

* Map keys are in the form "vendor-id/path-id". These ids uniquely identify an extra package. * The version is the incremental integer major revision of the package. * * @return A non-null possibly empty map of { string "vendor/path" => integer major revision } * @deprecated Starting with add-on schema 6, extras can have full revisions instead of just * major revisions. This API only returns the major revision. Callers should be modified * to use the new {code LocalSdk.getPkgInfo(PkgType.PKG_EXTRAS)} API instead. */ @Deprecated @NonNull public Map getExtrasVersions() { LocalPkgInfo[] pkgsInfos = mLocalSdk.getPkgsInfos(PkgType.PKG_EXTRA); Map extraVersions = new TreeMap(); for (LocalPkgInfo info : pkgsInfos) { assert info instanceof LocalExtraPkgInfo; if (info instanceof LocalExtraPkgInfo) { LocalExtraPkgInfo ei = (LocalExtraPkgInfo) info; IPkgDesc d = ei.getDesc(); String vendor = d.getVendor().getId(); String path = d.getPath(); int majorRev = d.getFullRevision().getMajor(); extraVersions.put(vendor + '/' + path, majorRev); } } return extraVersions; } /** Returns the platform tools version if installed, null otherwise. */ @Nullable public String getPlatformToolsVersion() { LocalPkgInfo info = mLocalSdk.getPkgInfo(PkgType.PKG_PLATFORM_TOOLS); IPkgDesc d = info == null ? null : info.getDesc(); if (d != null && d.hasFullRevision()) { return d.getFullRevision().toShortString(); } return null; } // ------------- public static class LayoutlibVersion implements Comparable { private final int mApi; private final int mRevision; public static final int NOT_SPECIFIED = 0; public LayoutlibVersion(int api, int revision) { mApi = api; mRevision = revision; } public int getApi() { return mApi; } public int getRevision() { return mRevision; } @Override public int compareTo(@NonNull LayoutlibVersion rhs) { boolean useRev = this.mRevision > NOT_SPECIFIED && rhs.mRevision > NOT_SPECIFIED; int lhsValue = (this.mApi << 16) + (useRev ? this.mRevision : 0); int rhsValue = (rhs.mApi << 16) + (useRev ? rhs.mRevision : 0); return lhsValue - rhsValue; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy