/*
* Copyright 2016 Flipkart Internet Pvt. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.flipkart.android.proteus.toolbox;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.reflect.TypeToken;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* IdGeneratorImpl
*
* <p>
* An built in implementation of {@link IdGenerator} interface
* </p>
*
* @author aditya.sharat
*/
public class IdGeneratorImpl implements IdGenerator {
private static final ClassLoader ID_MAP_CLASS_LOADER = new TypeToken<Map<String, Integer>>() {
}.getClass().getClassLoader();
private final HashMap<String, Integer> idMap = new HashMap<>();
private final AtomicInteger sNextGeneratedId;
public IdGeneratorImpl() {
sNextGeneratedId = new AtomicInteger(1);
}
public IdGeneratorImpl(Parcel source) {
sNextGeneratedId = new AtomicInteger(source.readInt());
source.readMap(idMap, ID_MAP_CLASS_LOADER);
}
public final static Parcelable.Creator<IdGeneratorImpl> CREATOR = new Creator<IdGeneratorImpl>() {
@Override
public IdGeneratorImpl createFromParcel(Parcel source) {
return new IdGeneratorImpl(source);
}
@Override
public IdGeneratorImpl[] newArray(int size) {
return new IdGeneratorImpl[size];
}
};
/**
* Flatten this object in to a Parcel.
*
* @param dest The Parcel in which the object should be written.
* @param flags Additional flags about how the object should be written.
* May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(sNextGeneratedId.get());
dest.writeMap(idMap);
}
/**
* Generates and returns a unique id, for the given key.
* If key exists, returns old value.
* Ensure that all
*
* @param idKey
* @return a unique ID integer for use with {@link android.view.View#setId(int)}.
*/
@Override
public synchronized int getUnique(String idKey) {
Integer existingId = idMap.get(idKey);
if (existingId == null) {
int newId = generateViewId();
idMap.put(idKey, newId);
existingId = newId;
}
return existingId;
}
/**
* Taken from Android View Source code API 17+
* <p/>
* Generate a value suitable for use.
* This value will not collide with ID values generated at build time by aapt for R.id.
*
* @return a generated ID value
*/
private int generateViewId() {
for (; ; ) {
final int result = sNextGeneratedId.get();
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
int newValue = result + 1;
if (newValue > 0x00FFFFFF) {
newValue = 1; // Roll over to 1, not 0.
}
if (sNextGeneratedId.compareAndSet(result, newValue)) {
return result;
}
}
}
/**
* Describe the kinds of special objects contained in this Parcelable's
* marshalled representation.
*
* @return a bitmask indicating the set of special object types marshalled
* by the Parcelable.
*/
@Override
public int describeContents() {
return 0;
}
}