android.util.ArrayMap

Here are the examples of the java api android.util.ArrayMap taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

249 Examples 7

19 Source : RequestManager.java
with Apache License 2.0
from zhkrb

public clreplaced RequestManager implements IRequestManager<String> {

    private static RequestManager sInstance;

    private ArrayMap<String, Disposable> mMap;

    public static RequestManager getInstance() {
        if (sInstance == null) {
            synchronized (RequestManager.clreplaced) {
                if (sInstance == null) {
                    sInstance = new RequestManager();
                }
            }
        }
        return sInstance;
    }

    public RequestManager() {
        mMap = new ArrayMap<>(0);
    }

    @Override
    public synchronized void add(String tag, Disposable subscription) {
        mMap.put(tag, subscription);
    }

    @Override
    public void remove(String tag) {
        if (!mMap.isEmpty()) {
            mMap.remove(tag);
        }
    }

    public void removeAll() {
        if (!mMap.isEmpty()) {
            mMap.clear();
        }
    }

    @Override
    public synchronized void cancel(String tag) {
        if (mMap.isEmpty()) {
            return;
        }
        if (mMap.get(tag) != null) {
            if (!Objects.requireNonNull(mMap.get(tag)).isDisposed()) {
                Objects.requireNonNull(mMap.get(tag)).dispose();
                remove(tag);
            }
        }
    }

    @Override
    public void cancelAll() {
        if (mMap.isEmpty()) {
            return;
        }
        Set<String> keys = mMap.keySet();
        for (String apiKey : keys) {
            cancel(apiKey);
        }
    }
}

19 Source : ResHelpers.java
with GNU General Public License v3.0
from tianma8023

public clreplaced ResHelpers {

    private static ArrayMap<String, Integer> sNameIdMap;

    static {
        sNameIdMap = new ArrayMap<>();
    }

    public static Integer getId(Resources res, String name) {
        if (!sNameIdMap.containsKey(name)) {
            int id = res.getIdentifier(name, "id", SystemUIHook.PACKAGE_NAME);
            sNameIdMap.put(name, id);
        }
        return sNameIdMap.get(name);
    }
}

19 Source : ResHelper.java
with GNU General Public License v3.0
from tianma8023

public clreplaced ResHelper {

    private static ArrayMap<String, Integer> sNameIdMap;

    static {
        sNameIdMap = new ArrayMap<>();
    }

    public static Integer getId(Resources res, String name) {
        if (!sNameIdMap.containsKey(name)) {
            int id = res.getIdentifier(name, "id", SecurityCenterHook.PACKAGE_NAME);
            sNameIdMap.put(name, id);
        }
        return sNameIdMap.get(name);
    }
}

19 Source : GenericItemAnimator.java
with MIT License
from Simdea

/**
 * This clreplaced is meant to serve as a base {@link RecyclerView.ItemAnimator},
 * responsible for coordinating default animations performed by {@link RecyclerView}.
 *
 * Created by Paulo Ribeiro on 10/7/2017.
 * Simdea © All Rights Reserved.
 * [email protected]
 */
public abstract clreplaced GenericItemAnimator extends DefaulreplacedemAnimator implements IAnimationFinished {

    /* View Holder Animations Map */
    private final ArrayMap<RecyclerView.ViewHolder, AnimatorSet> mCustomAnimationsMap = new ArrayMap<>();

    /**
     * {@inheritDoc}
     *
     * When animating {@link RecyclerView} items, we can ask the {@link RecyclerView} to keep the previous
     * {@link RecyclerView.ViewHolder} of the item as-is and provide a new {@link RecyclerView.ViewHolder} which will
     * animate changes from the previous one (only the new {@link RecyclerView.ViewHolder} will be visible
     * on the {@link RecyclerView}).
     *
     * But when writing custom item animators the same {@link RecyclerView.ViewHolder} should be used and the
     * animations should be handled manually. For these cases this procedure returns true.
     *
     * @param holder the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     * @return boolean value indicating whether the {@link RecyclerView} should reuse
     *         the {@link RecyclerView.ViewHolder} or a new one.
     */
    @Override
    public boolean canReuseUpdatedViewHolder(@NonNull final RecyclerView.ViewHolder holder) {
        return true;
    }

    /**
     * {@inheritDoc}
     *
     * Item's whose {@link RecyclerView.ViewHolder}s implement the {@link IAnimatedViewHolder} interface will have
     * their {@link IAnimatedViewHolder#runAddAnimation(GenericItemAnimator)} procedure called.
     *
     * @param holder the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     * @return a boolean value indicating whether the {@link RecyclerView} should use an entry animation
     *         for the {@link RecyclerView.ViewHolder}.
     */
    @Override
    public boolean animateAdd(@NonNull final RecyclerView.ViewHolder holder) {
        if (holder instanceof IAnimatedViewHolder) {
            ((IAnimatedViewHolder) holder).runAddAnimation(this);
            return false;
        }
        dispatchAddFinished(holder);
        return false;
    }

    /**
     * {@inheritDoc}
     *
     * Item's whose {@link RecyclerView.ViewHolder}s implement the {@link IAnimatedViewHolder} interface will have
     * their {@link IAnimatedViewHolder#runRemoveAnimation(GenericItemAnimator)} procedure called.
     *
     * @param holder the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     * @return a boolean value indicating whether the {@link RecyclerView} should use an exit animation
     *         for the {@link RecyclerView.ViewHolder}.
     */
    @Override
    public boolean animateRemove(@NonNull final RecyclerView.ViewHolder holder) {
        if (holder instanceof IAnimatedViewHolder) {
            ((IAnimatedViewHolder) holder).runRemoveAnimation(this);
            return false;
        }
        dispatchRemoveFinished(holder);
        return false;
    }

    /**
     * {@inheritDoc}
     *
     * Custom animations should be triggered on the {@link IGenericRecyclerViewLayout} implementation.
     * Since changes are usually triggered by the {@link RecyclerView.Adapter#notifyItemChanged(int, Object)} procedure,
     * we can preplaced additional arguments to it which will help the {@link IGenericRecyclerViewLayout} decide what
     * animation should be performed.
     * This procedure is used to catch the data before changes occur. The {@link RecyclerView} then calls
     * {@link RecyclerView.Adapter#onBindViewHolder(RecyclerView.ViewHolder, int, List)} and finally,
     * {@link RecyclerView.ItemAnimator} will call {@link RecyclerView.ItemAnimator
     * #recordPostLayoutInformation(RecyclerView.State, RecyclerView.ViewHolder)}.
     *
     * @param state the current {@link RecyclerView.State}.
     * @param holder the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     * @param changeFlags additional information about what changes happened in the Adapter
     *                    about the Item represented by this ViewHolder. For instance, if
     *                    item is deleted from the adapter, {@link #FLAG_REMOVED} will be set.
     * @param payloads The payload list that was previously preplaceded to
     *                 {@link RecyclerView.Adapter#notifyItemChanged(int, Object)} or
     *                 {@link RecyclerView.Adapter#notifyItemRangeChanged(int, int, Object)}.
     * @return an ItemHolderInfo instance that preserves necessary information about the ViewHolder.
     */
    @NonNull
    @Override
    public ItemHolderInfo recordPreLayoutInformation(@NonNull final RecyclerView.State state, @NonNull final RecyclerView.ViewHolder holder, @IntRange(from = 0) final int changeFlags, @NonNull final List<Object> payloads) {
        if (changeFlags == FLAG_CHANGED) {
            for (final Object payload : payloads) {
                if (payload instanceof Integer) {
                    return new GenericAnimatedViewHolderInfo((Integer) payload);
                }
            }
        }
        return super.recordPreLayoutInformation(state, holder, changeFlags, payloads);
    }

    /**
     * {@inheritDoc}
     *
     * Item's whose {@link RecyclerView.ViewHolder}s implement the {@link IAnimatedViewHolder} interface will have
     * their {@link IAnimatedViewHolder#runChangeAnimation(GenericItemAnimator)} procedure called.
     *
     * @param oldHolder the old {@link RecyclerView} item's {@link RecyclerView.ViewHolder}. Might be the same
     *                  instance with newHolder.
     * @param newHolder the new {@link RecyclerView} item's {@link RecyclerView.ViewHolder}. Might be the same
     *                  instance with oldHolder.
     * @param preInfo The information that was returned from
     *                {@link #recordPreLayoutInformation(RecyclerView.State, RecyclerView.ViewHolder, int, List)}.
     * @param postInfo The information that was returned from {@link
     *                 #recordPreLayoutInformation(RecyclerView.State, RecyclerView.ViewHolder, int, List)}.
     * @return a boolean value indicating whether the {@link RecyclerView} should use a change animation
     *         for the {@link RecyclerView.ViewHolder}.
     */
    @Override
    public boolean animateChange(@NonNull final RecyclerView.ViewHolder oldHolder, @NonNull final RecyclerView.ViewHolder newHolder, @NonNull final ItemHolderInfo preInfo, @NonNull final ItemHolderInfo postInfo) {
        cancelCurrentAnimationIfExists(newHolder);
        if (preInfo instanceof GenericAnimatedViewHolderInfo && newHolder instanceof IAnimatedViewHolder) {
            final GenericAnimatedViewHolderInfo holderInfo = (GenericAnimatedViewHolderInfo) preInfo;
            final IAnimatedViewHolder holder = (IAnimatedViewHolder) newHolder;
            /* Call custom animation handlers */
            final AnimatorSet animatorSet = handleCustomAnimation(holderInfo, holder);
            if (animatorSet != null) {
                mCustomAnimationsMap.put(newHolder, animatorSet);
                animatorSet.start();
            }
        }
        return false;
    }

    /**
     * Procedure meant to handle the report when the animation for the {@link RecyclerView.ViewHolder} has finished.
     * @param holder the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     * @param animationFinishedOperation an Integer value representing the animation operation that has finished.
     *                                   See {@link GenericAnimationFinishedOperation} for more details.
     */
    @Override
    public void onAnimationFinished(@NonNull final RecyclerView.ViewHolder holder, @IntRange(from = 0) final int animationFinishedOperation) {
        switch(animationFinishedOperation) {
            case ADD_ANIMATION_FINISHED:
                dispatchAddFinished(holder);
                break;
            case REMOVE_ANIMATION_FINISHED:
                dispatchRemoveFinished(holder);
                break;
            case CHANGE_ANIMATION_FINISHED:
                dispatchChangeFinished(holder, false);
                if (mCustomAnimationsMap.containsKey(holder)) {
                    mCustomAnimationsMap.remove(holder);
                }
                break;
            default:
                throw new UnsupportedOperationException(GMLRVAConstants.UNSUPPORTED_ERROR);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void endAnimation(@NonNull final RecyclerView.ViewHolder item) {
        super.endAnimation(item);
        cancelCurrentAnimationIfExists(item);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void endAnimations() {
        super.endAnimations();
        for (final AnimatorSet animatorSet : mCustomAnimationsMap.values()) {
            animatorSet.cancel();
        }
    }

    /**
     * Abstract procedure meant to dispatch the intended animations whenever
     * {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, ItemHolderInfo, ItemHolderInfo)} is
     * called.
     * This procedure should be implement by clreplacedes extending this Item Animator base clreplaced.
     *
     * @param holderInfo The information that was returned from
     *                   {@link #recordPreLayoutInformation(RecyclerView.State, RecyclerView.ViewHolder, int, List)}.
     * @param holder the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     * @return the resulting {@link AnimatorSet} for the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     */
    @Nullable
    public abstract AnimatorSet handleCustomAnimation(@NonNull final GenericAnimatedViewHolderInfo holderInfo, @NonNull final IAnimatedViewHolder holder);

    /**
     * Auxiliary procedure meant to allow {@link RecyclerView} to stop animations on its items, when they
     * disappear from the device's screen, thus being ready to be recycled.
     * @param item the {@link RecyclerView} item's {@link RecyclerView.ViewHolder}.
     */
    private void cancelCurrentAnimationIfExists(@NonNull final RecyclerView.ViewHolder item) {
        if (mCustomAnimationsMap.containsKey(item)) {
            mCustomAnimationsMap.get(item).cancel();
        }
    }
}

19 Source : UserAgentOverride.java
with Mozilla Public License 2.0
from MozillaReality

public clreplaced UserAgentOverride {

    private final static String LOGTAG = SystemUtils.createLogtag(UserAgentOverride.clreplaced);

    private static final String NO_OVERRIDE_FOUND = "NO OVERRIDE USER AGENT FOUND";

    private ArrayMap<String, String> mOverrideMap;

    private ArrayMap<String, String> mOverrideCache;

    public UserAgentOverride() {
        mOverrideMap = new ArrayMap<>();
        mOverrideCache = new ArrayMap<>();
    }

    public void loadOverridesFromreplacedets(Activity aActivity, String aFileName) {
        String json = null;
        try (InputStream is = aActivity.getreplacedets().open(aFileName)) {
            int size = is.available();
            byte[] buffer = new byte[size];
            is.read(buffer);
            is.close();
            json = new String(buffer, "UTF-8");
            importJSONData(json);
        } catch (IOException e) {
            Log.e(LOGTAG, "Failed reading user agent override file: " + aFileName + " Error: " + e.getMessage());
        }
    }

    public String lookupOverride(final String aUri) {
        if (aUri == null) {
            return null;
        }
        Log.d(LOGTAG, "lookupOverride for: " + aUri);
        URI uri;
        try {
            uri = new URI(aUri);
        } catch (URISyntaxException e) {
            Log.d(LOGTAG, "Error parsing URL: " + aUri + " " + e.getMessage());
            return null;
        }
        String fullDomain = uri.getHost();
        if (fullDomain == null) {
            return null;
        }
        fullDomain = fullDomain.toLowerCase();
        String override = mOverrideCache.get(fullDomain);
        if (override != null) {
            Log.d(LOGTAG, "Found override: " + override);
            return override.equals(NO_OVERRIDE_FOUND) ? null : override;
        }
        List<String> domains = Arrays.asList(fullDomain.split("\\."));
        final int domainCount = domains.size();
        String[] checkedDomains = new String[domainCount];
        for (int ix = 0; ix < domainCount; ix++) {
            String domain = TextUtils.join(".", domains.subList(ix, domainCount));
            checkedDomains[ix] = domain;
            override = mOverrideCache.get(domain);
            if (override != null) {
                Log.d(LOGTAG, "found cached override: " + override);
                addToCache(checkedDomains, override);
                return override.equals(NO_OVERRIDE_FOUND) ? null : override;
            }
            String domainHash = hashDomain(domain);
            if (domainHash == null) {
                Log.d(LOGTAG, "Failed to hash domain: " + domain);
                return null;
            }
            Log.d(LOGTAG, "hash: " + domainHash);
            override = mOverrideMap.get(domainHash);
            if (override != null) {
                Log.d(LOGTAG, "found override from hash: " + override);
                addToCache(checkedDomains, override);
                return override;
            }
        }
        addToCache(checkedDomains, NO_OVERRIDE_FOUND);
        return null;
    }

    private void addToCache(String[] aDomains, String aOverride) {
        for (String domain : aDomains) {
            if (domain == null) {
                Log.d(LOGTAG, "Found null domain in checked list");
                continue;
            } else {
                Log.d(LOGTAG, domain + " override: " + aOverride);
            }
            mOverrideCache.put(domain, aOverride);
        }
    }

    private String hashDomain(String aDomain) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] digest = md.digest(aDomain.getBytes());
            StringBuilder sb = new StringBuilder();
            for (int value : digest) {
                sb.append(Integer.toString((value & 0xff) + 0x100, 16).substring(1));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            Log.e(LOGTAG, "Error while trying to hash domain: " + e.getMessage());
        }
        return null;
    }

    private void importJSONData(final String aData) {
        try {
            JSONObject json = new JSONObject(aData);
            Iterator<String> iter = json.keys();
            while (iter.hasNext()) {
                String key = iter.next();
                try {
                    String value = json.getString(key);
                    Log.d(LOGTAG, "User agent override: " + key + " -> " + value);
                    mOverrideMap.put(key, value);
                } catch (JSONException e) {
                    Log.e(LOGTAG, "Failed to find UA Override while parsing file for key: " + key);
                }
            }
        } catch (JSONException e) {
            Log.e(LOGTAG, "Failed to import user agent override JSON data: " + e.getMessage());
        }
    }
}

19 Source : UnknownAppVisibilityController.java
with Apache License 2.0
from lulululbj

/**
 * Manages the set of {@link AppWindowToken}s for which we don't know yet whether it's visible or
 * not. This happens when starting an activity while the lockscreen is showing. In that case, the
 * keyguard flags an app might set influence it's visibility, so we wait until this is resolved to
 * start the transition to avoid flickers.
 */
clreplaced UnknownAppVisibilityController {

    private static final String TAG = TAG_WITH_CLreplaced_NAME ? "UnknownAppVisibility" : TAG_WM;

    /**
     * We are currently waiting until the app is done resuming.
     */
    private static final int UNKNOWN_STATE_WAITING_RESUME = 1;

    /**
     * The activity has finished resuming, and we are waiting on the next relayout.
     */
    private static final int UNKNOWN_STATE_WAITING_RELAYOUT = 2;

    /**
     * The client called {@link Session#relayout} with the appropriate Keyguard flags and we are
     * waiting until activity manager has updated the visibilities of all the apps.
     */
    private static final int UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE = 3;

    // Set of apps for which we don't know yet whether it's visible or not, depending on what kind
    // of lockscreen flags the app might set during its first relayout.
    private final ArrayMap<AppWindowToken, Integer> mUnknownApps = new ArrayMap<>();

    private final WindowManagerService mService;

    UnknownAppVisibilityController(WindowManagerService service) {
        mService = service;
    }

    boolean allResolved() {
        return mUnknownApps.isEmpty();
    }

    void clear() {
        mUnknownApps.clear();
    }

    String getDebugMessage() {
        final StringBuilder builder = new StringBuilder();
        for (int i = mUnknownApps.size() - 1; i >= 0; i--) {
            builder.append("app=").append(mUnknownApps.keyAt(i)).append(" state=").append(mUnknownApps.valueAt(i));
            if (i != 0) {
                builder.append(' ');
            }
        }
        return builder.toString();
    }

    void appRemovedOrHidden(@NonNull AppWindowToken appWindow) {
        if (DEBUG_UNKNOWN_APP_VISIBILITY) {
            Slog.d(TAG, "App removed or hidden appWindow=" + appWindow);
        }
        mUnknownApps.remove(appWindow);
    }

    /**
     * Notifies that {@param appWindow} has been launched behind Keyguard, and we need to wait until
     * it is resumed and relaid out to resolve the visibility.
     */
    void notifyLaunched(@NonNull AppWindowToken appWindow) {
        if (DEBUG_UNKNOWN_APP_VISIBILITY) {
            Slog.d(TAG, "App launched appWindow=" + appWindow);
        }
        mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RESUME);
    }

    /**
     * Notifies that {@param appWindow} has finished resuming.
     */
    void notifyAppResumedFinished(@NonNull AppWindowToken appWindow) {
        if (mUnknownApps.containsKey(appWindow) && mUnknownApps.get(appWindow) == UNKNOWN_STATE_WAITING_RESUME) {
            if (DEBUG_UNKNOWN_APP_VISIBILITY) {
                Slog.d(TAG, "App resume finished appWindow=" + appWindow);
            }
            mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_RELAYOUT);
        }
    }

    /**
     * Notifies that {@param appWindow} has relaid out.
     */
    void notifyRelayouted(@NonNull AppWindowToken appWindow) {
        if (!mUnknownApps.containsKey(appWindow)) {
            return;
        }
        if (DEBUG_UNKNOWN_APP_VISIBILITY) {
            Slog.d(TAG, "App relayouted appWindow=" + appWindow);
        }
        int state = mUnknownApps.get(appWindow);
        if (state == UNKNOWN_STATE_WAITING_RELAYOUT) {
            mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE);
            mService.notifyKeyguardFlagsChanged(this::notifyVisibilitiesUpdated);
        }
    }

    private void notifyVisibilitiesUpdated() {
        if (DEBUG_UNKNOWN_APP_VISIBILITY) {
            Slog.d(TAG, "Visibility updated DONE");
        }
        boolean changed = false;
        for (int i = mUnknownApps.size() - 1; i >= 0; i--) {
            if (mUnknownApps.valueAt(i) == UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE) {
                mUnknownApps.removeAt(i);
                changed = true;
            }
        }
        if (changed) {
            mService.mWindowPlacerLocked.performSurfacePlacement();
        }
    }

    void dump(PrintWriter pw, String prefix) {
        if (mUnknownApps.isEmpty()) {
            return;
        }
        pw.println(prefix + "Unknown visibilities:");
        for (int i = mUnknownApps.size() - 1; i >= 0; i--) {
            pw.println(prefix + "  app=" + mUnknownApps.keyAt(i) + " state=" + mUnknownApps.valueAt(i));
        }
    }
}

19 Source : TaskSnapshotCache.java
with Apache License 2.0
from lulululbj

/**
 * Caches snapshots. See {@link TaskSnapshotController}.
 * <p>
 * Access to this clreplaced should be guarded by the global window manager lock.
 */
clreplaced TaskSnapshotCache {

    private final WindowManagerService mService;

    private final TaskSnapshotLoader mLoader;

    private final ArrayMap<AppWindowToken, Integer> mAppTaskMap = new ArrayMap<>();

    private final ArrayMap<Integer, CacheEntry> mRunningCache = new ArrayMap<>();

    TaskSnapshotCache(WindowManagerService service, TaskSnapshotLoader loader) {
        mService = service;
        mLoader = loader;
    }

    void putSnapshot(Task task, TaskSnapshot snapshot) {
        final CacheEntry entry = mRunningCache.get(task.mTaskId);
        if (entry != null) {
            mAppTaskMap.remove(entry.topApp);
        }
        final AppWindowToken top = task.getTopChild();
        mAppTaskMap.put(top, task.mTaskId);
        mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, task.getTopChild()));
    }

    /**
     * If {@param restoreFromDisk} equals {@code true}, DO NOT HOLD THE WINDOW MANAGER LOCK!
     */
    @Nullable
    TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk, boolean reducedResolution) {
        synchronized (mService.mWindowMap) {
            // Try the running cache.
            final CacheEntry entry = mRunningCache.get(taskId);
            if (entry != null) {
                return entry.snapshot;
            }
        }
        // Try to restore from disk if asked.
        if (!restoreFromDisk) {
            return null;
        }
        return tryRestoreFromDisk(taskId, userId, reducedResolution);
    }

    /**
     * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD!
     */
    private TaskSnapshot tryRestoreFromDisk(int taskId, int userId, boolean reducedResolution) {
        final TaskSnapshot snapshot = mLoader.loadTask(taskId, userId, reducedResolution);
        if (snapshot == null) {
            return null;
        }
        return snapshot;
    }

    /**
     * Called when an app token has been removed
     */
    void onAppRemoved(AppWindowToken wtoken) {
        final Integer taskId = mAppTaskMap.get(wtoken);
        if (taskId != null) {
            removeRunningEntry(taskId);
        }
    }

    /**
     * Callend when an app window token's process died.
     */
    void onAppDied(AppWindowToken wtoken) {
        final Integer taskId = mAppTaskMap.get(wtoken);
        if (taskId != null) {
            removeRunningEntry(taskId);
        }
    }

    void onTaskRemoved(int taskId) {
        removeRunningEntry(taskId);
    }

    private void removeRunningEntry(int taskId) {
        final CacheEntry entry = mRunningCache.get(taskId);
        if (entry != null) {
            mAppTaskMap.remove(entry.topApp);
            mRunningCache.remove(taskId);
        }
    }

    void dump(PrintWriter pw, String prefix) {
        final String doublePrefix = prefix + "  ";
        final String triplePrefix = doublePrefix + "  ";
        pw.println(prefix + "SnapshotCache");
        for (int i = mRunningCache.size() - 1; i >= 0; i--) {
            final CacheEntry entry = mRunningCache.valueAt(i);
            pw.println(doublePrefix + "Entry taskId=" + mRunningCache.keyAt(i));
            pw.println(triplePrefix + "topApp=" + entry.topApp);
            pw.println(triplePrefix + "snapshot=" + entry.snapshot);
        }
    }

    private static final clreplaced CacheEntry {

        /**
         * The snapshot.
         */
        final TaskSnapshot snapshot;

        /**
         * The app token that was on top of the task when the snapshot was taken
         */
        final AppWindowToken topApp;

        CacheEntry(TaskSnapshot snapshot, AppWindowToken topApp) {
            this.snapshot = snapshot;
            this.topApp = topApp;
        }
    }
}

19 Source : CpuFrequencies.java
with Apache License 2.0
from lulululbj

/**
 * Return a new map containing the filename-value pairs.
 */
public ArrayMap<String, String> toSysFileMap() {
    final ArrayMap<String, String> map = new ArrayMap<>();
    addToSysFileMap(map);
    return map;
}

19 Source : ShortcutLauncher.java
with Apache License 2.0
from lulululbj

/**
 * Launcher information used by {@link ShortcutService}.
 *
 * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
 */
