com.android.tools.idea.sdk.SdkPackages.java Source code

Java tutorial

Introduction

Here is the source code for com.android.tools.idea.sdk.SdkPackages.java

Source

/*
 * Copyright (C) 2015 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.tools.idea.sdk;

import com.android.annotations.NonNull;
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.LocalPkgInfo;
import com.android.tools.idea.sdk.remote.RemotePkgInfo;
import com.android.tools.idea.sdk.remote.UpdatablePkgInfo;
import com.google.common.base.Predicate;
import com.google.common.collect.*;

import java.util.Map;
import java.util.Set;

/**
 * Store of current local and remote packages, in convenient forms.
 */
public final class SdkPackages {
    private final Set<UpdatablePkgInfo> myUpdatedPkgs = Sets.newTreeSet();
    private final Set<RemotePkgInfo> myNewPkgs = Sets.newTreeSet();
    private final long myTimestampMs;
    private Map<String, UpdatablePkgInfo> myConsolidatedPkgs = Maps.newTreeMap();
    private LocalPkgInfo[] myLocalPkgInfos = new LocalPkgInfo[0];
    private Multimap<PkgType, RemotePkgInfo> myRemotePkgInfos = TreeMultimap.create();

    SdkPackages() {
        myTimestampMs = System.currentTimeMillis();
    }

    public SdkPackages(LocalPkgInfo[] localPkgs, Multimap<PkgType, RemotePkgInfo> remotePkgs) {
        this();
        setLocalPkgInfos(localPkgs);
        setRemotePkgInfos(remotePkgs);
    }

    /**
     * Returns the timestamp (in {@link System#currentTimeMillis()} time) when this object was created.
     */
    public long getTimestampMs() {
        return myTimestampMs;
    }

    /**
     * Returns the set of packages that have local updates available.
     * Use {@link LocalPkgInfo#getUpdate()} to retrieve the computed updated candidate.
     *
     * @return A non-null, possibly empty Set of update candidates.
     */
    @NonNull
    public Set<UpdatablePkgInfo> getUpdatedPkgs() {
        return myUpdatedPkgs;
    }

    /**
     * Returns the set of new remote packages that are not locally present
     * and that the user could install.
     *
     * @return A non-null, possibly empty Set of new install candidates.
     */
    @NonNull
    public Set<RemotePkgInfo> getNewPkgs() {
        return myNewPkgs;
    }

    /**
     * Returns a map of package install ids to {@link UpdatablePackageInfo}s representing all known
     * local and remote packages. Remote packages corresponding to local packages will be represented
     * by a single item containing both the local and remote info.
     * {@see IPkgDesc#getInstallId()}
     */
    @NonNull
    public Map<String, UpdatablePkgInfo> getConsolidatedPkgs() {
        return myConsolidatedPkgs;
    }

    @NonNull
    public LocalPkgInfo[] getLocalPkgInfos() {
        return myLocalPkgInfos;
    }

    public Multimap<PkgType, RemotePkgInfo> getRemotePkgInfos() {
        return myRemotePkgInfos;
    }

    void setLocalPkgInfos(LocalPkgInfo[] packages) {
        myLocalPkgInfos = packages;
        computeUpdates();
    }

    void setRemotePkgInfos(Multimap<PkgType, RemotePkgInfo> packages) {
        myRemotePkgInfos = Multimaps.filterValues(packages, new Predicate<RemotePkgInfo>() {
            @Override
            public boolean apply(RemotePkgInfo input) {
                return input.hasCompatibleArchive();
            }
        });
        computeUpdates();
    }

    private void computeUpdates() {
        Map<String, UpdatablePkgInfo> newConsolidatedPkgs = Maps.newTreeMap();
        UpdatablePkgInfo[] updatablePkgInfos = new UpdatablePkgInfo[myLocalPkgInfos.length];
        for (int i = 0; i < myLocalPkgInfos.length; i++) {
            updatablePkgInfos[i] = new UpdatablePkgInfo(myLocalPkgInfos[i]);
        }
        Set<RemotePkgInfo> updates = Sets.newTreeSet();

        // Find updates to locally installed packages
        for (UpdatablePkgInfo info : updatablePkgInfos) {
            IPkgDesc localDesc = info.getLocalInfo().getDesc();
            for (RemotePkgInfo remote : myRemotePkgInfos.get(localDesc.getType())) {
                if (remote.getPkgDesc().isUpdateFor(localDesc, FullRevision.PreviewComparison.IGNORE)) {
                    info.addRemote(remote);
                    myUpdatedPkgs.add(info);
                    updates.add(remote);
                }
            }
            // the consolidated packages map is always keyed by the non-preview installid, whether or not the UpdatablePackage happens to
            // contain a preview package.
            newConsolidatedPkgs.put(info.getPkgDesc(true).getBaseInstallId(), info);
        }

        // Find new packages not yet installed
        nextRemote: for (RemotePkgInfo remote : myRemotePkgInfos.values()) {
            if (updates.contains(remote)) {
                // if package is already a known update, it's not new.
                continue nextRemote;
            }
            IPkgDesc remoteDesc = remote.getPkgDesc();
            for (UpdatablePkgInfo info : updatablePkgInfos) {
                IPkgDesc localDesc = info.getLocalInfo().getDesc();
                if (remoteDesc.compareTo(localDesc) == 0
                        || remoteDesc.isUpdateFor(localDesc, FullRevision.PreviewComparison.IGNORE)
                        || localDesc.isUpdateFor(remoteDesc,
                                FullRevision.PreviewComparison.IGNORE) /* shouldn't happen in the normal case */) {
                    // if package is same as an installed or is an update for an installed
                    // one, then it's not new.
                    continue nextRemote;
                }
            }

            myNewPkgs.add(remote);
            String key = remoteDesc.getBaseInstallId();
            UpdatablePkgInfo existing = newConsolidatedPkgs.get(key);
            if (existing != null) {
                existing.addRemote(remote);
            } else {
                newConsolidatedPkgs.put(key, new UpdatablePkgInfo(remote));
            }
        }
        myConsolidatedPkgs = newConsolidatedPkgs;
    }
}