下面列出了android.util.SparseIntArray#keyAt ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Notifies the tracker that the app transition is starting.
*
* @param windowingModeToReason A map from windowing mode to a reason integer, which must be on
* of ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
*/
void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestamp) {
if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
return;
}
if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
mCurrentTransitionDelayMs = calculateDelay(timestamp);
mLoggedTransitionStarting = true;
for (int index = windowingModeToReason.size() - 1; index >= 0; index--) {
final int windowingMode = windowingModeToReason.keyAt(index);
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
windowingMode);
if (info == null) {
continue;
}
info.reason = windowingModeToReason.valueAt(index);
}
if (allWindowsDrawn()) {
reset(false /* abort */, null /* WindowingModeTransitionInfo */);
}
}
/** Get the list of publically visible output formats; does not include IMPL_DEFINED */
private int[] getPublicFormats(boolean output) {
int[] formats = new int[getPublicFormatCount(output)];
int i = 0;
SparseIntArray map = getFormatsMap(output);
for (int j = 0; j < map.size(); j++) {
int format = map.keyAt(j);
formats[i++] = imageFormatToPublic(format);
}
if (output) {
for (int j = 0; j < mDepthOutputFormats.size(); j++) {
formats[i++] = depthFormatToPublic(mDepthOutputFormats.keyAt(j));
}
}
if (formats.length != i) {
throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
}
return formats;
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
if (mGroupedKeyModels.size() > 0) {
final int keyIndex = mGroupedKeyModels.keyAt(position);
holder.groupItemContainer.setTag(keyIndex);
final ApplicationKey key = mMeshNetwork.getAppKey(keyIndex);
holder.mGroupAppKeyTitle.setText(key.getName());
final SparseIntArray groupedModels = mGroupedKeyModels.valueAt(position);
holder.mGroupGrid.setRowCount(1);
//Remove all child views to avoid duplicating
holder.mGroupGrid.removeAllViews();
for (int i = 0; i < groupedModels.size(); i++) {
final int modelId = groupedModels.keyAt(i);
final int count = groupedModels.valueAt(i);
inflateView(holder, keyIndex, modelId, count, i);
}
}
}
/**
* Based off {@link java.util.AbstractMap#equals} -- with simplifications because we're guaranteed
* sparse int arrays with no nullable values or casts.
*
* <p>TODO Make this a utility method, along with hashcode.
*/
public static boolean sparseIntArrayEquals(SparseIntArray a, SparseIntArray b) {
if (a == b) {
return true;
}
int aSize = a.size();
if (aSize != b.size()) {
return false;
}
// Sparse int arrays keep a sorted list of values: which means equality can just walk through
// both arrays to check.
for (int i = 0; i < aSize; i++) {
if (a.keyAt(i) != b.keyAt(i) || a.valueAt(i) != b.valueAt(i)) {
return false;
}
}
return true;
}
static int findFirstKeyLessThan(SparseIntArray cache, int position) {
int lo = 0;
int hi = cache.size() - 1;
while (lo <= hi) {
// Using unsigned shift here to divide by two because it is guaranteed to not
// overflow.
final int mid = (lo + hi) >>> 1;
final int midVal = cache.keyAt(mid);
if (midVal < position) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
int index = lo - 1;
if (index >= 0 && index < cache.size()) {
return cache.keyAt(index);
}
return -1;
}
static int findFirstKeyLessThan(SparseIntArray cache, int position) {
int lo = 0;
int hi = cache.size() - 1;
while (lo <= hi) {
// Using unsigned shift here to divide by two because it is guaranteed to not
// overflow.
final int mid = (lo + hi) >>> 1;
final int midVal = cache.keyAt(mid);
if (midVal < position) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
int index = lo - 1;
if (index >= 0 && index < cache.size()) {
return cache.keyAt(index);
}
return -1;
}
private static Pair[] toPairArray(SparseIntArray counts) {
final int s = counts.size();
Pair[] pairs = new Pair[s];
for (int i = 0; i < s; i++) {
Pair p = new Pair();
p.key = counts.keyAt(i);
p.value = counts.valueAt(i);
pairs[i] = p;
}
return pairs;
}
/**
* Dump per uid binder proxy counts to the logcat.
*/
private void dumpPerUidProxyCounts() {
SparseIntArray counts = BinderInternal.nGetBinderProxyPerUidCounts();
if (counts.size() == 0) return;
Log.d(Binder.TAG, "Per Uid Binder Proxy Counts:");
for (int i = 0; i < counts.size(); i++) {
final int uid = counts.keyAt(i);
final int binderCount = counts.valueAt(i);
Log.d(Binder.TAG, "UID : " + uid + " count = " + binderCount);
}
}
/**
* Creates a new instance of the GenericByteArrayPool class
*
* @param memoryTrimmableRegistry the memory manager to register with
* @param poolParams provider for pool parameters
* @param poolStatsTracker
*/
public GenericByteArrayPool(
MemoryTrimmableRegistry memoryTrimmableRegistry,
PoolParams poolParams,
PoolStatsTracker poolStatsTracker) {
super(memoryTrimmableRegistry, poolParams, poolStatsTracker);
final SparseIntArray bucketSizes = poolParams.bucketSizes;
mBucketSizes = new int[bucketSizes.size()];
for (int i = 0; i < bucketSizes.size(); ++i) {
mBucketSizes[i] = bucketSizes.keyAt(i);
}
initialize();
}
/**
* Subtracts b from the current value while being aware of core restarts.
*
* <p>Cpu clusters can be switched on and off as required by some devices: in those cases, the
* measured frequency can go <em>down</em> across snapshots legally.
*
* <p>If the time in state for any core appears to have reduced, we can infer that the core was
* switched off and restarted. In that case, a better approximation is the current value of the
* snapshot instead of a meaningless subtraction.
*
* <p>Some tests make this behavior more explicit: {@see CpuFrequencyMetricsTest#testDiff} and
* {@see CpuFrequencyMetricsTest#testDiffWithCoreReset} for expected behavior.
*/
@Override
public CpuFrequencyMetrics diff(
@Nullable CpuFrequencyMetrics b, @Nullable CpuFrequencyMetrics output) {
if (output == null) {
output = new CpuFrequencyMetrics();
}
if (b == null) {
output.set(this);
} else {
for (int i = 0; i < timeInStateS.length; i++) {
SparseIntArray aCore = timeInStateS[i];
SparseIntArray bCore = b.timeInStateS[i];
SparseIntArray outputCore = output.timeInStateS[i];
boolean hasCoreReset = false;
for (int j = 0, size = aCore.size(); j < size && !hasCoreReset; j++) {
int frequency = aCore.keyAt(j);
int difference = aCore.valueAt(j) - bCore.get(frequency, 0);
if (difference < 0) {
hasCoreReset = true;
break;
}
outputCore.put(frequency, difference);
}
if (hasCoreReset) {
copyArrayInto(aCore, outputCore);
}
}
}
return output;
}
/** Based off {@link AbstractMap#hashCode()}: returns the sum of the hashcodes of the entries. */
@Override
public int hashCode() {
int hash = 0;
for (int i = 0; i < timeInStateS.length; i++) {
SparseIntArray array = timeInStateS[i];
for (int j = 0, size = timeInStateS[i].size(); j < size; j++) {
// hash of an integer is the integer itself - see {@link Integers#hashCode}
hash += array.keyAt(j) ^ array.valueAt(j);
}
}
return hash;
}
private int findLeftLimit(SparseIntArray points, int end) {
int index = findPointIndex(points, end);
if (index >= 0) {
int limit = points.keyAt(index);
if (limit < end) {
return limit;
}
if (index > 0) {
return points.keyAt(index - 1);
}
}
return 0;
}
/**
* Initialize a new instance of the MemoryChunkPool
*
* @param memoryTrimmableRegistry the memory manager to register with
* @param poolParams provider for pool parameters
* @param memoryChunkPoolStatsTracker the pool stats tracker
*/
MemoryChunkPool(
MemoryTrimmableRegistry memoryTrimmableRegistry,
PoolParams poolParams,
PoolStatsTracker memoryChunkPoolStatsTracker) {
super(memoryTrimmableRegistry, poolParams, memoryChunkPoolStatsTracker);
SparseIntArray bucketSizes = poolParams.bucketSizes;
mBucketSizes = new int[bucketSizes.size()];
for (int i = 0; i < mBucketSizes.length; ++i) {
mBucketSizes[i] = bucketSizes.keyAt(i);
}
initialize();
}
/**
* Creates a new instance of the GenericByteArrayPool class
* @param memoryTrimmableRegistry the memory manager to register with
* @param poolParams provider for pool parameters
* @param poolStatsTracker
*/
public GenericByteArrayPool(
MemoryTrimmableRegistry memoryTrimmableRegistry,
PoolParams poolParams,
PoolStatsTracker poolStatsTracker) {
super(memoryTrimmableRegistry, poolParams, poolStatsTracker);
final SparseIntArray bucketSizes = poolParams.bucketSizes;
mBucketSizes = new int[bucketSizes.size()];
for (int i = 0; i < bucketSizes.size(); ++i) {
mBucketSizes[i] = bucketSizes.keyAt(i);
}
initialize();
}
/**
* Creates a new instance of the NativeMemoryChunkPool class
* @param memoryTrimmableRegistry the memory manager to register with
* @param poolParams provider for pool parameters
* @param nativeMemoryChunkPoolStatsTracker
*/
public NativeMemoryChunkPool(
MemoryTrimmableRegistry memoryTrimmableRegistry,
PoolParams poolParams,
PoolStatsTracker nativeMemoryChunkPoolStatsTracker) {
super(memoryTrimmableRegistry, poolParams, nativeMemoryChunkPoolStatsTracker);
SparseIntArray bucketSizes = poolParams.bucketSizes;
mBucketSizes = new int[bucketSizes.size()];
for (int i = 0; i < mBucketSizes.length; ++i) {
mBucketSizes[i] = bucketSizes.keyAt(i);
}
initialize();
}
/**
* Initialize the list of buckets. Get the bucket sizes (and bucket lengths) from the bucket sizes
* provider
*
* @param inUseCounts map of current buckets and their in use counts
*/
private synchronized void legacyInitBuckets(SparseIntArray inUseCounts) {
Preconditions.checkNotNull(inUseCounts);
// clear out all the buckets
mBuckets.clear();
// create the new buckets
final SparseIntArray bucketSizes = mPoolParams.bucketSizes;
if (bucketSizes != null) {
for (int i = 0; i < bucketSizes.size(); ++i) {
final int bucketSize = bucketSizes.keyAt(i);
final int maxLength = bucketSizes.valueAt(i);
int bucketInUseCount = inUseCounts.get(bucketSize, 0);
mBuckets.put(
bucketSize,
new Bucket<V>(
getSizeInBytes(bucketSize),
maxLength,
bucketInUseCount,
mPoolParams.fixBucketsReinitialization));
}
mAllowNewBuckets = false;
} else {
mAllowNewBuckets = true;
}
}
private static boolean sparseIntArrayEquals(SparseIntArray a, SparseIntArray b) {
if (a == b) return true;
if (a == null) return b == null;
if (b == null) return false;
int size = a.size();
if (size != b.size()) return false;
for (int i=0; i<size; ++i) {
if (a.keyAt(i) != b.keyAt(i)) return false;
if (a.valueAt(i) != b.valueAt(i)) return false;
}
return true;
}
/**
* Finds {@link ViewNode ViewNodes} that have the requested ids.
*
* @param ids The ids of the node to find.
*
* @return The nodes indexed in the same way as the ids.
*
* @hide
*/
@NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId[] ids) {
final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
final ViewNode[] foundNodes = new AssistStructure.ViewNode[ids.length];
// Indexes of foundNodes that are not found yet
final SparseIntArray missingNodeIndexes = new SparseIntArray(ids.length);
for (int i = 0; i < ids.length; i++) {
if (mViewNodeLookupTable != null) {
int lookupTableIndex = mViewNodeLookupTable.indexOfKey(ids[i]);
if (lookupTableIndex >= 0) {
foundNodes[i] = mViewNodeLookupTable.valueAt(lookupTableIndex);
} else {
missingNodeIndexes.put(i, /* ignored */ 0);
}
} else {
missingNodeIndexes.put(i, /* ignored */ 0);
}
}
final int numWindowNodes = mStructure.getWindowNodeCount();
for (int i = 0; i < numWindowNodes; i++) {
nodesToProcess.add(mStructure.getWindowNodeAt(i).getRootViewNode());
}
while (missingNodeIndexes.size() > 0 && !nodesToProcess.isEmpty()) {
final ViewNode node = nodesToProcess.removeFirst();
for (int i = 0; i < missingNodeIndexes.size(); i++) {
final int index = missingNodeIndexes.keyAt(i);
final AutofillId id = ids[index];
if (id.equals(node.getAutofillId())) {
foundNodes[index] = node;
if (mViewNodeLookupTable == null) {
mViewNodeLookupTable = new ArrayMap<>(ids.length);
}
mViewNodeLookupTable.put(id, node);
missingNodeIndexes.removeAt(i);
break;
}
}
for (int i = 0; i < node.getChildCount(); i++) {
nodesToProcess.addLast(node.getChildAt(i));
}
}
// Remember which ids could not be resolved to not search for them again the next time
for (int i = 0; i < missingNodeIndexes.size(); i++) {
if (mViewNodeLookupTable == null) {
mViewNodeLookupTable = new ArrayMap<>(missingNodeIndexes.size());
}
mViewNodeLookupTable.put(ids[missingNodeIndexes.keyAt(i)], null);
}
return foundNodes;
}
private int getPoemImageId() {
final SparseIntArray imgList = poemTheme.getImageList();
// the line below seems weird, but relies on the fact that the index of SparseIntArray could be any integer
return imgList.keyAt(imgList.indexOfValue(imgList.get(poemImagePager.getCurrentItem() + 1)));
}
/**
* Handles restoring an individual tab.
*
* @param tabToRestore Meta data about the tab to be restored.
* @param tabState The previously serialized state of the tab to be restored.
* @param setAsActive Whether the tab should be set as the active tab as part of the
* restoration process.
*/
@VisibleForTesting
protected void restoreTab(
TabRestoreDetails tabToRestore, TabState tabState, boolean setAsActive) {
// If we don't have enough information about the Tab, bail out.
boolean isIncognito = isIncognitoTabBeingRestored(tabToRestore, tabState);
if (tabState == null) {
if (tabToRestore.isIncognito == null) {
Log.w(TAG, "Failed to restore tab: not enough info about its type was available.");
return;
} else if (isIncognito) {
Log.i(TAG, "Failed to restore Incognito tab: its TabState could not be restored.");
return;
}
}
TabModel model = mTabModelSelector.getModel(isIncognito);
SparseIntArray restoredTabs = isIncognito ? mIncognitoTabsRestored : mNormalTabsRestored;
int restoredIndex = 0;
if (tabToRestore.fromMerge) {
// Put any tabs being merged into this list at the end.
restoredIndex = mTabModelSelector.getModel(isIncognito).getCount();
} else if (restoredTabs.size() > 0
&& tabToRestore.originalIndex > restoredTabs.keyAt(restoredTabs.size() - 1)) {
// If the tab's index is too large, restore it at the end of the list.
restoredIndex = restoredTabs.size();
} else {
// Otherwise try to find the tab we should restore before, if any.
for (int i = 0; i < restoredTabs.size(); i++) {
if (restoredTabs.keyAt(i) > tabToRestore.originalIndex) {
Tab nextTabByIndex = TabModelUtils.getTabById(model, restoredTabs.valueAt(i));
restoredIndex = nextTabByIndex != null ? model.indexOf(nextTabByIndex) : -1;
break;
}
}
}
int tabId = tabToRestore.id;
if (tabState != null) {
mTabCreatorManager.getTabCreator(isIncognito).createFrozenTab(
tabState, tabToRestore.id, restoredIndex);
} else {
if (NewTabPage.isNTPUrl(tabToRestore.url) && !setAsActive && !tabToRestore.fromMerge) {
Log.i(TAG, "Skipping restore of non-selected NTP.");
return;
}
Log.w(TAG, "Failed to restore TabState; creating Tab with last known URL.");
Tab fallbackTab = mTabCreatorManager.getTabCreator(isIncognito).createNewTab(
new LoadUrlParams(tabToRestore.url), TabModel.TabLaunchType.FROM_RESTORE, null);
tabId = fallbackTab.getId();
model.moveTab(tabId, restoredIndex);
}
// If the tab is being restored from a merge and its index is 0, then the model being
// merged into doesn't contain any tabs. Select the first tab to avoid having no tab
// selected. TODO(twellington): The first tab will always be selected. Instead, the tab that
// was selected in the other model before the merge should be selected after the merge.
if (setAsActive || (tabToRestore.fromMerge && restoredIndex == 0)) {
boolean wasIncognitoTabModelSelected = mTabModelSelector.isIncognitoSelected();
int selectedModelTabCount = mTabModelSelector.getCurrentModel().getCount();
TabModelUtils.setIndex(model, TabModelUtils.getTabIndexById(model, tabId));
boolean isIncognitoTabModelSelected = mTabModelSelector.isIncognitoSelected();
// Setting the index will cause the tab's model to be selected. Set it back to the model
// that was selected before setting the index if the index is being set during a merge
// unless the previously selected model is empty (e.g. showing the empty background
// view on tablets).
if (tabToRestore.fromMerge
&& wasIncognitoTabModelSelected != isIncognitoTabModelSelected
&& selectedModelTabCount != 0) {
mTabModelSelector.selectModel(wasIncognitoTabModelSelected);
}
}
restoredTabs.put(tabToRestore.originalIndex, tabId);
}