clreplaced ShortcutLauncher extends ShortcutPackageItem {

    private static final String TAG = ShortcutService.TAG;

    static final String TAG_ROOT = "launcher-pins";

    private static final String TAG_PACKAGE = "package";

    private static final String TAG_PIN = "pin";

    private static final String ATTR_LAUNCHER_USER_ID = "launcher-user";

    private static final String ATTR_VALUE = "value";

    private static final String ATTR_PACKAGE_NAME = "package-name";

    private static final String ATTR_PACKAGE_USER_ID = "package-user";

    private final int mOwnerUserId;

    /**
     * Package name -> IDs.
     */
    final private ArrayMap<PackageWithUser, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();

    private ShortcutLauncher(@NonNull ShortcutUser shortcutUser, @UserIdInt int ownerUserId, @NonNull String packageName, @UserIdInt int launcherUserId, ShortcutPackageInfo spi) {
        super(shortcutUser, launcherUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty());
        mOwnerUserId = ownerUserId;
    }

    public ShortcutLauncher(@NonNull ShortcutUser shortcutUser, @UserIdInt int ownerUserId, @NonNull String packageName, @UserIdInt int launcherUserId) {
        this(shortcutUser, ownerUserId, packageName, launcherUserId, null);
    }

    @Override
    public int getOwnerUserId() {
        return mOwnerUserId;
    }

    @Override
    protected boolean canRestoreAnyVersion() {
        // Launcher's pinned shortcuts can be restored to an older version.
        return true;
    }

    /**
     * Called when the new package can't receive the backup, due to signature or version mismatch.
     */
    private void onRestoreBlocked() {
        final ArrayList<PackageWithUser> pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet());
        mPinnedShortcuts.clear();
        for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
            final PackageWithUser pu = pinnedPackages.get(i);
            final ShortcutPackage p = mShortcutUser.getPackageShortcutsIfExists(pu.packageName);
            if (p != null) {
                p.refreshPinnedFlags();
            }
        }
    }

    @Override
    protected void onRestored(int restoreBlockReason) {
        // For launcher, possible reasons here are DISABLED_REASON_SIGNATURE_MISMATCH or
        // DISABLED_REASON_BACKUP_NOT_SUPPORTED.
        // DISABLED_REASON_VERSION_LOWER will NOT happen because we don't check version
        // code for launchers.
        if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
            onRestoreBlocked();
        }
    }

    /**
     * Pin the given shortcuts, replacing the current pinned ones.
     */
    public void pinShortcuts(@UserIdInt int packageUserId, @NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) {
        final ShortcutPackage packageShortcuts = mShortcutUser.getPackageShortcutsIfExists(packageName);
        if (packageShortcuts == null) {
            // No need to instantiate.
            return;
        }
        final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
        final int idSize = ids.size();
        if (idSize == 0) {
            mPinnedShortcuts.remove(pu);
        } else {
            final ArraySet<String> prevSet = mPinnedShortcuts.get(pu);
            // Actually pin shortcuts.
            // This logic here is to make sure a launcher cannot pin a shortcut that is floating
            // (i.e. not dynamic nor manifest but is pinned) and pinned by another launcher.
            // In this case, technically the shortcut doesn't exist to this launcher, so it can't
            // pin it.
            // (Maybe unnecessarily strict...)
            final ArraySet<String> newSet = new ArraySet<>();
            for (int i = 0; i < idSize; i++) {
                final String id = ids.get(i);
                final ShortcutInfo si = packageShortcuts.findShortcutById(id);
                if (si == null) {
                    continue;
                }
                if (si.isDynamic() || si.isManifestShortcut() || (prevSet != null && prevSet.contains(id)) || forPinRequest) {
                    newSet.add(id);
                }
            }
            mPinnedShortcuts.put(pu, newSet);
        }
        packageShortcuts.refreshPinnedFlags();
    }

    /**
     * Return the pinned shortcut IDs for the publisher package.
     */
    @Nullable
    public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName, @UserIdInt int packageUserId) {
        return mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName));
    }

    /**
     * Return true if the given shortcut is pinned by this launcher.<code></code>
     */
    public boolean hasPinned(ShortcutInfo shortcut) {
        final ArraySet<String> pinned = getPinnedShortcutIds(shortcut.getPackage(), shortcut.getUserId());
        return (pinned != null) && pinned.contains(shortcut.getId());
    }

    /**
     * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List, boolean)}
     */
    public void addPinnedShortcut(@NonNull String packageName, @UserIdInt int packageUserId, String id, boolean forPinRequest) {
        final ArraySet<String> pinnedSet = getPinnedShortcutIds(packageName, packageUserId);
        final ArrayList<String> pinnedList;
        if (pinnedSet != null) {
            pinnedList = new ArrayList<>(pinnedSet.size() + 1);
            pinnedList.addAll(pinnedSet);
        } else {
            pinnedList = new ArrayList<>(1);
        }
        pinnedList.add(id);
        pinShortcuts(packageUserId, packageName, pinnedList, forPinRequest);
    }

    boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) {
        return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null;
    }

    public void ensurePackageInfo() {
        final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures(getPackageName(), getPackageUserId());
        if (pi == null) {
            Slog.w(TAG, "Package not found: " + getPackageName());
            return;
        }
        getPackageInfo().updateFromPackageInfo(pi);
    }

    /**
     * Persist.
     */
    @Override
    public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException {
        if (forBackup && !getPackageInfo().isBackupAllowed()) {
            // If an launcher app doesn't support backup&restore, then nothing to do.
            return;
        }
        final int size = mPinnedShortcuts.size();
        if (size == 0) {
            // Nothing to write.
            return;
        }
        out.startTag(null, TAG_ROOT);
        ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName());
        ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId());
        getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);
        for (int i = 0; i < size; i++) {
            final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
            if (forBackup && (pu.userId != getOwnerUserId())) {
                // Target package on a different user, skip. (i.e. work profile)
                continue;
            }
            out.startTag(null, TAG_PACKAGE);
            ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, pu.packageName);
            ShortcutService.writeAttr(out, ATTR_PACKAGE_USER_ID, pu.userId);
            final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
            final int idSize = ids.size();
            for (int j = 0; j < idSize; j++) {
                ShortcutService.writeTagValue(out, TAG_PIN, ids.valueAt(j));
            }
            out.endTag(null, TAG_PACKAGE);
        }
        out.endTag(null, TAG_ROOT);
    }

    /**
     * Load.
     */
    public static ShortcutLauncher loadFromXml(XmlPullParser parser, ShortcutUser shortcutUser, int ownerUserId, boolean fromBackup) throws IOException, XmlPullParserException {
        final String launcherPackageName = ShortcutService.parseStringAttribute(parser, ATTR_PACKAGE_NAME);
        // If restoring, just use the real user ID.
        final int launcherUserId = fromBackup ? ownerUserId : ShortcutService.parseIntAttribute(parser, ATTR_LAUNCHER_USER_ID, ownerUserId);
        final ShortcutLauncher ret = new ShortcutLauncher(shortcutUser, ownerUserId, launcherPackageName, launcherUserId);
        ArraySet<String> ids = null;
        final int outerDepth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOreplacedENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }
            final int depth = parser.getDepth();
            final String tag = parser.getName();
            if (depth == outerDepth + 1) {
                switch(tag) {
                    case ShortcutPackageInfo.TAG_ROOT:
                        ret.getPackageInfo().loadFromXml(parser, fromBackup);
                        continue;
                    case TAG_PACKAGE:
                        {
                            final String packageName = ShortcutService.parseStringAttribute(parser, ATTR_PACKAGE_NAME);
                            final int packageUserId = fromBackup ? ownerUserId : ShortcutService.parseIntAttribute(parser, ATTR_PACKAGE_USER_ID, ownerUserId);
                            ids = new ArraySet<>();
                            ret.mPinnedShortcuts.put(PackageWithUser.of(packageUserId, packageName), ids);
                            continue;
                        }
                }
            }
            if (depth == outerDepth + 2) {
                switch(tag) {
                    case TAG_PIN:
                        {
                            if (ids == null) {
                                Slog.w(TAG, TAG_PIN + " in invalid place");
                            } else {
                                ids.add(ShortcutService.parseStringAttribute(parser, ATTR_VALUE));
                            }
                            continue;
                        }
                }
            }
            ShortcutService.warnForInvalidTag(depth, tag);
        }
        return ret;
    }

    public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
        pw.println();
        pw.print(prefix);
        pw.print("Launcher: ");
        pw.print(getPackageName());
        pw.print("  Package user: ");
        pw.print(getPackageUserId());
        pw.print("  Owner user: ");
        pw.print(getOwnerUserId());
        pw.println();
        getPackageInfo().dump(pw, prefix + "  ");
        pw.println();
        final int size = mPinnedShortcuts.size();
        for (int i = 0; i < size; i++) {
            pw.println();
            final PackageWithUser pu = mPinnedShortcuts.keyAt(i);
            pw.print(prefix);
            pw.print("  ");
            pw.print("Package: ");
            pw.print(pu.packageName);
            pw.print("  User: ");
            pw.println(pu.userId);
            final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
            final int idSize = ids.size();
            for (int j = 0; j < idSize; j++) {
                pw.print(prefix);
                pw.print("    Pinned: ");
                pw.print(ids.valueAt(j));
                pw.println();
            }
        }
    }

    @Override
    public JSONObject dumpCheckin(boolean clear) throws JSONException {
        final JSONObject result = super.dumpCheckin(clear);
        // Nothing really interesting to dump.
        return result;
    }

    @VisibleForTesting
    ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
        return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
    }
}

19 Source : PackageKeySetData.java
with Apache License 2.0
from lulululbj

public clreplaced PackageKeySetData {

    static final long KEYSET_UNreplacedIGNED = -1;

    /* KeySet containing all signing keys - superset of the others */
    private long mProperSigningKeySet;

    private long[] mUpgradeKeySets;

    private final ArrayMap<String, Long> mKeySetAliases = new ArrayMap<String, Long>();

    PackageKeySetData() {
        mProperSigningKeySet = KEYSET_UNreplacedIGNED;
    }

    PackageKeySetData(PackageKeySetData original) {
        mProperSigningKeySet = original.mProperSigningKeySet;
        mUpgradeKeySets = ArrayUtils.cloneOrNull(original.mUpgradeKeySets);
        mKeySetAliases.putAll(original.mKeySetAliases);
    }

    protected void setProperSigningKeySet(long ks) {
        mProperSigningKeySet = ks;
        return;
    }

    protected long getProperSigningKeySet() {
        return mProperSigningKeySet;
    }

    protected void addUpgradeKeySet(String alias) {
        if (alias == null) {
            return;
        }
        /* must have previously been defined */
        Long ks = mKeySetAliases.get(alias);
        if (ks != null) {
            mUpgradeKeySets = ArrayUtils.appendLong(mUpgradeKeySets, ks);
        } else {
            throw new IllegalArgumentException("Upgrade keyset alias " + alias + "does not refer to a defined keyset alias!");
        }
    }

    /*
     * Used only when restoring keyset data from persistent storage.  Must
     * correspond to a defined-keyset.
     */
    protected void addUpgradeKeySetById(long ks) {
        mUpgradeKeySets = ArrayUtils.appendLong(mUpgradeKeySets, ks);
    }

    protected void removeAllUpgradeKeySets() {
        mUpgradeKeySets = null;
        return;
    }

    protected long[] getUpgradeKeySets() {
        return mUpgradeKeySets;
    }

    protected ArrayMap<String, Long> getAliases() {
        return mKeySetAliases;
    }

    /*
     * Replace defined keysets with new ones.
     */
    protected void setAliases(ArrayMap<String, Long> newAliases) {
        /* remove old aliases */
        removeAllDefinedKeySets();
        /* add new ones */
        final int newAlireplacedize = newAliases.size();
        for (int i = 0; i < newAlireplacedize; i++) {
            mKeySetAliases.put(newAliases.keyAt(i), newAliases.valueAt(i));
            ;
        }
    }

    protected void addDefinedKeySet(long ks, String alias) {
        mKeySetAliases.put(alias, ks);
    }

    protected void removeAllDefinedKeySets() {
        final int alireplacedize = mKeySetAliases.size();
        for (int i = 0; i < alireplacedize; i++) {
            mKeySetAliases.removeAt(i);
        }
    }

    protected boolean isUsingDefinedKeySets() {
        /* should never be the case that mUpgradeKeySets.length == 0 */
        return (mKeySetAliases.size() > 0);
    }

    protected boolean isUsingUpgradeKeySets() {
        /* should never be the case that mUpgradeKeySets.length == 0 */
        return (mUpgradeKeySets != null && mUpgradeKeySets.length > 0);
    }
}

19 Source : SnoozeHelper.java
with Apache License 2.0
from lulululbj

protected boolean cancel(int userId, String pkg, String tag, int id) {
    if (mSnoozedNotifications.containsKey(userId)) {
        ArrayMap<String, NotificationRecord> recordsForPkg = mSnoozedNotifications.get(userId).get(pkg);
        if (recordsForPkg != null) {
            final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet();
            String key = null;
            for (Map.Entry<String, NotificationRecord> record : records) {
                final StatusBarNotification sbn = record.getValue().sbn;
                if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
                    record.getValue().isCanceled = true;
                    return true;
                }
            }
        }
    }
    return false;
}

19 Source : SnoozeHelper.java
with Apache License 2.0
from lulululbj

/**
 * Updates the notification record so the most up to date information is shown on re-post.
 */
protected void update(int userId, NotificationRecord record) {
    ArrayMap<String, ArrayMap<String, NotificationRecord>> records = mSnoozedNotifications.get(userId);
    if (records == null) {
        return;
    }
    ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName());
    if (pkgRecords == null) {
        return;
    }
    NotificationRecord existing = pkgRecords.get(record.getKey());
    if (existing != null && existing.isCanceled) {
        return;
    }
    pkgRecords.put(record.getKey(), record);
}

19 Source : SnoozeHelper.java
with Apache License 2.0
from lulululbj

protected boolean cancel(int userId, String pkg) {
    if (mSnoozedNotifications.containsKey(userId)) {
        if (mSnoozedNotifications.get(userId).containsKey(pkg)) {
            ArrayMap<String, NotificationRecord> records = mSnoozedNotifications.get(userId).get(pkg);
            int N = records.size();
            for (int i = 0; i < N; i++) {
                records.valueAt(i).isCanceled = true;
            }
            return true;
        }
    }
    return false;
}

19 Source : SnoozeHelper.java
with Apache License 2.0
from lulululbj

/**
 * Records a snoozed notification.
 */
protected void snooze(NotificationRecord record) {
    int userId = record.getUser().getIdentifier();
    if (DEBUG) {
        Slog.d(TAG, "Snoozing " + record.getKey());
    }
    ArrayMap<String, ArrayMap<String, NotificationRecord>> records = mSnoozedNotifications.get(userId);
    if (records == null) {
        records = new ArrayMap<>();
    }
    ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName());
    if (pkgRecords == null) {
        pkgRecords = new ArrayMap<>();
    }
    pkgRecords.put(record.getKey(), record);
    records.put(record.sbn.getPackageName(), pkgRecords);
    mSnoozedNotifications.put(userId, records);
    mPackages.put(record.getKey(), record.sbn.getPackageName());
    mUsers.put(record.getKey(), userId);
}

19 Source : NetworkStatsCollection.java
with Apache License 2.0
from lulululbj

/**
 * Collection of {@link NetworkStatsHistory}, stored based on combined key of
 * {@link NetworkIdenreplacedySet}, UID, set, and tag. Knows how to persist itself.
 */
public clreplaced NetworkStatsCollection implements FileRotator.Reader {

    /**
     * File header magic number: "ANET"
     */
    private static final int FILE_MAGIC = 0x414E4554;

    private static final int VERSION_NETWORK_INIT = 1;

    private static final int VERSION_UID_INIT = 1;

    private static final int VERSION_UID_WITH_IDENT = 2;

    private static final int VERSION_UID_WITH_TAG = 3;

    private static final int VERSION_UID_WITH_SET = 4;

    private static final int VERSION_UNIFIED_INIT = 16;

    private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>();

    private final long mBucketDuration;

    private long mStartMillis;

    private long mEndMillis;

    private long mTotalBytes;

    private boolean mDirty;

    public NetworkStatsCollection(long bucketDuration) {
        mBucketDuration = bucketDuration;
        reset();
    }

    public void clear() {
        reset();
    }

    public void reset() {
        mStats.clear();
        mStartMillis = Long.MAX_VALUE;
        mEndMillis = Long.MIN_VALUE;
        mTotalBytes = 0;
        mDirty = false;
    }

    public long getStartMillis() {
        return mStartMillis;
    }

    /**
     * Return first atomic bucket in this collection, which is more conservative
     * than {@link #mStartMillis}.
     */
    public long getFirstAtomicBucketMillis() {
        if (mStartMillis == Long.MAX_VALUE) {
            return Long.MAX_VALUE;
        } else {
            return mStartMillis + mBucketDuration;
        }
    }

    public long getEndMillis() {
        return mEndMillis;
    }

    public long getTotalBytes() {
        return mTotalBytes;
    }

    public boolean isDirty() {
        return mDirty;
    }

    public void clearDirty() {
        mDirty = false;
    }

    public boolean isEmpty() {
        return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
    }

    @VisibleForTesting
    public long roundUp(long time) {
        if (time == Long.MIN_VALUE || time == Long.MAX_VALUE || time == SubscriptionPlan.TIME_UNKNOWN) {
            return time;
        } else {
            final long mod = time % mBucketDuration;
            if (mod > 0) {
                time -= mod;
                time += mBucketDuration;
            }
            return time;
        }
    }

    @VisibleForTesting
    public long roundDown(long time) {
        if (time == Long.MIN_VALUE || time == Long.MAX_VALUE || time == SubscriptionPlan.TIME_UNKNOWN) {
            return time;
        } else {
            final long mod = time % mBucketDuration;
            if (mod > 0) {
                time -= mod;
            }
            return time;
        }
    }

    /**
     * Safely multiple a value by a rational.
     * <p>
     * Internally it uses integer-based math whenever possible, but switches
     * over to double-based math if values would overflow.
     */
    @VisibleForTesting
    public static long multiplySafe(long value, long num, long den) {
        if (den == 0)
            den = 1;
        long x = value;
        long y = num;
        // Logic shamelessly borrowed from Math.multiplyExact()
        long r = x * y;
        long ax = Math.abs(x);
        long ay = Math.abs(y);
        if (((ax | ay) >>> 31 != 0)) {
            // Some bits greater than 2^31 that might cause overflow
            // Check the result using the divide operator
            // and check for the special case of Long.MIN_VALUE * -1
            if (((y != 0) && (r / y != x)) || (x == Long.MIN_VALUE && y == -1)) {
                // Use double math to avoid overflowing
                return (long) (((double) num / den) * value);
            }
        }
        return r / den;
    }

    public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
        return getRelevantUids(accessLevel, Binder.getCallingUid());
    }

    public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, final int callerUid) {
        IntArray uids = new IntArray();
        for (int i = 0; i < mStats.size(); i++) {
            final Key key = mStats.keyAt(i);
            if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) {
                int j = uids.binarySearch(key.uid);
                if (j < 0) {
                    j = ~j;
                    uids.add(j, key.uid);
                }
            }
        }
        return uids.toArray();
    }

    /**
     * Combine all {@link NetworkStatsHistory} in this collection which match
     * the requested parameters.
     */
    public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) {
        if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) {
            throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid);
        }
        // 180 days of history should be enough for anyone; if we end up needing
        // more, we'll dynamically grow the history object.
        final int bucketEstimate = (int) MathUtils.constrain(((end - start) / mBucketDuration), 0, (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration);
        final NetworkStatsHistory combined = new NetworkStatsHistory(mBucketDuration, bucketEstimate, fields);
        // shortcut when we know stats will be empty
        if (start == end)
            return combined;
        // Figure out the window of time that we should be augmenting (if any)
        long augmentStart = SubscriptionPlan.TIME_UNKNOWN;
        long augmentEnd = (augmentPlan != null) ? augmentPlan.getDataUsageTime() : SubscriptionPlan.TIME_UNKNOWN;
        // And if augmenting, we might need to collect more data to adjust with
        long collectStart = start;
        long collectEnd = end;
        if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) {
            final Iterator<Range<ZonedDateTime>> it = augmentPlan.cycleIterator();
            while (it.hasNext()) {
                final Range<ZonedDateTime> cycle = it.next();
                final long cycleStart = cycle.getLower().toInstant().toEpochMilli();
                final long cycleEnd = cycle.getUpper().toInstant().toEpochMilli();
                if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) {
                    augmentStart = cycleStart;
                    collectStart = Long.min(collectStart, augmentStart);
                    collectEnd = Long.max(collectEnd, augmentEnd);
                    break;
                }
            }
        }
        if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) {
            // Shrink augmentation window so we don't risk undercounting.
            augmentStart = roundUp(augmentStart);
            augmentEnd = roundDown(augmentEnd);
            // Grow collection window so we get all the stats needed.
            collectStart = roundDown(collectStart);
            collectEnd = roundUp(collectEnd);
        }
        for (int i = 0; i < mStats.size(); i++) {
            final Key key = mStats.keyAt(i);
            if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag && templateMatches(template, key.ident)) {
                final NetworkStatsHistory value = mStats.valueAt(i);
                combined.recordHistory(value, collectStart, collectEnd);
            }
        }
        if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) {
            final NetworkStatsHistory.Entry entry = combined.getValues(augmentStart, augmentEnd, null);
            // If we don't have any recorded data for this time period, give
            // ourselves something to scale with.
            if (entry.rxBytes == 0 || entry.txBytes == 0) {
                combined.recordData(augmentStart, augmentEnd, new NetworkStats.Entry(1, 0, 1, 0, 0));
                combined.getValues(augmentStart, augmentEnd, entry);
            }
            final long rawBytes = entry.rxBytes + entry.txBytes;
            final long rawRxBytes = entry.rxBytes;
            final long rawTxBytes = entry.txBytes;
            final long targetBytes = augmentPlan.getDataUsageBytes();
            final long targetRxBytes = multiplySafe(targetBytes, rawRxBytes, rawBytes);
            final long targetTxBytes = multiplySafe(targetBytes, rawTxBytes, rawBytes);
            // Scale all matching buckets to reach anchor target
            final long beforeTotal = combined.getTotalBytes();
            for (int i = 0; i < combined.size(); i++) {
                combined.getValues(i, entry);
                if (entry.bucketStart >= augmentStart && entry.bucketStart + entry.bucketDuration <= augmentEnd) {
                    entry.rxBytes = multiplySafe(targetRxBytes, entry.rxBytes, rawRxBytes);
                    entry.txBytes = multiplySafe(targetTxBytes, entry.txBytes, rawTxBytes);
                    // We purposefully clear out packet counters to indicate
                    // that this data has been augmented.
                    entry.rxPackets = 0;
                    entry.txPackets = 0;
                    combined.setValues(i, entry);
                }
            }
            final long deltaTotal = combined.getTotalBytes() - beforeTotal;
            if (deltaTotal != 0) {
                Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
            }
            // Finally we can slice data as originally requested
            final NetworkStatsHistory sliced = new NetworkStatsHistory(mBucketDuration, bucketEstimate, fields);
            sliced.recordHistory(combined, start, end);
            return sliced;
        } else {
            return combined;
        }
    }

    /**
     * Summarize all {@link NetworkStatsHistory} in this collection which match
     * the requested parameters.
     */
    public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) {
        final long now = System.currentTimeMillis();
        final NetworkStats stats = new NetworkStats(end - start, 24);
        // shortcut when we know stats will be empty
        if (start == end)
            return stats;
        final NetworkStats.Entry entry = new NetworkStats.Entry();
        NetworkStatsHistory.Entry historyEntry = null;
        for (int i = 0; i < mStats.size(); i++) {
            final Key key = mStats.keyAt(i);
            if (templateMatches(template, key.ident) && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel) && key.set < NetworkStats.SET_DEBUG_START) {
                final NetworkStatsHistory value = mStats.valueAt(i);
                historyEntry = value.getValues(start, end, now, historyEntry);
                entry.iface = IFACE_ALL;
                entry.uid = key.uid;
                entry.set = key.set;
                entry.tag = key.tag;
                entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() ? DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO;
                entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO;
                entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO;
                entry.rxBytes = historyEntry.rxBytes;
                entry.rxPackets = historyEntry.rxPackets;
                entry.txBytes = historyEntry.txBytes;
                entry.txPackets = historyEntry.txPackets;
                entry.operations = historyEntry.operations;
                if (!entry.isEmpty()) {
                    stats.combineValues(entry);
                }
            }
        }
        return stats;
    }

    /**
     * Record given {@link android.net.NetworkStats.Entry} into this collection.
     */
    public void recordData(NetworkIdenreplacedySet ident, int uid, int set, int tag, long start, long end, NetworkStats.Entry entry) {
        final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag);
        history.recordData(start, end, entry);
        noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes);
    }

    /**
     * Record given {@link NetworkStatsHistory} into this collection.
     */
    private void recordHistory(Key key, NetworkStatsHistory history) {
        if (history.size() == 0)
            return;
        noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes());
        NetworkStatsHistory target = mStats.get(key);
        if (target == null) {
            target = new NetworkStatsHistory(history.getBucketDuration());
            mStats.put(key, target);
        }
        target.recordEntireHistory(history);
    }

    /**
     * Record all {@link NetworkStatsHistory} contained in the given collection
     * into this collection.
     */
    public void recordCollection(NetworkStatsCollection another) {
        for (int i = 0; i < another.mStats.size(); i++) {
            final Key key = another.mStats.keyAt(i);
            final NetworkStatsHistory value = another.mStats.valueAt(i);
            recordHistory(key, value);
        }
    }

    private NetworkStatsHistory findOrCreateHistory(NetworkIdenreplacedySet ident, int uid, int set, int tag) {
        final Key key = new Key(ident, uid, set, tag);
        final NetworkStatsHistory existing = mStats.get(key);
        // update when no existing, or when bucket duration changed
        NetworkStatsHistory updated = null;
        if (existing == null) {
            updated = new NetworkStatsHistory(mBucketDuration, 10);
        } else if (existing.getBucketDuration() != mBucketDuration) {
            updated = new NetworkStatsHistory(existing, mBucketDuration);
        }
        if (updated != null) {
            mStats.put(key, updated);
            return updated;
        } else {
            return existing;
        }
    }

    @Override
    public void read(InputStream in) throws IOException {
        read(new DataInputStream(in));
    }

    public void read(DataInputStream in) throws IOException {
        // verify file magic header intact
        final int magic = in.readInt();
        if (magic != FILE_MAGIC) {
            throw new ProtocolException("unexpected magic: " + magic);
        }
        final int version = in.readInt();
        switch(version) {
            case VERSION_UNIFIED_INIT:
                {
                    // uid := size *(NetworkIdenreplacedySet size *(uid set tag NetworkStatsHistory))
                    final int identSize = in.readInt();
                    for (int i = 0; i < identSize; i++) {
                        final NetworkIdenreplacedySet ident = new NetworkIdenreplacedySet(in);
                        final int size = in.readInt();
                        for (int j = 0; j < size; j++) {
                            final int uid = in.readInt();
                            final int set = in.readInt();
                            final int tag = in.readInt();
                            final Key key = new Key(ident, uid, set, tag);
                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
                            recordHistory(key, history);
                        }
                    }
                    break;
                }
            default:
                {
                    throw new ProtocolException("unexpected version: " + version);
                }
        }
    }

    public void write(DataOutputStream out) throws IOException {
        // cluster key lists grouped by ident
        final HashMap<NetworkIdenreplacedySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
        for (Key key : mStats.keySet()) {
            ArrayList<Key> keys = keysByIdent.get(key.ident);
            if (keys == null) {
                keys = Lists.newArrayList();
                keysByIdent.put(key.ident, keys);
            }
            keys.add(key);
        }
        out.writeInt(FILE_MAGIC);
        out.writeInt(VERSION_UNIFIED_INIT);
        out.writeInt(keysByIdent.size());
        for (NetworkIdenreplacedySet ident : keysByIdent.keySet()) {
            final ArrayList<Key> keys = keysByIdent.get(ident);
            ident.writeToStream(out);
            out.writeInt(keys.size());
            for (Key key : keys) {
                final NetworkStatsHistory history = mStats.get(key);
                out.writeInt(key.uid);
                out.writeInt(key.set);
                out.writeInt(key.tag);
                history.writeToStream(out);
            }
        }
        out.flush();
    }

    @Deprecated
    public void readLegacyNetwork(File file) throws IOException {
        final AtomicFile inputFile = new AtomicFile(file);
        DataInputStream in = null;
        try {
            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
            // verify file magic header intact
            final int magic = in.readInt();
            if (magic != FILE_MAGIC) {
                throw new ProtocolException("unexpected magic: " + magic);
            }
            final int version = in.readInt();
            switch(version) {
                case VERSION_NETWORK_INIT:
                    {
                        // network := size *(NetworkIdenreplacedySet NetworkStatsHistory)
                        final int size = in.readInt();
                        for (int i = 0; i < size; i++) {
                            final NetworkIdenreplacedySet ident = new NetworkIdenreplacedySet(in);
                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
                            final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE);
                            recordHistory(key, history);
                        }
                        break;
                    }
                default:
                    {
                        throw new ProtocolException("unexpected version: " + version);
                    }
            }
        } catch (FileNotFoundException e) {
        // missing stats is okay, probably first boot
        } finally {
            IoUtils.closeQuietly(in);
        }
    }

    @Deprecated
    public void readLegacyUid(File file, boolean onlyTags) throws IOException {
        final AtomicFile inputFile = new AtomicFile(file);
        DataInputStream in = null;
        try {
            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
            // verify file magic header intact
            final int magic = in.readInt();
            if (magic != FILE_MAGIC) {
                throw new ProtocolException("unexpected magic: " + magic);
            }
            final int version = in.readInt();
            switch(version) {
                case VERSION_UID_INIT:
                    {
                        // uid := size *(UID NetworkStatsHistory)
                        // drop this data version, since we don't have a good
                        // mapping into NetworkIdenreplacedySet.
                        break;
                    }
                case VERSION_UID_WITH_IDENT:
                    {
                        // uid := size *(NetworkIdenreplacedySet size *(UID NetworkStatsHistory))
                        // drop this data version, since this version only existed
                        // for a short time.
                        break;
                    }
                case VERSION_UID_WITH_TAG:
                case VERSION_UID_WITH_SET:
                    {
                        // uid := size *(NetworkIdenreplacedySet size *(uid set tag NetworkStatsHistory))
                        final int identSize = in.readInt();
                        for (int i = 0; i < identSize; i++) {
                            final NetworkIdenreplacedySet ident = new NetworkIdenreplacedySet(in);
                            final int size = in.readInt();
                            for (int j = 0; j < size; j++) {
                                final int uid = in.readInt();
                                final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() : SET_DEFAULT;
                                final int tag = in.readInt();
                                final Key key = new Key(ident, uid, set, tag);
                                final NetworkStatsHistory history = new NetworkStatsHistory(in);
                                if ((tag == TAG_NONE) != onlyTags) {
                                    recordHistory(key, history);
                                }
                            }
                        }
                        break;
                    }
                default:
                    {
                        throw new ProtocolException("unexpected version: " + version);
                    }
            }
        } catch (FileNotFoundException e) {
        // missing stats is okay, probably first boot
        } finally {
            IoUtils.closeQuietly(in);
        }
    }

    /**
     * Remove any {@link NetworkStatsHistory} attributed to the requested UID,
     * moving any {@link NetworkStats#TAG_NONE} series to
     * {@link TrafficStats#UID_REMOVED}.
     */
    public void removeUids(int[] uids) {
        final ArrayList<Key> knownKeys = Lists.newArrayList();
        knownKeys.addAll(mStats.keySet());
        // migrate all UID stats into special "removed" bucket
        for (Key key : knownKeys) {
            if (ArrayUtils.contains(uids, key.uid)) {
                // only migrate combined TAG_NONE history
                if (key.tag == TAG_NONE) {
                    final NetworkStatsHistory uidHistory = mStats.get(key);
                    final NetworkStatsHistory removedHistory = findOrCreateHistory(key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
                    removedHistory.recordEntireHistory(uidHistory);
                }
                mStats.remove(key);
                mDirty = true;
            }
        }
    }

    private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) {
        if (startMillis < mStartMillis)
            mStartMillis = startMillis;
        if (endMillis > mEndMillis)
            mEndMillis = endMillis;
        mTotalBytes += totalBytes;
        mDirty = true;
    }

    private int estimateBuckets() {
        return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5) / mBucketDuration);
    }

    private ArrayList<Key> getSortedKeys() {
        final ArrayList<Key> keys = Lists.newArrayList();
        keys.addAll(mStats.keySet());
        Collections.sort(keys);
        return keys;
    }

    public void dump(IndentingPrintWriter pw) {
        for (Key key : getSortedKeys()) {
            pw.print("ident=");
            pw.print(key.ident.toString());
            pw.print(" uid=");
            pw.print(key.uid);
            pw.print(" set=");
            pw.print(NetworkStats.setToString(key.set));
            pw.print(" tag=");
            pw.println(NetworkStats.tagToString(key.tag));
            final NetworkStatsHistory history = mStats.get(key);
            pw.increaseIndent();
            history.dump(pw, true);
            pw.decreaseIndent();
        }
    }

    public void writeToProto(ProtoOutputStream proto, long tag) {
        final long start = proto.start(tag);
        for (Key key : getSortedKeys()) {
            final long startStats = proto.start(NetworkStatsCollectionProto.STATS);
            // Key
            final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
            key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENreplacedY);
            proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
            proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
            proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
            proto.end(startKey);
            // Value
            final NetworkStatsHistory history = mStats.get(key);
            history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY);
            proto.end(startStats);
        }
        proto.end(start);
    }

    public void dumpCheckin(PrintWriter pw, long start, long end) {
        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell");
        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi");
        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth");
        dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt");
    }

    /**
     * Dump all contained stats that match requested parameters, but group
     * together all matching {@link NetworkTemplate} under a single prefix.
     */
    private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate, String groupPrefix) {
        final ArrayMap<Key, NetworkStatsHistory> grouped = new ArrayMap<>();
        // Walk through all history, grouping by matching network templates
        for (int i = 0; i < mStats.size(); i++) {
            final Key key = mStats.keyAt(i);
            final NetworkStatsHistory value = mStats.valueAt(i);
            if (!templateMatches(groupTemplate, key.ident))
                continue;
            if (key.set >= NetworkStats.SET_DEBUG_START)
                continue;
            final Key groupKey = new Key(null, key.uid, key.set, key.tag);
            NetworkStatsHistory groupHistory = grouped.get(groupKey);
            if (groupHistory == null) {
                groupHistory = new NetworkStatsHistory(value.getBucketDuration());
                grouped.put(groupKey, groupHistory);
            }
            groupHistory.recordHistory(value, start, end);
        }
        for (int i = 0; i < grouped.size(); i++) {
            final Key key = grouped.keyAt(i);
            final NetworkStatsHistory value = grouped.valueAt(i);
            if (value.size() == 0)
                continue;
            pw.print("c,");
            pw.print(groupPrefix);
            pw.print(',');
            pw.print(key.uid);
            pw.print(',');
            pw.print(NetworkStats.setToCheckinString(key.set));
            pw.print(',');
            pw.print(key.tag);
            pw.println();
            value.dumpCheckin(pw);
        }
    }

    /**
     * Test if given {@link NetworkTemplate} matches any {@link NetworkIdenreplacedy}
     * in the given {@link NetworkIdenreplacedySet}.
     */
    private static boolean templateMatches(NetworkTemplate template, NetworkIdenreplacedySet identSet) {
        for (NetworkIdenreplacedy ident : identSet) {
            if (template.matches(ident)) {
                return true;
            }
        }
        return false;
    }

    private static clreplaced Key implements Comparable<Key> {

        public final NetworkIdenreplacedySet ident;

        public final int uid;

        public final int set;

        public final int tag;

        private final int hashCode;

        public Key(NetworkIdenreplacedySet ident, int uid, int set, int tag) {
            this.ident = ident;
            this.uid = uid;
            this.set = set;
            this.tag = tag;
            hashCode = Objects.hash(ident, uid, set, tag);
        }

        @Override
        public int hashCode() {
            return hashCode;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Key) {
                final Key key = (Key) obj;
                return uid == key.uid && set == key.set && tag == key.tag && Objects.equals(ident, key.ident);
            }
            return false;
        }

        @Override
        public int compareTo(Key another) {
            int res = 0;
            if (ident != null && another.ident != null) {
                res = ident.compareTo(another.ident);
            }
            if (res == 0) {
                res = Integer.compare(uid, another.uid);
            }
            if (res == 0) {
                res = Integer.compare(set, another.set);
            }
            if (res == 0) {
                res = Integer.compare(tag, another.tag);
            }
            return res;
        }
    }
}

