Java Code Examples for android.util.ArrayMap#keyAt()

The following examples show how to use android.util.ArrayMap#keyAt() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: ContentService.java    From AndroidComponentPlugin with Apache License 2.0 6 votes vote down vote up
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();
    }
}
 
Example 2
Source File: ActivityTransitionCoordinator.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * 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;
    }
}
 
Example 3
Source File: Transition.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * Resumes 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 resume(View sceneRoot) {
    if (mPaused) {
        if (!mEnded) {
            ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
            int numOldAnims = runningAnimators.size();
            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.resume();
                }
            }
            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).onTransitionResume(this);
                }
            }
        }
        mPaused = false;
    }
}
 
Example 4
Source File: Transition.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * 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;
    }
}
 
Example 5
Source File: AccessibilityButtonController.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * 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));
    }
}
 
Example 6
Source File: AccessibilityButtonController.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * 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));
    }
}
 
Example 7
Source File: ArtManagerService.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * Dumps the profiles for the given package.
 */
public void dumpProfiles(PackageParser.Package pkg) {
    final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
    try {
        ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
        for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
            String codePath = packageProfileNames.keyAt(i);
            String profileName = packageProfileNames.valueAt(i);
            synchronized (mInstallLock) {
                mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
            }
        }
    } catch (InstallerException e) {
        Slog.w(TAG, "Failed to dump profiles", e);
    }
}
 
Example 8
Source File: ContentService.java    From AndroidComponentPlugin with Apache License 2.0 6 votes vote down vote up
@GuardedBy("mCache")
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();
    }
}
 
Example 9
Source File: FingerprintGestureController.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
/**
 * 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);
        }
    }
}
 
Example 10
Source File: KeySetManagerService.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/**
 * Inform the system that the given package defines the given KeySets.
 * Remove any KeySets the package no longer defines.
 */
void addDefinedKeySetsToPackageLPw(PackageSetting pkg,
        ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
    ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();

    /* add all of the newly defined KeySets */
    ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
    final int defMapSize = definedMapping.size();
    for (int i = 0; i < defMapSize; i++) {
        String alias = definedMapping.keyAt(i);
        ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
        if (alias != null && pubKeys != null && pubKeys.size() > 0) {
            KeySetHandle ks = addKeySetLPw(pubKeys);
            newKeySetAliases.put(alias, ks.getId());
        }
    }

    /* remove each of the old references */
    final int prevDefSize = prevDefinedKeySets.size();
    for (int i = 0; i < prevDefSize; i++) {
        decrementKeySetLPw(prevDefinedKeySets.valueAt(i));
    }
    pkg.keySetData.removeAllUpgradeKeySets();

    /* switch to the just-added */
    pkg.keySetData.setAliases(newKeySetAliases);
    return;
}
 
Example 11
Source File: ManagedServices.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
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);
    }
}
 
Example 12
Source File: ManagedServices.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
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);
}
 
Example 13
Source File: AccessibilityService.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/**
 * 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);
        }
    }
}
 
Example 14
Source File: AccessibilityService.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/**
 * Dispatches the soft keyboard show mode change to any registered listeners. This should
 * be called on the service's main thread.
 */
void dispatchSoftKeyboardShowModeChanged(final int showMode) {
    final ArrayMap<OnShowModeChangedListener, Handler> entries;
    synchronized (mLock) {
        if (mListeners == null || mListeners.isEmpty()) {
            Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback"
                    + " with no listeners registered!");
            setSoftKeyboardCallbackEnabled(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 OnShowModeChangedListener listener = entries.keyAt(i);
        final Handler handler = entries.valueAt(i);
        if (handler != null) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    listener.onShowModeChanged(SoftKeyboardController.this, showMode);
                }
            });
        } else {
            // We're already on the main thread, just run the listener.
            listener.onShowModeChanged(this, showMode);
        }
    }
}
 
Example 15
Source File: Transition.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/**
 * Match start/end values by View instance. Adds matched values to mStartValuesList
 * and mEndValuesList and removes them from unmatchedStart and unmatchedEnd.
 */
