blob: 95e60e88b3351289e635a306eb03dcb377bb7396 [file] [log] [blame]
/*
* 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.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.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultimap;
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 Set<UpdatablePkgInfo> myConsolidatedPkgs = Sets.newTreeSet();
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 set of {@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..
*/
@NonNull
public Set<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 = packages;
computeUpdates();
}
private void computeUpdates() {
Set<UpdatablePkgInfo> newConsolidatedPkgs = Sets.newTreeSet();
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) {
RemotePkgInfo update = findUpdate(info);
if (update != null) {
info.setRemote(update);
myUpdatedPkgs.add(info);
updates.add(update);
}
newConsolidatedPkgs.add(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)) {
// 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);
newConsolidatedPkgs.add(new UpdatablePkgInfo(remote));
}
myConsolidatedPkgs = newConsolidatedPkgs;
}
private RemotePkgInfo findUpdate(@NonNull UpdatablePkgInfo info) {
RemotePkgInfo currUpdatePkg = null;
IPkgDesc currUpdateDesc = null;
IPkgDesc localDesc = info.getLocalInfo().getDesc();
for (RemotePkgInfo remote: myRemotePkgInfos.get(localDesc.getType())) {
IPkgDesc remoteDesc = remote.getPkgDesc();
if ((currUpdateDesc == null && remoteDesc.isUpdateFor(localDesc)) ||
(currUpdateDesc != null && remoteDesc.isUpdateFor(currUpdateDesc))) {
currUpdatePkg = remote;
currUpdateDesc = remoteDesc;
}
}
return currUpdatePkg;
}
}