19 Source : LockGuard.java
with Apache License 2.0
from lulululbj

/**
 * LockGuard is a mechanism to help detect lock inversions inside the system
 * server. It works by requiring each lock acquisition site to follow this
 * pattern:
 *
 * <pre>
 * synchronized (LockGuard.guard(lock)) {
 * }
 * </pre>
 *
 * <pre>
 * $ find services/ -name "*.java" -exec sed -i -r \
 *     's/synchronized.?\((.+?)\)/synchronized \(com.android.server.LockGuard.guard\(\1\)\)/' {} \;
 * </pre>
 *
 * The {@link #guard(Object)} method internally verifies that all locking is
 * done in a consistent order, and will log if any inversion is detected. For
 * example, if the calling thread is trying to acquire the
 * {@code ActivityManager} lock while holding the {@code PackageManager} lock,
 * it will yell.
 * <p>
 * This clreplaced requires no prior knowledge of locks or their ordering; it derives
 * all of this data at runtime. However, this means the overhead is
 * <em>substantial</em> and it should not be enabled by default. For example,
 * here are some benchmarked timings:
 * <ul>
 * <li>An unguarded synchronized block takes 40ns.
 * <li>A guarded synchronized block takes 50ns when disabled.
 * <li>A guarded synchronized block takes 460ns per lock checked when enabled.
 * </ul>
 * <p>
 * This clreplaced also supports a second simpler mode of operation where well-known
 * locks are explicitly registered and checked via indexes.
 */
public clreplaced LockGuard {

    private static final String TAG = "LockGuard";

    /**
     * Well-known locks ordered by fixed index. Locks with a specific index
     * should never be acquired while holding a lock of a lower index.
     */
    public static final int INDEX_APP_OPS = 0;

    public static final int INDEX_POWER = 1;

    public static final int INDEX_USER = 2;

    public static final int INDEX_PACKAGES = 3;

    public static final int INDEX_STORAGE = 4;

    public static final int INDEX_WINDOW = 5;

    public static final int INDEX_ACTIVITY = 6;

    public static final int INDEX_DPMS = 7;

    private static Object[] sKnownFixed = new Object[INDEX_DPMS + 1];

    private static ArrayMap<Object, LockInfo> sKnown = new ArrayMap<>(0, true);

    private static clreplaced LockInfo {

        /**
         * Friendly label to describe this lock
         */
        public String label;

        /**
         * Child locks that can be acquired while this lock is already held
         */
        public ArraySet<Object> children = new ArraySet<>(0, true);

        /**
         * If true, do wtf instead of a warning log.
         */
        public boolean doWtf;
    }

    private static LockInfo findOrCreateLockInfo(Object lock) {
        LockInfo info = sKnown.get(lock);
        if (info == null) {
            info = new LockInfo();
            info.label = "0x" + Integer.toHexString(System.idenreplacedyHashCode(lock)) + " [" + new Throwable().getStackTrace()[2].toString() + "]";
            sKnown.put(lock, info);
        }
        return info;
    }

    /**
     * Check if the calling thread is holding any locks in an inverted order.
     *
     * @param lock The lock the calling thread is attempting to acquire.
     */
    public static Object guard(Object lock) {
        // If we already hold this lock, ignore
        if (lock == null || Thread.holdsLock(lock))
            return lock;
        // Check to see if we're already holding any child locks
        boolean triggered = false;
        final LockInfo info = findOrCreateLockInfo(lock);
        for (int i = 0; i < info.children.size(); i++) {
            final Object child = info.children.valueAt(i);
            if (child == null)
                continue;
            if (Thread.holdsLock(child)) {
                doLog(lock, "Calling thread " + Thread.currentThread().getName() + " is holding " + lockToString(child) + " while trying to acquire " + lockToString(lock));
                triggered = true;
            }
        }
        if (!triggered) {
            // If no trouble found above, record this lock as being a valid
            // child of all locks currently being held
            for (int i = 0; i < sKnown.size(); i++) {
                final Object test = sKnown.keyAt(i);
                if (test == null || test == lock)
                    continue;
                if (Thread.holdsLock(test)) {
                    sKnown.valueAt(i).children.add(lock);
                }
            }
        }
        return lock;
    }

    /**
     * Yell if any lower-level locks are being held by the calling thread that
     * is about to acquire the given lock.
     */
    public static void guard(int index) {
        for (int i = 0; i < index; i++) {
            final Object lock = sKnownFixed[i];
            if (lock != null && Thread.holdsLock(lock)) {
                // Note in this case sKnownFixed may not contain a lock at the given index,
                // which is okay and in that case we just don't do a WTF.
                final Object targetMayBeNull = sKnownFixed[index];
                doLog(targetMayBeNull, "Calling thread " + Thread.currentThread().getName() + " is holding " + lockToString(i) + " while trying to acquire " + lockToString(index));
            }
        }
    }

    private static void doLog(@Nullable Object lock, String message) {
        if (lock != null && findOrCreateLockInfo(lock).doWtf) {
            // Don't want to call into ActivityManager with any lock held, so let's just call it
            // from a new thread. We don't want to use known threads (e.g. BackgroundThread) either
            // because they may be stuck too.
            final Throwable stackTrace = new RuntimeException(message);
            new Thread(() -> Slog.wtf(TAG, stackTrace)).start();
            return;
        }
        Slog.w(TAG, message, new Throwable());
    }

    /**
     * Report the given lock with a well-known label.
     */
    public static Object installLock(Object lock, String label) {
        final LockInfo info = findOrCreateLockInfo(lock);
        info.label = label;
        return lock;
    }

    /**
     * Report the given lock with a well-known index.
     */
    public static Object installLock(Object lock, int index) {
        return installLock(lock, index, /*doWtf=*/
        false);
    }

    /**
     * Report the given lock with a well-known index.
     */
    public static Object installLock(Object lock, int index, boolean doWtf) {
        sKnownFixed[index] = lock;
        final LockInfo info = findOrCreateLockInfo(lock);
        info.doWtf = doWtf;
        info.label = "Lock-" + lockToString(index);
        return lock;
    }

    public static Object installNewLock(int index) {
        return installNewLock(index, /*doWtf=*/
        false);
    }

    public static Object installNewLock(int index, boolean doWtf) {
        final Object lock = new Object();
        installLock(lock, index, doWtf);
        return lock;
    }

    private static String lockToString(Object lock) {
        final LockInfo info = sKnown.get(lock);
        if (info != null && !TextUtils.isEmpty(info.label)) {
            return info.label;
        } else {
            return "0x" + Integer.toHexString(System.idenreplacedyHashCode(lock));
        }
    }

    private static String lockToString(int index) {
        switch(index) {
            case INDEX_APP_OPS:
                return "APP_OPS";
            case INDEX_POWER:
                return "POWER";
            case INDEX_USER:
                return "USER";
            case INDEX_PACKAGES:
                return "PACKAGES";
            case INDEX_STORAGE:
                return "STORAGE";
            case INDEX_WINDOW:
                return "WINDOW";
            case INDEX_ACTIVITY:
                return "ACTIVITY";
            case INDEX_DPMS:
                return "DPMS";
            default:
                return Integer.toString(index);
        }
    }

    public static void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        for (int i = 0; i < sKnown.size(); i++) {
            final Object lock = sKnown.keyAt(i);
            final LockInfo info = sKnown.valueAt(i);
            pw.println("Lock " + lockToString(lock) + ":");
            for (int j = 0; j < info.children.size(); j++) {
                pw.println("  Child " + lockToString(info.children.valueAt(j)));
            }
            pw.println();
        }
    }
}

19 Source : IpConnectivityMetrics.java
with Apache License 2.0
from lulululbj

private static ArrayMap<Clreplaced<?>, TokenBucket> makeRateLimitingBuckets() {
    ArrayMap<Clreplaced<?>, TokenBucket> map = new ArrayMap<>();
    // one token every minute, 50 tokens max: burst of ~50 events every hour.
    map.put(ApfProgramEvent.clreplaced, new TokenBucket((int) DateUtils.MINUTE_IN_MILLIS, 50));
    return map;
}

19 Source : EntityConfidence.java
with Apache License 2.0
from lulululbj

/**
 * Helper object for setting and getting enreplacedy scores for clreplacedified text.
 *
 * @hide
 */
final clreplaced EnreplacedyConfidence implements Parcelable {

    private final ArrayMap<String, Float> mEnreplacedyConfidence = new ArrayMap<>();

    private final ArrayList<String> mSortedEnreplacedies = new ArrayList<>();

    EnreplacedyConfidence() {
    }

    EnreplacedyConfidence(@NonNull EnreplacedyConfidence source) {
        Preconditions.checkNotNull(source);
        mEnreplacedyConfidence.putAll(source.mEnreplacedyConfidence);
        mSortedEnreplacedies.addAll(source.mSortedEnreplacedies);
    }

    /**
     * Constructs an EnreplacedyConfidence from a map of enreplacedy to confidence.
     *
     * Map entries that have 0 confidence are removed, and values greater than 1 are clamped to 1.
     *
     * @param source a map from enreplacedy to a confidence value in the range 0 (low confidence) to
     *               1 (high confidence).
     */
    EnreplacedyConfidence(@NonNull Map<String, Float> source) {
        Preconditions.checkNotNull(source);
        // Prune non-existent enreplacedies and clamp to 1.
        mEnreplacedyConfidence.ensureCapacity(source.size());
        for (Map.Entry<String, Float> it : source.entrySet()) {
            if (it.getValue() <= 0)
                continue;
            mEnreplacedyConfidence.put(it.getKey(), Math.min(1, it.getValue()));
        }
        resetSortedEnreplacediesFromMap();
    }

    /**
     * Returns an immutable list of enreplacedies found in the clreplacedified text ordered from
     * high confidence to low confidence.
     */
    @NonNull
    public List<String> getEnreplacedies() {
        return Collections.unmodifiableList(mSortedEnreplacedies);
    }

    /**
     * Returns the confidence score for the specified enreplacedy. The value ranges from
     * 0 (low confidence) to 1 (high confidence). 0 indicates that the enreplacedy was not found for the
     * clreplacedified text.
     */
    @FloatRange(from = 0.0, to = 1.0)
    public float getConfidenceScore(String enreplacedy) {
        if (mEnreplacedyConfidence.containsKey(enreplacedy)) {
            return mEnreplacedyConfidence.get(enreplacedy);
        }
        return 0;
    }

    @Override
    public String toString() {
        return mEnreplacedyConfidence.toString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mEnreplacedyConfidence.size());
        for (Map.Entry<String, Float> entry : mEnreplacedyConfidence.entrySet()) {
            dest.writeString(entry.getKey());
            dest.writeFloat(entry.getValue());
        }
    }

    public static final Parcelable.Creator<EnreplacedyConfidence> CREATOR = new Parcelable.Creator<EnreplacedyConfidence>() {

        @Override
        public EnreplacedyConfidence createFromParcel(Parcel in) {
            return new EnreplacedyConfidence(in);
        }

        @Override
        public EnreplacedyConfidence[] newArray(int size) {
            return new EnreplacedyConfidence[size];
        }
    };

    private EnreplacedyConfidence(Parcel in) {
        final int numEnreplacedies = in.readInt();
        mEnreplacedyConfidence.ensureCapacity(numEnreplacedies);
        for (int i = 0; i < numEnreplacedies; ++i) {
            mEnreplacedyConfidence.put(in.readString(), in.readFloat());
        }
        resetSortedEnreplacediesFromMap();
    }

    private void resetSortedEnreplacediesFromMap() {
        mSortedEnreplacedies.clear();
        mSortedEnreplacedies.ensureCapacity(mEnreplacedyConfidence.size());
        mSortedEnreplacedies.addAll(mEnreplacedyConfidence.keySet());
        mSortedEnreplacedies.sort((e1, e2) -> {
            float score1 = mEnreplacedyConfidence.get(e1);
            float score2 = mEnreplacedyConfidence.get(e2);
            return Float.compare(score2, score1);
        });
    }
}

19 Source : TransitionManager.java
with Apache License 2.0
from lulululbj

/**
 * This clreplaced manages the set of transitions that fire when there is a
 * change of {@link Scene}. To use the manager, add scenes along with
 * transition objects with calls to {@link #setTransition(Scene, Transition)}
 * or {@link #setTransition(Scene, Scene, Transition)}. Setting specific
 * transitions for scene changes is not required; by default, a Scene change
 * will use {@link AutoTransition} to do something reasonable for most
 * situations. Specifying other transitions for particular scene changes is
 * only necessary if the application wants different transition behavior
 * in these situations.
 *
 * <p>TransitionManagers can be declared in XML resource files inside the
 * <code>res/transition</code> directory. TransitionManager resources consist of
 * the <code>transitionManager</code>tag name, containing one or more
 * <code>transition</code> tags, each of which describe the relationship of
 * that transition to the from/to scene information in that tag.
 * For example, here is a resource file that declares several scene
 * transitions:</p>
 *
 * {@sample development/samples/ApiDemos/res/transition/transitions_mgr.xml TransitionManager}
 *
 * <p>For each of the <code>fromScene</code> and <code>toScene</code> attributes,
 * there is a reference to a standard XML layout file. This is equivalent to
 * creating a scene from a layout in code by calling
 * {@link Scene#getSceneForLayout(ViewGroup, int, Context)}. For the
 * <code>transition</code> attribute, there is a reference to a resource
 * file in the <code>res/transition</code> directory which describes that
 * transition.</p>
 *
 * Information on XML resource descriptions for transitions can be found for
 * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
 * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
 * and {@link android.R.styleable#TransitionManager}.
 */
public clreplaced TransitionManager {

    // TODO: how to handle enter/exit?
    private static String LOG_TAG = "TransitionManager";

    private static Transition sDefaultTransition = new AutoTransition();

    private static final String[] EMPTY_STRINGS = new String[0];

    ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();

    ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions = new ArrayMap<Scene, ArrayMap<Scene, Transition>>();

    private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>> sRunningTransitions = new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();

    private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();

    /**
     * Sets the transition to be used for any scene change for which no
     * other transition is explicitly set. The initial value is
     * an {@link AutoTransition} instance.
     *
     * @param transition The default transition to be used for scene changes.
     *
     * @hide pending later changes
     */
    public void setDefaultTransition(Transition transition) {
        sDefaultTransition = transition;
    }

    /**
     * Gets the current default transition. The initial value is an {@link
     * AutoTransition} instance.
     *
     * @return The current default transition.
     * @see #setDefaultTransition(Transition)
     *
     * @hide pending later changes
     */
    public static Transition getDefaultTransition() {
        return sDefaultTransition;
    }

    /**
     * Sets a specific transition to occur when the given scene is entered.
     *
     * @param scene The scene which, when applied, will cause the given
     * transition to run.
     * @param transition The transition that will play when the given scene is
     * entered. A value of null will result in the default behavior of
     * using the default transition instead.
     */
    public void setTransition(Scene scene, Transition transition) {
        mSceneTransitions.put(scene, transition);
    }

    /**
     * Sets a specific transition to occur when the given pair of scenes is
     * exited/entered.
     *
     * @param fromScene The scene being exited when the given transition will
     * be run
     * @param toScene The scene being entered when the given transition will
     * be run
     * @param transition The transition that will play when the given scene is
     * entered. A value of null will result in the default behavior of
     * using the default transition instead.
     */
    public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
        ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
        if (sceneTransitionMap == null) {
            sceneTransitionMap = new ArrayMap<Scene, Transition>();
            mScenePairTransitions.put(toScene, sceneTransitionMap);
        }
        sceneTransitionMap.put(fromScene, transition);
    }

    /**
     * Returns the Transition for the given scene being entered. The result
     * depends not only on the given scene, but also the scene which the
     * {@link Scene#getSceneRoot() sceneRoot} of the Scene is currently in.
     *
     * @param scene The scene being entered
     * @return The Transition to be used for the given scene change. If no
     * Transition was specified for this scene change, the default transition
     * will be used instead.
     * @hide
     */
    @TestApi
    public Transition getTransition(Scene scene) {
        Transition transition = null;
        ViewGroup sceneRoot = scene.getSceneRoot();
        if (sceneRoot != null) {
            // TODO: cached in Scene instead? long-term, cache in View itself
            Scene currScene = Scene.getCurrentScene(sceneRoot);
            if (currScene != null) {
                ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(scene);
                if (sceneTransitionMap != null) {
                    transition = sceneTransitionMap.get(currScene);
                    if (transition != null) {
                        return transition;
                    }
                }
            }
        }
        transition = mSceneTransitions.get(scene);
        return (transition != null) ? transition : sDefaultTransition;
    }

    /**
     * This is where all of the work of a transition/scene-change is
     * orchestrated. This method captures the start values for the given
     * transition, exits the current Scene, enters the new scene, captures
     * the end values for the transition, and finally plays the
     * resulting values-populated transition.
     *
     * @param scene The scene being entered
     * @param transition The transition to play for this scene change
     */
    private static void changeScene(Scene scene, Transition transition) {
        final ViewGroup sceneRoot = scene.getSceneRoot();
        if (!sPendingTransitions.contains(sceneRoot)) {
            if (transition == null) {
                scene.enter();
            } else {
                sPendingTransitions.add(sceneRoot);
                Transition transitionClone = transition.clone();
                transitionClone.setSceneRoot(sceneRoot);
                Scene oldScene = Scene.getCurrentScene(sceneRoot);
                if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
                    transitionClone.setCanRemoveViews(true);
                }
                sceneChangeSetup(sceneRoot, transitionClone);
                scene.enter();
                sceneChangeRunTransition(sceneRoot, transitionClone);
            }
        }
    }

    private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
        WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions = sRunningTransitions.get();
        if (runningTransitions == null || runningTransitions.get() == null) {
            ArrayMap<ViewGroup, ArrayList<Transition>> transitions = new ArrayMap<ViewGroup, ArrayList<Transition>>();
            runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>(transitions);
            sRunningTransitions.set(runningTransitions);
        }
        return runningTransitions.get();
    }

    private static void sceneChangeRunTransition(final ViewGroup sceneRoot, final Transition transition) {
        if (transition != null && sceneRoot != null) {
            MultiListener listener = new MultiListener(transition, sceneRoot);
            sceneRoot.addOnAttachStateChangeListener(listener);
            sceneRoot.getViewTreeObserver().addOnPreDrawListener(listener);
        }
    }

    /**
     * This private utility clreplaced is used to listen for both OnPreDraw and
     * OnAttachStateChange events. OnPreDraw events are the main ones we care
     * about since that's what triggers the transition to take place.
     * OnAttachStateChange events are also important in case the view is removed
     * from the hierarchy before the OnPreDraw event takes place; it's used to
     * clean up things since the OnPreDraw listener didn't get called in time.
     */
    private static clreplaced MultiListener implements ViewTreeObserver.OnPreDrawListener, View.OnAttachStateChangeListener {

        Transition mTransition;

        ViewGroup mSceneRoot;

        final ViewTreeObserver mViewTreeObserver;

        MultiListener(Transition transition, ViewGroup sceneRoot) {
            mTransition = transition;
            mSceneRoot = sceneRoot;
            mViewTreeObserver = mSceneRoot.getViewTreeObserver();
        }

        private void removeListeners() {
            if (mViewTreeObserver.isAlive()) {
                mViewTreeObserver.removeOnPreDrawListener(this);
            } else {
                mSceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
            }
            mSceneRoot.removeOnAttachStateChangeListener(this);
        }

        @Override
        public void onViewAttachedToWindow(View v) {
        }

        @Override
        public void onViewDetachedFromWindow(View v) {
            removeListeners();
            sPendingTransitions.remove(mSceneRoot);
            ArrayList<Transition> runningTransitions = getRunningTransitions().get(mSceneRoot);
            if (runningTransitions != null && runningTransitions.size() > 0) {
                for (Transition runningTransition : runningTransitions) {
                    runningTransition.resume(mSceneRoot);
                }
            }
            mTransition.clearValues(true);
        }

        @Override
        public boolean onPreDraw() {
            removeListeners();
            // Don't start the transition if it's no longer pending.
            if (!sPendingTransitions.remove(mSceneRoot)) {
                return true;
            }
            // Add to running list, handle end to remove it
            final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions = getRunningTransitions();
            ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot);
            ArrayList<Transition> previousRunningTransitions = null;
            if (currentTransitions == null) {
                currentTransitions = new ArrayList<Transition>();
                runningTransitions.put(mSceneRoot, currentTransitions);
            } else if (currentTransitions.size() > 0) {
                previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
            }
            currentTransitions.add(mTransition);
            mTransition.addListener(new TransitionListenerAdapter() {

                @Override
                public void onTransitionEnd(Transition transition) {
                    ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot);
                    currentTransitions.remove(transition);
                }
            });
            mTransition.captureValues(mSceneRoot, false);
            if (previousRunningTransitions != null) {
                for (Transition runningTransition : previousRunningTransitions) {
                    runningTransition.resume(mSceneRoot);
                }
            }
            mTransition.playTransition(mSceneRoot);
            return true;
        }
    }

    private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
        // Capture current values
        ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
        if (runningTransitions != null && runningTransitions.size() > 0) {
            for (Transition runningTransition : runningTransitions) {
                runningTransition.pause(sceneRoot);
            }
        }
        if (transition != null) {
            transition.captureValues(sceneRoot, true);
        }
        // Notify previous scene that it is being exited
        Scene previousScene = Scene.getCurrentScene(sceneRoot);
        if (previousScene != null) {
            previousScene.exit();
        }
    }

    /**
     * Change to the given scene, using the
     * appropriate transition for this particular scene change
     * (as specified to the TransitionManager, or the default
     * if no such transition exists).
     *
     * @param scene The Scene to change to
     */
    public void transitionTo(Scene scene) {
        // Auto transition if there is no transition declared for the Scene, but there is
        // a root or parent view
        changeScene(scene, getTransition(scene));
    }

    /**
     * Convenience method to simply change to the given scene using
     * the default transition for TransitionManager.
     *
     * @param scene The Scene to change to
     */
    public static void go(Scene scene) {
        changeScene(scene, sDefaultTransition);
    }

    /**
     * Convenience method to simply change to the given scene using
     * the given transition.
     *
     * <p>Preplaceding in <code>null</code> for the transition parameter will
     * result in the scene changing without any transition running, and is
     * equivalent to calling {@link Scene#exit()} on the scene root's
     * current scene, followed by {@link Scene#enter()} on the scene
     * specified by the <code>scene</code> parameter.</p>
     *
     * @param scene The Scene to change to
     * @param transition The transition to use for this scene change. A
     * value of null causes the scene change to happen with no transition.
     */
    public static void go(Scene scene, Transition transition) {
        changeScene(scene, transition);
    }

    /**
     * Convenience method to animate, using the default transition,
     * to a new scene defined by all changes within the given scene root between
     * calling this method and the next rendering frame.
     * Equivalent to calling {@link #beginDelayedTransition(ViewGroup, Transition)}
     * with a value of <code>null</code> for the <code>transition</code> parameter.
     *
     * @param sceneRoot The root of the View hierarchy to run the transition on.
     */
    public static void beginDelayedTransition(final ViewGroup sceneRoot) {
        beginDelayedTransition(sceneRoot, null);
    }

    /**
     * Convenience method to animate to a new scene defined by all changes within
     * the given scene root between calling this method and the next rendering frame.
     * Calling this method causes TransitionManager to capture current values in the
     * scene root and then post a request to run a transition on the next frame.
     * At that time, the new values in the scene root will be captured and changes
     * will be animated. There is no need to create a Scene; it is implied by
     * changes which take place between calling this method and the next frame when
     * the transition begins.
     *
     * <p>Calling this method several times before the next frame (for example, if
     * unrelated code also wants to make dynamic changes and run a transition on
     * the same scene root), only the first call will trigger capturing values
     * and exiting the current scene. Subsequent calls to the method with the
     * same scene root during the same frame will be ignored.</p>
     *
     * <p>Preplaceding in <code>null</code> for the transition parameter will
     * cause the TransitionManager to use its default transition.</p>
     *
     * @param sceneRoot The root of the View hierarchy to run the transition on.
     * @param transition The transition to use for this change. A
     * value of null causes the TransitionManager to use the default transition.
     */
    public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
        if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
            if (Transition.DBG) {
                Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " + sceneRoot + ", " + transition);
            }
            sPendingTransitions.add(sceneRoot);
            if (transition == null) {
                transition = sDefaultTransition;
            }
            final Transition transitionClone = transition.clone();
            sceneChangeSetup(sceneRoot, transitionClone);
            Scene.setCurrentScene(sceneRoot, null);
            sceneChangeRunTransition(sceneRoot, transitionClone);
        }
    }

    /**
     * Ends all pending and ongoing transitions on the specified scene root.
     *
     * @param sceneRoot The root of the View hierarchy to end transitions on.
     */
    public static void endTransitions(final ViewGroup sceneRoot) {
        sPendingTransitions.remove(sceneRoot);
        final ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
        if (runningTransitions != null && !runningTransitions.isEmpty()) {
            // Make a copy in case this is called by an onTransitionEnd listener
            ArrayList<Transition> copy = new ArrayList(runningTransitions);
            for (int i = copy.size() - 1; i >= 0; i--) {
                final Transition transition = copy.get(i);
                transition.forceToEnd(sceneRoot);
            }
        }
    }
}

