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
19
Source : RequestManager.java
with Apache License 2.0
from zhkrb
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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