下面列出了android.util.ArrayMap#size ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void reloadSharedPreferences() {
// Build the list of all per-context impls (i.e. caches) we know about
ArrayList<SharedPreferencesImpl> spImpls = new ArrayList<>();
synchronized (ContextImpl.class) {
final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
for (int i = 0; i < cache.size(); i++) {
final SharedPreferencesImpl sp = cache.valueAt(i);
if (sp != null) {
spImpls.add(sp);
}
}
}
// Issue the reload outside the cache lock
for (int i = 0; i < spImpls.size(); i++) {
spImpls.get(i).startReloadIfChangedUnexpectedly();
}
}
private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
if (userCache == null) return;
ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
if (packageCache == null) return;
if (uri != null) {
for (int i = 0; i < packageCache.size();) {
final Pair<String, Uri> key = packageCache.keyAt(i);
if (key.second != null && key.second.toString().startsWith(uri.toString())) {
if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key);
packageCache.removeAt(i);
} else {
i++;
}
}
} else {
if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
packageCache.clear();
}
}
protected boolean cancel(int userId, boolean includeCurrentProfiles) {
int[] userIds = {userId};
if (includeCurrentProfiles) {
userIds = mUserProfiles.getCurrentProfileIds();
}
final int N = userIds.length;
for (int i = 0; i < N; i++) {
final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
mSnoozedNotifications.get(userIds[i]);
if (snoozedPkgs != null) {
final int M = snoozedPkgs.size();
for (int j = 0; j < M; j++) {
final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
if (records != null) {
int P = records.size();
for (int k = 0; k < P; k++) {
records.valueAt(k).isCanceled = true;
}
}
}
return true;
}
}
return false;
}
/**
* Flatten an ArrayMap into the parcel at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
/* package */ void writeArrayMapInternal(ArrayMap<String, Object> val) {
if (val == null) {
writeInt(-1);
return;
}
// Keep the format of this Parcel in sync with writeToParcelInner() in
// frameworks/native/libs/binder/PersistableBundle.cpp.
final int N = val.size();
writeInt(N);
if (DEBUG_ARRAY_MAP) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
}
int startPos;
for (int i=0; i<N; i++) {
if (DEBUG_ARRAY_MAP) startPos = dataPosition();
writeString(val.keyAt(i));
writeValue(val.valueAt(i));
if (DEBUG_ARRAY_MAP) Log.d(TAG, " Write #" + i + " "
+ (dataPosition()-startPos) + " bytes: key=0x"
+ Integer.toHexString(val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0)
+ " " + val.keyAt(i));
}
}
/**
* Calls the {@link SharedElementCallback#onSharedElementStart(List, List, List)} or
* {@link SharedElementCallback#onSharedElementEnd(List, List, List)} on the appropriate
* incoming or outgoing fragment.
*
* @param inFragment The incoming fragment
* @param outFragment The outgoing fragment
* @param isPop Is the incoming fragment part of a pop transaction?
* @param sharedElements The shared element Views
* @param isStart Call the start or end call on the SharedElementCallback
*/
private static void callSharedElementStartEnd(Fragment inFragment, Fragment outFragment,
boolean isPop, ArrayMap<String, View> sharedElements, boolean isStart) {
SharedElementCallback sharedElementCallback = isPop
? outFragment.getEnterTransitionCallback()
: inFragment.getEnterTransitionCallback();
if (sharedElementCallback != null) {
ArrayList<View> views = new ArrayList<>();
ArrayList<String> names = new ArrayList<>();
final int count = sharedElements == null ? 0 : sharedElements.size();
for (int i = 0; i < count; i++) {
names.add(sharedElements.keyAt(i));
views.add(sharedElements.valueAt(i));
}
if (isStart) {
sharedElementCallback.onSharedElementStart(names, views, null);
} else {
sharedElementCallback.onSharedElementEnd(names, views, null);
}
}
}
/**
* Dispatches the accessibility button click to any registered callbacks. This should
* be called on the service's main thread.
*/
void dispatchAccessibilityButtonClicked() {
final ArrayMap<AccessibilityButtonCallback, Handler> entries;
synchronized (mLock) {
if (mCallbacks == null || mCallbacks.isEmpty()) {
Slog.w(LOG_TAG, "Received accessibility button click with no callbacks!");
return;
}
// Callbacks may remove themselves. Perform a shallow copy to avoid concurrent
// modification.
entries = new ArrayMap<>(mCallbacks);
}
for (int i = 0, count = entries.size(); i < count; i++) {
final AccessibilityButtonCallback callback = entries.keyAt(i);
final Handler handler = entries.valueAt(i);
handler.post(() -> callback.onClicked(this));
}
}
/**
* Notifies the registered {@link AccessibilityStateChangeListener}s.
*/
private void notifyAccessibilityStateChanged() {
final boolean isEnabled;
final ArrayMap<AccessibilityStateChangeListener, Handler> listeners;
synchronized (mLock) {
if (mAccessibilityStateChangeListeners.isEmpty()) {
return;
}
isEnabled = isEnabled();
listeners = new ArrayMap<>(mAccessibilityStateChangeListeners);
}
final int numListeners = listeners.size();
for (int i = 0; i < numListeners; i++) {
final AccessibilityStateChangeListener listener = listeners.keyAt(i);
listeners.valueAt(i).post(() ->
listener.onAccessibilityStateChanged(isEnabled));
}
}
private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
boolean removed = false;
final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
if (approvedByType != null) {
int M = approvedByType.size();
for (int j = 0; j < M; j++) {
final ArraySet<String> approved = approvedByType.valueAt(j);
int O = approved.size();
for (int k = O - 1; k >= 0; k--) {
final String packageOrComponent = approved.valueAt(k);
final String packageName = getPackageName(packageOrComponent);
if (TextUtils.equals(pkg, packageName)) {
approved.removeAt(k);
if (DEBUG) {
Slog.v(TAG, "Removing " + packageOrComponent
+ " from approved list; uninstalled");
}
}
}
}
}
return removed;
}
/**
* Match start/end values by Adapter transitionName. Adds matched values to mStartValuesList
* and mEndValuesList and removes them from unmatchedStart and unmatchedEnd, using
* startNames and endNames as a guide for which Views have unique transitionNames.
*/
private void matchNames(ArrayMap<View, TransitionValues> unmatchedStart,
ArrayMap<View, TransitionValues> unmatchedEnd,
ArrayMap<String, View> startNames, ArrayMap<String, View> endNames) {
int numStartNames = startNames.size();
for (int i = 0; i < numStartNames; i++) {
View startView = startNames.valueAt(i);
if (startView != null && isValidTarget(startView)) {
View endView = endNames.get(startNames.keyAt(i));
if (endView != null && isValidTarget(endView)) {
TransitionValues startValues = unmatchedStart.get(startView);
TransitionValues endValues = unmatchedEnd.get(endView);
if (startValues != null && endValues != null) {
mStartValuesList.add(startValues);
mEndValuesList.add(endValues);
unmatchedStart.remove(startView);
unmatchedEnd.remove(endView);
}
}
}
}
}
void copyInternal(BaseBundle from, boolean deep) {
synchronized (from) {
if (from.mParcelledData != null) {
if (from.isEmptyParcel()) {
mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
mParcelledByNative = false;
} else {
mParcelledData = Parcel.obtain();
mParcelledData.appendFrom(from.mParcelledData, 0,
from.mParcelledData.dataSize());
mParcelledData.setDataPosition(0);
mParcelledByNative = from.mParcelledByNative;
}
} else {
mParcelledData = null;
mParcelledByNative = false;
}
if (from.mMap != null) {
if (!deep) {
mMap = new ArrayMap<>(from.mMap);
} else {
final ArrayMap<String, Object> fromMap = from.mMap;
final int N = fromMap.size();
mMap = new ArrayMap<>(N);
for (int i = 0; i < N; i++) {
mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
}
}
} else {
mMap = null;
}
mClassLoader = from.mClassLoader;
}
}
private static <T> void addKeys(ArraySet<T> set, ArrayMap<T, ?> map) {
if (map != null) {
for (int i = 0; i < map.size(); i++) {
set.add(map.keyAt(i));
}
}
}
/**
* Dispatches magnification changes to any registered listeners. This
* should be called on the service's main thread.
*/
void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
final float centerX, final float centerY) {
final ArrayMap<OnMagnificationChangedListener, Handler> entries;
synchronized (mLock) {
if (mListeners == null || mListeners.isEmpty()) {
Slog.d(LOG_TAG, "Received magnification changed "
+ "callback with no listeners registered!");
setMagnificationCallbackEnabled(false);
return;
}
// Listeners may remove themselves. Perform a shallow copy to avoid concurrent
// modification.
entries = new ArrayMap<>(mListeners);
}
for (int i = 0, count = entries.size(); i < count; i++) {
final OnMagnificationChangedListener listener = entries.keyAt(i);
final Handler handler = entries.valueAt(i);
if (handler != null) {
handler.post(new Runnable() {
@Override
public void run() {
listener.onMagnificationChanged(MagnificationController.this,
region, scale, centerX, centerY);
}
});
} else {
// We're already on the main thread, just run the listener.
listener.onMagnificationChanged(this, region, scale, centerX, centerY);
}
}
}
/**
* New overall state record
*/
private void writeBackupState(ArrayMap<String, Long> state, ParcelFileDescriptor stateFile) {
try {
FileOutputStream fos = new FileOutputStream(stateFile.getFileDescriptor());
// We explicitly don't close 'out' because we must not close the backing fd.
// The FileOutputStream will not close it implicitly.
@SuppressWarnings("resource")
DataOutputStream out = new DataOutputStream(fos);
out.writeInt(mCurrentBlobVersion);
final int N = (state != null) ? state.size() : 0;
out.writeInt(N);
for (int i = 0; i < N; i++) {
final String key = state.keyAt(i);
final long checksum = state.valueAt(i).longValue();
if (DEBUG) {
Log.i(TAG, " writing key " + key + " checksum = " + checksum);
}
out.writeUTF(key);
out.writeLong(checksum);
}
} catch (IOException e) {
Log.e(TAG, "Unable to write updated state", e);
}
}
/**
* Clear the profiles for the given package.
*/
public void clearAppProfiles(PackageParser.Package pkg) {
try {
ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
String profileName = packageProfileNames.valueAt(i);
mInstaller.clearAppProfiles(pkg.packageName, profileName);
}
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
}
/**
* Add Views from sharedElements into views that have the transitionName in the
* nameOverridesSet.
*
* @param views Views list to add shared elements to
* @param sharedElements List of shared elements
* @param nameOverridesSet The transition names for all views to be copied from
* sharedElements to views.
*/
private static void addSharedElementsWithMatchingNames(ArrayList<View> views,
ArrayMap<String, View> sharedElements, Collection<String> nameOverridesSet) {
for (int i = sharedElements.size() - 1; i >= 0; i--) {
View view = sharedElements.valueAt(i);
if (view != null && nameOverridesSet.contains(view.getTransitionName())) {
views.add(view);
}
}
}
/**
* Add the statistics from the right {@link UsageStats} to the left. The package name for
* both {@link UsageStats} objects must be the same.
* @param right The {@link UsageStats} object to merge into this one.
* @throws java.lang.IllegalArgumentException if the package names of the two
* {@link UsageStats} objects are different.
*/
public void add(UsageStats right) {
if (!mPackageName.equals(right.mPackageName)) {
throw new IllegalArgumentException("Can't merge UsageStats for package '" +
mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
}
// We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
// regards to their mEndTimeStamp.
if (right.mBeginTimeStamp > mBeginTimeStamp) {
// Even though incoming UsageStat begins after this one, its last time used fields
// may somehow be empty or chronologically preceding the older UsageStat.
mLastEvent = Math.max(mLastEvent, right.mLastEvent);
mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed);
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
mLaunchCount += right.mLaunchCount;
mAppLaunchCount += right.mAppLaunchCount;
if (mChooserCounts == null) {
mChooserCounts = right.mChooserCounts;
} else if (right.mChooserCounts != null) {
final int chooserCountsSize = right.mChooserCounts.size();
for (int i = 0; i < chooserCountsSize; i++) {
String action = right.mChooserCounts.keyAt(i);
ArrayMap<String, Integer> counts = right.mChooserCounts.valueAt(i);
if (!mChooserCounts.containsKey(action) || mChooserCounts.get(action) == null) {
mChooserCounts.put(action, counts);
continue;
}
final int annotationSize = counts.size();
for (int j = 0; j < annotationSize; j++) {
String key = counts.keyAt(j);
int rightValue = counts.valueAt(j);
int leftValue = mChooserCounts.get(action).getOrDefault(key, 0);
mChooserCounts.get(action).put(key, leftValue + rightValue);
}
}
}
}
private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
synchronized (mLock) {
if (sessionId != mSessionId) {
return;
}
final AutofillClient client = getClient();
if (client == null) {
return;
}
final int itemCount = ids.size();
int numApplied = 0;
ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null;
final View[] views = client.autofillClientFindViewsByAutofillIdTraversal(
Helper.toArray(ids));
ArrayList<AutofillId> failedIds = null;
for (int i = 0; i < itemCount; i++) {
final AutofillId id = ids.get(i);
final AutofillValue value = values.get(i);
final int viewId = id.getViewId();
final View view = views[i];
if (view == null) {
// Most likely view has been removed after the initial request was sent to the
// the service; this is fine, but we need to update the view status in the
// server side so it can be triggered again.
Log.d(TAG, "autofill(): no View with id " + id);
if (failedIds == null) {
failedIds = new ArrayList<>();
}
failedIds.add(id);
continue;
}
if (id.isVirtual()) {
if (virtualValues == null) {
// Most likely there will be just one view with virtual children.
virtualValues = new ArrayMap<>(1);
}
SparseArray<AutofillValue> valuesByParent = virtualValues.get(view);
if (valuesByParent == null) {
// We don't know the size yet, but usually it will be just a few fields...
valuesByParent = new SparseArray<>(5);
virtualValues.put(view, valuesByParent);
}
valuesByParent.put(id.getVirtualChildId(), value);
} else {
// Mark the view as to be autofilled with 'value'
if (mLastAutofilledData == null) {
mLastAutofilledData = new ParcelableMap(itemCount - i);
}
mLastAutofilledData.put(id, value);
view.autofill(value);
// Set as autofilled if the values match now, e.g. when the value was updated
// synchronously.
// If autofill happens async, the view is set to autofilled in
// notifyValueChanged.
setAutofilledIfValuesIs(view, value);
numApplied++;
}
}
if (failedIds != null) {
if (sVerbose) {
Log.v(TAG, "autofill(): total failed views: " + failedIds);
}
try {
mService.setAutofillFailure(mSessionId, failedIds, mContext.getUserId());
} catch (RemoteException e) {
// In theory, we could ignore this error since it's not a big deal, but
// in reality, we rather crash the app anyways, as the failure could be
// a consequence of something going wrong on the server side...
e.rethrowFromSystemServer();
}
}
if (virtualValues != null) {
for (int i = 0; i < virtualValues.size(); i++) {
final View parent = virtualValues.keyAt(i);
final SparseArray<AutofillValue> childrenValues = virtualValues.valueAt(i);
parent.autofill(childrenValues);
numApplied += childrenValues.size();
// TODO: we should provide a callback so the parent can call failures; something
// like notifyAutofillFailed(View view, int[] childrenIds);
}
}
mMetricsLogger.write(newLog(MetricsEvent.AUTOFILL_DATASET_APPLIED)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied));
}
}
public void dumpLPr(PrintWriter pw, String packageName,
DumpState dumpState) {
boolean printedHeader = false;
for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
String keySetPackage = e.getKey();
if (packageName != null && !packageName.equals(keySetPackage)) {
continue;
}
if (!printedHeader) {
if (dumpState.onTitlePrinted())
pw.println();
pw.println("Key Set Manager:");
printedHeader = true;
}
PackageSetting pkg = e.getValue();
pw.print(" ["); pw.print(keySetPackage); pw.println("]");
if (pkg.keySetData != null) {
boolean printedLabel = false;
for (ArrayMap.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
if (!printedLabel) {
pw.print(" KeySets Aliases: ");
printedLabel = true;
} else {
pw.print(", ");
}
pw.print(entry.getKey());
pw.print('=');
pw.print(Long.toString(entry.getValue()));
}
if (printedLabel) {
pw.println("");
}
printedLabel = false;
if (pkg.keySetData.isUsingDefinedKeySets()) {
ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
final int dksSize = definedKeySets.size();
for (int i = 0; i < dksSize; i++) {
if (!printedLabel) {
pw.print(" Defined KeySets: ");
printedLabel = true;
} else {
pw.print(", ");
}
pw.print(Long.toString(definedKeySets.valueAt(i)));
}
}
if (printedLabel) {
pw.println("");
}
printedLabel = false;
final long signingKeySet = pkg.keySetData.getProperSigningKeySet();
pw.print(" Signing KeySets: ");
pw.print(Long.toString(signingKeySet));
pw.println("");
if (pkg.keySetData.isUsingUpgradeKeySets()) {
for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
if (!printedLabel) {
pw.print(" Upgrade KeySets: ");
printedLabel = true;
} else {
pw.print(", ");
}
pw.print(Long.toString(keySetId));
}
}
if (printedLabel) {
pw.println("");
}
}
}
}
void dump(PrintWriter pw, String header, String prefix, long now, long nowElapsed,
int filterUid) {
final long period = getTotalTime(now);
pw.print(prefix); pw.print(header); pw.print(" at ");
pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartClockTime).toString());
pw.print(" (");
TimeUtils.formatDuration(mStartElapsedTime, nowElapsed, pw);
pw.print(") over ");
TimeUtils.formatDuration(period, pw);
pw.println(":");
final int NE = mEntries.size();
for (int i = 0; i < NE; i++) {
int uid = mEntries.keyAt(i);
if (filterUid != -1 && filterUid != UserHandle.getAppId(uid)) {
continue;
}
ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
final int NP = uidMap.size();
for (int j = 0; j < NP; j++) {
PackageEntry pe = uidMap.valueAt(j);
pw.print(prefix); pw.print(" ");
UserHandle.formatUid(pw, uid);
pw.print(" / "); pw.print(uidMap.keyAt(j));
pw.println(":");
pw.print(prefix); pw.print(" ");
printDuration(pw, period, pe.getPendingTime(now), pe.pendingCount, "pending");
printDuration(pw, period, pe.getActiveTime(now), pe.activeCount, "active");
printDuration(pw, period, pe.getActiveTopTime(now), pe.activeTopCount,
"active-top");
if (pe.pendingNesting > 0 || pe.hadPending) {
pw.print(" (pending)");
}
if (pe.activeNesting > 0 || pe.hadActive) {
pw.print(" (active)");
}
if (pe.activeTopNesting > 0 || pe.hadActiveTop) {
pw.print(" (active-top)");
}
pw.println();
if (pe.stopReasons.size() > 0) {
pw.print(prefix); pw.print(" ");
for (int k = 0; k < pe.stopReasons.size(); k++) {
if (k > 0) {
pw.print(", ");
}
pw.print(pe.stopReasons.valueAt(k));
pw.print("x ");
pw.print(JobParameters.getReasonName(pe.stopReasons.keyAt(k)));
}
pw.println();
}
}
}
pw.print(prefix); pw.print(" Max concurrency: ");
pw.print(mMaxTotalActive); pw.print(" total, ");
pw.print(mMaxFgActive); pw.println(" foreground");
}
/**
* There are three ways to call this:
* - no service specified: dump all the services
* - a flattened component name that matched an existing service was specified as the
* first arg: dump that one service
* - the first arg isn't the flattened component name of an existing service:
* dump all services whose component contains the first arg as a substring
*/
protected boolean dumpService(FileDescriptor fd, PrintWriter pw, final String name,
String[] args, int opti, boolean dumpAll) {
final ArrayList<ServiceRecord> services = new ArrayList<>();
final Predicate<ServiceRecord> filter = DumpUtils.filterRecord(name);
synchronized (mAm) {
int[] users = mAm.mUserController.getUsers();
for (int user : users) {
ServiceMap smap = mServiceMap.get(user);
if (smap == null) {
continue;
}
ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByName;
for (int i=0; i<alls.size(); i++) {
ServiceRecord r1 = alls.valueAt(i);
if (filter.test(r1)) {
services.add(r1);
}
}
}
}
if (services.size() <= 0) {
return false;
}
// Sort by component name.
services.sort(Comparator.comparing(WithComponentName::getComponentName));
boolean needSep = false;
for (int i=0; i<services.size(); i++) {
if (needSep) {
pw.println();
}
needSep = true;
dumpService("", fd, pw, services.get(i), args, dumpAll);
}
return true;
}