19 Source : RemoteCallbackList.java
with Apache License 2.0
from lulululbj

/**
 * Takes care of the grunt work of maintaining a list of remote interfaces,
 * typically for the use of performing callbacks from a
 * {@link android.app.Service} to its clients.  In particular, this:
 *
 * <ul>
 * <li> Keeps track of a set of registered {@link IInterface} callbacks,
 * taking care to identify them through their underlying unique {@link IBinder}
 * (by calling {@link IInterface#asBinder IInterface.asBinder()}.
 * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to
 * each registered interface, so that it can be cleaned out of the list if its
 * process goes away.
 * <li> Performs locking of the underlying list of interfaces to deal with
 * mulreplacedhreaded incoming calls, and a thread-safe way to iterate over a
 * snapshot of the list without holding its lock.
 * </ul>
 *
 * <p>To use this clreplaced, simply create a single instance along with your
 * service, and call its {@link #register} and {@link #unregister} methods
 * as client register and unregister with your service.  To call back on to
 * the registered clients, use {@link #beginBroadcast},
 * {@link #getBroadcasreplacedem}, and {@link #finishBroadcast}.
 *
 * <p>If a registered callback's process goes away, this clreplaced will take
 * care of automatically removing it from the list.  If you want to do
 * additional work in this situation, you can create a subclreplaced that
 * implements the {@link #onCallbackDied} method.
 */
public clreplaced RemoteCallbackList<E extends IInterface> {

    private static final String TAG = "RemoteCallbackList";

    /*package*/
    ArrayMap<IBinder, Callback> mCallbacks = new ArrayMap<IBinder, Callback>();

    private Object[] mActiveBroadcast;

    private int mBroadcastCount = -1;

    private boolean mKilled = false;

    private StringBuilder mRecentCallers;

    private final clreplaced Callback implements IBinder.DeathRecipient {

        final E mCallback;

        final Object mCookie;

        Callback(E callback, Object cookie) {
            mCallback = callback;
            mCookie = cookie;
        }

        public void binderDied() {
            synchronized (mCallbacks) {
                mCallbacks.remove(mCallback.asBinder());
            }
            onCallbackDied(mCallback, mCookie);
        }
    }

    /**
     * Simple version of {@link RemoteCallbackList#register(E, Object)}
     * that does not take a cookie object.
     */
    public boolean register(E callback) {
        return register(callback, null);
    }

    /**
     * Add a new callback to the list.  This callback will remain in the list
     * until a corresponding call to {@link #unregister} or its hosting process
     * goes away.  If the callback was already registered (determined by
     * checking to see if the {@link IInterface#asBinder callback.asBinder()}
     * object is already in the list), then it will be left as-is.
     * Registrations are not counted; a single call to {@link #unregister}
     * will remove a callback after any number calls to register it.
     *
     * @param callback The callback interface to be added to the list.  Must
     * not be null -- preplaceding null here will cause a NullPointerException.
     * Most services will want to check for null before calling this with
     * an object given from a client, so that clients can't crash the
     * service with bad data.
     *
     * @param cookie Optional additional data to be replacedociated with this
     * callback.
     *
     * @return Returns true if the callback was successfully added to the list.
     * Returns false if it was not added, either because {@link #kill} had
     * previously been called or the callback's process has gone away.
     *
     * @see #unregister
     * @see #kill
     * @see #onCallbackDied
     */
    public boolean register(E callback, Object cookie) {
        synchronized (mCallbacks) {
            if (mKilled) {
                return false;
            }
            // Flag unusual case that could be caused by a leak. b/36778087
            logExcessiveCallbacks();
            IBinder binder = callback.asBinder();
            try {
                Callback cb = new Callback(callback, cookie);
                binder.linkToDeath(cb, 0);
                mCallbacks.put(binder, cb);
                return true;
            } catch (RemoteException e) {
                return false;
            }
        }
    }

    /**
     * Remove from the list a callback that was previously added with
     * {@link #register}.  This uses the
     * {@link IInterface#asBinder callback.asBinder()} object to correctly
     * find the previous registration.
     * Registrations are not counted; a single unregister call will remove
     * a callback after any number calls to {@link #register} for it.
     *
     * @param callback The callback to be removed from the list.  Preplaceding
     * null here will cause a NullPointerException, so you will generally want
     * to check for null before calling.
     *
     * @return Returns true if the callback was found and unregistered.  Returns
     * false if the given callback was not found on the list.
     *
     * @see #register
     */
    public boolean unregister(E callback) {
        synchronized (mCallbacks) {
            Callback cb = mCallbacks.remove(callback.asBinder());
            if (cb != null) {
                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
                return true;
            }
            return false;
        }
    }

    /**
     * Disable this callback list.  All registered callbacks are unregistered,
     * and the list is disabled so that future calls to {@link #register} will
     * fail.  This should be used when a Service is stopping, to prevent clients
     * from registering callbacks after it is stopped.
     *
     * @see #register
     */
    public void kill() {
        synchronized (mCallbacks) {
            for (int cbi = mCallbacks.size() - 1; cbi >= 0; cbi--) {
                Callback cb = mCallbacks.valueAt(cbi);
                cb.mCallback.asBinder().unlinkToDeath(cb, 0);
            }
            mCallbacks.clear();
            mKilled = true;
        }
    }

    /**
     * Old version of {@link #onCallbackDied(E, Object)} that
     * does not provide a cookie.
     */
    public void onCallbackDied(E callback) {
    }

    /**
     * Called when the process hosting a callback in the list has gone away.
     * The default implementation calls {@link #onCallbackDied(E)}
     * for backwards compatibility.
     *
     * @param callback The callback whose process has died.  Note that, since
     * its process has died, you can not make any calls on to this interface.
     * You can, however, retrieve its IBinder and compare it with another
     * IBinder to see if it is the same object.
     * @param cookie The cookie object original provided to
     * {@link #register(E, Object)}.
     *
     * @see #register
     */
    public void onCallbackDied(E callback, Object cookie) {
        onCallbackDied(callback);
    }

    /**
     * Prepare to start making calls to the currently registered callbacks.
     * This creates a copy of the callback list, which you can retrieve items
     * from using {@link #getBroadcasreplacedem}.  Note that only one broadcast can
     * be active at a time, so you must be sure to always call this from the
     * same thread (usually by scheduling with {@link Handler}) or
     * do your own synchronization.  You must call {@link #finishBroadcast}
     * when done.
     *
     * <p>A typical loop delivering a broadcast looks like this:
     *
     * <pre>
     * int i = callbacks.beginBroadcast();
     * while (i > 0) {
     *     i--;
     *     try {
     *         callbacks.getBroadcasreplacedem(i).somethingHappened();
     *     } catch (RemoteException e) {
     *         // The RemoteCallbackList will take care of removing
     *         // the dead object for us.
     *     }
     * }
     * callbacks.finishBroadcast();</pre>
     *
     * @return Returns the number of callbacks in the broadcast, to be used
     * with {@link #getBroadcasreplacedem} to determine the range of indices you
     * can supply.
     *
     * @see #getBroadcasreplacedem
     * @see #finishBroadcast
     */
    public int beginBroadcast() {
        synchronized (mCallbacks) {
            if (mBroadcastCount > 0) {
                throw new IllegalStateException("beginBroadcast() called while already in a broadcast");
            }
            final int N = mBroadcastCount = mCallbacks.size();
            if (N <= 0) {
                return 0;
            }
            Object[] active = mActiveBroadcast;
            if (active == null || active.length < N) {
                mActiveBroadcast = active = new Object[N];
            }
            for (int i = 0; i < N; i++) {
                active[i] = mCallbacks.valueAt(i);
            }
            return N;
        }
    }

    /**
     * Retrieve an item in the active broadcast that was previously started
     * with {@link #beginBroadcast}.  This can <em>only</em> be called after
     * the broadcast is started, and its data is no longer valid after
     * calling {@link #finishBroadcast}.
     *
     * <p>Note that it is possible for the process of one of the returned
     * callbacks to go away before you call it, so you will need to catch
     * {@link RemoteException} when calling on to the returned object.
     * The callback list itself, however, will take care of unregistering
     * these objects once it detects that it is no longer valid, so you can
     * handle such an exception by simply ignoring it.
     *
     * @param index Which of the registered callbacks you would like to
     * retrieve.  Ranges from 0 to 1-{@link #beginBroadcast}.
     *
     * @return Returns the callback interface that you can call.  This will
     * always be non-null.
     *
     * @see #beginBroadcast
     */
    public E getBroadcasreplacedem(int index) {
        return ((Callback) mActiveBroadcast[index]).mCallback;
    }

    /**
     * Retrieve the cookie replacedociated with the item
     * returned by {@link #getBroadcasreplacedem(int)}.
     *
     * @see #getBroadcasreplacedem
     */
    public Object getBroadcastCookie(int index) {
        return ((Callback) mActiveBroadcast[index]).mCookie;
    }

    /**
     * Clean up the state of a broadcast previously initiated by calling
     * {@link #beginBroadcast}.  This must always be called when you are done
     * with a broadcast.
     *
     * @see #beginBroadcast
     */
    public void finishBroadcast() {
        synchronized (mCallbacks) {
            if (mBroadcastCount < 0) {
                throw new IllegalStateException("finishBroadcast() called outside of a broadcast");
            }
            Object[] active = mActiveBroadcast;
            if (active != null) {
                final int N = mBroadcastCount;
                for (int i = 0; i < N; i++) {
                    active[i] = null;
                }
            }
            mBroadcastCount = -1;
        }
    }

    /**
     * Performs {@code action} on each callback, calling
     * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
     *
     * @hide
     */
    public void broadcast(Consumer<E> action) {
        int itemCount = beginBroadcast();
        try {
            for (int i = 0; i < itemCount; i++) {
                action.accept(getBroadcasreplacedem(i));
            }
        } finally {
            finishBroadcast();
        }
    }

    /**
     * Performs {@code action} for each cookie replacedociated with a callback, calling
     * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
     *
     * @hide
     */
    public <C> void broadcastForEachCookie(Consumer<C> action) {
        int itemCount = beginBroadcast();
        try {
            for (int i = 0; i < itemCount; i++) {
                action.accept((C) getBroadcastCookie(i));
            }
        } finally {
            finishBroadcast();
        }
    }

    /**
     * Returns the number of registered callbacks. Note that the number of registered
     * callbacks may differ from the value returned by {@link #beginBroadcast()} since
     * the former returns the number of callbacks registered at the time of the call
     * and the second the number of callback to which the broadcast will be delivered.
     * <p>
     * This function is useful to decide whether to schedule a broadcast if this
     * requires doing some work which otherwise would not be performed.
     * </p>
     *
     * @return The size.
     */
    public int getRegisteredCallbackCount() {
        synchronized (mCallbacks) {
            if (mKilled) {
                return 0;
            }
            return mCallbacks.size();
        }
    }

    /**
     * Return a currently registered callback.  Note that this is
     * <em>not</em> the same as {@link #getBroadcasreplacedem} and should not be used
     * interchangeably with it.  This method returns the registered callback at the given
     * index, not the current broadcast state.  This means that it is not itself thread-safe:
     * any call to {@link #register} or {@link #unregister} will change these indices, so you
     * must do your own thread safety between these to protect from such changes.
     *
     * @param index Index of which callback registration to return, from 0 to
     * {@link #getRegisteredCallbackCount()} - 1.
     *
     * @return Returns whatever callback is replacedociated with this index, or null if
     * {@link #kill()} has been called.
     */
    public E getRegisteredCallbackItem(int index) {
        synchronized (mCallbacks) {
            if (mKilled) {
                return null;
            }
            return mCallbacks.valueAt(index).mCallback;
        }
    }

    /**
     * Return any cookie replacedociated with a currently registered callback.  Note that this is
     * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used
     * interchangeably with it.  This method returns the current cookie registered at the given
     * index, not the current broadcast state.  This means that it is not itself thread-safe:
     * any call to {@link #register} or {@link #unregister} will change these indices, so you
     * must do your own thread safety between these to protect from such changes.
     *
     * @param index Index of which registration cookie to return, from 0 to
     * {@link #getRegisteredCallbackCount()} - 1.
     *
     * @return Returns whatever cookie object is replacedociated with this index, or null if
     * {@link #kill()} has been called.
     */
    public Object getRegisteredCallbackCookie(int index) {
        synchronized (mCallbacks) {
            if (mKilled) {
                return null;
            }
            return mCallbacks.valueAt(index).mCookie;
        }
    }

    /**
     * @hide
     */
    public void dump(PrintWriter pw, String prefix) {
        pw.print(prefix);
        pw.print("callbacks: ");
        pw.println(mCallbacks.size());
        pw.print(prefix);
        pw.print("killed: ");
        pw.println(mKilled);
        pw.print(prefix);
        pw.print("broadcasts count: ");
        pw.println(mBroadcastCount);
    }

    private void logExcessiveCallbacks() {
        final long size = mCallbacks.size();
        final long TOO_MANY = 3000;
        final long MAX_CHARS = 1000;
        if (size >= TOO_MANY) {
            if (size == TOO_MANY && mRecentCallers == null) {
                mRecentCallers = new StringBuilder();
            }
            if (mRecentCallers != null && mRecentCallers.length() < MAX_CHARS) {
                mRecentCallers.append(Debug.getCallers(5));
                mRecentCallers.append('\n');
                if (mRecentCallers.length() >= MAX_CHARS) {
                    Slog.wtf(TAG, "More than " + TOO_MANY + " remote callbacks registered. Recent callers:\n" + mRecentCallers.toString());
                    mRecentCallers = null;
                }
            }
        }
    }
}

19 Source : HealthStatsWriter.java
with Apache License 2.0
from lulululbj

/**
 * Clreplaced to write the health stats data into a parcel, so it can then be
 * retrieved via a {@link HealthStats} object.
 *
 * There is an attempt to keep this clreplaced as low overhead as possible, for
 * example storing an int[] and a long[] instead of a TimerStat[].
 *
 * @hide
 */
public clreplaced HealthStatsWriter {

    private final HealthKeys.Constants mConstants;

    // TimerStat fields
    private final boolean[] mTimerFields;

    private final int[] mTimerCounts;

    private final long[] mTimerTimes;

    // Measurement fields
    private final boolean[] mMeasurementFields;

    private final long[] mMeasurementValues;

    // Stats fields
    private final ArrayMap<String, HealthStatsWriter>[] mStatsValues;

    // Timers fields
    private final ArrayMap<String, TimerStat>[] mTimersValues;

    // Measurements fields
    private final ArrayMap<String, Long>[] mMeasurementsValues;

    /**
     * Construct a HealthStatsWriter object with the given constants.
     *
     * The "getDataType()" of the resulting HealthStats object will be the
     * short name of the java clreplaced that the Constants object was initalized
     * with.
     */
    public HealthStatsWriter(HealthKeys.Constants constants) {
        mConstants = constants;
        // TimerStat
        final int timerCount = constants.getSize(HealthKeys.TYPE_TIMER);
        mTimerFields = new boolean[timerCount];
        mTimerCounts = new int[timerCount];
        mTimerTimes = new long[timerCount];
        // Measurement
        final int measurementCount = constants.getSize(HealthKeys.TYPE_MEASUREMENT);
        mMeasurementFields = new boolean[measurementCount];
        mMeasurementValues = new long[measurementCount];
        // Stats
        final int statsCount = constants.getSize(HealthKeys.TYPE_STATS);
        mStatsValues = new ArrayMap[statsCount];
        // Timers
        final int timersCount = constants.getSize(HealthKeys.TYPE_TIMERS);
        mTimersValues = new ArrayMap[timersCount];
        // Measurements
        final int measurementsCount = constants.getSize(HealthKeys.TYPE_MEASUREMENTS);
        mMeasurementsValues = new ArrayMap[measurementsCount];
    }

    /**
     * Add a timer for the given key.
     */
    public void addTimer(int timerId, int count, long time) {
        final int index = mConstants.getIndex(HealthKeys.TYPE_TIMER, timerId);
        mTimerFields[index] = true;
        mTimerCounts[index] = count;
        mTimerTimes[index] = time;
    }

    /**
     * Add a measurement for the given key.
     */
    public void addMeasurement(int measurementId, long value) {
        final int index = mConstants.getIndex(HealthKeys.TYPE_MEASUREMENT, measurementId);
        mMeasurementFields[index] = true;
        mMeasurementValues[index] = value;
    }

    /**
     * Add a recursive HealthStats object for the given key and string name. The value
     * is stored as a HealthStatsWriter until this object is written to a parcel, so
     * don't attempt to reuse the HealthStatsWriter.
     *
     * The value field should not be null.
     */
    public void addStats(int key, String name, HealthStatsWriter value) {
        final int index = mConstants.getIndex(HealthKeys.TYPE_STATS, key);
        ArrayMap<String, HealthStatsWriter> map = mStatsValues[index];
        if (map == null) {
            map = mStatsValues[index] = new ArrayMap<String, HealthStatsWriter>(1);
        }
        map.put(name, value);
    }

    /**
     * Add a TimerStat for the given key and string name.
     *
     * The value field should not be null.
     */
    public void addTimers(int key, String name, TimerStat value) {
        final int index = mConstants.getIndex(HealthKeys.TYPE_TIMERS, key);
        ArrayMap<String, TimerStat> map = mTimersValues[index];
        if (map == null) {
            map = mTimersValues[index] = new ArrayMap<String, TimerStat>(1);
        }
        map.put(name, value);
    }

    /**
     * Add a measurement for the given key and string name.
     */
    public void addMeasurements(int key, String name, long value) {
        final int index = mConstants.getIndex(HealthKeys.TYPE_MEASUREMENTS, key);
        ArrayMap<String, Long> map = mMeasurementsValues[index];
        if (map == null) {
            map = mMeasurementsValues[index] = new ArrayMap<String, Long>(1);
        }
        map.put(name, value);
    }

    /**
     * Flattens the data in this HealthStatsWriter to the Parcel format
     * that can be unparceled into a HealthStat.
     * @more
     * (Called flattenToParcel because this HealthStatsWriter itself is
     * not parcelable and we don't flatten all the business about the
     * HealthKeys.Constants, only the values that were actually supplied)
     */
    public void flattenToParcel(Parcel out) {
        int[] keys;
        // Header fields
        out.writeString(mConstants.getDataType());
        // TimerStat fields
        out.writeInt(countBooleanArray(mTimerFields));
        keys = mConstants.getKeys(HealthKeys.TYPE_TIMER);
        for (int i = 0; i < keys.length; i++) {
            if (mTimerFields[i]) {
                out.writeInt(keys[i]);
                out.writeInt(mTimerCounts[i]);
                out.writeLong(mTimerTimes[i]);
            }
        }
        // Measurement fields
        out.writeInt(countBooleanArray(mMeasurementFields));
        keys = mConstants.getKeys(HealthKeys.TYPE_MEASUREMENT);
        for (int i = 0; i < keys.length; i++) {
            if (mMeasurementFields[i]) {
                out.writeInt(keys[i]);
                out.writeLong(mMeasurementValues[i]);
            }
        }
        // Stats
        out.writeInt(countObjectArray(mStatsValues));
        keys = mConstants.getKeys(HealthKeys.TYPE_STATS);
        for (int i = 0; i < keys.length; i++) {
            if (mStatsValues[i] != null) {
                out.writeInt(keys[i]);
                writeHealthStatsWriterMap(out, mStatsValues[i]);
            }
        }
        // Timers
        out.writeInt(countObjectArray(mTimersValues));
        keys = mConstants.getKeys(HealthKeys.TYPE_TIMERS);
        for (int i = 0; i < keys.length; i++) {
            if (mTimersValues[i] != null) {
                out.writeInt(keys[i]);
                writeParcelableMap(out, mTimersValues[i]);
            }
        }
        // Measurements
        out.writeInt(countObjectArray(mMeasurementsValues));
        keys = mConstants.getKeys(HealthKeys.TYPE_MEASUREMENTS);
        for (int i = 0; i < keys.length; i++) {
            if (mMeasurementsValues[i] != null) {
                out.writeInt(keys[i]);
                writeLongsMap(out, mMeasurementsValues[i]);
            }
        }
    }

    /**
     * Count how many of the fields have been set.
     */
    private static int countBooleanArray(boolean[] fields) {
        int count = 0;
        final int N = fields.length;
        for (int i = 0; i < N; i++) {
            if (fields[i]) {
                count++;
            }
        }
        return count;
    }

    /**
     * Count how many of the fields have been set.
     */
    private static <T extends Object> int countObjectArray(T[] fields) {
        int count = 0;
        final int N = fields.length;
        for (int i = 0; i < N; i++) {
            if (fields[i] != null) {
                count++;
            }
        }
        return count;
    }

    /**
     * Write a map of String to HealthStatsWriter to the Parcel.
     */
    private static void writeHealthStatsWriterMap(Parcel out, ArrayMap<String, HealthStatsWriter> map) {
        final int N = map.size();
        out.writeInt(N);
        for (int i = 0; i < N; i++) {
            out.writeString(map.keyAt(i));
            map.valueAt(i).flattenToParcel(out);
        }
    }

    /**
     * Write a map of String to Parcelables to the Parcel.
     */
    private static <T extends Parcelable> void writeParcelableMap(Parcel out, ArrayMap<String, T> map) {
        final int N = map.size();
        out.writeInt(N);
        for (int i = 0; i < N; i++) {
            out.writeString(map.keyAt(i));
            map.valueAt(i).writeToParcel(out, 0);
        }
    }

    /**
     * Write a map of String to Longs to the Parcel.
     */
    private static void writeLongsMap(Parcel out, ArrayMap<String, Long> map) {
        final int N = map.size();
        out.writeInt(N);
        for (int i = 0; i < N; i++) {
            out.writeString(map.keyAt(i));
            out.writeLong(map.valueAt(i));
        }
    }
}

19 Source : HealthStats.java
with Apache License 2.0
from lulululbj

/**
 * A HealthStats object contains system health data about an application.
 *
 * <p>
 * <b>Data Types</b><br>
 * Each of the keys references data in one of five data types:
 *
 * <p>
 * A <b>measurement</b> metric contains a sinlge {@code long} value. That value may
 * be a count, a time, or some other type of value. The unit for a measurement
 * (COUNT, MS, etc) will always be in the name of the constant for the key to
 * retrieve it. For example, the
 * {@link android.os.health.UidHealthStats#MEASUREMENT_WIFI_TX_MS UidHealthStats.MEASUREMENT_WIFI_TX_MS}
 * value is the number of milliseconds (ms) that were spent transmitting on wifi by an
 * application.  The
 * {@link android.os.health.UidHealthStats#MEASUREMENT_MOBILE_RX_PACKETS UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS}
 * measurement is the number of packets received on behalf of an application.
 * The {@link android.os.health.UidHealthStats#MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
 *     UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT}
 * measurement is the number of times the user touched the screen, causing the
 * screen to stay awake.
 *
 * <p>
 * A <b>timer</b> metric contains an {@code int} count and a {@code long} time,
 * measured in milliseconds. Timers track how many times a resource was used, and
 * the total duration for that usage. For example, the
 * {@link android.os.health.UidHealthStats#TIMER_FLASHLIGHT}
 * timer tracks how many times the application turned on the flashlight, and for
 * how many milliseconds total it kept it on.
 *
 * <p>
 * A <b>measurement map</b> metric is a mapping of {@link java.lang.String} names to
 * {@link java.lang.Long} values.  The names typically are application provided names. For
 * example, the
 * {@link android.os.health.PackageHealthStats#MEASUREMENTS_WAKEUP_ALARMS_COUNT
 *         PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT}
 * measurement map is a mapping of the tag provided to the
 * {@link android.app.AlarmManager} when the alarm is scheduled.
 *
 * <p>
 * A <b>timer map</b> metric is a mapping of {@link java.lang.String} names to
 * {@link android.os.health.TimerStat} objects. The names are typically application
 * provided names.  For example, the
 * {@link android.os.health.UidHealthStats#TIMERS_WAKELOCKS_PARTIAL UidHealthStats.TIMERS_WAKELOCKS_PARTIAL}
 * is a mapping of tag provided to the {@link android.os.PowerManager} when the
 * wakelock is created to the number of times and for how long each wakelock was
 * active.
 *
 * <p>
 * Lastly, a <b>health stats</b> metric is a mapping of {@link java.lang.String}
 * names to a recursive {@link android.os.health.HealthStats} object containing
 * more detailed information. For example, the
 * {@link android.os.health.UidHealthStats#STATS_PACKAGES UidHealthStats.STATS_PACKAGES}
 * metric is a mapping of the package names for each of the APKs sharing a uid to
 * the information recorded for that apk.  The returned HealthStats objects will
 * each be replacedociated with a different set of constants.  For the HealthStats
 * returned for UidHealthStats.STATS_PACKAGES, the keys come from the
 * {@link android.os.health.PackageHealthStats}  clreplaced.
 *
 * <p>
 * The keys that are available are subject to change, depending on what a particular
 * device or software version is capable of recording. Applications must handle the absence of
 * data without crashing.
 */
