下面列出了android.util.ArrayMap#valueAt ( ) 实例代码,或者点击链接到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();
}
}
/**
* Pauses this transition, sending out calls to {@link
* TransitionListener#onTransitionPause(Transition)} to all listeners
* and pausing all running animators started by this transition.
*
* @hide
*/
public void pause(View sceneRoot) {
if (!mEnded) {
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
int numOldAnims = runningAnimators.size();
if (sceneRoot != null) {
WindowId windowId = sceneRoot.getWindowId();
for (int i = numOldAnims - 1; i >= 0; i--) {
AnimationInfo info = runningAnimators.valueAt(i);
if (info.view != null && windowId != null && windowId.equals(info.windowId)) {
Animator anim = runningAnimators.keyAt(i);
anim.pause();
}
}
}
if (mListeners != null && mListeners.size() > 0) {
ArrayList<TransitionListener> tmpListeners =
(ArrayList<TransitionListener>) mListeners.clone();
int numListeners = tmpListeners.size();
for (int i = 0; i < numListeners; ++i) {
tmpListeners.get(i).onTransitionPause(this);
}
}
mPaused = true;
}
}
/**
* Dispatches the accessibility button availability changes to any registered callbacks.
* This should be called on the service's main thread.
*/
void dispatchAccessibilityButtonAvailabilityChanged(boolean available) {
final ArrayMap<AccessibilityButtonCallback, Handler> entries;
synchronized (mLock) {
if (mCallbacks == null || mCallbacks.isEmpty()) {
Slog.w(LOG_TAG,
"Received accessibility button availability change 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.onAvailabilityChanged(this, available));
}
}
private Condition[] removeDuplicateConditions(String pkg, Condition[] conditions) {
if (conditions == null || conditions.length == 0) return null;
final int N = conditions.length;
final ArrayMap<Uri, Condition> valid = new ArrayMap<Uri, Condition>(N);
for (int i = 0; i < N; i++) {
final Uri id = conditions[i].id;
if (valid.containsKey(id)) {
Slog.w(TAG, "Ignoring condition from " + pkg + " for duplicate id: " + id);
continue;
}
valid.put(id, conditions[i]);
}
if (valid.size() == 0) return null;
if (valid.size() == N) return conditions;
final Condition[] rt = new Condition[valid.size()];
for (int i = 0; i < rt.length; i++) {
rt[i] = valid.valueAt(i);
}
return rt;
}
/**
* Called when gesture detection becomes active or inactive
* @hide
*/
public void onGestureDetectionActiveChanged(boolean active) {
final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
synchronized (mLock) {
handlerMap = new ArrayMap<>(mCallbackHandlerMap);
}
int numListeners = handlerMap.size();
for (int i = 0; i < numListeners; i++) {
FingerprintGestureCallback callback = handlerMap.keyAt(i);
Handler handler = handlerMap.valueAt(i);
if (handler != null) {
handler.post(() -> callback.onGestureDetectionAvailabilityChanged(active));
} else {
callback.onGestureDetectionAvailabilityChanged(active);
}
}
}
/**
* 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);
}
}
}
}
}
/**
* Iterates over the shared elements and adds them to the members in order.
* Shared elements that are nested in other shared elements are placed after the
* elements that they are nested in. This means that layout ordering can be done
* from first to last.
*
* @param sharedElements The map of transition names to shared elements to set into
* the member fields.
*/
private void setSharedElements(ArrayMap<String, View> sharedElements) {
boolean isFirstRun = true;
while (!sharedElements.isEmpty()) {
final int numSharedElements = sharedElements.size();
for (int i = numSharedElements - 1; i >= 0; i--) {
final View view = sharedElements.valueAt(i);
final String name = sharedElements.keyAt(i);
if (isFirstRun && (view == null || !view.isAttachedToWindow() || name == null)) {
sharedElements.removeAt(i);
} else if (!isNested(view, sharedElements)) {
mSharedElementNames.add(name);
mSharedElements.add(view);
sharedElements.removeAt(i);
}
}
isFirstRun = false;
}
}
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;
}
protected @NonNull List<NotificationRecord> getSnoozed() {
List<NotificationRecord> snoozedForUser = new ArrayList<>();
int[] userIds = mUserProfiles.getCurrentProfileIds();
if (userIds != null) {
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) {
snoozedForUser.addAll(records.values());
}
}
}
}
}
return snoozedForUser;
}
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;
}
public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
out.startTag(null, getConfig().xmlTag);
out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
if (forBackup) {
trimApprovedListsAccordingToInstalledServices();
}
final int N = mApproved.size();
for (int i = 0 ; i < N; i++) {
final int userId = mApproved.keyAt(i);
final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
if (approvedByType != null) {
final int M = approvedByType.size();
for (int j = 0; j < M; j++) {
final boolean isPrimary = approvedByType.keyAt(j);
final Set<String> approved = approvedByType.valueAt(j);
if (approved != null) {
String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
out.startTag(null, TAG_MANAGED_SERVICES);
out.attribute(null, ATT_APPROVED_LIST, allowedItems);
out.attribute(null, ATT_USER_ID, Integer.toString(userId));
out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
out.endTag(null, TAG_MANAGED_SERVICES);
if (!forBackup && isPrimary) {
// Also write values to settings, for observers who haven't migrated yet
Settings.Secure.putStringForUser(mContext.getContentResolver(),
getConfig().secureSettingName, allowedItems, userId);
}
}
}
}
}
out.endTag(null, getConfig().xmlTag);
}
/**
* 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);
}
}
}
public void dump(ProtoOutputStream proto, DumpFilter filter) {
proto.write(ManagedServicesProto.CAPTION, getCaption());
final int N = mApproved.size();
for (int i = 0 ; i < N; i++) {
final int userId = mApproved.keyAt(i);
final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
if (approvedByType != null) {
final int M = approvedByType.size();
for (int j = 0; j < M; j++) {
final boolean isPrimary = approvedByType.keyAt(j);
final ArraySet<String> approved = approvedByType.valueAt(j);
if (approvedByType != null && approvedByType.size() > 0) {
final long sToken = proto.start(ManagedServicesProto.APPROVED);
for (String s : approved) {
proto.write(ServiceProto.NAME, s);
}
proto.write(ServiceProto.USER_ID, userId);
proto.write(ServiceProto.IS_PRIMARY, isPrimary);
proto.end(sToken);
}
}
}
}
for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
if (filter != null && !filter.matches(cmpt)) continue;
cmpt.writeToProto(proto, ManagedServicesProto.ENABLED);
}
for (ManagedServiceInfo info : mServices) {
if (filter != null && !filter.matches(info.component)) continue;
info.writeToProto(proto, ManagedServicesProto.LIVE_SERVICES, this);
}
for (ComponentName name : mSnoozingForCurrentProfiles) {
name.writeToProto(proto, ManagedServicesProto.SNOOZED);
}
}
private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses,
boolean evenPersistent, boolean doit, boolean killProcess,
ArrayMap<ComponentName, ServiceRecord> services) {
boolean didSomething = false;
for (int i = services.size() - 1; i >= 0; i--) {
ServiceRecord service = services.valueAt(i);
final boolean sameComponent = packageName == null
|| (service.packageName.equals(packageName)
&& (filterByClasses == null
|| filterByClasses.contains(service.name.getClassName())));
if (sameComponent
&& (service.app == null || evenPersistent || !service.app.persistent)) {
if (!doit) {
return true;
}
didSomething = true;
Slog.i(TAG, " Force stopping service " + service);
if (service.app != null) {
service.app.removed = killProcess;
if (!service.app.persistent) {
service.app.services.remove(service);
if (service.whitelistManager) {
updateWhitelistManagerLocked(service.app);
}
}
}
service.app = null;
service.isolatedProc = null;
if (mTmpCollectionResults == null) {
mTmpCollectionResults = new ArrayList<>();
}
mTmpCollectionResults.add(service);
}
}
return didSomething;
}
/**
* Force the transition to move to its end state, ending all the animators.
*
* @hide
*/
void forceToEnd(ViewGroup sceneRoot) {
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
int numOldAnims = runningAnimators.size();
if (sceneRoot != null) {
WindowId windowId = sceneRoot.getWindowId();
for (int i = numOldAnims - 1; i >= 0; i--) {
AnimationInfo info = runningAnimators.valueAt(i);
if (info.view != null && windowId != null && windowId.equals(info.windowId)) {
Animator anim = runningAnimators.keyAt(i);
anim.end();
}
}
}
}
protected List<String> getAllowedPackages(int userId) {
final List<String> allowedPackages = new ArrayList<>();
final ArrayMap<Boolean, ArraySet<String>> allowedByType =
mApproved.getOrDefault(userId, new ArrayMap<>());
for (int i = 0; i < allowedByType.size(); i++) {
final ArraySet<String> allowed = allowedByType.valueAt(i);
for (int j = 0; j < allowed.size(); j++) {
String pkgName = getPackageName(allowed.valueAt(j));
if (!TextUtils.isEmpty(pkgName)) {
allowedPackages.add(pkgName);
}
}
}
return allowedPackages;
}
@Override
public JSONObject dumpCheckin(boolean clear) throws JSONException {
final JSONObject result = super.dumpCheckin(clear);
int numDynamic = 0;
int numPinned = 0;
int numManifest = 0;
int numBitmaps = 0;
long totalBitmapSize = 0;
final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts;
final int size = shortcuts.size();
for (int i = 0; i < size; i++) {
final ShortcutInfo si = shortcuts.valueAt(i);
if (si.isDynamic()) numDynamic++;
if (si.isDeclaredInManifest()) numManifest++;
if (si.isPinned()) numPinned++;
if (si.getBitmapPath() != null) {
numBitmaps++;
totalBitmapSize += new File(si.getBitmapPath()).length();
}
}
result.put(KEY_DYNAMIC, numDynamic);
result.put(KEY_MANIFEST, numManifest);
result.put(KEY_PINNED, numPinned);
result.put(KEY_BITMAPS, numBitmaps);
result.put(KEY_BITMAP_BYTES, totalBitmapSize);
// TODO Log update frequency too.
return result;
}
private void doWriteState() {
boolean wroteState = false;
final int version;
final ArrayMap<String, Setting> settings;
synchronized (mLock) {
version = mVersion;
settings = new ArrayMap<>(mSettings);
mDirty = false;
mWriteScheduled = false;
}
synchronized (mWriteLock) {
if (DEBUG_PERSISTENCE) {
Slog.i(LOG_TAG, "[PERSIST START]");
}
AtomicFile destination = new AtomicFile(mStatePersistFile);
FileOutputStream out = null;
try {
out = destination.startWrite();
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(out, StandardCharsets.UTF_8.name());
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_SETTINGS);
serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
final int settingCount = settings.size();
for (int i = 0; i < settingCount; i++) {
Setting setting = settings.valueAt(i);
writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
setting.getTag(), setting.isDefaultFromSystem());
if (DEBUG_PERSISTENCE) {
Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "="
+ setting.getValue());
}
}
serializer.endTag(null, TAG_SETTINGS);
serializer.endDocument();
destination.finishWrite(out);
wroteState = true;
if (DEBUG_PERSISTENCE) {
Slog.i(LOG_TAG, "[PERSIST END]");
}
} catch (Throwable t) {
Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t);
destination.failWrite(out);
} finally {
IoUtils.closeQuietly(out);
}
}
if (wroteState) {
synchronized (mLock) {
addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null);
}
}
}
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 dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
pw.println();
pw.print(prefix);
pw.print("Package: ");
pw.print(getPackageName());
pw.print(" UID: ");
pw.print(mPackageUid);
pw.println();
pw.print(prefix);
pw.print(" ");
pw.print("Calls: ");
pw.print(getApiCallCount(/*unlimited=*/ false));
pw.println();
// getApiCallCount() may have updated mLastKnownForegroundElapsedTime.
pw.print(prefix);
pw.print(" ");
pw.print("Last known FG: ");
pw.print(mLastKnownForegroundElapsedTime);
pw.println();
// This should be after getApiCallCount(), which may update it.
pw.print(prefix);
pw.print(" ");
pw.print("Last reset: [");
pw.print(mLastResetTime);
pw.print("] ");
pw.print(ShortcutService.formatTime(mLastResetTime));
pw.println();
getPackageInfo().dump(pw, prefix + " ");
pw.println();
pw.print(prefix);
pw.println(" Shortcuts:");
long totalBitmapSize = 0;
final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts;
final int size = shortcuts.size();
for (int i = 0; i < size; i++) {
final ShortcutInfo si = shortcuts.valueAt(i);
pw.println(si.toDumpString(prefix + " "));
if (si.getBitmapPath() != null) {
final long len = new File(si.getBitmapPath()).length();
pw.print(prefix);
pw.print(" ");
pw.print("bitmap size=");
pw.println(len);
totalBitmapSize += len;
}
}
pw.print(prefix);
pw.print(" ");
pw.print("Total bitmap size: ");
pw.print(totalBitmapSize);
pw.print(" (");
pw.print(Formatter.formatFileSize(mShortcutUser.mService.mContext, totalBitmapSize));
pw.println(")");
}