Java tutorial
/* * 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; } }