public clreplaced HealthStats {

    // Header fields
    private String mDataType;

    // TimerStat fields
    private int[] mTimerKeys;

    private int[] mTimerCounts;

    private long[] mTimerTimes;

    // Measurement fields
    private int[] mMeasurementKeys;

    private long[] mMeasurementValues;

    // Stats fields
    private int[] mStatsKeys;

    private ArrayMap<String, HealthStats>[] mStatsValues;

    // Timers fields
    private int[] mTimersKeys;

    private ArrayMap<String, TimerStat>[] mTimersValues;

    // Measurements fields
    private int[] mMeasurementsKeys;

    private ArrayMap<String, Long>[] mMeasurementsValues;

    /**
     * HealthStats empty constructor not implemented because this
     * clreplaced is read-only.
     */
    private HealthStats() {
        throw new RuntimeException("unsupported");
    }

    /**
     * Construct a health stats object from a parcel.
     *
     * @hide
     */
    public HealthStats(Parcel in) {
        int count;
        // Header fields
        mDataType = in.readString();
        // TimerStat fields
        count = in.readInt();
        mTimerKeys = new int[count];
        mTimerCounts = new int[count];
        mTimerTimes = new long[count];
        for (int i = 0; i < count; i++) {
            mTimerKeys[i] = in.readInt();
            mTimerCounts[i] = in.readInt();
            mTimerTimes[i] = in.readLong();
        }
        // Measurement fields
        count = in.readInt();
        mMeasurementKeys = new int[count];
        mMeasurementValues = new long[count];
        for (int i = 0; i < count; i++) {
            mMeasurementKeys[i] = in.readInt();
            mMeasurementValues[i] = in.readLong();
        }
        // Stats fields
        count = in.readInt();
        mStatsKeys = new int[count];
        mStatsValues = new ArrayMap[count];
        for (int i = 0; i < count; i++) {
            mStatsKeys[i] = in.readInt();
            mStatsValues[i] = createHealthStatsMap(in);
        }
        // Timers fields
        count = in.readInt();
        mTimersKeys = new int[count];
        mTimersValues = new ArrayMap[count];
        for (int i = 0; i < count; i++) {
            mTimersKeys[i] = in.readInt();
            mTimersValues[i] = createParcelableMap(in, TimerStat.CREATOR);
        }
        // Measurements fields
        count = in.readInt();
        mMeasurementsKeys = new int[count];
        mMeasurementsValues = new ArrayMap[count];
        for (int i = 0; i < count; i++) {
            mMeasurementsKeys[i] = in.readInt();
            mMeasurementsValues[i] = createLongsMap(in);
        }
    }

    /**
     * Get a name representing the contents of this object.
     *
     * @see UidHealthStats
     * @see PackageHealthStats
     * @see PidHealthStats
     * @see ProcessHealthStats
     * @see ServiceHealthStats
     */
    public String getDataType() {
        return mDataType;
    }

    /**
     * Return whether this object contains a TimerStat for the supplied key.
     */
    public boolean hasTimer(int key) {
        return getIndex(mTimerKeys, key) >= 0;
    }

    /**
     * Return a TimerStat object for the given key.
     *
     * This will allocate a new {@link TimerStat} object, which may be wasteful. Instead, use
     * {@link #getTimerCount} and {@link #getTimerTime}.
     *
     * @throws IndexOutOfBoundsException When the key is not present in this object.
     * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
     */
    public TimerStat getTimer(int key) {
        final int index = getIndex(mTimerKeys, key);
        if (index < 0) {
            throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType + " key=" + key);
        }
        return new TimerStat(mTimerCounts[index], mTimerTimes[index]);
    }

    /**
     * Get the count for the timer for the given key.
     *
     * @throws IndexOutOfBoundsException When the key is not present in this object.
     * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
     */
    public int getTimerCount(int key) {
        final int index = getIndex(mTimerKeys, key);
        if (index < 0) {
            throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType + " key=" + key);
        }
        return mTimerCounts[index];
    }

    /**
     * Get the time for the timer for the given key, in milliseconds.
     *
     * @throws IndexOutOfBoundsException When the key is not present in this object.
     * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
     */
    public long getTimerTime(int key) {
        final int index = getIndex(mTimerKeys, key);
        if (index < 0) {
            throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType + " key=" + key);
        }
        return mTimerTimes[index];
    }

    /**
     * Get the number of timer values in this object. Can be used to iterate through
     * the available timers.
     *
     * @see #getTimerKeyAt
     */
    public int getTimerKeyCount() {
        return mTimerKeys.length;
    }

    /**
     * Get the key for the timer at the given index.  Index must be between 0 and the result
     * of {@link #getTimerKeyCount getTimerKeyCount()}.
     *
     * @see #getTimerKeyCount
     */
    public int getTimerKeyAt(int index) {
        return mTimerKeys[index];
    }

    /**
     * Return whether this object contains a measurement for the supplied key.
     */
    public boolean hasMeasurement(int key) {
        return getIndex(mMeasurementKeys, key) >= 0;
    }

    /**
     * Get the measurement for the given key.
     *
     * @throws IndexOutOfBoundsException When the key is not present in this object.
     * @see #hasMeasurement hasMeasurement(int) To check if a value for the given key is present.
     */
    public long getMeasurement(int key) {
        final int index = getIndex(mMeasurementKeys, key);
        if (index < 0) {
            throw new IndexOutOfBoundsException("Bad measurement key dataType=" + mDataType + " key=" + key);
        }
        return mMeasurementValues[index];
    }

    /**
     * Get the number of measurement values in this object. Can be used to iterate through
     * the available measurements.
     *
     * @see #getMeasurementKeyAt
     */
    public int getMeasurementKeyCount() {
        return mMeasurementKeys.length;
    }

    /**
     * Get the key for the measurement at the given index.  Index must be between 0 and the result
     * of {@link #getMeasurementKeyCount getMeasurementKeyCount()}.
     *
     * @see #getMeasurementKeyCount
     */
    public int getMeasurementKeyAt(int index) {
        return mMeasurementKeys[index];
    }

    /**
     * Return whether this object contains a HealthStats map for the supplied key.
     */
    public boolean hreplacedtats(int key) {
        return getIndex(mStatsKeys, key) >= 0;
    }

    /**
     * Get the HealthStats map for the given key.
     *
     * @throws IndexOutOfBoundsException When the key is not present in this object.
     * @see #hreplacedtats hreplacedtats(int) To check if a value for the given key is present.
     */
    public Map<String, HealthStats> getStats(int key) {
        final int index = getIndex(mStatsKeys, key);
        if (index < 0) {
            throw new IndexOutOfBoundsException("Bad stats key dataType=" + mDataType + " key=" + key);
        }
        return mStatsValues[index];
    }

    /**
     * Get the number of HealthStat map values in this object. Can be used to iterate through
     * the available measurements.
     *
     * @see #getMeasurementKeyAt
     */
    public int getStatsKeyCount() {
        return mStatsKeys.length;
    }

    /**
     * Get the key for the timer at the given index.  Index must be between 0 and the result
     * of {@link #getStatsKeyCount getStatsKeyCount()}.
     *
     * @see #getStatsKeyCount
     */
    public int getStatsKeyAt(int index) {
        return mStatsKeys[index];
    }

    /**
     * Return whether this object contains a timers map for the supplied key.
     */
    public boolean hasTimers(int key) {
        return getIndex(mTimersKeys, key) >= 0;
    }

    /**
     * Get the TimerStat map for the given key.
     *
     * @throws IndexOutOfBoundsException When the key is not present in this object.
     * @see #hasTimers hasTimers(int) To check if a value for the given key is present.
     */
    public Map<String, TimerStat> getTimers(int key) {
        final int index = getIndex(mTimersKeys, key);
        if (index < 0) {
            throw new IndexOutOfBoundsException("Bad timers key dataType=" + mDataType + " key=" + key);
        }
        return mTimersValues[index];
    }

    /**
     * Get the number of timer map values in this object. Can be used to iterate through
     * the available timer maps.
     *
     * @see #getTimersKeyAt
     */
    public int getTimersKeyCount() {
        return mTimersKeys.length;
    }

    /**
     * Get the key for the timer map at the given index.  Index must be between 0 and the result
     * of {@link #getTimersKeyCount getTimersKeyCount()}.
     *
     * @see #getTimersKeyCount
     */
    public int getTimersKeyAt(int index) {
        return mTimersKeys[index];
    }

    /**
     * Return whether this object contains a measurements map for the supplied key.
     */
    public boolean hasMeasurements(int key) {
        return getIndex(mMeasurementsKeys, key) >= 0;
    }

    /**
     * Get the measurements map for the given key.
     *
     * @throws IndexOutOfBoundsException When the key is not present in this object.
     * @see #hasMeasurements To check if a value for the given key is present.
     */
    public Map<String, Long> getMeasurements(int key) {
        final int index = getIndex(mMeasurementsKeys, key);
        if (index < 0) {
            throw new IndexOutOfBoundsException("Bad measurements key dataType=" + mDataType + " key=" + key);
        }
        return mMeasurementsValues[index];
    }

    /**
     * Get the number of measurement map values in this object. Can be used to iterate through
     * the available measurement maps.
     *
     * @see #getMeasurementsKeyAt
     */
    public int getMeasurementsKeyCount() {
        return mMeasurementsKeys.length;
    }

    /**
     * Get the key for the measurement map at the given index.
     * Index must be between 0 and the result
     * of {@link #getMeasurementsKeyCount getMeasurementsKeyCount()}.
     *
     * @see #getMeasurementsKeyCount
     */
    public int getMeasurementsKeyAt(int index) {
        return mMeasurementsKeys[index];
    }

    /**
     * Get the index in keys of key.
     */
    private static int getIndex(int[] keys, int key) {
        return Arrays.binarySearch(keys, key);
    }

    /**
     * Create an ArrayMap<String,HealthStats> from the given Parcel.
     */
    private static ArrayMap<String, HealthStats> createHealthStatsMap(Parcel in) {
        final int count = in.readInt();
        final ArrayMap<String, HealthStats> result = new ArrayMap<String, HealthStats>(count);
        for (int i = 0; i < count; i++) {
            result.put(in.readString(), new HealthStats(in));
        }
        return result;
    }

    /**
     * Create an ArrayMap<String,T extends Parcelable> from the given Parcel using
     * the given Parcelable.Creator.
     */
    private static <T extends Parcelable> ArrayMap<String, T> createParcelableMap(Parcel in, Parcelable.Creator<T> creator) {
        final int count = in.readInt();
        final ArrayMap<String, T> result = new ArrayMap<String, T>(count);
        for (int i = 0; i < count; i++) {
            result.put(in.readString(), creator.createFromParcel(in));
        }
        return result;
    }

    /**
     * Create an ArrayMap<String,Long> from the given Parcel.
     */
    private static ArrayMap<String, Long> createLongsMap(Parcel in) {
        final int count = in.readInt();
        final ArrayMap<String, Long> result = new ArrayMap<String, Long>(count);
        for (int i = 0; i < count; i++) {
            result.put(in.readString(), in.readLong());
        }
        return result;
    }
}

19 Source : UndoManager.java
with Apache License 2.0
from lulululbj

/**
 * Top-level clreplaced for managing and interacting with the global undo state for
 * a doreplacedent or application.  This clreplaced supports both undo and redo and has
 * helpers for merging undoable operations together as they are performed.
 *
 * <p>A single undoable operation is represented by {@link UndoOperation} which
 * apps implement to define their undo/redo behavior.  The UndoManager keeps
 * a stack of undo states; each state can have one or more undo operations
 * inside of it.</p>
 *
 * <p>Updates to the stack must be done inside of a {@link #beginUpdate}/{@link #endUpdate()}
 * pair.  During this time you can add new operations to the stack with
 * {@link #addOperation}, retrieve and modify existing operations with
 * {@link #getLastOperation}, control the label shown to the user for this operation
 * with {@link #setUndoLabel} and {@link #suggestUndoLabel}, etc.</p>
 *
 * <p>Every {link UndoOperation} is replacedociated with an {@link UndoOwner}, which identifies
 * the data it belongs to.  The owner is used to indicate how operations are dependent
 * on each other -- operations with the same owner are dependent on others with the
 * same owner.  For example, you may have a doreplacedent with multiple embedded objects.  If the
 * doreplacedent itself and each embedded object use different owners, then you
 * can provide undo semantics appropriate to the user's context: while within
 * an embedded object, only edits to that object are seen and the user can
 * undo/redo them without needing to impact edits in other objects; while
 * within the larger doreplacedent, all edits can be seen and the user must
 * undo/redo them as a single stream.</p>
 *
 * @hide
 */
public clreplaced UndoManager {

    // The common case is a single undo owner (e.g. for a TextView), so default to that capacity.
    private final ArrayMap<String, UndoOwner> mOwners = new ArrayMap<String, UndoOwner>(1);

    private final ArrayList<UndoState> mUndos = new ArrayList<UndoState>();

    private final ArrayList<UndoState> mRedos = new ArrayList<UndoState>();

    private int mUpdateCount;

    private int mHistorySize = 20;

    private UndoState mWorking;

    private int mCommitId = 1;

    private boolean mInUndo;

    private boolean mMerged;

    private int mStateSeq;

    private int mNextSavedIdx;

    private UndoOwner[] mStateOwners;

    /**
     * Never merge with the last undo state.
     */
    public static final int MERGE_MODE_NONE = 0;

    /**
     * Allow merge with the last undo state only if it contains
     * operations with the caller's owner.
     */
    public static final int MERGE_MODE_UNIQUE = 1;

    /**
     * Always allow merge with the last undo state, if possible.
     */
    public static final int MERGE_MODE_ANY = 2;

    public UndoOwner getOwner(String tag, Object data) {
        if (tag == null) {
            throw new NullPointerException("tag can't be null");
        }
        if (data == null) {
            throw new NullPointerException("data can't be null");
        }
        UndoOwner owner = mOwners.get(tag);
        if (owner != null) {
            if (owner.mData != data) {
                if (owner.mData != null) {
                    throw new IllegalStateException("Owner " + owner + " already exists with data " + owner.mData + " but giving different data " + data);
                }
                owner.mData = data;
            }
            return owner;
        }
        owner = new UndoOwner(tag, this);
        owner.mData = data;
        mOwners.put(tag, owner);
        return owner;
    }

    void removeOwner(UndoOwner owner) {
        // XXX need to figure out how to prune.
        if (false) {
            mOwners.remove(owner.mTag);
        }
    }

    /**
     * Flatten the current undo state into a Parcel object, which can later be restored
     * with {@link #restoreInstanceState(android.os.Parcel, java.lang.ClreplacedLoader)}.
     */
    public void saveInstanceState(Parcel p) {
        if (mUpdateCount > 0) {
            throw new IllegalStateException("Can't save state while updating");
        }
        mStateSeq++;
        if (mStateSeq <= 0) {
            mStateSeq = 0;
        }
        mNextSavedIdx = 0;
        p.writeInt(mHistorySize);
        p.writeInt(mOwners.size());
        // XXX eventually we need to be smart here about limiting the
        // number of undo states we write to not exceed X bytes.
        int i = mUndos.size();
        while (i > 0) {
            p.writeInt(1);
            i--;
            mUndos.get(i).writeToParcel(p);
        }
        i = mRedos.size();
        while (i > 0) {
            p.writeInt(2);
            i--;
            mRedos.get(i).writeToParcel(p);
        }
        p.writeInt(0);
    }

    void saveOwner(UndoOwner owner, Parcel out) {
        if (owner.mStateSeq == mStateSeq) {
            out.writeInt(owner.mSavedIdx);
        } else {
            owner.mStateSeq = mStateSeq;
            owner.mSavedIdx = mNextSavedIdx;
            out.writeInt(owner.mSavedIdx);
            out.writeString(owner.mTag);
            out.writeInt(owner.mOpCount);
            mNextSavedIdx++;
        }
    }

    /**
     * Restore an undo state previously created with {@link #saveInstanceState(Parcel)}.  This
     * will restore the UndoManager's state to almost exactly what it was at the point it had
     * been previously saved; the only information not restored is the data object
     * replacedociated with each {@link UndoOwner}, which requires separate calls to
     * {@link #getOwner(String, Object)} to re-replacedociate the owner with its data.
     */
    public void restoreInstanceState(Parcel p, ClreplacedLoader loader) {
        if (mUpdateCount > 0) {
            throw new IllegalStateException("Can't save state while updating");
        }
        forgetUndos(null, -1);
        forgetRedos(null, -1);
        mHistorySize = p.readInt();
        mStateOwners = new UndoOwner[p.readInt()];
        int stype;
        while ((stype = p.readInt()) != 0) {
            UndoState ustate = new UndoState(this, p, loader);
            if (stype == 1) {
                mUndos.add(0, ustate);
            } else {
                mRedos.add(0, ustate);
            }
        }
    }

    UndoOwner restoreOwner(Parcel in) {
        int idx = in.readInt();
        UndoOwner owner = mStateOwners[idx];
        if (owner == null) {
            String tag = in.readString();
            int opCount = in.readInt();
            owner = new UndoOwner(tag, this);
            owner.mOpCount = opCount;
            mStateOwners[idx] = owner;
            mOwners.put(tag, owner);
        }
        return owner;
    }

    /**
     * Set the maximum number of undo states that will be retained.
     */
    public void setHistorySize(int size) {
        mHistorySize = size;
        if (mHistorySize >= 0 && countUndos(null) > mHistorySize) {
            forgetUndos(null, countUndos(null) - mHistorySize);
        }
    }

    /**
     * Return the current maximum number of undo states.
     */
    public int getHistorySize() {
        return mHistorySize;
    }

    /**
     * Perform undo of last/top <var>count</var> undo states.  The states impacted
     * by this can be limited through <var>owners</var>.
     * @param owners Optional set of owners that should be impacted.  If null, all
     * undo states will be visible and available for undo.  If non-null, only those
     * states that contain one of the owners specified here will be visible.
     * @param count Number of undo states to pop.
     * @return Returns the number of undo states that were actually popped.
     */
    public int undo(UndoOwner[] owners, int count) {
        if (mWorking != null) {
            throw new IllegalStateException("Can't be called during an update");
        }
        int num = 0;
        int i = -1;
        mInUndo = true;
        UndoState us = getTopUndo(null);
        if (us != null) {
            us.makeExecuted();
        }
        while (count > 0 && (i = findPrevState(mUndos, owners, i)) >= 0) {
            UndoState state = mUndos.remove(i);
            state.undo();
            mRedos.add(state);
            count--;
            num++;
        }
        mInUndo = false;
        return num;
    }

    /**
     * Perform redo of last/top <var>count</var> undo states in the transient redo stack.
     * The states impacted by this can be limited through <var>owners</var>.
     * @param owners Optional set of owners that should be impacted.  If null, all
     * undo states will be visible and available for undo.  If non-null, only those
     * states that contain one of the owners specified here will be visible.
     * @param count Number of undo states to pop.
     * @return Returns the number of undo states that were actually redone.
     */
    public int redo(UndoOwner[] owners, int count) {
        if (mWorking != null) {
            throw new IllegalStateException("Can't be called during an update");
        }
        int num = 0;
        int i = -1;
        mInUndo = true;
        while (count > 0 && (i = findPrevState(mRedos, owners, i)) >= 0) {
            UndoState state = mRedos.remove(i);
            state.redo();
            mUndos.add(state);
            count--;
            num++;
        }
        mInUndo = false;
        return num;
    }

    /**
     * Returns true if we are currently inside of an undo/redo operation.  This is
     * useful for editors to know whether they should be generating new undo state
     * when they see edit operations happening.
     */
    public boolean isInUndo() {
        return mInUndo;
    }

    public int forgetUndos(UndoOwner[] owners, int count) {
        if (count < 0) {
            count = mUndos.size();
        }
        int removed = 0;
        int i = 0;
        while (i < mUndos.size() && removed < count) {
            UndoState state = mUndos.get(i);
            if (count > 0 && matchOwners(state, owners)) {
                state.destroy();
                mUndos.remove(i);
                removed++;
            } else {
                i++;
            }
        }
        return removed;
    }

    public int forgetRedos(UndoOwner[] owners, int count) {
        if (count < 0) {
            count = mRedos.size();
        }
        int removed = 0;
        int i = 0;
        while (i < mRedos.size() && removed < count) {
            UndoState state = mRedos.get(i);
            if (count > 0 && matchOwners(state, owners)) {
                state.destroy();
                mRedos.remove(i);
                removed++;
            } else {
                i++;
            }
        }
        return removed;
    }

    /**
     * Return the number of undo states on the undo stack.
     * @param owners If non-null, only those states containing an operation with one of
     * the owners supplied here will be counted.
     */
    public int countUndos(UndoOwner[] owners) {
        if (owners == null) {
            return mUndos.size();
        }
        int count = 0;
        int i = 0;
        while ((i = findNextState(mUndos, owners, i)) >= 0) {
            count++;
            i++;
        }
        return count;
    }

    /**
     * Return the number of redo states on the undo stack.
     * @param owners If non-null, only those states containing an operation with one of
     * the owners supplied here will be counted.
     */
    public int countRedos(UndoOwner[] owners) {
        if (owners == null) {
            return mRedos.size();
        }
        int count = 0;
        int i = 0;
        while ((i = findNextState(mRedos, owners, i)) >= 0) {
            count++;
            i++;
        }
        return count;
    }

    /**
     * Return the user-visible label for the top undo state on the stack.
     * @param owners If non-null, will select the top-most undo state containing an
     * operation with one of the owners supplied here.
     */
    public CharSequence getUndoLabel(UndoOwner[] owners) {
        UndoState state = getTopUndo(owners);
        return state != null ? state.getLabel() : null;
    }

    /**
     * Return the user-visible label for the top redo state on the stack.
     * @param owners If non-null, will select the top-most undo state containing an
     * operation with one of the owners supplied here.
     */
    public CharSequence getRedoLabel(UndoOwner[] owners) {
        UndoState state = getTopRedo(owners);
        return state != null ? state.getLabel() : null;
    }

    /**
     * Start creating a new undo state.  Multiple calls to this function will nest until
     * they are all matched by a later call to {@link #endUpdate}.
     * @param label Optional user-visible label for this new undo state.
     */
    public void beginUpdate(CharSequence label) {
        if (mInUndo) {
            throw new IllegalStateException("Can't being update while performing undo/redo");
        }
        if (mUpdateCount <= 0) {
            createWorkingState();
            mMerged = false;
            mUpdateCount = 0;
        }
        mWorking.updateLabel(label);
        mUpdateCount++;
    }

    private void createWorkingState() {
        mWorking = new UndoState(this, mCommitId++);
        if (mCommitId < 0) {
            mCommitId = 1;
        }
    }

    /**
     * Returns true if currently inside of a {@link #beginUpdate}.
     */
    public boolean isInUpdate() {
        return mUpdateCount > 0;
    }

    /**
     * Forcibly set a new for the new undo state being built within a {@link #beginUpdate}.
     * Any existing label will be replaced with this one.
     */
    public void setUndoLabel(CharSequence label) {
        if (mWorking == null) {
            throw new IllegalStateException("Must be called during an update");
        }
        mWorking.setLabel(label);
    }

    /**
     * Set a new for the new undo state being built within a {@link #beginUpdate}, but
     * only if there is not a label currently set for it.
     */
    public void suggestUndoLabel(CharSequence label) {
        if (mWorking == null) {
            throw new IllegalStateException("Must be called during an update");
        }
        mWorking.updateLabel(label);
    }

    /**
     * Return the number of times {@link #beginUpdate} has been called without a matching
     * {@link #endUpdate} call.
     */
    public int getUpdateNestingLevel() {
        return mUpdateCount;
    }

    /**
     * Check whether there is an {@link UndoOperation} in the current {@link #beginUpdate}
     * undo state.
     * @param owner Optional owner of the operation to look for.  If null, will succeed
     * if there is any operation; if non-null, will only succeed if there is an operation
     * with the given owner.
     * @return Returns true if there is a matching operation in the current undo state.
     */
    public boolean hasOperation(UndoOwner owner) {
        if (mWorking == null) {
            throw new IllegalStateException("Must be called during an update");
        }
        return mWorking.hasOperation(owner);
    }

    /**
     * Return the most recent {@link UndoOperation} that was added to the update.
     * @param mergeMode May be either {@link #MERGE_MODE_NONE} or {@link #MERGE_MODE_ANY}.
     */
    public UndoOperation<?> getLastOperation(int mergeMode) {
        return getLastOperation(null, null, mergeMode);
    }

    /**
     * Return the most recent {@link UndoOperation} that was added to the update and
     * has the given owner.
     * @param owner Optional owner of last operation to retrieve.  If null, the last
     * operation regardless of owner will be retrieved; if non-null, the last operation
     * matching the given owner will be retrieved.
     * @param mergeMode May be either {@link #MERGE_MODE_NONE}, {@link #MERGE_MODE_UNIQUE},
     * or {@link #MERGE_MODE_ANY}.
     */
    public UndoOperation<?> getLastOperation(UndoOwner owner, int mergeMode) {
        return getLastOperation(null, owner, mergeMode);
    }

    /**
     * Return the most recent {@link UndoOperation} that was added to the update and
     * has the given owner.
     * @param clazz Optional clreplaced of the last operation to retrieve.  If null, the
     * last operation regardless of clreplaced will be retrieved; if non-null, the last
     * operation whose clreplaced is the same as the given clreplaced will be retrieved.
     * @param owner Optional owner of last operation to retrieve.  If null, the last
     * operation regardless of owner will be retrieved; if non-null, the last operation
     * matching the given owner will be retrieved.
     * @param mergeMode May be either {@link #MERGE_MODE_NONE}, {@link #MERGE_MODE_UNIQUE},
     * or {@link #MERGE_MODE_ANY}.
     */
    public <T extends UndoOperation> T getLastOperation(Clreplaced<T> clazz, UndoOwner owner, int mergeMode) {
        if (mWorking == null) {
            throw new IllegalStateException("Must be called during an update");
        }
        if (mergeMode != MERGE_MODE_NONE && !mMerged && !mWorking.hasData()) {
            UndoState state = getTopUndo(null);
            UndoOperation<?> last;
            if (state != null && (mergeMode == MERGE_MODE_ANY || !state.hasMultipleOwners()) && state.canMerge() && (last = state.getLastOperation(clazz, owner)) != null) {
                if (last.allowMerge()) {
                    mWorking.destroy();
                    mWorking = state;
                    mUndos.remove(state);
                    mMerged = true;
                    return (T) last;
                }
            }
        }
        return mWorking.getLastOperation(clazz, owner);
    }

    /**
     * Add a new UndoOperation to the current update.
     * @param op The new operation to add.
     * @param mergeMode May be either {@link #MERGE_MODE_NONE}, {@link #MERGE_MODE_UNIQUE},
     * or {@link #MERGE_MODE_ANY}.
     */
    public void addOperation(UndoOperation<?> op, int mergeMode) {
        if (mWorking == null) {
            throw new IllegalStateException("Must be called during an update");
        }
        UndoOwner owner = op.getOwner();
        if (owner.mManager != this) {
            throw new IllegalArgumentException("Given operation's owner is not in this undo manager.");
        }
        if (mergeMode != MERGE_MODE_NONE && !mMerged && !mWorking.hasData()) {
            UndoState state = getTopUndo(null);
            if (state != null && (mergeMode == MERGE_MODE_ANY || !state.hasMultipleOwners()) && state.canMerge() && state.hasOperation(op.getOwner())) {
                mWorking.destroy();
                mWorking = state;
                mUndos.remove(state);
                mMerged = true;
            }
        }
        mWorking.addOperation(op);
    }

    /**
     * Finish the creation of an undo state, matching a previous call to
     * {@link #beginUpdate}.
     */
    public void endUpdate() {
        if (mWorking == null) {
            throw new IllegalStateException("Must be called during an update");
        }
        mUpdateCount--;
        if (mUpdateCount == 0) {
            pushWorkingState();
        }
    }

    private void pushWorkingState() {
        int N = mUndos.size() + 1;
        if (mWorking.hasData()) {
            mUndos.add(mWorking);
            forgetRedos(null, -1);
            mWorking.commit();
            if (N >= 2) {
                // The state before this one can no longer be merged, ever.
                // The only way to get back to it is for the user to perform
                // an undo.
                mUndos.get(N - 2).makeExecuted();
            }
        } else {
            mWorking.destroy();
        }
        mWorking = null;
        if (mHistorySize >= 0 && N > mHistorySize) {
            forgetUndos(null, N - mHistorySize);
        }
    }

    /**
     * Commit the last finished undo state.  This undo state can no longer be
     * modified with further {@link #MERGE_MODE_UNIQUE} or
     * {@link #MERGE_MODE_ANY} merge modes.  If called while inside of an update,
     * this will push any changes in the current update on to the undo stack
     * and result with a fresh undo state, behaving as if {@link #endUpdate()}
     * had been called enough to unwind the current update, then the last state
     * committed, and {@link #beginUpdate} called to restore the update nesting.
     * @param owner The optional owner to determine whether to perform the commit.
     * If this is non-null, the commit will only execute if the current top undo
     * state contains an operation with the given owner.
     * @return Returns an integer identifier for the committed undo state, which
     * can later be used to try to uncommit the state to perform further edits on it.
     */
    public int commitState(UndoOwner owner) {
        if (mWorking != null && mWorking.hasData()) {
            if (owner == null || mWorking.hasOperation(owner)) {
                mWorking.setCanMerge(false);
                int commitId = mWorking.getCommitId();
                pushWorkingState();
                createWorkingState();
                mMerged = true;
                return commitId;
            }
        } else {
            UndoState state = getTopUndo(null);
            if (state != null && (owner == null || state.hasOperation(owner))) {
                state.setCanMerge(false);
                return state.getCommitId();
            }
        }
        return -1;
    }

    /**
     * Attempt to undo a previous call to {@link #commitState}.  This will work
     * if the undo state at the top of the stack has the given id, and has not been
     * involved in an undo operation.  Otherwise false is returned.
     * @param commitId The identifier for the state to be uncommitted, as returned
     * by {@link #commitState}.
     * @param owner Optional owner that must appear in the committed state.
     * @return Returns true if the uncommit is successful, else false.
     */
    public boolean uncommitState(int commitId, UndoOwner owner) {
        if (mWorking != null && mWorking.getCommitId() == commitId) {
            if (owner == null || mWorking.hasOperation(owner)) {
                return mWorking.setCanMerge(true);
            }
        } else {
            UndoState state = getTopUndo(null);
            if (state != null && (owner == null || state.hasOperation(owner))) {
                if (state.getCommitId() == commitId) {
                    return state.setCanMerge(true);
                }
            }
        }
        return false;
    }

    UndoState getTopUndo(UndoOwner[] owners) {
        if (mUndos.size() <= 0) {
            return null;
        }
        int i = findPrevState(mUndos, owners, -1);
        return i >= 0 ? mUndos.get(i) : null;
    }

    UndoState getTopRedo(UndoOwner[] owners) {
        if (mRedos.size() <= 0) {
            return null;
        }
        int i = findPrevState(mRedos, owners, -1);
        return i >= 0 ? mRedos.get(i) : null;
    }

    boolean matchOwners(UndoState state, UndoOwner[] owners) {
        if (owners == null) {
            return true;
        }
        for (int i = 0; i < owners.length; i++) {
            if (state.matchOwner(owners[i])) {
                return true;
            }
        }
        return false;
    }

    int findPrevState(ArrayList<UndoState> states, UndoOwner[] owners, int from) {
        final int N = states.size();
        if (from == -1) {
            from = N - 1;
        }
        if (from >= N) {
            return -1;
        }
        if (owners == null) {
            return from;
        }
        while (from >= 0) {
            UndoState state = states.get(from);
            if (matchOwners(state, owners)) {
                return from;
            }
            from--;
        }
        return -1;
    }

    int findNextState(ArrayList<UndoState> states, UndoOwner[] owners, int from) {
        final int N = states.size();
        if (from < 0) {
            from = 0;
        }
        if (from >= N) {
            return -1;
        }
        if (owners == null) {
            return from;
        }
        while (from < N) {
            UndoState state = states.get(from);
            if (matchOwners(state, owners)) {
                return from;
            }
            from++;
        }
        return -1;
    }

    final static clreplaced UndoState {

        private final UndoManager mManager;

        private final int mCommitId;

        private final ArrayList<UndoOperation<?>> mOperations = new ArrayList<UndoOperation<?>>();

        private ArrayList<UndoOperation<?>> mRecent;

        private CharSequence mLabel;

        private boolean mCanMerge = true;

        private boolean mExecuted;

        UndoState(UndoManager manager, int commitId) {
            mManager = manager;
            mCommitId = commitId;
        }

        UndoState(UndoManager manager, Parcel p, ClreplacedLoader loader) {
            mManager = manager;
            mCommitId = p.readInt();
            mCanMerge = p.readInt() != 0;
            mExecuted = p.readInt() != 0;
            mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
            final int N = p.readInt();
            for (int i = 0; i < N; i++) {
                UndoOwner owner = mManager.restoreOwner(p);
                UndoOperation op = (UndoOperation) p.readParcelable(loader);
                op.mOwner = owner;
                mOperations.add(op);
            }
        }

        void writeToParcel(Parcel p) {
            if (mRecent != null) {
                throw new IllegalStateException("Can't save state before committing");
            }
            p.writeInt(mCommitId);
            p.writeInt(mCanMerge ? 1 : 0);
            p.writeInt(mExecuted ? 1 : 0);
            TextUtils.writeToParcel(mLabel, p, 0);
            final int N = mOperations.size();
            p.writeInt(N);
            for (int i = 0; i < N; i++) {
                UndoOperation op = mOperations.get(i);
                mManager.saveOwner(op.mOwner, p);
                p.writeParcelable(op, 0);
            }
        }

        int getCommitId() {
            return mCommitId;
        }

        void setLabel(CharSequence label) {
            mLabel = label;
        }

        void updateLabel(CharSequence label) {
            if (mLabel != null) {
                mLabel = label;
            }
        }

        CharSequence getLabel() {
            return mLabel;
        }

        boolean setCanMerge(boolean state) {
            // Don't allow re-enabling of merging if state has been executed.
            if (state && mExecuted) {
                return false;
            }
            mCanMerge = state;
            return true;
        }

        void makeExecuted() {
            mExecuted = true;
        }

        boolean canMerge() {
            return mCanMerge && !mExecuted;
        }

        int countOperations() {
            return mOperations.size();
        }

        boolean hasOperation(UndoOwner owner) {
            final int N = mOperations.size();
            if (owner == null) {
                return N != 0;
            }
            for (int i = 0; i < N; i++) {
                if (mOperations.get(i).getOwner() == owner) {
                    return true;
                }
            }
            return false;
        }

        boolean hasMultipleOwners() {
            final int N = mOperations.size();
            if (N <= 1) {
                return false;
            }
            UndoOwner owner = mOperations.get(0).getOwner();
            for (int i = 1; i < N; i++) {
                if (mOperations.get(i).getOwner() != owner) {
                    return true;
                }
            }
            return false;
        }

        void addOperation(UndoOperation<?> op) {
            if (mOperations.contains(op)) {
                throw new IllegalStateException("Already holds " + op);
            }
            mOperations.add(op);
            if (mRecent == null) {
                mRecent = new ArrayList<UndoOperation<?>>();
                mRecent.add(op);
            }
            op.mOwner.mOpCount++;
        }

        <T extends UndoOperation> T getLastOperation(Clreplaced<T> clazz, UndoOwner owner) {
            final int N = mOperations.size();
            if (clazz == null && owner == null) {
                return N > 0 ? (T) mOperations.get(N - 1) : null;
            }
            // First look for the top-most operation with the same owner.
            for (int i = N - 1; i >= 0; i--) {
                UndoOperation<?> op = mOperations.get(i);
                if (owner != null && op.getOwner() != owner) {
                    continue;
                }
                // Return this operation if it has the same clreplaced that the caller wants.
                // Note that we don't search deeper for the clreplaced, because we don't want
                // to end up with a different order of operations for the same owner.
                if (clazz != null && op.getClreplaced() != clazz) {
                    return null;
                }
                return (T) op;
            }
            return null;
        }

        boolean matchOwner(UndoOwner owner) {
            for (int i = mOperations.size() - 1; i >= 0; i--) {
                if (mOperations.get(i).matchOwner(owner)) {
                    return true;
                }
            }
            return false;
        }

        boolean hasData() {
            for (int i = mOperations.size() - 1; i >= 0; i--) {
                if (mOperations.get(i).hasData()) {
                    return true;
                }
            }
            return false;
        }

        void commit() {
            final int N = mRecent != null ? mRecent.size() : 0;
            for (int i = 0; i < N; i++) {
                mRecent.get(i).commit();
            }
            mRecent = null;
        }

        void undo() {
            for (int i = mOperations.size() - 1; i >= 0; i--) {
                mOperations.get(i).undo();
            }
        }

        void redo() {
            final int N = mOperations.size();
            for (int i = 0; i < N; i++) {
                mOperations.get(i).redo();
            }
        }

        void destroy() {
            for (int i = mOperations.size() - 1; i >= 0; i--) {
                UndoOwner owner = mOperations.get(i).mOwner;
                owner.mOpCount--;
                if (owner.mOpCount <= 0) {
                    if (owner.mOpCount < 0) {
                        throw new IllegalStateException("Underflow of op count on owner " + owner + " in op " + mOperations.get(i));
                    }
                    mManager.removeOwner(owner);
                }
            }
        }
    }
}

