gt:             if (info instanceof LocalExtraPkgInfo) {
context: /*
   * 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.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.util.Collections;
  import java.util.EnumSet;
  import java.util.HashMap;
  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$
  
      /**
       * 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()
      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.
       * <p/>
       * 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<FullRevision> getBuildTools() {
          LocalPkgInfo[] pkgs = mLocalSdk.getPkgsInfos(PkgType.PKG_BUILD_TOOLS);
          TreeSet<FullRevision> bt = new TreeSet<FullRevision>();
          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);
      }
  
      /**
       * Returns the greatest {@link LayoutlibVersion} found amongst all platform
       * targets currently loaded in the SDK.
       * <p/>
       * 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 <em>root samples directories</em> 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<File, String> getExtraSamples() {
  
          LocalPkgInfo[] pkgsInfos = mLocalSdk.getPkgsInfos(PkgType.PKG_EXTRA);
          Map<File, String> samples = new HashMap<File, String>();
  
          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 <em>local</em> SDK with their major revision.
       * <p/>
       * 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<String, Integer> getExtrasVersions() {
          LocalPkgInfo[] pkgsInfos = mLocalSdk.getPkgsInfos(PkgType.PKG_EXTRA);
          Map<String, Integer> extraVersions = new TreeMap<String, Integer>();
  
          for (LocalPkgInfo info : pkgsInfos) {
              assert info instanceof LocalExtraPkgInfo;
  