blob: 88dd03333262ed9a809a9cad1f19fb7ca73fb73d [file] [log] [blame]
/*
* Copyright (C) 2011 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.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.PackageManager.UninstallReason;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.Signature;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.overlay.OverlayPaths;
import android.os.PersistableBundle;
import android.os.incremental.IncrementalManager;
import android.service.pm.PackageProto;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.File;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
/**
* Settings base class for pending and resolved classes.
*/
public abstract class PackageSettingBase extends SettingBase {
private static final int[] EMPTY_INT_ARRAY = new int[0];
public final String name;
final String realName;
/** @see AndroidPackage#getPath() */
private File mPath;
private String mPathString;
String[] usesStaticLibraries;
long[] usesStaticLibrariesVersions;
/**
* The path under which native libraries have been unpacked. This path is
* always derived at runtime, and is only stored here for cleanup when a
* package is uninstalled.
*/
@Deprecated
String legacyNativeLibraryPathString;
/**
* The primary CPU abi for this package.
*/
public String primaryCpuAbiString;
/**
* The secondary CPU abi for this package.
*/
public String secondaryCpuAbiString;
/**
* The install time CPU override, if any. This value is written at install time
* and doesn't change during the life of an install. If non-null,
* {@code primaryCpuAbiString} will contain the same value.
*/
String cpuAbiOverrideString;
long timeStamp;
long firstInstallTime;
long lastUpdateTime;
long versionCode;
boolean uidError;
PackageSignatures signatures;
boolean installPermissionsFixed;
PackageKeySetData keySetData = new PackageKeySetData();
static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
// Whether this package is currently stopped, thus can not be
// started until explicitly launched by the user.
private final SparseArray<PackageUserState> mUserState = new SparseArray<>();
/**
* Non-persisted value. During an "upgrade without restart", we need the set
* of all previous code paths so we can surgically add the new APKs to the
* active classloader. If at any point an application is upgraded with a
* restart, this field will be cleared since the classloader would be created
* using the full set of code paths when the package's process is started.
*/
Set<String> mOldCodePaths;
/** Information about how this package was installed/updated. */
@NonNull InstallSource installSource;
/** UUID of {@link VolumeInfo} hosting this app */
String volumeUuid;
/** The category of this app, as hinted by the installer */
int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
/** Whether or not an update is available. Ostensibly only for instant apps. */
boolean updateAvailable;
boolean forceQueryableOverride;
@NonNull
public IncrementalStates incrementalStates;
PackageSettingBase(String name, String realName, @NonNull File path,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
long pVersionCode, int pkgFlags, int pkgPrivateFlags,
String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
super(pkgFlags, pkgPrivateFlags);
this.name = name;
this.realName = realName;
this.usesStaticLibraries = usesStaticLibraries;
this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
setPath(path);
this.legacyNativeLibraryPathString = legacyNativeLibraryPathString;
this.primaryCpuAbiString = primaryCpuAbiString;
this.secondaryCpuAbiString = secondaryCpuAbiString;
this.cpuAbiOverrideString = cpuAbiOverrideString;
this.versionCode = pVersionCode;
this.signatures = new PackageSignatures();
this.installSource = InstallSource.EMPTY;
this.incrementalStates = new IncrementalStates();
}
/**
* New instance of PackageSetting with one-level-deep cloning.
* <p>
* IMPORTANT: With a shallow copy, we do NOT create new contained objects.
* This means, for example, changes to the user state of the original PackageSetting
* will also change the user state in its copy.
*/
PackageSettingBase(PackageSettingBase base, String realName) {
super(base);
name = base.name;
this.realName = realName;
doCopy(base);
}
// A copy constructor used to create snapshots. The boolean is present only to
// match up with the constructor in PackageSetting.
PackageSettingBase(PackageSettingBase orig, boolean snapshot) {
super(orig);
name = orig.name;
realName = orig.realName;
doCopy(orig);
// Clone the user states.
for (int i = 0; i < mUserState.size(); i++) {
mUserState.put(mUserState.keyAt(i), new PackageUserState(mUserState.valueAt(i)));
}
}
public void setInstallerPackageName(String packageName) {
installSource = installSource.setInstallerPackage(packageName);
onChanged();
}
public void setInstallSource(InstallSource installSource) {
this.installSource = Objects.requireNonNull(installSource);
onChanged();
}
void removeInstallerPackage(String packageName) {
installSource = installSource.removeInstallerPackage(packageName);
onChanged();
}
public void setIsOrphaned(boolean isOrphaned) {
installSource = installSource.setIsOrphaned(isOrphaned);
onChanged();
}
public void setVolumeUuid(String volumeUuid) {
this.volumeUuid = volumeUuid;
onChanged();
}
public String getVolumeUuid() {
return volumeUuid;
}
public void setTimeStamp(long newStamp) {
timeStamp = newStamp;
onChanged();
}
public void setUpdateAvailable(boolean updateAvailable) {
this.updateAvailable = updateAvailable;
onChanged();
}
public boolean isUpdateAvailable() {
return updateAvailable;
}
public boolean isSharedUser() {
return false;
}
public Signature[] getSignatures() {
return signatures.mSigningDetails.signatures;
}
public PackageParser.SigningDetails getSigningDetails() {
return signatures.mSigningDetails;
}
/**
* Makes a shallow copy of the given package settings.
*
* NOTE: For some fields [such as keySetData, signatures, mUserState, verificationInfo, etc...],
* the original object is copied and a new one is not created.
*/
public void copyFrom(PackageSettingBase orig) {
super.copyFrom(orig);
doCopy(orig);
}
private void doCopy(PackageSettingBase orig) {
setPath(orig.getPath());
cpuAbiOverrideString = orig.cpuAbiOverrideString;
firstInstallTime = orig.firstInstallTime;
installPermissionsFixed = orig.installPermissionsFixed;
installSource = orig.installSource;
keySetData = orig.keySetData;
lastUpdateTime = orig.lastUpdateTime;
legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
// Intentionally skip mOldCodePaths; it's not relevant for copies
primaryCpuAbiString = orig.primaryCpuAbiString;
secondaryCpuAbiString = orig.secondaryCpuAbiString;
signatures = orig.signatures;
timeStamp = orig.timeStamp;
uidError = orig.uidError;
mUserState.clear();
for (int i = 0; i < orig.mUserState.size(); i++) {
mUserState.put(orig.mUserState.keyAt(i), orig.mUserState.valueAt(i));
}
versionCode = orig.versionCode;
volumeUuid = orig.volumeUuid;
categoryHint = orig.categoryHint;
usesStaticLibraries = orig.usesStaticLibraries != null
? Arrays.copyOf(orig.usesStaticLibraries,
orig.usesStaticLibraries.length) : null;
usesStaticLibrariesVersions = orig.usesStaticLibrariesVersions != null
? Arrays.copyOf(orig.usesStaticLibrariesVersions,
orig.usesStaticLibrariesVersions.length) : null;
updateAvailable = orig.updateAvailable;
forceQueryableOverride = orig.forceQueryableOverride;
incrementalStates = orig.incrementalStates;
}
@VisibleForTesting
PackageUserState modifyUserState(int userId) {
PackageUserState state = mUserState.get(userId);
if (state == null) {
state = new PackageUserState();
mUserState.put(userId, state);
onChanged();
}
return state;
}
public PackageUserState readUserState(int userId) {
PackageUserState state = mUserState.get(userId);
if (state == null) {
return DEFAULT_USER_STATE;
}
state.categoryHint = categoryHint;
return state;
}
void setEnabled(int state, int userId, String callingPackage) {
PackageUserState st = modifyUserState(userId);
st.enabled = state;
st.lastDisableAppCaller = callingPackage;
onChanged();
}
int getEnabled(int userId) {
return readUserState(userId).enabled;
}
String getLastDisabledAppCaller(int userId) {
return readUserState(userId).lastDisableAppCaller;
}
void setInstalled(boolean inst, int userId) {
modifyUserState(userId).installed = inst;
onChanged();
}
boolean getInstalled(int userId) {
return readUserState(userId).installed;
}
int getInstallReason(int userId) {
return readUserState(userId).installReason;
}
void setInstallReason(int installReason, int userId) {
modifyUserState(userId).installReason = installReason;
onChanged();
}
int getUninstallReason(int userId) {
return readUserState(userId).uninstallReason;
}
void setUninstallReason(@UninstallReason int uninstallReason, int userId) {
modifyUserState(userId).uninstallReason = uninstallReason;
onChanged();
}
boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) {
boolean returnValue = modifyUserState(userId).setOverlayPaths(overlayPaths);
onChanged();
return returnValue;
}
OverlayPaths getOverlayPaths(int userId) {
return readUserState(userId).getOverlayPaths();
}
boolean setOverlayPathsForLibrary(String libName, OverlayPaths overlayPaths,
int userId) {
boolean returnValue = modifyUserState(userId)
.setSharedLibraryOverlayPaths(libName, overlayPaths);
onChanged();
return returnValue;
}
Map<String, OverlayPaths> getOverlayPathsForLibrary(int userId) {
return readUserState(userId).getSharedLibraryOverlayPaths();
}
/**
* Only use for testing. Do NOT use in production code.
*/
@VisibleForTesting
@Deprecated
public SparseArray<PackageUserState> getUserState() {
return mUserState;
}
boolean isAnyInstalled(int[] users) {
for (int user: users) {
if (readUserState(user).installed) {
return true;
}
}
return false;
}
int[] queryInstalledUsers(int[] users, boolean installed) {
int num = 0;
for (int user : users) {
if (getInstalled(user) == installed) {
num++;
}
}
int[] res = new int[num];
num = 0;
for (int user : users) {
if (getInstalled(user) == installed) {
res[num] = user;
num++;
}
}
return res;
}
long getCeDataInode(int userId) {
return readUserState(userId).ceDataInode;
}
void setCeDataInode(long ceDataInode, int userId) {
modifyUserState(userId).ceDataInode = ceDataInode;
onChanged();
}
boolean getStopped(int userId) {
return readUserState(userId).stopped;
}
void setStopped(boolean stop, int userId) {
modifyUserState(userId).stopped = stop;
onChanged();
}
boolean getNotLaunched(int userId) {
return readUserState(userId).notLaunched;
}
void setNotLaunched(boolean stop, int userId) {
modifyUserState(userId).notLaunched = stop;
onChanged();
}
boolean getHidden(int userId) {
return readUserState(userId).hidden;
}
void setHidden(boolean hidden, int userId) {
modifyUserState(userId).hidden = hidden;
onChanged();
}
int getDistractionFlags(int userId) {
return readUserState(userId).distractionFlags;
}
void setDistractionFlags(int distractionFlags, int userId) {
modifyUserState(userId).distractionFlags = distractionFlags;
onChanged();
}
boolean getSuspended(int userId) {
return readUserState(userId).suspended;
}
boolean isSuspendedBy(String suspendingPackage, int userId) {
final PackageUserState state = readUserState(userId);
return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
}
void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
final PackageUserState.SuspendParams newSuspendParams =
PackageUserState.SuspendParams.getInstanceOrNull(dialogInfo, appExtras,
launcherExtras);
if (existingUserState.suspendParams == null) {
existingUserState.suspendParams = new ArrayMap<>();
}
existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
existingUserState.suspended = true;
onChanged();
}
void removeSuspension(String suspendingPackage, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
if (existingUserState.suspendParams != null) {
existingUserState.suspendParams.remove(suspendingPackage);
if (existingUserState.suspendParams.size() == 0) {
existingUserState.suspendParams = null;
}
}
existingUserState.suspended = (existingUserState.suspendParams != null);
onChanged();
}
void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
if (existingUserState.suspendParams != null) {
for (int i = existingUserState.suspendParams.size() - 1; i >= 0; i--) {
final String suspendingPackage = existingUserState.suspendParams.keyAt(i);
if (suspendingPackagePredicate.test(suspendingPackage)) {
existingUserState.suspendParams.removeAt(i);
}
}
if (existingUserState.suspendParams.size() == 0) {
existingUserState.suspendParams = null;
}
}
existingUserState.suspended = (existingUserState.suspendParams != null);
onChanged();
}
public boolean getInstantApp(int userId) {
return readUserState(userId).instantApp;
}
void setInstantApp(boolean instantApp, int userId) {
modifyUserState(userId).instantApp = instantApp;
onChanged();
}
boolean getVirtulalPreload(int userId) {
return readUserState(userId).virtualPreload;
}
void setVirtualPreload(boolean virtualPreload, int userId) {
modifyUserState(userId).virtualPreload = virtualPreload;
onChanged();
}
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended,
ArrayMap<String, PackageUserState.SuspendParams> suspendParams, boolean instantApp,
boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int installReason, int uninstallReason, String harmfulAppWarning,
String splashScreenTheme) {
PackageUserState state = modifyUserState(userId);
state.ceDataInode = ceDataInode;
state.enabled = enabled;
state.installed = installed;
state.stopped = stopped;
state.notLaunched = notLaunched;
state.hidden = hidden;
state.distractionFlags = distractionFlags;
state.suspended = suspended;
state.suspendParams = suspendParams;
state.lastDisableAppCaller = lastDisableAppCaller;
state.enabledComponents = enabledComponents;
state.disabledComponents = disabledComponents;
state.installReason = installReason;
state.uninstallReason = uninstallReason;
state.instantApp = instantApp;
state.virtualPreload = virtualPreload;
state.harmfulAppWarning = harmfulAppWarning;
state.splashScreenTheme = splashScreenTheme;
onChanged();
}
void setUserState(int userId, PackageUserState otherState) {
setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
otherState.stopped, otherState.notLaunched, otherState.hidden,
otherState.distractionFlags, otherState.suspended, otherState.suspendParams,
otherState.instantApp,
otherState.virtualPreload, otherState.lastDisableAppCaller,
otherState.enabledComponents, otherState.disabledComponents,
otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning,
otherState.splashScreenTheme);
}
ArraySet<String> getEnabledComponents(int userId) {
return readUserState(userId).enabledComponents;
}
ArraySet<String> getDisabledComponents(int userId) {
return readUserState(userId).disabledComponents;
}
void setEnabledComponents(ArraySet<String> components, int userId) {
modifyUserState(userId).enabledComponents = components;
onChanged();
}
void setDisabledComponents(ArraySet<String> components, int userId) {
modifyUserState(userId).disabledComponents = components;
onChanged();
}
void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
modifyUserState(userId).enabledComponents = components != null
? new ArraySet<String>(components) : null;
onChanged();
}
void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
modifyUserState(userId).disabledComponents = components != null
? new ArraySet<String>(components) : null;
onChanged();
}
PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
PackageUserState state = modifyUserState(userId);
boolean changed = false;
if (disabled && state.disabledComponents == null) {
state.disabledComponents = new ArraySet<String>(1);
changed = true;
}
if (enabled && state.enabledComponents == null) {
state.enabledComponents = new ArraySet<String>(1);
changed = true;
}
if (changed) {
onChanged();
}
return state;
}
void addDisabledComponent(String componentClassName, int userId) {
modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
onChanged();
}
void addEnabledComponent(String componentClassName, int userId) {
modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
onChanged();
}
boolean enableComponentLPw(String componentClassName, int userId) {
PackageUserState state = modifyUserStateComponents(userId, false, true);
boolean changed = state.disabledComponents != null
? state.disabledComponents.remove(componentClassName) : false;
changed |= state.enabledComponents.add(componentClassName);
if (changed) {
onChanged();
}
return changed;
}
boolean disableComponentLPw(String componentClassName, int userId) {
PackageUserState state = modifyUserStateComponents(userId, true, false);
boolean changed = state.enabledComponents != null
? state.enabledComponents.remove(componentClassName) : false;
changed |= state.disabledComponents.add(componentClassName);
if (changed) {
onChanged();
}
return changed;
}
boolean restoreComponentLPw(String componentClassName, int userId) {
PackageUserState state = modifyUserStateComponents(userId, true, true);
boolean changed = state.disabledComponents != null
? state.disabledComponents.remove(componentClassName) : false;
changed |= state.enabledComponents != null
? state.enabledComponents.remove(componentClassName) : false;
if (changed) {
onChanged();
}
return changed;
}
int getCurrentEnabledStateLPr(String componentName, int userId) {
PackageUserState state = readUserState(userId);
if (state.enabledComponents != null && state.enabledComponents.contains(componentName)) {
return COMPONENT_ENABLED_STATE_ENABLED;
} else if (state.disabledComponents != null
&& state.disabledComponents.contains(componentName)) {
return COMPONENT_ENABLED_STATE_DISABLED;
} else {
return COMPONENT_ENABLED_STATE_DEFAULT;
}
}
void removeUser(int userId) {
mUserState.delete(userId);
onChanged();
}
public int[] getNotInstalledUserIds() {
int count = 0;
int userStateCount = mUserState.size();
for (int i = 0; i < userStateCount; i++) {
if (!mUserState.valueAt(i).installed) {
count++;
}
}
if (count == 0) return EMPTY_INT_ARRAY;
int[] excludedUserIds = new int[count];
int idx = 0;
for (int i = 0; i < userStateCount; i++) {
if (!mUserState.valueAt(i).installed) {
excludedUserIds[idx++] = mUserState.keyAt(i);
}
}
return excludedUserIds;
}
protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
int count = mUserState.size();
for (int i = 0; i < count; i++) {
final long userToken = proto.start(fieldId);
final int userId = mUserState.keyAt(i);
final PackageUserState state = mUserState.valueAt(i);
proto.write(PackageProto.UserInfoProto.ID, userId);
final int installType;
if (state.instantApp) {
installType = PackageProto.UserInfoProto.INSTANT_APP_INSTALL;
} else if (state.installed) {
installType = PackageProto.UserInfoProto.FULL_APP_INSTALL;
} else {
installType = PackageProto.UserInfoProto.NOT_INSTALLED_FOR_USER;
}
proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
proto.write(PackageProto.UserInfoProto.DISTRACTION_FLAGS, state.distractionFlags);
proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
if (state.suspended) {
for (int j = 0; j < state.suspendParams.size(); j++) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
state.suspendParams.keyAt(j));
}
}
proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
proto.write(
PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER,
state.lastDisableAppCaller);
proto.end(userToken);
}
}
void setHarmfulAppWarning(int userId, String harmfulAppWarning) {
PackageUserState userState = modifyUserState(userId);
userState.harmfulAppWarning = harmfulAppWarning;
onChanged();
}
String getHarmfulAppWarning(int userId) {
PackageUserState userState = readUserState(userId);
return userState.harmfulAppWarning;
}
/**
* @see #mPath
*/
PackageSettingBase setPath(@NonNull File path) {
this.mPath = path;
this.mPathString = path.toString();
onChanged();
return this;
}
/** @see #mPath */
File getPath() {
return mPath;
}
/** @see #mPath */
String getPathString() {
return mPathString;
}
/**
* @see PackageUserState#overrideLabelAndIcon(ComponentName, String, Integer)
*
* @param userId the specific user to change the label/icon for
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public boolean overrideNonLocalizedLabelAndIcon(@NonNull ComponentName component,
@Nullable String label, @Nullable Integer icon, @UserIdInt int userId) {
boolean returnValue = modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
onChanged();
return returnValue;
}
/**
* @see PackageUserState#resetOverrideComponentLabelIcon()
*
* @param userId the specific user to reset
*/
public void resetOverrideComponentLabelIcon(@UserIdInt int userId) {
modifyUserState(userId).resetOverrideComponentLabelIcon();
onChanged();
}
/**
* @param userId the specified user to modify the theme for
* @param themeName the theme name to persist
* @see android.window.SplashScreen#setSplashScreenTheme(int)
*/
public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) {
modifyUserState(userId).splashScreenTheme = themeName;
onChanged();
}
/**
* @param userId the specified user to get the theme setting from
* @return the theme name previously persisted for the user or null
* if no splashscreen theme is persisted.
* @see android.window.SplashScreen#setSplashScreenTheme(int)
*/
@Nullable
public String getSplashScreenTheme(@UserIdInt int userId) {
return readUserState(userId).splashScreenTheme;
}
/**
* @return True if package is still being loaded, false if the package is fully loaded.
*/
public boolean isPackageLoading() {
return getIncrementalStates().isLoading();
}
/**
* @return all current states in a Parcelable.
*/
public IncrementalStatesInfo getIncrementalStates() {
return incrementalStates.getIncrementalStatesInfo();
}
/**
* Called to indicate that the package installation has been committed. This will create a
* new loading state with default values.
* For a package installed on Incremental, the loading state is true.
* For non-Incremental packages, the loading state is false.
*/
public void setStatesOnCommit() {
incrementalStates.onCommit(IncrementalManager.isIncrementalPath(getPathString()));
onChanged();
}
/**
* Called to set the callback to listen for loading state changes.
*/
public void setIncrementalStatesCallback(IncrementalStates.Callback callback) {
incrementalStates.setCallback(callback);
onChanged();
}
/**
* Called to report progress changes. This might trigger loading state change.
* @see IncrementalStates#setProgress(float)
*/
public void setLoadingProgress(float progress) {
incrementalStates.setProgress(progress);
onChanged();
}
public long getFirstInstallTime() {
return firstInstallTime;
}
public String getName() {
return name;
}
protected PackageSettingBase updateFrom(PackageSettingBase other) {
super.copyFrom(other);
setPath(other.getPath());
this.usesStaticLibraries = other.usesStaticLibraries;
this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions;
this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString;
this.primaryCpuAbiString = other.primaryCpuAbiString;
this.secondaryCpuAbiString = other.secondaryCpuAbiString;
this.cpuAbiOverrideString = other.cpuAbiOverrideString;
this.timeStamp = other.timeStamp;
this.firstInstallTime = other.firstInstallTime;
this.lastUpdateTime = other.lastUpdateTime;
this.versionCode = other.versionCode;
this.uidError = other.uidError;
this.signatures = other.signatures;
this.installPermissionsFixed = other.installPermissionsFixed;
this.keySetData = other.keySetData;
this.installSource = other.installSource;
this.volumeUuid = other.volumeUuid;
this.categoryHint = other.categoryHint;
this.updateAvailable = other.updateAvailable;
this.forceQueryableOverride = other.forceQueryableOverride;
this.incrementalStates = other.incrementalStates;
if (mOldCodePaths != null) {
if (other.mOldCodePaths != null) {
mOldCodePaths.clear();
mOldCodePaths.addAll(other.mOldCodePaths);
} else {
mOldCodePaths = null;
}
}
mUserState.clear();
for (int i = 0; i < other.mUserState.size(); i++) {
mUserState.put(other.mUserState.keyAt(i), other.mUserState.valueAt(i));
}
onChanged();
return this;
}
}