19 Source : FallbackCategoryProvider.java
with Apache License 2.0
from lulululbj

/**
 * Clreplaced that provides fallback values for {@link ApplicationInfo#category}.
 *
 * @hide
 */
public clreplaced FallbackCategoryProvider {

    private static final String TAG = "FallbackCategoryProvider";

    private static final ArrayMap<String, Integer> sFallbacks = new ArrayMap<>();

    public static void loadFallbacks() {
        sFallbacks.clear();
        if (SystemProperties.getBoolean("fw.ignore_fb_categories", false)) {
            Log.d(TAG, "Ignoring fallback categories");
            return;
        }
        final replacedetManager replacedets = new replacedetManager();
        replacedets.addreplacedetPath("/system/framework/framework-res.apk");
        final Resources res = new Resources(replacedets, null, null);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(res.openRawResource(com.android.internal.R.raw.fallback_categories)))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.charAt(0) == '#')
                    continue;
                final String[] split = line.split(",");
                if (split.length == 2) {
                    sFallbacks.put(split[0], Integer.parseInt(split[1]));
                }
            }
            Log.d(TAG, "Found " + sFallbacks.size() + " fallback categories");
        } catch (IOException | NumberFormatException e) {
            Log.w(TAG, "Failed to read fallback categories", e);
        }
    }

    public static int getFallbackCategory(String packageName) {
        return sFallbacks.getOrDefault(packageName, ApplicationInfo.CATEGORY_UNDEFINED);
    }
}

19 Source : UsageStats.java
with Apache License 2.0
from lulululbj

/**
 * Contains usage statistics for an app package for a specific
 * time range.
 */
public final clreplaced UsageStats implements Parcelable {

    /**
     * {@hide}
     */
    public String mPackageName;

    /**
     * {@hide}
     */
    public long mBeginTimeStamp;

    /**
     * {@hide}
     */
    public long mEndTimeStamp;

    /**
     * Last time used by the user with an explicit action (notification, activity launch).
     * {@hide}
     */
    public long mLastTimeUsed;

    /**
     * {@hide}
     */
    public long mTotalTimeInForeground;

    /**
     * {@hide}
     */
    public int mLaunchCount;

    /**
     * {@hide}
     */
    public int mAppLaunchCount;

    /**
     * {@hide}
     */
    public int mLastEvent;

    /**
     * {@hide}
     */
    public ArrayMap<String, ArrayMap<String, Integer>> mChooserCounts;

    /**
     * {@hide}
     */
    public UsageStats() {
    }

    public UsageStats(UsageStats stats) {
        mPackageName = stats.mPackageName;
        mBeginTimeStamp = stats.mBeginTimeStamp;
        mEndTimeStamp = stats.mEndTimeStamp;
        mLastTimeUsed = stats.mLastTimeUsed;
        mTotalTimeInForeground = stats.mTotalTimeInForeground;
        mLaunchCount = stats.mLaunchCount;
        mAppLaunchCount = stats.mAppLaunchCount;
        mLastEvent = stats.mLastEvent;
        mChooserCounts = stats.mChooserCounts;
    }

    /**
     * {@hide}
     */
    public UsageStats getObfuscatedForInstantApp() {
        final UsageStats ret = new UsageStats(this);
        ret.mPackageName = UsageEvents.INSTANT_APP_PACKAGE_NAME;
        return ret;
    }

    public String getPackageName() {
        return mPackageName;
    }

    /**
     * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents,
     * measured in milliseconds since the epoch.
     * <p/>
     * See {@link System#currentTimeMillis()}.
     */
    public long getFirstTimeStamp() {
        return mBeginTimeStamp;
    }

    /**
     * Get the end of the time range this {@link android.app.usage.UsageStats} represents,
     * measured in milliseconds since the epoch.
     * <p/>
     * See {@link System#currentTimeMillis()}.
     */
    public long getLastTimeStamp() {
        return mEndTimeStamp;
    }

    /**
     * Get the last time this package was used, measured in milliseconds since the epoch.
     * <p/>
     * See {@link System#currentTimeMillis()}.
     */
    public long getLastTimeUsed() {
        return mLastTimeUsed;
    }

    /**
     * Get the total time this package spent in the foreground, measured in milliseconds.
     */
    public long getTotalTimeInForeground() {
        return mTotalTimeInForeground;
    }

    /**
     * Returns the number of times the app was launched as an activity from outside of the app.
     * Excludes intra-app activity transitions.
     * @hide
     */
    @SystemApi
    public int getAppLaunchCount() {
        return mAppLaunchCount;
    }

    /**
     * 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);
                }
            }
        }
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mPackageName);
        dest.writeLong(mBeginTimeStamp);
        dest.writeLong(mEndTimeStamp);
        dest.writeLong(mLastTimeUsed);
        dest.writeLong(mTotalTimeInForeground);
        dest.writeInt(mLaunchCount);
        dest.writeInt(mAppLaunchCount);
        dest.writeInt(mLastEvent);
        Bundle allCounts = new Bundle();
        if (mChooserCounts != null) {
            final int chooserCountSize = mChooserCounts.size();
            for (int i = 0; i < chooserCountSize; i++) {
                String action = mChooserCounts.keyAt(i);
                ArrayMap<String, Integer> counts = mChooserCounts.valueAt(i);
                Bundle currentCounts = new Bundle();
                final int annotationSize = counts.size();
                for (int j = 0; j < annotationSize; j++) {
                    currentCounts.putInt(counts.keyAt(j), counts.valueAt(j));
                }
                allCounts.putBundle(action, currentCounts);
            }
        }
        dest.writeBundle(allCounts);
    }

    public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {

        @Override
        public UsageStats createFromParcel(Parcel in) {
            UsageStats stats = new UsageStats();
            stats.mPackageName = in.readString();
            stats.mBeginTimeStamp = in.readLong();
            stats.mEndTimeStamp = in.readLong();
            stats.mLastTimeUsed = in.readLong();
            stats.mTotalTimeInForeground = in.readLong();
            stats.mLaunchCount = in.readInt();
            stats.mAppLaunchCount = in.readInt();
            stats.mLastEvent = in.readInt();
            Bundle allCounts = in.readBundle();
            if (allCounts != null) {
                stats.mChooserCounts = new ArrayMap<>();
                for (String action : allCounts.keySet()) {
                    if (!stats.mChooserCounts.containsKey(action)) {
                        ArrayMap<String, Integer> newCounts = new ArrayMap<>();
                        stats.mChooserCounts.put(action, newCounts);
                    }
                    Bundle currentCounts = allCounts.getBundle(action);
                    if (currentCounts != null) {
                        for (String key : currentCounts.keySet()) {
                            int value = currentCounts.getInt(key);
                            if (value > 0) {
                                stats.mChooserCounts.get(action).put(key, value);
                            }
                        }
                    }
                }
            }
            return stats;
        }

        @Override
        public UsageStats[] newArray(int size) {
            return new UsageStats[size];
        }
    };
}

19 Source : ApplicationLoaders.java
with Apache License 2.0
from lulululbj

/**
 * @hide
 */
public clreplaced ApplicationLoaders {

    public static ApplicationLoaders getDefault() {
        return gApplicationLoaders;
    }

    ClreplacedLoader getClreplacedLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClreplacedLoader parent, String clreplacedLoaderName) {
        // For normal usage the cache key used is the same as the zip path.
        return getClreplacedLoader(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, zip, clreplacedLoaderName);
    }

    private ClreplacedLoader getClreplacedLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClreplacedLoader parent, String cacheKey, String clreplacedLoaderName) {
        /*
         * This is the parent we use if they preplaced "null" in.  In theory
         * this should be the "system" clreplaced loader; in practice we
         * don't use that and can happily (and more efficiently) use the
         * bootstrap clreplaced loader.
         */
        ClreplacedLoader baseParent = ClreplacedLoader.getSystemClreplacedLoader().getParent();
        synchronized (mLoaders) {
            if (parent == null) {
                parent = baseParent;
            }
            /*
             * If we're one step up from the base clreplaced loader, find
             * something in our cache.  Otherwise, we create a whole
             * new ClreplacedLoader for the zip archive.
             */
            if (parent == baseParent) {
                ClreplacedLoader loader = mLoaders.get(cacheKey);
                if (loader != null) {
                    return loader;
                }
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                ClreplacedLoader clreplacedloader = ClreplacedLoaderFactory.createClreplacedLoader(zip, librarySearchPath, libraryPermittedPath, parent, targetSdkVersion, isBundled, clreplacedLoaderName);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setLayerPaths");
                GraphicsEnvironment.getInstance().setLayerPaths(clreplacedloader, librarySearchPath, libraryPermittedPath);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                mLoaders.put(cacheKey, clreplacedloader);
                return clreplacedloader;
            }
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
            ClreplacedLoader loader = ClreplacedLoaderFactory.createClreplacedLoader(zip, null, parent, clreplacedLoaderName);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            return loader;
        }
    }

    /**
     * Creates a clreplacedloader for the WebView APK and places it in the cache of loaders maintained
     * by this clreplaced. This is used in the WebView zygote, where its presence in the cache speeds up
     * startup and enables memory sharing.
     */
    public ClreplacedLoader createAndCacheWebViewClreplacedLoader(String packagePath, String libsPath, String cacheKey) {
        // The correct paths are calculated by WebViewZygote in the system server and preplaceded to
        // us here. We hardcode the other parameters: WebView always targets the current SDK,
        // does not need to use non-public system libraries, and uses the base clreplacedloader as its
        // parent to permit usage of the cache.
        // The cache key is preplaceded separately to enable the stub WebView to be cached under the
        // stub's APK path, when the actual package path is the donor APK.
        return getClreplacedLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, cacheKey, null);
    }

    /**
     * Adds a new path the clreplacedpath of the given loader.
     * @throws IllegalStateException if the provided clreplaced loader is not a {@link PathClreplacedLoader}.
     */
    void addPath(ClreplacedLoader clreplacedLoader, String dexPath) {
        if (!(clreplacedLoader instanceof PathClreplacedLoader)) {
            throw new IllegalStateException("clreplaced loader is not a PathClreplacedLoader");
        }
        final PathClreplacedLoader baseDexClreplacedLoader = (PathClreplacedLoader) clreplacedLoader;
        baseDexClreplacedLoader.addDexPath(dexPath);
    }

    /**
     * @hide
     */
    void addNative(ClreplacedLoader clreplacedLoader, Collection<String> libPaths) {
        if (!(clreplacedLoader instanceof PathClreplacedLoader)) {
            throw new IllegalStateException("clreplaced loader is not a PathClreplacedLoader");
        }
        final PathClreplacedLoader baseDexClreplacedLoader = (PathClreplacedLoader) clreplacedLoader;
        baseDexClreplacedLoader.addNativePath(libPaths);
    }

    private final ArrayMap<String, ClreplacedLoader> mLoaders = new ArrayMap<>();

    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
}

19 Source : AnimationHandler.java
with Apache License 2.0
from lulululbj

/**
 * This custom, static handler handles the timing pulse that is shared by all active
 * ValueAnimators. This approach ensures that the setting of animation values will happen on the
 * same thread that animations start on, and that all animations will share the same times for
 * calculating their values, which makes synchronizing animations possible.
 *
 * The handler uses the Creplacedographer by default for doing periodic callbacks. A custom
 * AnimationFrameCallbackProvider can be set on the handler to provide timing pulse that
 * may be independent of UI frame update. This could be useful in testing.
 *
 * @hide
 */
public clreplaced AnimationHandler {

    /**
     * Internal per-thread collections used to avoid set collisions as animations start and end
     * while being processed.
     * @hide
     */
    private final ArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime = new ArrayMap<>();

    private final ArrayList<AnimationFrameCallback> mAnimationCallbacks = new ArrayList<>();

    private final ArrayList<AnimationFrameCallback> mCommitCallbacks = new ArrayList<>();

    private AnimationFrameCallbackProvider mProvider;

    private final Creplacedographer.FrameCallback mFrameCallback = new Creplacedographer.FrameCallback() {

        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                getProvider().postFrameCallback(this);
            }
        }
    };

    public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();

    private boolean mListDirty = false;

    public static AnimationHandler getInstance() {
        if (sAnimatorHandler.get() == null) {
            sAnimatorHandler.set(new AnimationHandler());
        }
        return sAnimatorHandler.get();
    }

    /**
     * By default, the Creplacedographer is used to provide timing for frame callbacks. A custom
     * provider can be used here to provide different timing pulse.
     */
    public void setProvider(AnimationFrameCallbackProvider provider) {
        if (provider == null) {
            mProvider = new MyFrameCallbackProvider();
        } else {
            mProvider = provider;
        }
    }

    private AnimationFrameCallbackProvider getProvider() {
        if (mProvider == null) {
            mProvider = new MyFrameCallbackProvider();
        }
        return mProvider;
    }

    /**
     * Register to get a callback on the next frame after the delay.
     */
    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        if (mAnimationCallbacks.size() == 0) {
            getProvider().postFrameCallback(mFrameCallback);
        }
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }
        if (delay > 0) {
            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
        }
    }

    /**
     * Register to get a one shot callback for frame commit timing. Frame commit timing is the
     * time *after* traversals are done, as opposed to the animation frame timing, which is
     * before any traversals. This timing can be used to adjust the start time of an animation
     * when expensive traversals create big delta between the animation frame timing and the time
     * that animation is first shown on screen.
     *
     * Note this should only be called when the animation has already registered to receive
     * animation frame callbacks. This callback will be guaranteed to happen *after* the next
     * animation frame callback.
     */
    public void addOneShotCommitCallback(final AnimationFrameCallback callback) {
        if (!mCommitCallbacks.contains(callback)) {
            mCommitCallbacks.add(callback);
        }
    }

    /**
     * Removes the given callback from the list, so it will no longer be called for frame related
     * timing.
     */
    public void removeCallback(AnimationFrameCallback callback) {
        mCommitCallbacks.remove(callback);
        mDelayedCallbackStartTime.remove(callback);
        int id = mAnimationCallbacks.indexOf(callback);
        if (id >= 0) {
            mAnimationCallbacks.set(id, null);
            mListDirty = true;
        }
    }

    private void doAnimationFrame(long frameTime) {
        long currentTime = SystemClock.uptimeMillis();
        final int size = mAnimationCallbacks.size();
        for (int i = 0; i < size; i++) {
            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
            if (callback == null) {
                continue;
            }
            if (isCallbackDue(callback, currentTime)) {
                callback.doAnimationFrame(frameTime);
                if (mCommitCallbacks.contains(callback)) {
                    getProvider().postCommitCallback(new Runnable() {

                        @Override
                        public void run() {
                            commitAnimationFrame(callback, getProvider().getFrameTime());
                        }
                    });
                }
            }
        }
        cleanUpList();
    }

    private void commitAnimationFrame(AnimationFrameCallback callback, long frameTime) {
        if (!mDelayedCallbackStartTime.containsKey(callback) && mCommitCallbacks.contains(callback)) {
            callback.commitAnimationFrame(frameTime);
            mCommitCallbacks.remove(callback);
        }
    }

    /**
     * Remove the callbacks from mDelayedCallbackStartTime once they have preplaceded the initial delay
     * so that they can start getting frame callbacks.
     *
     * @return true if they have preplaceded the initial delay or have no delay, false otherwise.
     */
    private boolean isCallbackDue(AnimationFrameCallback callback, long currentTime) {
        Long startTime = mDelayedCallbackStartTime.get(callback);
        if (startTime == null) {
            return true;
        }
        if (startTime < currentTime) {
            mDelayedCallbackStartTime.remove(callback);
            return true;
        }
        return false;
    }

    /**
     * Return the number of callbacks that have registered for frame callbacks.
     */
    public static int getAnimationCount() {
        AnimationHandler handler = sAnimatorHandler.get();
        if (handler == null) {
            return 0;
        }
        return handler.getCallbackSize();
    }

    public static void setFrameDelay(long delay) {
        getInstance().getProvider().setFrameDelay(delay);
    }

    public static long getFrameDelay() {
        return getInstance().getProvider().getFrameDelay();
    }

    void autoCancelBasedOn(ObjectAnimator objectAnimator) {
        for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
            AnimationFrameCallback cb = mAnimationCallbacks.get(i);
            if (cb == null) {
                continue;
            }
            if (objectAnimator.shouldAutoCancel(cb)) {
                ((Animator) mAnimationCallbacks.get(i)).cancel();
            }
        }
    }

    private void cleanUpList() {
        if (mListDirty) {
            for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
                if (mAnimationCallbacks.get(i) == null) {
                    mAnimationCallbacks.remove(i);
                }
            }
            mListDirty = false;
        }
    }

    private int getCallbackSize() {
        int count = 0;
        int size = mAnimationCallbacks.size();
        for (int i = size - 1; i >= 0; i--) {
            if (mAnimationCallbacks.get(i) != null) {
                count++;
            }
        }
        return count;
    }

    /**
     * Default provider of timing pulse that uses Creplacedographer for frame callbacks.
     */
    private clreplaced MyFrameCallbackProvider implements AnimationFrameCallbackProvider {

        final Creplacedographer mCreplacedographer = Creplacedographer.getInstance();

        @Override
        public void postFrameCallback(Creplacedographer.FrameCallback callback) {
            mCreplacedographer.postFrameCallback(callback);
        }

        @Override
        public void postCommitCallback(Runnable runnable) {
            mCreplacedographer.postCallback(Creplacedographer.CALLBACK_COMMIT, runnable, null);
        }

        @Override
        public long getFrameTime() {
            return mCreplacedographer.getFrameTime();
        }

        @Override
        public long getFrameDelay() {
            return Creplacedographer.getFrameDelay();
        }

        @Override
        public void setFrameDelay(long delay) {
            Creplacedographer.setFrameDelay(delay);
        }
    }

    /**
     * Callbacks that receives notifications for animation timing and frame commit timing.
     */
    interface AnimationFrameCallback {

        /**
         * Run animation based on the frame time.
         * @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time
         *                  base.
         * @return if the animation has finished.
         */
        boolean doAnimationFrame(long frameTime);

        /**
         * This notifies the callback of frame commit time. Frame commit time is the time after
         * traversals happen, as opposed to the normal animation frame time that is before
         * traversals. This is used to compensate expensive traversals that happen as the
         * animation starts. When traversals take a long time to complete, the rendering of the
         * initial frame will be delayed (by a long time). But since the startTime of the
         * animation is set before the traversal, by the time of next frame, a lot of time would
         * have preplaceded since startTime was set, the animation will consequently skip a few frames
         * to respect the new frameTime. By having the commit time, we can adjust the start time to
         * when the first frame was drawn (after any expensive traversals) so that no frames
         * will be skipped.
         *
         * @param frameTime The frame time after traversals happen, if any, in the
         *                  {@link SystemClock#uptimeMillis()} time base.
         */
        void commitAnimationFrame(long frameTime);
    }

    /**
     * The intention for having this interface is to increase the testability of ValueAnimator.
     * Specifically, we can have a custom implementation of the interface below and provide
     * timing pulse without using Creplacedographer. That way we could use any arbitrary interval for
     * our timing pulse in the tests.
     *
     * @hide
     */
    public interface AnimationFrameCallbackProvider {

        void postFrameCallback(Creplacedographer.FrameCallback callback);

        void postCommitCallback(Runnable runnable);

        long getFrameTime();

        long getFrameDelay();

        void setFrameDelay(long delay);
    }
}

19 Source : FingerprintGestureController.java
with Apache License 2.0
from lulululbj

/**
 * An {@link AccessibilityService} can capture gestures performed on a device's fingerprint
 * sensor, as long as the device has a sensor capable of detecting gestures.
 * <p>
 * This capability must be declared by the service as
 * {@link AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}. It also requires
 * the permission {@link android.Manifest.permission#USE_FINGERPRINT}.
 * <p>
 * Because capturing fingerprint gestures may have side effects, services with the capability only
 * capture gestures when {@link AccessibilityServiceInfo#FLAG_REQUEST_FINGERPRINT_GESTURES} is set.
 * <p>
 * <strong>Note: </strong>The fingerprint sensor is used for authentication in critical use cases,
 * so services must carefully design their user's experience when performing gestures on the sensor.
 * When the sensor is in use by an app, for example, when authenticating or enrolling a user,
 * the sensor will not detect gestures. Services need to ensure that users understand when the
 * sensor is in-use for authentication to prevent users from authenticating unintentionally when
 * trying to interact with the service. They can use
 * {@link FingerprintGestureCallback#onGestureDetectionAvailabilityChanged(boolean)} to learn when
 * gesture detection becomes unavailable.
 * <p>
 * Multiple accessibility services may listen for fingerprint gestures simultaneously, so services
 * should provide a way for the user to disable the use of this feature so multiple services don't
 * conflict with each other.
 * <p>
 * {@see android.hardware.fingerprint.FingerprintManager#isHardwareDetected}
 */
public final clreplaced FingerprintGestureController {

    /**
     * Identifier for a swipe right on the fingerprint sensor
     */
    public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 0x00000001;

    /**
     * Identifier for a swipe left on the fingerprint sensor
     */
    public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 0x00000002;

    /**
     * Identifier for a swipe up on the fingerprint sensor
     */
    public static final int FINGERPRINT_GESTURE_SWIPE_UP = 0x00000004;

    /**
     * Identifier for a swipe down on the fingerprint sensor
     */
    public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 0x00000008;

    private static final String LOG_TAG = "FingerprintGestureController";

    private final Object mLock = new Object();

    private final IAccessibilityServiceConnection mAccessibilityServiceConnection;

    private final ArrayMap<FingerprintGestureCallback, Handler> mCallbackHandlerMap = new ArrayMap<>(1);

    /**
     * @param connection The connection to use for system interactions
     * @hide
     */
    @VisibleForTesting
    public FingerprintGestureController(IAccessibilityServiceConnection connection) {
        mAccessibilityServiceConnection = connection;
    }

    /**
     * Gets if the fingerprint sensor's gesture detection is available.
     *
     * @return {@code true} if the sensor's gesture detection is available. {@code false} if it is
     * not currently detecting gestures (for example, if it is enrolling a finger).
     */
    public boolean isGestureDetectionAvailable() {
        try {
            return mAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable();
        } catch (RemoteException re) {
            Log.w(LOG_TAG, "Failed to check if fingerprint gestures are active", re);
            re.rethrowFromSystemServer();
            return false;
        }
    }

    /**
     * Register a callback to be informed of fingerprint sensor gesture events.
     *
     * @param callback The listener to be added.
     * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
     * on the service's main thread.
     */
    public void registerFingerprintGestureCallback(@NonNull FingerprintGestureCallback callback, @Nullable Handler handler) {
        synchronized (mLock) {
            mCallbackHandlerMap.put(callback, handler);
        }
    }

    /**
     * Unregister a listener added with {@link #registerFingerprintGestureCallback}.
     *
     * @param callback The callback to remove. Removing a callback that was never added has no
     * effect.
     */
    public void unregisterFingerprintGestureCallback(FingerprintGestureCallback callback) {
        synchronized (mLock) {
            mCallbackHandlerMap.remove(callback);
        }
    }

    /**
     * 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);
            }
        }
    }

    /**
     * Called when gesture is detected.
     * @hide
     */
    public void onGesture(int gesture) {
        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.onGestureDetected(gesture));
            } else {
                callback.onGestureDetected(gesture);
            }
        }
    }

    /**
     * Clreplaced that is called back when fingerprint gestures are being used for accessibility.
     */
    public abstract static clreplaced FingerprintGestureCallback {

        /**
         * Called when the fingerprint sensor's gesture detection becomes available or unavailable.
         *
         * @param available Whether or not the sensor's gesture detection is now available.
         */
        public void onGestureDetectionAvailabilityChanged(boolean available) {
        }

        /**
         * Called when the fingerprint sensor detects gestures.
         *
         * @param gesture The id of the gesture that was detected. For example,
         * {@link #FINGERPRINT_GESTURE_SWIPE_RIGHT}.
         */
        public void onGestureDetected(int gesture) {
        }
    }
}