private void matchInstances(ArrayMap<View, TransitionValues> unmatchedStart,
        ArrayMap<View, TransitionValues> unmatchedEnd) {
    for (int i = unmatchedStart.size() - 1; i >= 0; i--) {
        View view = unmatchedStart.keyAt(i);
        if (view != null && isValidTarget(view)) {
            TransitionValues end = unmatchedEnd.remove(view);
            if (end != null && end.view != null && isValidTarget(end.view)) {
                TransitionValues start = unmatchedStart.removeAt(i);
                mStartValuesList.add(start);
                mEndValuesList.add(end);
            }
        }
    }
}
 
Example 16
Source File: FragmentTransition.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/**
 * Utility to find the String key in {@code map} that maps to {@code value}.
 */
private static String findKeyForValue(ArrayMap<String, String> map, String value) {
    final int numElements = map.size();
    for (int i = 0; i < numElements; i++) {
        if (value.equals(map.valueAt(i))) {
            return map.keyAt(i);
        }
    }
    return null;
}
 
Example 17
Source File: Transition.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/**
 * 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();
            }
        }
    }
}
 
Example 18
Source File: ManagedServices.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
public void dump(PrintWriter pw, DumpFilter filter) {
    pw.println("    Allowed " + getCaption() + "s:");
    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) {
                    pw.println("      " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
                            + " (user: " + userId + " isPrimary: " + isPrimary + ")");
                }
            }
        }
    }

    pw.println("    All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
            + ") enabled for current profiles:");
    for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
        if (filter != null && !filter.matches(cmpt)) continue;
        pw.println("      " + cmpt);
    }

    pw.println("    Live " + getCaption() + "s (" + mServices.size() + "):");
    for (ManagedServiceInfo info : mServices) {
        if (filter != null && !filter.matches(info.component)) continue;
        pw.println("      " + info.component
                + " (user " + info.userid + "): " + info.service
                + (info.isSystem?" SYSTEM":"")
                + (info.isGuest(this)?" GUEST":""));
    }

    pw.println("    Snoozed " + getCaption() + "s (" +
            mSnoozingForCurrentProfiles.size() + "):");
    for (ComponentName name : mSnoozingForCurrentProfiles) {
        pw.println("      " + name.flattenToShortString());
    }
}
 
Example 19
Source File: AutofillManager.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
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));
    }
}
 
Example 20
Source File: Transition.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
/**
 * Called by TransitionManager to play the transition. This calls
 * createAnimators() to set things up and create all of the animations and then
 * runAnimations() to actually start the animations.
 */
void playTransition(ViewGroup sceneRoot) {
    mStartValuesList = new ArrayList<TransitionValues>();
    mEndValuesList = new ArrayList<TransitionValues>();
    matchStartAndEnd(mStartValues, mEndValues);

    ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
    int numOldAnims = runningAnimators.size();
    WindowId windowId = sceneRoot.getWindowId();
    for (int i = numOldAnims - 1; i >= 0; i--) {
        Animator anim = runningAnimators.keyAt(i);
        if (anim != null) {
            AnimationInfo oldInfo = runningAnimators.get(anim);
            if (oldInfo != null && oldInfo.view != null && oldInfo.windowId == windowId) {
                TransitionValues oldValues = oldInfo.values;
                View oldView = oldInfo.view;
                TransitionValues startValues = getTransitionValues(oldView, true);
                TransitionValues endValues = getMatchedTransitionValues(oldView, true);
                if (startValues == null && endValues == null) {
                    endValues = mEndValues.viewValues.get(oldView);
                }
                boolean cancel = (startValues != null || endValues != null) &&
                        oldInfo.transition.isTransitionRequired(oldValues, endValues);
                if (cancel) {
                    if (anim.isRunning() || anim.isStarted()) {
                        if (DBG) {
                            Log.d(LOG_TAG, "Canceling anim " + anim);
                        }
                        anim.cancel();
                    } else {
                        if (DBG) {
                            Log.d(LOG_TAG, "removing anim from info list: " + anim);
                        }
                        runningAnimators.remove(anim);
                    }
                }
            }
        }
    }

    createAnimators(sceneRoot, mStartValues, mEndValues, mStartValuesList, mEndValuesList);
    runAnimators();
}