19 Source : AccessibilityButtonController.java
with Apache License 2.0
from lulululbj

/**
 * Controller for the accessibility button within the system's navigation area
 * <p>
 * This clreplaced may be used to query the accessibility button's state and register
 * callbacks for interactions with and state changes to the accessibility button when
 * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
 * </p>
 * <p>
 * <strong>Note:</strong> This clreplaced and
 * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} should not be used as
 * the sole means for offering functionality to users via an {@link AccessibilityService}.
 * Some device implementations may choose not to provide a software-rendered system
 * navigation area, making this affordance permanently unavailable.
 * </p>
 * <p>
 * <strong>Note:</strong> On device implementations where the accessibility button is
 * supported, it may not be available at all times, such as when a foreground application uses
 * {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}. A user may also choose to replacedign
 * this button to another accessibility service or feature. In each of these cases, a
 * registered {@link AccessibilityButtonCallback}'s
 * {@link AccessibilityButtonCallback#onAvailabilityChanged(AccessibilityButtonController, boolean)}
 * method will be invoked to provide notifications of changes in the accessibility button's
 * availability to the registering service.
 * </p>
 */
public final clreplaced AccessibilityButtonController {

    private static final String LOG_TAG = "A11yButtonController";

    private final IAccessibilityServiceConnection mServiceConnection;

    private final Object mLock;

    private ArrayMap<AccessibilityButtonCallback, Handler> mCallbacks;

    AccessibilityButtonController(@NonNull IAccessibilityServiceConnection serviceConnection) {
        mServiceConnection = serviceConnection;
        mLock = new Object();
    }

    /**
     * Retrieves whether the accessibility button in the system's navigation area is
     * available to the calling service.
     * <p>
     * <strong>Note:</strong> If the service is not yet connected (e.g.
     * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
     * service has been disconnected, this method will have no effect and return {@code false}.
     * </p>
     *
     * @return {@code true} if the accessibility button in the system's navigation area is
     * available to the calling service, {@code false} otherwise
     */
    public boolean isAccessibilityButtonAvailable() {
        try {
            return mServiceConnection.isAccessibilityButtonAvailable();
        } catch (RemoteException re) {
            Slog.w(LOG_TAG, "Failed to get accessibility button availability.", re);
            re.rethrowFromSystemServer();
            return false;
        }
    }

    /**
     * Registers the provided {@link AccessibilityButtonCallback} for interaction and state
     * changes callbacks related to the accessibility button.
     *
     * @param callback the callback to add, must be non-null
     */
    public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback) {
        registerAccessibilityButtonCallback(callback, new Handler(Looper.getMainLooper()));
    }

    /**
     * Registers the provided {@link AccessibilityButtonCallback} for interaction and state
     * change callbacks related to the accessibility button. The callback will occur on the
     * specified {@link Handler}'s thread, or on the services's main thread if the handler is
     * {@code null}.
     *
     * @param callback the callback to add, must be non-null
     * @param handler the handler on which the callback should execute, must be non-null
     */
    public void registerAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback, @NonNull Handler handler) {
        Preconditions.checkNotNull(callback);
        Preconditions.checkNotNull(handler);
        synchronized (mLock) {
            if (mCallbacks == null) {
                mCallbacks = new ArrayMap<>();
            }
            mCallbacks.put(callback, handler);
        }
    }

    /**
     * Unregisters the provided {@link AccessibilityButtonCallback} for interaction and state
     * change callbacks related to the accessibility button.
     *
     * @param callback the callback to remove, must be non-null
     */
    public void unregisterAccessibilityButtonCallback(@NonNull AccessibilityButtonCallback callback) {
        Preconditions.checkNotNull(callback);
        synchronized (mLock) {
            if (mCallbacks == null) {
                return;
            }
            final int keyIndex = mCallbacks.indexOfKey(callback);
            final boolean hasKey = keyIndex >= 0;
            if (hasKey) {
                mCallbacks.removeAt(keyIndex);
            }
        }
    }

    /**
     * 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));
        }
    }

    /**
     * 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));
        }
    }

    /**
     * Callback for interaction with and changes to state of the accessibility button
     * within the system's navigation area.
     */
    public static abstract clreplaced AccessibilityButtonCallback {

        /**
         * Called when the accessibility button in the system's navigation area is clicked.
         *
         * @param controller the controller used to register for this callback
         */
        public void onClicked(AccessibilityButtonController controller) {
        }

        /**
         * Called when the availability of the accessibility button in the system's
         * navigation area has changed. The accessibility button may become unavailable
         * because the device shopped showing the button, the button was replacedigned to another
         * service, or for other reasons.
         *
         * @param controller the controller used to register for this callback
         * @param available {@code true} if the accessibility button is available to this
         *                  service, {@code false} otherwise
         */
        public void onAvailabilityChanged(AccessibilityButtonController controller, boolean available) {
        }
    }
}

19 Source : TraceHelper.java
with Apache License 2.0
from Launcher3-dev

/**
 * A wrapper around {@link Trace} to allow easier proguarding for production builds.
 * <p>
 * To enable any tracing log, execute the following command:
 * $ adb shell setprop log.tag.TAGNAME VERBOSE
 */
public clreplaced TraceHelper {

    private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD;

    private static final boolean SYSTEM_TRACE = false;

    private static final ArrayMap<String, MutableLong> sUpTimes = ENABLED ? new ArrayMap<>() : null;

    public static void beginSection(String sectionName) {
        if (ENABLED) {
            MutableLong time = sUpTimes.get(sectionName);
            if (time == null) {
                time = new MutableLong(isLoggable(sectionName, VERBOSE) ? 0 : -1);
                sUpTimes.put(sectionName, time);
            }
            if (time.value >= 0) {
                if (SYSTEM_TRACE) {
                    Trace.beginSection(sectionName);
                }
                time.value = SystemClock.uptimeMillis();
            }
        }
    }

    public static void parreplacedionSection(String sectionName, String parreplacedion) {
        if (ENABLED) {
            MutableLong time = sUpTimes.get(sectionName);
            if (time != null && time.value >= 0) {
                if (SYSTEM_TRACE) {
                    Trace.endSection();
                    Trace.beginSection(sectionName);
                }
                long now = SystemClock.uptimeMillis();
                Log.d(sectionName, parreplacedion + " : " + (now - time.value));
                time.value = now;
            }
        }
    }

    public static void endSection(String sectionName) {
        if (ENABLED) {
            endSection(sectionName, "End");
        }
    }

    public static void endSection(String sectionName, String msg) {
        if (ENABLED) {
            MutableLong time = sUpTimes.get(sectionName);
            if (time != null && time.value >= 0) {
                if (SYSTEM_TRACE) {
                    Trace.endSection();
                }
                Log.d(sectionName, msg + " : " + (SystemClock.uptimeMillis() - time.value));
            }
        }
    }
}

19 Source : UninstallOrDeleteUtil.java
with Apache License 2.0
from Launcher3-dev

/**
 * 卸载或者删除应用图标
 */
public final clreplaced UninstallOrDeleteUtil {

    private static final ArrayMap<UserHandle, Boolean> mUninstallDisabledCache = new ArrayMap<>(1);

    /**
     * 是否支持卸载
     *
     * @param launcher Launcher
     * @param info     要卸载应用对象
     *
     * @return
     */
    public static boolean supportsUninstall(Launcher launcher, ItemInfo info) {
        return supportsAccessibilityDrop(launcher, info, getViewUnderDrag(launcher, info));
    }

    private static View getViewUnderDrag(Launcher launcher, ItemInfo info) {
        if (info instanceof LauncherAppWidgetInfo && info.container == CONTAINER_DESKTOP && launcher.getWorkspace().getDragInfo() != null) {
            return launcher.getWorkspace().getDragInfo().cell;
        }
        return null;
    }

    private static boolean supportsAccessibilityDrop(Launcher launcher, ItemInfo info, View view) {
        if (view instanceof AppWidgetHostView) {
            // 插件
            if (getReconfigurableWidgetId(view) != INVALID_APPWIDGET_ID) {
                return true;
            }
            return false;
        }
        Boolean uninstallDisabled = mUninstallDisabledCache.get(info.user);
        if (uninstallDisabled == null) {
            UserManager userManager = (UserManager) launcher.getSystemService(Context.USER_SERVICE);
            Bundle restrictions = userManager.getUserRestrictions(info.user);
            uninstallDisabled = restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false);
            mUninstallDisabledCache.put(info.user, uninstallDisabled);
        }
        // Cancel any pending alarm and set cache expiry after some time
        if (uninstallDisabled) {
            // 不允许卸载
            return false;
        }
        if (info instanceof ItemInfoWithIcon) {
            ItemInfoWithIcon iconInfo = (ItemInfoWithIcon) info;
            if ((iconInfo.runtimeStatusFlags & FLAG_SYSTEM_MASK) != 0) {
                return (iconInfo.runtimeStatusFlags & FLAG_SYSTEM_NO) != 0;
            }
        }
        return getUninstallTarget(launcher, info) != null;
    }

    /**
     * @return the component name that should be uninstalled or null.
     */
    private static ComponentName getUninstallTarget(Launcher launcher, ItemInfo item) {
        Intent intent = null;
        UserHandle user = null;
        if (item != null && item.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
            intent = item.getIntent();
            user = item.user;
        }
        if (intent != null) {
            LauncherActivityInfo info = LauncherAppsCompat.getInstance(launcher).resolveActivity(intent, user);
            if (info != null && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                return info.getComponentName();
            }
        }
        return null;
    }

    /**
     * Verifies that the view is an reconfigurable widget and returns the corresponding widget Id,
     * otherwise return {@code INVALID_APPWIDGET_ID}
     */
    private static int getReconfigurableWidgetId(View view) {
        if (!(view instanceof AppWidgetHostView)) {
            return INVALID_APPWIDGET_ID;
        }
        AppWidgetHostView hostView = (AppWidgetHostView) view;
        AppWidgetProviderInfo widgetInfo = hostView.getAppWidgetInfo();
        if (widgetInfo == null || widgetInfo.configure == null) {
            return INVALID_APPWIDGET_ID;
        }
        if ((LauncherAppWidgetProviderInfo.fromProviderInfo(view.getContext(), widgetInfo).getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) == 0) {
            return INVALID_APPWIDGET_ID;
        }
        return hostView.getAppWidgetId();
    }

    /**
     * Performs the drop action and returns the target component for the dragObject or null if
     * the action was not performed.
     */
    public static ComponentName startUninstallApk(Launcher launcher, ItemInfo info) {
        ComponentName cn = getUninstallTarget(launcher, info);
        if (cn == null) {
            // System applications cannot be installed. For now, show a toast explaining that.
            // We may give them the option of disabling apps this way.
            Toast.makeText(launcher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
            return null;
        }
        try {
            Intent i = Intent.parseUri(launcher.getString(R.string.delete_package_intent), 0).setData(Uri.fromParts("package", cn.getPackageName(), cn.getClreplacedName())).putExtra(Intent.EXTRA_USER, info.user);
            launcher.startActivity(i);
            return cn;
        } catch (URISyntaxException e) {
            XLog.e(XLog.getTag(), XLog.TAG_GU + "Failed to parse intent to start uninstall activity for item=" + info);
            return null;
        }
    }
}

19 Source : SecondaryDropTarget.java
with Apache License 2.0
from Launcher3-dev

/**
 * Drop target which provides a secondary option for an item.
 * For app targets: shows as uninstall
 * For configurable widgets: shows as setup
 */
public clreplaced SecondaryDropTarget extends ButtonDropTarget implements OnAlarmListener {

    private static final String TAG = "SecondaryDropTarget";

    private static final long CACHE_EXPIRE_TIMEOUT = 5000;

    private final ArrayMap<UserHandle, Boolean> mUninstallDisabledCache = new ArrayMap<>(1);

    private final Alarm mCacheExpireAlarm;

    protected int mCurrentAccessibilityAction = -1;

    public SecondaryDropTarget(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SecondaryDropTarget(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mCacheExpireAlarm = new Alarm();
        mCacheExpireAlarm.setOnAlarmListener(this);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        setupUi(UNINSTALL);
    }

    protected void setupUi(int action) {
        if (action == mCurrentAccessibilityAction) {
            return;
        }
        mCurrentAccessibilityAction = action;
        if (action == UNINSTALL) {
            mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
            setDrawable(R.drawable.ic_uninstall_shadow);
            updateText(R.string.uninstall_drop_target_label);
        } else {
            mHoverColor = Themes.getColorAccent(getContext());
            setDrawable(R.drawable.ic_setup_shadow);
            updateText(R.string.gadget_setup_text);
        }
    }

    @Override
    public void onAlarm(Alarm alarm) {
        mUninstallDisabledCache.clear();
    }

    @Override
    public int getAccessibilityAction() {
        return mCurrentAccessibilityAction;
    }

    @Override
    public Target getDropTargetForLogging() {
        Target t = LoggerUtils.newTarget(Target.Type.CONTROL);
        t.controlType = mCurrentAccessibilityAction == UNINSTALL ? ControlType.UNINSTALL_TARGET : ControlType.SETTINGS_BUTTON;
        return t;
    }

    @Override
    protected boolean supportsDrop(ItemInfo info) {
        return supportsAccessibilityDrop(info, getViewUnderDrag(info));
    }

    @Override
    public boolean supportsAccessibilityDrop(ItemInfo info, View view) {
        if (view instanceof AppWidgetHostView) {
            if (getReconfigurableWidgetId(view) != INVALID_APPWIDGET_ID) {
                setupUi(RECONFIGURE);
                return true;
            }
            return false;
        }
        setupUi(UNINSTALL);
        Boolean uninstallDisabled = mUninstallDisabledCache.get(info.user);
        if (uninstallDisabled == null) {
            UserManager userManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
            Bundle restrictions = userManager.getUserRestrictions(info.user);
            uninstallDisabled = restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false);
            mUninstallDisabledCache.put(info.user, uninstallDisabled);
        }
        // Cancel any pending alarm and set cache expiry after some time
        mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
        if (uninstallDisabled) {
            return false;
        }
        if (info instanceof ItemInfoWithIcon) {
            ItemInfoWithIcon iconInfo = (ItemInfoWithIcon) info;
            if ((iconInfo.runtimeStatusFlags & FLAG_SYSTEM_MASK) != 0) {
                return (iconInfo.runtimeStatusFlags & FLAG_SYSTEM_NO) != 0;
            }
        }
        return getUninstallTarget(info) != null;
    }

    /**
     * @return the component name that should be uninstalled or null.
     */
    private ComponentName getUninstallTarget(ItemInfo item) {
        Intent intent = null;
        UserHandle user = null;
        if (item != null && item.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
            intent = item.getIntent();
            user = item.user;
        }
        if (intent != null) {
            LauncherActivityInfo info = LauncherAppsCompat.getInstance(mLauncher).resolveActivity(intent, user);
            if (info != null && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                return info.getComponentName();
            }
        }
        return null;
    }

    @Override
    public void onDrop(DragObject d, DragOptions options) {
        // Defer onComplete
        d.dragSource = new DeferredOnComplete(d.dragSource, getContext());
        super.onDrop(d, options);
    }

    @Override
    public void completeDrop(final DragObject d) {
        ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo);
        if (d.dragSource instanceof DeferredOnComplete) {
            DeferredOnComplete deferred = (DeferredOnComplete) d.dragSource;
            if (target != null) {
                deferred.mPackageName = target.getPackageName();
                mLauncher.setOnResumeCallback(deferred);
            } else {
                deferred.sendFailure();
            }
        }
    }

    private View getViewUnderDrag(ItemInfo info) {
        if (info instanceof LauncherAppWidgetInfo && info.container == CONTAINER_DESKTOP && mLauncher.getWorkspace().getDragInfo() != null) {
            return mLauncher.getWorkspace().getDragInfo().cell;
        }
        return null;
    }

    /**
     * Verifies that the view is an reconfigurable widget and returns the corresponding widget Id,
     * otherwise return {@code INVALID_APPWIDGET_ID}
     */
    private int getReconfigurableWidgetId(View view) {
        if (!(view instanceof AppWidgetHostView)) {
            return INVALID_APPWIDGET_ID;
        }
        AppWidgetHostView hostView = (AppWidgetHostView) view;
        AppWidgetProviderInfo widgetInfo = hostView.getAppWidgetInfo();
        if (widgetInfo == null || widgetInfo.configure == null) {
            return INVALID_APPWIDGET_ID;
        }
        if ((LauncherAppWidgetProviderInfo.fromProviderInfo(getContext(), widgetInfo).getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) == 0) {
            return INVALID_APPWIDGET_ID;
        }
        return hostView.getAppWidgetId();
    }

    /**
     * Performs the drop action and returns the target component for the dragObject or null if
     * the action was not performed.
     */
    protected ComponentName performDropAction(View view, ItemInfo info) {
        if (mCurrentAccessibilityAction == RECONFIGURE) {
            int widgetId = getReconfigurableWidgetId(view);
            if (widgetId != INVALID_APPWIDGET_ID) {
                mLauncher.getAppWidgetHost().startConfigActivity(mLauncher, widgetId, -1);
            }
            return null;
        }
        // else: mCurrentAccessibilityAction == UNINSTALL
        ComponentName cn = getUninstallTarget(info);
        if (cn == null) {
            // System applications cannot be installed. For now, show a toast explaining that.
            // We may give them the option of disabling apps this way.
            Toast.makeText(mLauncher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
            return null;
        }
        try {
            Intent i = Intent.parseUri(mLauncher.getString(R.string.delete_package_intent), 0).setData(Uri.fromParts("package", cn.getPackageName(), cn.getClreplacedName())).putExtra(Intent.EXTRA_USER, info.user);
            mLauncher.startActivity(i);
            return cn;
        } catch (URISyntaxException e) {
            Log.e(TAG, "Failed to parse intent to start uninstall activity for item=" + info);
            return null;
        }
    }

    @Override
    public void onAccessibilityDrop(View view, ItemInfo item) {
        performDropAction(view, item);
    }

    /**
     * A wrapper around {@link DragSource} which delays the {@link #onDropCompleted} action until
     * {@link #onLauncherResume}
     */
    private clreplaced DeferredOnComplete implements DragSource, OnResumeCallback {

        private final DragSource mOriginal;

        private final Context mContext;

        private String mPackageName;

        private DragObject mDragObject;

        public DeferredOnComplete(DragSource original, Context context) {
            mOriginal = original;
            mContext = context;
        }

        @Override
        public void onDropCompleted(View target, DragObject d, boolean success) {
            mDragObject = d;
        }

        @Override
        public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
            mOriginal.fillInLogContainerData(v, info, target, targetParent);
        }

        @Override
        public void onLauncherResume() {
            // We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well.
            if (LauncherAppsCompat.getInstance(mContext).getApplicationInfo(mPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, mDragObject.dragInfo.user) == null) {
                mDragObject.dragSource = mOriginal;
                mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
            } else {
                sendFailure();
            }
        }

        public void sendFailure() {
            mDragObject.dragSource = mOriginal;
            mDragObject.cancelled = true;
            mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, false);
        }
    }
}

19 Source : LoggerUtils.java
with Apache License 2.0
from Launcher3-dev

/**
 * Helper methods for logging.
 */
public clreplaced LoggerUtils {

    private static final ArrayMap<Clreplaced, SparseArray<String>> sNameCache = new ArrayMap<>();

    private static final String UNKNOWN = "UNKNOWN";

    public static String getFieldName(int value, Clreplaced c) {
        SparseArray<String> cache;
        synchronized (sNameCache) {
            cache = sNameCache.get(c);
            if (cache == null) {
                cache = new SparseArray<>();
                for (Field f : c.getDeclaredFields()) {
                    if (f.getType() == int.clreplaced && Modifier.isStatic(f.getModifiers())) {
                        try {
                            f.setAccessible(true);
                            cache.put(f.getInt(null), f.getName());
                        } catch (IllegalAccessException e) {
                        // Ignore
                        }
                    }
                }
                sNameCache.put(c, cache);
            }
        }
        String result = cache.get(value);
        return result != null ? result : UNKNOWN;
    }

    public static String getActionStr(Action action) {
        String str = "";
        switch(action.type) {
            case Action.Type.TOUCH:
                str += getFieldName(action.touch, Action.Touch.clreplaced);
                if (action.touch == Action.Touch.SWIPE || action.touch == Action.Touch.FLING) {
                    str += " direction=" + getFieldName(action.dir, Action.Direction.clreplaced);
                }
                return str;
            case Action.Type.COMMAND:
                return getFieldName(action.command, Action.Command.clreplaced);
            default:
                return getFieldName(action.type, Action.Type.clreplaced);
        }
    }

    public static String getTargetStr(Target t) {
        if (t == null) {
            return "";
        }
        String str = "";
        switch(t.type) {
            case Target.Type.ITEM:
                str = gereplacedemStr(t);
                break;
            case Target.Type.CONTROL:
                str = getFieldName(t.controlType, ControlType.clreplaced);
                break;
            case Target.Type.CONTAINER:
                str = getFieldName(t.containerType, ContainerType.clreplaced);
                if (t.containerType == ContainerType.WORKSPACE || t.containerType == ContainerType.HOTSEAT) {
                    str += " id=" + t.pageIndex;
                } else if (t.containerType == ContainerType.FOLDER) {
                    str += " grid(" + t.gridX + "," + t.gridY + ")";
                }
                break;
            default:
                str += "UNKNOWN TARGET TYPE";
        }
        if (t.tipType != TipType.DEFAULT_NONE) {
            str += " " + getFieldName(t.tipType, TipType.clreplaced);
        }
        return str;
    }

    private static String gereplacedemStr(Target t) {
        String typeStr = getFieldName(t.itemType, ItemType.clreplaced);
        if (t.packageNameHash != 0) {
            typeStr += ", packageHash=" + t.packageNameHash;
        }
        if (t.componentHash != 0) {
            typeStr += ", componentHash=" + t.componentHash;
        }
        if (t.intentHash != 0) {
            typeStr += ", intentHash=" + t.intentHash;
        }
        if ((t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0) && t.itemType != ItemType.TASK) {
            typeStr += ", predictiveRank=" + t.predictedRank + ", grid(" + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY + "), pageIdx=" + t.pageIndex;
        }
        if (t.itemType == ItemType.TASK) {
            typeStr += ", pageIdx=" + t.pageIndex;
        }
        return typeStr;
    }

    public static Target newItemTarget(int itemType) {
        Target t = newTarget(Target.Type.ITEM);
        t.itemType = itemType;
        return t;
    }

    public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) {
        return (v.getTag() instanceof ItemInfo) ? newItemTarget((ItemInfo) v.getTag(), instantAppResolver) : newTarget(Target.Type.ITEM);
    }

    public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) {
        Target t = newTarget(Target.Type.ITEM);
        switch(info.itemType) {
            case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                t.itemType = (instantAppResolver != null && info instanceof ShortcutInfo && instantAppResolver.isInstantApp(((ShortcutInfo) info))) ? ItemType.WEB_APP : ItemType.APP_ICON;
                // Never replacedigned
                t.predictedRank = -100;
                break;
            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                t.itemType = ItemType.SHORTCUT;
                break;
            case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                t.itemType = ItemType.FOLDER_ICON;
                break;
            case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
                t.itemType = ItemType.WIDGET;
                break;
            case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                t.itemType = ItemType.DEEPSHORTCUT;
                break;
        }
        return t;
    }

    public static Target newDropTarget(View v) {
        if (!(v instanceof ButtonDropTarget)) {
            return newTarget(Target.Type.CONTAINER);
        }
        if (v instanceof ButtonDropTarget) {
            return ((ButtonDropTarget) v).getDropTargetForLogging();
        }
        return newTarget(Target.Type.CONTROL);
    }

    public static Target newTarget(int targetType, TargetExtension extension) {
        Target t = new Target();
        t.type = targetType;
        t.extension = extension;
        return t;
    }

    public static Target newTarget(int targetType) {
        Target t = new Target();
        t.type = targetType;
        return t;
    }

    public static Target newControlTarget(int controlType) {
        Target t = newTarget(Target.Type.CONTROL);
        t.controlType = controlType;
        return t;
    }

    public static Target newContainerTarget(int containerType) {
        Target t = newTarget(Target.Type.CONTAINER);
        t.containerType = containerType;
        return t;
    }

    public static Action newAction(int type) {
        Action a = new Action();
        a.type = type;
        return a;
    }

    public static Action newCommandAction(int command) {
        Action a = newAction(Action.Type.COMMAND);
        a.command = command;
        return a;
    }

    public static Action newTouchAction(int touch) {
        Action a = newAction(Action.Type.TOUCH);
        a.touch = touch;
        return a;
    }

    public static LauncherEvent newLauncherEvent(Action action, Target... srcTargets) {
        LauncherEvent event = new LauncherEvent();
        event.srcTarget = srcTargets;
        event.action = action;
        return event;
    }
}

19 Source : AutoInstallsLayout.java
with Apache License 2.0
from Launcher3-dev

// 添加各个解析器
protected ArrayMap<String, TagParser> getLayoutElementsMap() {
    ArrayMap<String, TagParser> parsers = new ArrayMap<>();
    // app
    parsers.put(TAG_APP_ICON, new AppShortcutParser());
    parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
    // Folder
    parsers.put(TAG_FOLDER, new FolderParser());
    // Widget
    parsers.put(TAG_APPWIDGET, new PendingWidgetParser());
    // Shortcut
    parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
    return parsers;
}

19 Source : AutoInstallsLayout.java
with Apache License 2.0
from Launcher3-dev

protected ArrayMap<String, TagParser> getFolderElementsMap() {
    ArrayMap<String, TagParser> parsers = new ArrayMap<>();
    parsers.put(TAG_APP_ICON, new AppShortcutParser());
    parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser());
    parsers.put(TAG_SHORTCUT, new ShortcutParser(mSourceRes));
    return parsers;
}

19 Source : RemoteCallbackMap.java
with Apache License 2.0
from Jween

public clreplaced RemoteCallbackMap<E extends IInterface> {

    private static final String TAG = "SchizoCallbackList";

    private final ArrayMap<IBinder, DeathCallback> callbacks = new ArrayMap<>();

    private final ArrayMap<Object, IBinder> cookies = new ArrayMap<>();

    private boolean isKilled = false;

    private final clreplaced DeathCallback implements IBinder.DeathRecipient {

        final E callback;

        final Object cookie;

        DeathCallback(E callback, Object cookie) {
            this.callback = callback;
            this.cookie = cookie;
        }

        public void binderDied() {
            synchronized (callbacks) {
                callbacks.remove(callback.asBinder());
                cookies.remove(cookie);
            }
            onCallbackDied(callback, cookie);
        }
    }

    public boolean register(E callback, Object cookie) {
        synchronized (callbacks) {
            if (isKilled) {
                return false;
            }
            IBinder binder = callback.asBinder();
            try {
                DeathCallback cb = new DeathCallback(callback, cookie);
                binder.linkToDeath(cb, 0);
                callbacks.put(binder, cb);
                cookies.put(cookie, binder);
                return true;
            } catch (RemoteException e) {
                return false;
            }
        }
    }

    public E getCallback(Object cookie) {
        synchronized (callbacks) {
            if (isKilled) {
                return null;
            }
            IBinder binder = cookies.get(cookie);
            if (binder != null) {
                DeathCallback cb = callbacks.get(binder);
                if (cb != null) {
                    return cb.callback;
                }
            }
            return null;
        }
    }

    public boolean isRegistered(Object cookie) {
        return getCallback(cookie) != null;
    }

    /**
     * Remove from the list a callback that was previously added with
     * {@link #register}.  This uses the
     * {@link IInterface#asBinder callback.asBinder()} object to correctly
     * find the previous registration.
     * Registrations are not counted; a single unregister call will remove
     * a callback after any number calls to {@link #register} for it.
     *
     * @param callback The callback to be removed from the list.  Preplaceding
     * null here will cause a NullPointerException, so you will generally want
     * to check for null before calling.
     *
     * @return Returns true if the callback was found and unregistered.  Returns
     * false if the given callback was not found on the list.
     *
     * @see #register
     */
    public boolean unregister(E callback) {
        synchronized (callbacks) {
            DeathCallback cb = callbacks.remove(callback.asBinder());
            if (cb != null) {
                cookies.remove(cb.cookie);
                cb.callback.asBinder().unlinkToDeath(cb, 0);
                return true;
            }
            return false;
        }
    }

    /**
     * Disable this callback list.  All registered callbacks are unregistered,
     * and the list is disabled so that future calls to {@link #register} will
     * fail.  This should be used when a Service is stopping, to prevent clients
     * from registering callbacks after it is stopped.
     *
     * @see #register
     */
    public void kill() {
        synchronized (callbacks) {
            for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
                DeathCallback cb = callbacks.valueAt(cbi);
                cb.callback.asBinder().unlinkToDeath(cb, 0);
            }
            callbacks.clear();
            cookies.clear();
            isKilled = true;
        }
    }

    public void onCallbackDied(E callback, Object cookie) {
    }

    public int getRegisteredCallbackCount() {
        synchronized (callbacks) {
            if (isKilled) {
                return 0;
            }
            return callbacks.size();
        }
    }
}

19 Source : FontCache.java
with GNU General Public License v3.0
from Cocos-BCX

public clreplaced FontCache {

    private static ArrayMap<String, Typeface> fontCache = new ArrayMap<String, Typeface>();

    public static Typeface getTypeface(String fontName, Context context) {
        Typeface tf = fontCache.get(fontName);
        if (tf == null) {
            try {
                tf = Typeface.createFromreplacedet(context.getreplacedets(), fontName);
            } catch (Exception e) {
                return null;
            }
            fontCache.put(fontName, tf);
        }
        return tf;
    }
}

19 Source : ApplicationLoaders.java
with MIT License
from BaoBaoJianqiang

/**
 * @hide
 */
public clreplaced ApplicationLoaders {

    public static ApplicationLoaders getDefault() {
        return gApplicationLoaders;
    }

    ClreplacedLoader getClreplacedLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClreplacedLoader parent, String clreplacedLoaderName) {
        // For normal usage the cache key used is the same as the zip path.
        return getClreplacedLoader(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, zip, clreplacedLoaderName);
    }

    private ClreplacedLoader getClreplacedLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClreplacedLoader parent, String cacheKey, String clreplacedLoaderName) {
        /*
         * This is the parent we use if they preplaced "null" in.  In theory
         * this should be the "system" clreplaced loader; in practice we
         * don't use that and can happily (and more efficiently) use the
         * bootstrap clreplaced loader.
         */
        ClreplacedLoader baseParent = ClreplacedLoader.getSystemClreplacedLoader().getParent();
        synchronized (mLoaders) {
            if (parent == null) {
                parent = baseParent;
            }
            /*
             * If we're one step up from the base clreplaced loader, find
             * something in our cache.  Otherwise, we create a whole
             * new ClreplacedLoader for the zip archive.
             */
            if (parent == baseParent) {
                ClreplacedLoader loader = mLoaders.get(cacheKey);
                if (loader != null) {
                    return loader;
                }
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                ClreplacedLoader clreplacedloader = ClreplacedLoaderFactory.createClreplacedLoader(zip, librarySearchPath, libraryPermittedPath, parent, targetSdkVersion, isBundled, clreplacedLoaderName);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setupVulkanLayerPath");
                setupVulkanLayerPath(clreplacedloader, librarySearchPath);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                mLoaders.put(cacheKey, clreplacedloader);
                return clreplacedloader;
            }
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
            ClreplacedLoader loader = ClreplacedLoaderFactory.createClreplacedLoader(zip, null, parent, clreplacedLoaderName);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            return loader;
        }
    }

    /**
     * Creates a clreplacedloader for the WebView APK and places it in the cache of loaders maintained
     * by this clreplaced. This is used in the WebView zygote, where its presence in the cache speeds up
     * startup and enables memory sharing.
     */
    public ClreplacedLoader createAndCacheWebViewClreplacedLoader(String packagePath, String libsPath, String cacheKey) {
        // The correct paths are calculated by WebViewZygote in the system server and preplaceded to
        // us here. We hardcode the other parameters: WebView always targets the current SDK,
        // does not need to use non-public system libraries, and uses the base clreplacedloader as its
        // parent to permit usage of the cache.
        // The cache key is preplaceded separately to enable the stub WebView to be cached under the
        // stub's APK path, when the actual package path is the donor APK.
        return getClreplacedLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, cacheKey, null);
    }

    private static native void setupVulkanLayerPath(ClreplacedLoader clreplacedLoader, String librarySearchPath);

    /**
     * Adds a new path the clreplacedpath of the given loader.
     * @throws IllegalStateException if the provided clreplaced loader is not a {@link PathClreplacedLoader}.
     */
    void addPath(ClreplacedLoader clreplacedLoader, String dexPath) {
        if (!(clreplacedLoader instanceof PathClreplacedLoader)) {
            throw new IllegalStateException("clreplaced loader is not a PathClreplacedLoader");
        }
        final PathClreplacedLoader baseDexClreplacedLoader = (PathClreplacedLoader) clreplacedLoader;
        baseDexClreplacedLoader.addDexPath(dexPath);
    }

    private final ArrayMap<String, ClreplacedLoader> mLoaders = new ArrayMap<>();

    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
}

19 Source : ApplicationLoaders.java
with MIT License
from BaoBaoJianqiang

/**
 * @hide
 */
public clreplaced ApplicationLoaders {

    public static ApplicationLoaders getDefault() {
        return gApplicationLoaders;
    }

    ClreplacedLoader getClreplacedLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClreplacedLoader parent) {
        // For normal usage the cache key used is the same as the zip path.
        return getClreplacedLoader(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, zip);
    }

    private ClreplacedLoader getClreplacedLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClreplacedLoader parent, String cacheKey) {
        /*
         * This is the parent we use if they preplaced "null" in.  In theory
         * this should be the "system" clreplaced loader; in practice we
         * don't use that and can happily (and more efficiently) use the
         * bootstrap clreplaced loader.
         */
        ClreplacedLoader baseParent = ClreplacedLoader.getSystemClreplacedLoader().getParent();
        synchronized (mLoaders) {
            if (parent == null) {
                parent = baseParent;
            }
            /*
             * If we're one step up from the base clreplaced loader, find
             * something in our cache.  Otherwise, we create a whole
             * new ClreplacedLoader for the zip archive.
             */
            if (parent == baseParent) {
                ClreplacedLoader loader = mLoaders.get(cacheKey);
                if (loader != null) {
                    return loader;
                }
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                PathClreplacedLoader pathClreplacedloader = PathClreplacedLoaderFactory.createClreplacedLoader(zip, librarySearchPath, libraryPermittedPath, parent, targetSdkVersion, isBundled);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setupVulkanLayerPath");
                setupVulkanLayerPath(pathClreplacedloader, librarySearchPath);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                mLoaders.put(cacheKey, pathClreplacedloader);
                return pathClreplacedloader;
            }
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
            PathClreplacedLoader pathClreplacedloader = new PathClreplacedLoader(zip, parent);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            return pathClreplacedloader;
        }
    }

    /**
     * Creates a clreplacedloader for the WebView APK and places it in the cache of loaders maintained
     * by this clreplaced. This is used in the WebView zygote, where its presence in the cache speeds up
     * startup and enables memory sharing.
     */
    public ClreplacedLoader createAndCacheWebViewClreplacedLoader(String packagePath, String libsPath, String cacheKey) {
        // The correct paths are calculated by WebViewZygote in the system server and preplaceded to
        // us here. We hardcode the other parameters: WebView always targets the current SDK,
        // does not need to use non-public system libraries, and uses the base clreplacedloader as its
        // parent to permit usage of the cache.
        // The cache key is preplaceded separately to enable the stub WebView to be cached under the
        // stub's APK path, when the actual package path is the donor APK.
        return getClreplacedLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, cacheKey);
    }

    private static native void setupVulkanLayerPath(ClreplacedLoader clreplacedLoader, String librarySearchPath);

    /**
     * Adds a new path the clreplacedpath of the given loader.
     * @throws IllegalStateException if the provided clreplaced loader is not a {@link PathClreplacedLoader}.
     */
    void addPath(ClreplacedLoader clreplacedLoader, String dexPath) {
        if (!(clreplacedLoader instanceof PathClreplacedLoader)) {
            throw new IllegalStateException("clreplaced loader is not a PathClreplacedLoader");
        }
        final PathClreplacedLoader baseDexClreplacedLoader = (PathClreplacedLoader) clreplacedLoader;
        baseDexClreplacedLoader.addDexPath(dexPath);
    }

    private final ArrayMap<String, ClreplacedLoader> mLoaders = new ArrayMap<String, ClreplacedLoader>();

    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
}

19 Source : ApplicationLoaders.java
with MIT License
from BaoBaoJianqiang

clreplaced ApplicationLoaders {

    public static ApplicationLoaders getDefault() {
        return gApplicationLoaders;
    }

    public ClreplacedLoader getClreplacedLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClreplacedLoader parent) {
        /*
         * This is the parent we use if they preplaced "null" in.  In theory
         * this should be the "system" clreplaced loader; in practice we
         * don't use that and can happily (and more efficiently) use the
         * bootstrap clreplaced loader.
         */
        ClreplacedLoader baseParent = ClreplacedLoader.getSystemClreplacedLoader().getParent();
        synchronized (mLoaders) {
            if (parent == null) {
                parent = baseParent;
            }
            /*
             * If we're one step up from the base clreplaced loader, find
             * something in our cache.  Otherwise, we create a whole
             * new ClreplacedLoader for the zip archive.
             */
            if (parent == baseParent) {
                ClreplacedLoader loader = mLoaders.get(zip);
                if (loader != null) {
                    return loader;
                }
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                PathClreplacedLoader pathClreplacedloader = PathClreplacedLoaderFactory.createClreplacedLoader(zip, librarySearchPath, libraryPermittedPath, parent, targetSdkVersion, isBundled);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setupVulkanLayerPath");
                setupVulkanLayerPath(pathClreplacedloader, librarySearchPath);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                mLoaders.put(zip, pathClreplacedloader);
                return pathClreplacedloader;
            }
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
            PathClreplacedLoader pathClreplacedloader = new PathClreplacedLoader(zip, parent);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            return pathClreplacedloader;
        }
    }

    private static native void setupVulkanLayerPath(ClreplacedLoader clreplacedLoader, String librarySearchPath);

    /**
     * Adds a new path the clreplacedpath of the given loader.
     * @throws IllegalStateException if the provided clreplaced loader is not a {@link PathClreplacedLoader}.
     */
    void addPath(ClreplacedLoader clreplacedLoader, String dexPath) {
        if (!(clreplacedLoader instanceof PathClreplacedLoader)) {
            throw new IllegalStateException("clreplaced loader is not a PathClreplacedLoader");
        }
        final PathClreplacedLoader baseDexClreplacedLoader = (PathClreplacedLoader) clreplacedLoader;
        baseDexClreplacedLoader.addDexPath(dexPath);
    }

    private final ArrayMap<String, ClreplacedLoader> mLoaders = new ArrayMap<String, ClreplacedLoader>();

    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
}

19 Source : ApplicationLoaders.java
with MIT License
from BaoBaoJianqiang

clreplaced ApplicationLoaders {

    public static ApplicationLoaders getDefault() {
        return gApplicationLoaders;
    }

    public ClreplacedLoader getClreplacedLoader(String zip, String libPath, ClreplacedLoader parent) {
        /*
         * This is the parent we use if they preplaced "null" in.  In theory
         * this should be the "system" clreplaced loader; in practice we
         * don't use that and can happily (and more efficiently) use the
         * bootstrap clreplaced loader.
         */
        ClreplacedLoader baseParent = ClreplacedLoader.getSystemClreplacedLoader().getParent();
        synchronized (mLoaders) {
            if (parent == null) {
                parent = baseParent;
            }
            /*
             * If we're one step up from the base clreplaced loader, find
             * something in our cache.  Otherwise, we create a whole
             * new ClreplacedLoader for the zip archive.
             */
            if (parent == baseParent) {
                ClreplacedLoader loader = mLoaders.get(zip);
                if (loader != null) {
                    return loader;
                }
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                PathClreplacedLoader pathClreplacedloader = new PathClreplacedLoader(zip, libPath, parent);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                mLoaders.put(zip, pathClreplacedloader);
                return pathClreplacedloader;
            }
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
            PathClreplacedLoader pathClreplacedloader = new PathClreplacedLoader(zip, parent);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            return pathClreplacedloader;
        }
    }

    private final ArrayMap<String, ClreplacedLoader> mLoaders = new ArrayMap<String, ClreplacedLoader>();

    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
}

19 Source : Bundler.java
with Apache License 2.0
from androidx

private static Map<Integer, String> initBundledTypeNames() {
    ArrayMap<Integer, String> map = new ArrayMap<>();
    map.put(PRIMITIVE, "primitive");
    map.put(IINTERFACE, "iInterface");
    map.put(IBINDER, "iBinder");
    map.put(MAP, "map");
    map.put(SET, "set");
    map.put(LIST, "list");
    map.put(OBJECT, "object");
    map.put(IMAGE, "image");
    return map;
}

19 Source : Bundler.java
with Apache License 2.0
from androidx

private static Map<Clreplaced<?>, String> initUnobfuscatedTypeNames() {
    // Init LUT for know type names, used for logging without proguard obfuscation.
    ArrayMap<Clreplaced<?>, String> map = new ArrayMap<>();
    map.put(Boolean.clreplaced, "bool");
    map.put(Byte.clreplaced, "byte");
    map.put(Short.clreplaced, "short");
    map.put(Integer.clreplaced, "int");
    map.put(Long.clreplaced, "long");
    map.put(Double.clreplaced, "double");
    map.put(Float.clreplaced, "float");
    map.put(String.clreplaced, "string");
    map.put(Parcelable.clreplaced, "parcelable");
    map.put(Map.clreplaced, "map");
    map.put(List.clreplaced, "list");
    map.put(IconCompat.clreplaced, "image");
    return map;
}

19 Source : LocalServices.java
with Apache License 2.0
from androidmalin

/**
 * This clreplaced is used in a similar way as ServiceManager, except the services registered here
 * are not Binder objects and are only available in the same process.
 *
 * Once all services are converted to the SystemService interface, this clreplaced can be absorbed
 * into SystemServiceManager.
 *
 * {@hide}
 */
public final clreplaced LocalServices {

    private LocalServices() {
    }

    private static final ArrayMap<Clreplaced<?>, Object> sLocalServiceObjects = new ArrayMap<Clreplaced<?>, Object>();

    /**
     * Returns a local service instance that implements the specified interface.
     *
     * @param type The type of service.
     * @return The service object.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getService(Clreplaced<T> type) {
        synchronized (sLocalServiceObjects) {
            return (T) sLocalServiceObjects.get(type);
        }
    }

    /**
     * Adds a service instance of the specified interface to the global registry of local services.
     */
    public static <T> void addService(Clreplaced<T> type, T service) {
        synchronized (sLocalServiceObjects) {
            if (sLocalServiceObjects.containsKey(type)) {
                throw new IllegalStateException("Overriding service registration");
            }
            sLocalServiceObjects.put(type, service);
        }
    }

    /**
     * Remove a service instance, must be only used in tests.
     */
    @VisibleForTesting
    public static <T> void removeServiceForTest(Clreplaced<T> type) {
        synchronized (sLocalServiceObjects) {
            sLocalServiceObjects.remove(type);
        }
    }
}

18 Source : UserSerialNumberCache.java
with Apache License 2.0
from zhanghai

clreplaced UserSerialNumberCache {

    private static final long CACHE_MILLIS = 1000;

    @NonNull
    private static final ArrayMap<UserHandle, long[]> sCache = new ArrayMap<>();

    UserSerialNumberCache() {
    }

    public static long getSerialNumber(@NonNull UserHandle user, @NonNull Context context) {
        synchronized (sCache) {
            long[] serialNumberAndTime = sCache.get(user);
            if (serialNumberAndTime == null) {
                serialNumberAndTime = new long[2];
                sCache.put(user, serialNumberAndTime);
            }
            long time = System.currentTimeMillis();
            if (serialNumberAndTime[1] + CACHE_MILLIS <= time) {
                UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
                serialNumberAndTime[0] = userManager.getSerialNumberForUser(user);
                serialNumberAndTime[1] = time;
            }
            return serialNumberAndTime[0];
        }
    }
}

18 Source : XmlUtils.java
with Apache License 2.0
from woesss

/**
 * Like {@link #readThisMapXml}, but returns an ArrayMap instead of HashMap.
 *
 * @hide
 */
public static ArrayMap<String, ?> readThisArrayMapXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback) throws XmlPullParserException, java.io.IOException {
    ArrayMap<String, Object> map = new ArrayMap<>();
    int eventType = parser.getEventType();
    do {
        if (eventType == parser.START_TAG) {
            Object val = readThisValueXml(parser, name, callback, true);
            map.put(name[0], val);
        } else if (eventType == parser.END_TAG) {
            if (parser.getName().equals(endTag)) {
                return map;
            }
            throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName());
        }
        eventType = parser.next();
    } while (eventType != parser.END_DOreplacedENT);
    throw new XmlPullParserException("Doreplacedent ended before " + endTag + " end tag");
}

18 Source : PauseLessAnimator.java
with Apache License 2.0
from vpaliy

public clreplaced PauseLessAnimator extends Animator {

    private final Animator mAnimator;

    private final ArrayMap<AnimatorListener, AnimatorListener> mListeners = new ArrayMap<>();

    public PauseLessAnimator(Animator animator) {
        mAnimator = animator;
    }

    @Override
    public void addListener(AnimatorListener listener) {
        AnimatorListener wrapper = new AnimatorListenerWrapper(this, listener);
        if (!mListeners.containsKey(listener)) {
            mListeners.put(listener, wrapper);
            mAnimator.addListener(wrapper);
        }
    }

    @Override
    public void cancel() {
        mAnimator.cancel();
    }

    @Override
    public void end() {
        mAnimator.end();
    }

    @Override
    public long getDuration() {
        return mAnimator.getDuration();
    }

    @Override
    public TimeInterpolator getInterpolator() {
        return mAnimator.getInterpolator();
    }

    @Override
    public ArrayList<AnimatorListener> getListeners() {
        return new ArrayList<>(mListeners.keySet());
    }

    @Override
    public long getStartDelay() {
        return mAnimator.getStartDelay();
    }

    @Override
    public boolean isPaused() {
        return mAnimator.isPaused();
    }

    @Override
    public boolean isRunning() {
        return mAnimator.isRunning();
    }

    @Override
    public boolean isStarted() {
        return mAnimator.isStarted();
    }

    @Override
    public void removeAllListeners() {
        super.removeAllListeners();
        mListeners.clear();
        mAnimator.removeAllListeners();
    }

    @Override
    public void removeListener(AnimatorListener listener) {
        AnimatorListener wrapper = mListeners.get(listener);
        if (wrapper != null) {
            mListeners.remove(listener);
            mAnimator.removeListener(wrapper);
        }
    }

    /* We don't want to override pause or resume methods
     * because we don't want them to affect mAnimator.
    public void pause();
    public void resume();
    public void addPauseListener(AnimatorPauseListener listener);
    public void removePauseListener(AnimatorPauseListener listener);
     */
    @Override
    public Animator setDuration(long durationMS) {
        mAnimator.setDuration(durationMS);
        return this;
    }

    @Override
    public void setInterpolator(TimeInterpolator timeInterpolator) {
        mAnimator.setInterpolator(timeInterpolator);
    }

    @Override
    public void setStartDelay(long delayMS) {
        mAnimator.setStartDelay(delayMS);
    }

    @Override
    public void setTarget(Object target) {
        mAnimator.setTarget(target);
    }

    @Override
    public void setupEndValues() {
        mAnimator.setupEndValues();
    }

    @Override
    public void setupStartValues() {
        mAnimator.setupStartValues();
    }

    @Override
    public void start() {
        mAnimator.start();
    }

    private static clreplaced AnimatorListenerWrapper implements Animator.AnimatorListener {

        private final Animator mAnimator;

        private final Animator.AnimatorListener mListener;

        public AnimatorListenerWrapper(Animator animator, Animator.AnimatorListener listener) {
            mAnimator = animator;
            mListener = listener;
        }

        @Override
        public void onAnimationStart(Animator animator) {
            mListener.onAnimationStart(mAnimator);
        }

        @Override
        public void onAnimationEnd(Animator animator) {
            mListener.onAnimationEnd(mAnimator);
        }

        @Override
        public void onAnimationCancel(Animator animator) {
            mListener.onAnimationCancel(mAnimator);
        }

        @Override
        public void onAnimationRepeat(Animator animator) {
            mListener.onAnimationRepeat(mAnimator);
        }
    }
}

18 Source : XmlUtils.java
with Apache License 2.0
from nikita36078

/**
 * Like {@link #readThisMapXml}, but returns an ArrayMap instead of HashMap.
 *
 * @hide
 */
public static final ArrayMap<String, ?> readThisArrayMapXml(XmlPullParser parser, String endTag, String[] name, ReadMapCallback callback) throws XmlPullParserException, java.io.IOException {
    ArrayMap<String, Object> map = new ArrayMap<>();
    int eventType = parser.getEventType();
    do {
        if (eventType == parser.START_TAG) {
            Object val = readThisValueXml(parser, name, callback, true);
            map.put(name[0], val);
        } else if (eventType == parser.END_TAG) {
            if (parser.getName().equals(endTag)) {
                return map;
            }
            throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName());
        }
        eventType = parser.next();
    } while (eventType != parser.END_DOreplacedENT);
    throw new XmlPullParserException("Doreplacedent ended before " + endTag + " end tag");
}

18 Source : SysConfigWrapper.java
with GNU General Public License v3.0
from MuntashirAkon

private static void convertToMap(final ArrayMap<String, ArrayMap<String, Boolean>> packagePermissionsMap, @NonNull ArrayMap<String, Set<String>> grantMap, @NonNull ArrayMap<String, Set<String>> denyMap) {
    ArrayMap<String, Boolean> perms;
    String packageName;
    for (int i = 0; i < grantMap.size(); ++i) {
        packageName = grantMap.keyAt(i);
        perms = packagePermissionsMap.get(packageName);
        if (perms == null) {
            perms = new ArrayMap<>();
            packagePermissionsMap.put(packageName, perms);
        }
        for (String permission : grantMap.valueAt(i)) {
            perms.put(permission, true);
        }
    }
    for (int i = 0; i < denyMap.size(); ++i) {
        packageName = denyMap.keyAt(i);
        perms = packagePermissionsMap.get(packageName);
        if (perms == null) {
            perms = new ArrayMap<>();
            packagePermissionsMap.put(packageName, perms);
        }
        for (String permission : denyMap.valueAt(i)) {
            perms.put(permission, false);
        }
    }
}

18 Source : ApiConfig.java
with Apache License 2.0
from Mp5A5

/**
 * @author :mp5a5 on 2018/12/27 20:51
 * @describe 网络请求配置文件
 * @email:[email protected]
 */
public clreplaced ApiConfig implements Serializable {

    private static int mInvalidToken;

    private static int mQuitCode;

    private static String mBaseUrl;

    private static int mDefaultTimeout = 2000;

    private static int mSucceedCode;

    private static String mTokenInvalidBroadcastFilter;

    private static String mQuitBroadcastFilter;

    private static ArrayMap<String, String> mHeads;

    private static String mToken = "";

    private static boolean mOpenHttps;

    private static SslSocketConfigure mSslSocketConfigure;

    private static List<Interceptor> mInterceptors;

    private ApiConfig(Builder builder) {
        mInvalidToken = builder.invalidateToken;
        mQuitCode = builder.quitCode;
        mBaseUrl = builder.baseUrl;
        mDefaultTimeout = builder.defaultTimeout;
        mSucceedCode = builder.succeedCode;
        mTokenInvalidBroadcastFilter = builder.tokenInvalidBroadcastFilter;
        mQuitBroadcastFilter = builder.quitBroadcastFilter;
        mHeads = builder.heads;
        mOpenHttps = builder.openHttps;
        mSslSocketConfigure = builder.sslSocketConfigure;
        mInterceptors = builder.interceptors;
    }

    public void init(Context appContext) {
        AppContextUtils.init(appContext);
    }

    public static int getInvalidToken() {
        return mInvalidToken;
    }

    public static String getBaseUrl() {
        return mBaseUrl;
    }

    public static int getDefaultTimeout() {
        return mDefaultTimeout;
    }

    public static int getSucceedCode() {
        return mSucceedCode;
    }

    public static String getTokenInvalidBroadcastFilter() {
        return mTokenInvalidBroadcastFilter;
    }

    public static String getQuitBroadcastFilter() {
        return mQuitBroadcastFilter;
    }

    public static ArrayMap<String, String> getHeads() {
        return mHeads;
    }

    public static void setHeads(ArrayMap<String, String> mHeads) {
        ApiConfig.mHeads = mHeads;
    }

    public static String getToken() {
        return mToken;
    }

    public static void setToken(String mToken) {
        ApiConfig.mToken = mToken;
    }

    public static boolean getOpenHttps() {
        return mOpenHttps;
    }

    public static int getQuitCode() {
        return mQuitCode;
    }

    public static SslSocketConfigure getSslSocketConfigure() {
        return mSslSocketConfigure;
    }

    public static List<Interceptor> getInterceptors() {
        return mInterceptors;
    }

    public static final clreplaced Builder {

        private int invalidateToken;

        private int quitCode;

        private String baseUrl;

        private int defaultTimeout;

        private int succeedCode;

        private String quitBroadcastFilter;

        private String tokenInvalidBroadcastFilter;

        private ArrayMap<String, String> heads;

        private boolean openHttps = false;

        private SslSocketConfigure sslSocketConfigure;

        private List<Interceptor> interceptors;

        public Builder setHeads(ArrayMap<String, String> heads) {
            this.heads = heads;
            return this;
        }

        public Builder setTokenInvalidFilter(@NonNull String filter) {
            this.tokenInvalidBroadcastFilter = filter;
            return this;
        }

        public Builder setQuitFilter(@NonNull String filter) {
            this.quitBroadcastFilter = filter;
            return this;
        }

        public Builder setSucceedCode(int succeedCode) {
            this.succeedCode = succeedCode;
            return this;
        }

        public Builder setBaseUrl(String mBaseUrl) {
            this.baseUrl = mBaseUrl;
            return this;
        }

        public Builder setInvalidToken(int invalidateToken) {
            this.invalidateToken = invalidateToken;
            return this;
        }

        public Builder setQuitCode(int quitCode) {
            this.quitCode = quitCode;
            return this;
        }

        public Builder setDefaultTimeout(int defaultTimeout) {
            this.defaultTimeout = defaultTimeout;
            return this;
        }

        public Builder setOpenHttps(boolean open) {
            this.openHttps = open;
            return this;
        }

        public Builder setSslSocketConfigure(SslSocketConfigure sslSocketConfigure) {
            this.sslSocketConfigure = sslSocketConfigure;
            return this;
        }

        public Builder setInterceptor(List<Interceptor> interceptors) {
            this.interceptors = interceptors;
            return this;
        }

        public ApiConfig build() {
            return new ApiConfig(this);
        }
    }

    public enum QuitType {

        /**
         * 退出app标志位
         */
        QUIT_APP_TAG(0, "quit_app_tag"),
        /**
         * 退出app event
         */
        QUIT_APP(1, "quit_app");

        public static final String TOKEN_INVALID_TAG = "token_invalid";

        public static final String REFRESH_TOKEN = "refresh_token";

        private int code;

        private String name;

        QuitType(int code, String name) {
            this.code = code;
            this.name = name;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public enum TokenType {

        /**
         * 退出token失效标志位
         */
        TOKEN_INVALID_TAG(0, "token_invalid_tag"),
        /**
         * 刷新token
         */
        TOKEN_REFRESH(1, "refresh_token");

        private int code;

        private String name;

        TokenType(int code, String name) {
            this.code = code;
            this.name = name;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

See More Examples