android.util.SparseArray

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

2069 Examples 7

19 Source : StateListImageButton.java
with MIT License
from zzhoujay

/**
 * Created by zhou on 2016/11/29.
 * 可以添加状态的ImageButton
 */
public clreplaced StateListImageButton extends AppCompatImageButton {

    private SparseArray<Drawable> drawableSparseArray;

    private int state;

    private StateChangeCallback stateChangeCallback;

    public StateListImageButton(Context context) {
        super(context);
        init(context);
    }

    public StateListImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public StateListImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        drawableSparseArray = new SparseArray<>();
    }

    private void setBackground() {
        Drawable drawable = drawableSparseArray.get(state);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            setBackground(drawable);
        } else {
            setBackgroundDrawable(drawable);
        }
    }

    public void addState(int state, Drawable drawable) {
        drawableSparseArray.put(state, drawable);
        setBackground();
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        setBackground();
        if (stateChangeCallback != null) {
            stateChangeCallback.stateChange(state);
        }
    }

    public StateChangeCallback getStateChangeCallback() {
        return stateChangeCallback;
    }

    public void setStateChangeCallback(StateChangeCallback stateChangeCallback) {
        this.stateChangeCallback = stateChangeCallback;
    }
}

19 Source : Style.java
with MIT License
from zzhoujay

/**
 * Created by zhou on 2016/11/26.
 * Style
 */
public abstract clreplaced Style<T extends Styleable> {

    private static final Style<BoldSpan> BOLD = new Style<BoldSpan>() {

        @Override
        public Clreplaced<BoldSpan> getSpanClreplaced() {
            return BoldSpan.clreplaced;
        }

        @Override
        public BoldSpan createSpan() {
            return new BoldSpan();
        }

        @Override
        public int getStyleType() {
            return StyleType.BOLD;
        }
    };

    private static final Style<ItalicSpan> ITALIC = new Style<ItalicSpan>() {

        @Override
        public Clreplaced<ItalicSpan> getSpanClreplaced() {
            return ItalicSpan.clreplaced;
        }

        @Override
        public ItalicSpan createSpan() {
            return new ItalicSpan();
        }

        @Override
        public int getStyleType() {
            return StyleType.ITALIC;
        }
    };

    private static final Style<DeleteSpan> DELETE = new Style<DeleteSpan>() {

        @Override
        public Clreplaced<DeleteSpan> getSpanClreplaced() {
            return DeleteSpan.clreplaced;
        }

        @Override
        public DeleteSpan createSpan() {
            return new DeleteSpan();
        }

        @Override
        public int getStyleType() {
            return StyleType.DELETE;
        }
    };

    private static final Style<UnderLineSpan> UNDER_LINE = new Style<UnderLineSpan>() {

        @Override
        public Clreplaced<UnderLineSpan> getSpanClreplaced() {
            return UnderLineSpan.clreplaced;
        }

        @Override
        public UnderLineSpan createSpan() {
            return new UnderLineSpan();
        }

        @Override
        public int getStyleType() {
            return StyleType.UNDER_LINE;
        }
    };

    private static final Style<QuoteSpan> QUOTE = new Style<QuoteSpan>() {

        @Override
        public Clreplaced<QuoteSpan> getSpanClreplaced() {
            return QuoteSpan.clreplaced;
        }

        @Override
        public QuoteSpan createSpan() {
            return new QuoteSpan();
        }

        @Override
        public int getStyleType() {
            return StyleType.QUOTE;
        }

        @Override
        public boolean paragraph() {
            return true;
        }
    };

    private static final Style<LinkSpan> LINK = new Style<LinkSpan>() {

        @Override
        public Clreplaced<LinkSpan> getSpanClreplaced() {
            return LinkSpan.clreplaced;
        }

        @Override
        public LinkSpan createSpan() {
            return null;
        }

        @Override
        public int getStyleType() {
            return StyleType.LINK;
        }

        @Override
        public LinkSpan createSpan(Object... args) {
            return new LinkSpan(args[0].toString());
        }

        @Override
        public boolean needArgument() {
            return true;
        }
    };

    private static final Style<ImageSpan> IMAGE = new Style<ImageSpan>() {

        @Override
        public Clreplaced<ImageSpan> getSpanClreplaced() {
            return ImageSpan.clreplaced;
        }

        @Override
        public ImageSpan createSpan() {
            return null;
        }

        @Override
        public int getStyleType() {
            return StyleType.IMAGE;
        }

        @Override
        public ImageSpan createSpan(Object... args) {
            return new ImageSpan(((Drawable) args[1]), args[0].toString());
        }

        @Override
        public boolean needArgument() {
            return true;
        }
    };

    private static final Style<CodeSpan> CODE = new Style<CodeSpan>() {

        @Override
        public Clreplaced<CodeSpan> getSpanClreplaced() {
            return CodeSpan.clreplaced;
        }

        @Override
        public CodeSpan createSpan() {
            return new CodeSpan();
        }

        @Override
        public int getStyleType() {
            return StyleType.CODE;
        }
    };

    private static final Style<HeadSpan> HEAD = new StyleExt<HeadSpan>() {

        @Override
        public Clreplaced<HeadSpan> getSpanClreplaced() {
            return HeadSpan.clreplaced;
        }

        @Override
        public HeadSpan createSpan() {
            return null;
        }

        @Override
        public int getStyleType() {
            return StyleType.HEAD;
        }

        @Override
        public HeadSpan createSpan(Object... args) {
            return new HeadSpan(((int) args[0]));
        }

        @Override
        public boolean needArgument() {
            return true;
        }

        @Override
        public void beforeStyle(SpannableStringBuilder ssb, int start, int end) {
            HeadSpan[] headSpans = ssb.getSpans(start, end, HeadSpan.clreplaced);
            for (HeadSpan headSpan : headSpans) {
                int s = ssb.getSpanStart(headSpan);
                int e = ssb.getSpanEnd(headSpan);
                ssb.removeSpan(headSpan);
                ssb.setSpan(headSpan, s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        @Override
        public int getStyleTypeState(int flag, HeadSpan headSpan) {
            int state;
            if (flag == Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) {
                state = StyleTypeStateSpec.StyleTypeState.STATE_EXIST;
            } else {
                state = StyleTypeStateSpec.StyleTypeState.STATE_ACTIVE;
            }
            byte arg1 = (byte) headSpan.getHeadSize();
            return StyleTypeStateSpec.makeStyleTypeStateSpec(headSpan.getStyleType(), state, arg1);
        }
    };

    private static final Style<ColorSpan> COLOR = new Style<ColorSpan>() {

        @Override
        public Clreplaced<ColorSpan> getSpanClreplaced() {
            return ColorSpan.clreplaced;
        }

        @Override
        public ColorSpan createSpan() {
            return null;
        }

        @Override
        public int getStyleType() {
            return StyleType.COLOR;
        }

        @Override
        public boolean needArgument() {
            return true;
        }

        @Override
        public ColorSpan createSpan(Object... args) {
            return new ColorSpan((Integer) args[0]);
        }
    };

    public abstract Clreplaced<T> getSpanClreplaced();

    public abstract T createSpan();

    @StyleType
    public abstract int getStyleType();

    public T createSpan(Object... args) {
        return createSpan();
    }

    public boolean needArgument() {
        return false;
    }

    public boolean paragraph() {
        return false;
    }

    private static final SparseArray<Style> styles;

    private static void register(Style style) {
        styles.append(style.getStyleType(), style);
    }

    static {
        styles = new SparseArray<>();
        register(BOLD);
        register(ITALIC);
        register(DELETE);
        register(UNDER_LINE);
        register(QUOTE);
        register(LINK);
        register(IMAGE);
        register(CODE);
        register(HEAD);
        register(COLOR);
    }

    public static Style get(Styleable styleable) {
        return styles.get(styleable.getStyleType());
    }

    public static Style get(@StyleType int styleType) {
        return styles.get(styleType);
    }
}

19 Source : DayWheelView.java
with Apache License 2.0
from zyyoona7

/**
 * 日 WheelView
 *
 * @author zyyoona7
 * @version v1.0.0
 * @since 2018/8/20.
 */
public clreplaced DayWheelView extends WheelView<Integer> {

    private static final SparseArray<List<Integer>> DAYS = new SparseArray<>(1);

    private int mYear;

    private int mMonth;

    private int mMaxYear = -1;

    private int mMinYear = -1;

    private int mMaxMonth = -1;

    private int mMinMonth = -1;

    private int mMaxDay = -1;

    private int mMinDay = -1;

    private Calendar mCalendar;

    public DayWheelView(Context context) {
        this(context, null);
    }

    public DayWheelView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DayWheelView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mCalendar = Calendar.getInstance();
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DayWheelView);
        mYear = typedArray.getInt(R.styleable.DayWheelView_wv_year, mCalendar.get(Calendar.YEAR));
        mMonth = typedArray.getInt(R.styleable.DayWheelView_wv_month, mCalendar.get(Calendar.MONTH) + 1);
        int selectedDay = typedArray.getInt(R.styleable.DayWheelView_wv_selectedDay, mCalendar.get(Calendar.DATE));
        typedArray.recycle();
        updateDay();
        setSelectedDay(selectedDay);
    }

    /**
     * 同时设置年份和月份
     *
     * @param year  年份
     * @param month 月份
     */
    public void setYearAndMonth(int year, int month) {
        mYear = year;
        mMonth = month;
        updateDay();
    }

    /**
     * 设置年份
     *
     * @param year 年份
     */
    public void setYear(int year) {
        mYear = year;
        updateDay();
    }

    /**
     * 获取年份
     *
     * @return 年份
     */
    public int getYear() {
        return mYear;
    }

    /**
     * 设置月份
     *
     * @param month 月份
     */
    public void setMonth(int month) {
        mMonth = month;
        updateDay();
    }

    /**
     * 获取月份
     *
     * @return 月份
     */
    public int getMonth() {
        return mMonth;
    }

    public void setMaxYearMonthAndDay(@IntRange(from = 0) int maxYear, @IntRange(from = 1, to = 12) int maxMonth, @IntRange(from = 1, to = 31) int maxDay) {
        mMaxYear = maxYear;
        mMaxMonth = maxMonth;
        mMaxDay = maxDay;
        checkCurrentSelected(getSelectedItemData());
    }

    public void setMinYearMonthAndDay(@IntRange(from = 0) int minYear, @IntRange(from = 1, to = 12) int minMonth, @IntRange(from = 1, to = 31) int minDay) {
        mMinYear = minYear;
        mMinMonth = minMonth;
        mMinDay = minDay;
        checkCurrentSelected(getSelectedItemData());
    }

    /**
     * 更新数据
     */
    private void updateDay() {
        mCalendar.set(Calendar.YEAR, mYear);
        mCalendar.set(Calendar.MONTH, mMonth - 1);
        mCalendar.set(Calendar.DATE, 1);
        mCalendar.roll(Calendar.DATE, -1);
        int days = mCalendar.get(Calendar.DATE);
        List<Integer> data = DAYS.get(days);
        if (data == null) {
            data = new ArrayList<>(1);
            for (int i = 1; i <= days; i++) {
                data.add(i);
            }
            DAYS.put(days, data);
        }
        super.setData(data);
        checkCurrentSelected(getSelectedItemData());
    }

    /**
     * 获取选中的日
     *
     * @return 选中的日
     */
    public int getSelectedDay() {
        return getSelectedItemData();
    }

    /**
     * 设置选中的日
     *
     * @param selectedDay 选中的日
     */
    public void setSelectedDay(int selectedDay) {
        setSelectedDay(selectedDay, false);
    }

    /**
     * 设置选中的日
     *
     * @param selectedDay    选中的日
     * @param isSmoothScroll 是否平滑滚动
     */
    public void setSelectedDay(int selectedDay, boolean isSmoothScroll) {
        setSelectedDay(selectedDay, isSmoothScroll, 0);
    }

    /**
     * 设置选中的日
     *
     * @param selectedDay    选中的日
     * @param isSmoothScroll 是否平滑滚动
     * @param smoothDuration 平滑滚动持续时间
     */
    public void setSelectedDay(int selectedDay, boolean isSmoothScroll, int smoothDuration) {
        int days = mCalendar.get(Calendar.DATE);
        if (selectedDay >= 1 && selectedDay <= days) {
            int shouldSelected = selectedDay;
            if (isMoreThanMaxDay(selectedDay)) {
                shouldSelected = mMaxDay;
            } else if (isLessThanMinDay(selectedDay)) {
                shouldSelected = mMinDay;
            }
            updateSelectedDay(shouldSelected, isSmoothScroll, smoothDuration);
        }
    }

    /**
     * 更新选中的日
     *
     * @param selectedDay    选中的日
     * @param isSmoothScroll 是否平滑滚动
     * @param smoothDuration 平滑滚动持续时间
     */
    private void updateSelectedDay(int selectedDay, boolean isSmoothScroll, int smoothDuration) {
        setSelectedItemPosition(selectedDay - 1, isSmoothScroll, smoothDuration);
    }

    @Override
    public void setData(List<Integer> dataList) {
        throw new UnsupportedOperationException("You can not invoke setData method in " + DayWheelView.clreplaced.getSimpleName() + ".");
    }

    @Override
    protected void onItemSelected(Integer data, int position) {
        checkCurrentSelected(data);
    }

    private void checkCurrentSelected(int data) {
        if (isMoreThanMaxDay(data)) {
            setSelectedDay(mMaxDay);
        } else if (isLessThanMinDay(data)) {
            setSelectedDay(mMinDay);
        }
    }

    private boolean isMoreThanMaxDay(int data) {
        return isCurrentMaxYear() && isCurrentMaxMonth() && data > mMaxDay && mMaxDay > 0;
    }

    private boolean isLessThanMinDay(int data) {
        return isCurrentMinYear() && isCurrentMinMonth() && data < mMinDay && mMinDay > 0;
    }

    private boolean isCurrentMaxYear() {
        return (mMaxYear > 0 && mYear == mMaxYear) || (mYear < 0 && mMaxYear < 0 && mMinYear < 0);
    }

    private boolean isCurrentMinYear() {
        return (mYear == mMinYear && mMinYear > 0) || (mYear < 0 && mMaxYear < 0 && mMinYear < 0);
    }

    private boolean isCurrentMaxMonth() {
        return (mMaxMonth > 0 && mMonth == mMaxMonth) || (mMonth < 0 && mMaxMonth < 0 && mMinMonth < 0);
    }

    private boolean isCurrentMinMonth() {
        return (mMonth == mMinMonth && mMinMonth > 0) || (mMonth < 0 && mMaxMonth < 0 && mMinMonth < 0);
    }
}

19 Source : HeartView.java
with Apache License 2.0
from zyyoona7

/**
 * Created by zyyoona7 on 2017/7/3.
 * 直播平台进入直播间点亮功能的心形view
 */
public clreplaced HeartView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private static final String TAG = "HeartView";

    private boolean isRunning = false;

    private Paint mPaint;

    private ConcurrentLinkedQueue<Heart> mHearts = null;

    private float mWidth;

    private float mHeight;

    private Matrix mMatrix;

    private SparseArray<Bitmap> mBitmapSparseArray;

    public HeartView(Context context) {
        this(context, null);
    }

    public HeartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(10);
        getHolder().addCallback(this);
        // 设置背景透明
        setZOrderOnTop(true);
        getHolder().setFormat(PixelFormat.TRANSLUCENT);
        // ----
        setFocusable(true);
        setKeepScreenOn(true);
        setFocusableInTouchMode(true);
        mHearts = new ConcurrentLinkedQueue<>();
        mMatrix = new Matrix();
        mBitmapSparseArray = new SparseArray<>();
        initBitmap(context);
    }

    /**
     * 初始化bitmap
     *
     * @param context
     */
    private void initBitmap(Context context) {
        Bitmap bitmap1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.heart_default);
        Bitmap bitmap2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart1);
        Bitmap bitmap3 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart2);
        Bitmap bitmap4 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart3);
        Bitmap bitmap5 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart4);
        Bitmap bitmap6 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart5);
        mBitmapSparseArray.put(Heart.DEFAULT, bitmap1);
        mBitmapSparseArray.put(Heart.PINK, bitmap2);
        mBitmapSparseArray.put(Heart.CYAN, bitmap3);
        mBitmapSparseArray.put(Heart.GREEN, bitmap4);
        mBitmapSparseArray.put(Heart.YELLOW, bitmap5);
        mBitmapSparseArray.put(Heart.BLUE, bitmap6);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = getWidth();
        mHeight = getHeight();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isRunning = true;
        new Thread(this).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning = false;
        // 回收bitmap
        for (int i = 0; i < mBitmapSparseArray.size(); i++) {
            if (mBitmapSparseArray.valueAt(i) != null) {
                mBitmapSparseArray.valueAt(i).recycle();
            }
        }
    }

    @Override
    public void run() {
        while (isRunning) {
            Canvas canvas = null;
            try {
                canvas = getHolder().lockCanvas();
                if (canvas != null) {
                    drawHeart(canvas);
                }
            } catch (Exception e) {
                Log.e(TAG, "run: " + e.getMessage());
            } finally {
                if (canvas != null) {
                    getHolder().unlockCanvasAndPost(canvas);
                }
            }
        }
    }

    /**
     * 画集合内的心形
     *
     * @param canvas
     */
    private void drawHeart(Canvas canvas) {
        // 清屏~
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        for (Heart heart : mHearts) {
            if (mBitmapSparseArray.get(heart.getType()) == null) {
                continue;
            }
            // 会覆盖掉之前的x,y数值
            mMatrix.setTranslate(0, 0);
            // 位移到x,y
            mMatrix.postTranslate(heart.getX(), heart.getY());
            // 缩放
            // mMatrix.postScale();
            // 旋转
            // mMatrix.postRotate();
            // 画bitmap
            canvas.drawBitmap(mBitmapSparseArray.get(heart.getType()), mMatrix, mPaint);
            // 计算时间
            if (heart.getT() < 1) {
                heart.setT(heart.getT() + heart.getSpeed());
                // 计算下次画的时候,x,y坐标
                handleBezierXY(heart);
            } else {
                removeHeart(heart);
            }
        }
    }

    /**
     * 计算实时的点坐标
     *
     * @param heart
     */
    private void handleBezierXY(Heart heart) {
        // 三阶贝塞尔曲线函数
        // x = (float) (Math.pow((1 - t), 3) * start.x + 3 * t * Math.pow((1 - t), 2) * control1.x + 3 * Math.pow(t, 2) * (1 - t) * control2.x + Math.pow(t, 3) * end.x);
        // y = (float) (Math.pow((1 - t), 3) * start.y + 3 * t * Math.pow((1 - t), 2) * control1.y + 3 * Math.pow(t, 2) * (1 - t) * control2.y + Math.pow(t, 3) * end.y);
        float x = (float) (Math.pow((1 - heart.getT()), 3) * heart.getStartX() + 3 * heart.getT() * Math.pow((1 - heart.getT()), 2) * heart.getControl1X() + 3 * Math.pow(heart.getT(), 2) * (1 - heart.getT()) * heart.getControl2X() + Math.pow(heart.getT(), 3) * heart.getEndX());
        float y = (float) (Math.pow((1 - heart.getT()), 3) * heart.getStartY() + 3 * heart.getT() * Math.pow((1 - heart.getT()), 2) * heart.getControl1Y() + 3 * Math.pow(heart.getT(), 2) * (1 - heart.getT()) * heart.getControl2Y() + Math.pow(heart.getT(), 3) * heart.getEndY());
        heart.setX(x);
        heart.setY(y);
    }

    /**
     * 添加heart
     */
    public void addHeart() {
        Heart heart = new Heart();
        initHeart(heart);
        mHearts.add(heart);
    }

    /**
     * 添加heart
     *
     * @param type
     */
    public void addHeart(int type) {
        Heart heart = new Heart();
        initHeart(heart);
        heart.setType(type);
        mHearts.add(heart);
    }

    /**
     * 重置
     *
     * @param heart
     */
    private void initHeart(Heart heart) {
        heart.initStartAndEnd(mWidth, mHeight);
        heart.initControl(mWidth, mHeight);
        heart.initSpeed();
    }

    /**
     * 移除Heart
     *
     * @param heart
     */
    private void removeHeart(Heart heart) {
        mHearts.remove(heart);
    }
}

19 Source : CustomLayoutManager.java
with Apache License 2.0
from zyyoona7

/**
 * Created by zyyoona7 on 2016/9/22.
 */
public clreplaced CustomLayoutManager extends RecyclerView.LayoutManager {

    private static final String TAG = "CustomLayoutManager";

    // 保存所有的Item的上下左右的偏移量信息
    private SparseArray<Rect> mAllItemsFrames;

    private int mHorizontalScrollOffset = 0;

    private int mTotalWidth = 0;

    // 每页的行列数
    private int mSpanColumns = 1;

    private int mSpanRows = 1;

    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT);
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        // 如果没有item,直接返回
        if (gereplacedemCount() <= 0)
            return;
        // 跳过preLayout,preLayout主要用于支持动画
        if (state.isPreLayout()) {
            return;
        }
        // 在布局之前,将所有的子View先Detach掉,放入到Scrap缓存中
        detachAndScrapAttachedViews(recycler);
        mAllItemsFrames = new SparseArray<>(gereplacedemCount());
        int currentWidth = 0;
        int currentHeight = 0;
        int currentPage = 1;
        int maxCurrentWidth = 0;
        View scrap = recycler.getViewForPosition(0);
        addView(scrap);
        measureChildWithMargins(scrap, 0, 0);
        int width = getDecoratedMeasuredWidth(scrap);
        int height = getDecoratedMeasuredHeight(scrap);
        detachAndScrapView(scrap, recycler);
        maxCurrentWidth = (getHorizontalSpace() / width) * width;
        Log.e(TAG, "onLayoutChildren: itemCount=" + gereplacedemCount());
        for (int i = 0; i < gereplacedemCount(); i++) {
            // 这里就是从缓存里面取出
            // View view = recycler.getViewForPosition(i);
            // 将View加入到RecyclerView中
            // addView(view);
            // measureChildWithMargins(view, 0, 0);
            Rect frame = mAllItemsFrames.get(i);
            if (frame == null) {
                frame = new Rect();
            }
            if (currentWidth + width > maxCurrentWidth * currentPage) {
                currentHeight += height;
                currentWidth = maxCurrentWidth * (currentPage - 1);
            }
            if (currentHeight + height > getVerticalSpace()) {
                currentWidth = maxCurrentWidth * currentPage;
                currentHeight = 0;
                currentPage++;
            }
            Log.e(TAG, "onLayoutChildren: currentWidth=" + currentWidth + ",currentHeight=" + currentHeight + ",horizontalSpan=" + getHorizontalSpace() + ",verticalSpace=" + getVerticalSpace() + ",currentPage=" + currentPage + ",maxWidth=" + maxCurrentWidth);
            frame.set(currentWidth, currentHeight, currentWidth + width, currentHeight + height);
            // 将当前的Item的Rect边界数据保存
            mAllItemsFrames.put(i, frame);
            currentWidth += width;
            mTotalWidth = maxCurrentWidth * currentPage;
            Log.e(TAG, "onLayoutChildren: totalWidth=" + mTotalWidth);
        }
        mTotalWidth = Math.max(mTotalWidth, getHorizontalSpace());
        recycleAndFillItems(recycler, state);
    }

    /**
     * 回收不需要的Item,并且将需要显示的Item从缓存中取出
     */
    private void recycleAndFillItems(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (state.isPreLayout()) {
            // 跳过preLayout,preLayout主要用于支持动画
            return;
        }
        // 当前scroll offset状态下的显示区域
        Rect displayFrame = new Rect(mHorizontalScrollOffset, 0, mHorizontalScrollOffset + getHorizontalSpace(), getVerticalSpace());
        /**
         * 将滑出屏幕的Items回收到Recycle缓存中
         */
        Rect childFrame = new Rect();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            childFrame.left = getDecoratedLeft(child);
            childFrame.top = getDecoratedTop(child);
            childFrame.right = getDecoratedRight(child);
            childFrame.bottom = getDecoratedBottom(child);
            // 如果Item没有在显示区域,就说明需要回收
            if (!Rect.intersects(displayFrame, childFrame)) {
                // 回收掉滑出屏幕的View
                removeAndRecycleView(child, recycler);
            }
        }
        // 重新显示需要出现在屏幕的子View
        for (int i = 0; i < gereplacedemCount(); i++) {
            if (Rect.intersects(displayFrame, mAllItemsFrames.get(i))) {
                View scrap = recycler.getViewForPosition(i);
                measureChildWithMargins(scrap, 0, 0);
                addView(scrap);
                Rect frame = mAllItemsFrames.get(i);
                // 将这个item布局出来
                layoutDecorated(scrap, frame.left - mHorizontalScrollOffset, frame.top, frame.right - mHorizontalScrollOffset, frame.bottom);
            }
        }
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        // 先detach掉所有的子View
        detachAndScrapAttachedViews(recycler);
        // 实际要滑动的距离
        int travel = dx;
        // 
        // 如果滑动到最左面
        if (mHorizontalScrollOffset + dx < 0) {
            travel = -mHorizontalScrollOffset;
        } else if (mHorizontalScrollOffset + dx > mTotalWidth - getHorizontalSpace()) {
            // 如果滑动到最右部
            travel = mTotalWidth - getHorizontalSpace() - mHorizontalScrollOffset;
        }
        // 
        // 将水平方向的偏移量+travel
        mHorizontalScrollOffset += travel;
        offsetChildrenHorizontal(-travel);
        recycleAndFillItems(recycler, state);
        Log.e(TAG, "scrollHorizontallyBy: childCount=" + getChildCount());
        return travel;
    }

    @Override
    public boolean canScrollHorizontally() {
        return true;
    }

    private int getVerticalSpace() {
        return getHeight() - getPaddingBottom() - getPaddingTop();
    }

    private int getHorizontalSpace() {
        return getWidth() - getPaddingRight() - getPaddingLeft();
    }
}

19 Source : HeartView.java
with Apache License 2.0
from zyyoona7

/**
 * Created by zyyoona7 on 2017/7/3.
 * 直播平台进入直播间点亮功能的心形view
 */
public clreplaced HeartView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private static final String TAG = "HeartView";

    private boolean isRunning = false;

    private Paint mPaint;

    private ConcurrentLinkedQueue<Heart> mHearts = null;

    private float mWidth;

    private float mHeight;

    private Matrix mMatrix;

    private SparseArray<Bitmap> mBitmapSparseArray;

    public HeartView(Context context) {
        this(context, null);
    }

    public HeartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(10);
        getHolder().addCallback(this);
        // 设置背景透明
        setZOrderOnTop(true);
        getHolder().setFormat(PixelFormat.TRANSLUCENT);
        // ----
        setFocusable(true);
        setKeepScreenOn(true);
        setFocusableInTouchMode(true);
        mHearts = new ConcurrentLinkedQueue<>();
        mMatrix = new Matrix();
        mBitmapSparseArray = new SparseArray<>();
        Bitmap bitmap1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.heart_default);
        Bitmap bitmap2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart1);
        Bitmap bitmap3 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart2);
        Bitmap bitmap4 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart3);
        Bitmap bitmap5 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart4);
        Bitmap bitmap6 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ss_heart5);
        mBitmapSparseArray.put(Heart.DEFAULT, bitmap1);
        mBitmapSparseArray.put(Heart.PINK, bitmap2);
        mBitmapSparseArray.put(Heart.CYAN, bitmap3);
        mBitmapSparseArray.put(Heart.GREEN, bitmap4);
        mBitmapSparseArray.put(Heart.YELLOW, bitmap5);
        mBitmapSparseArray.put(Heart.BLUE, bitmap6);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = getWidth();
        mHeight = getHeight();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isRunning = true;
        new Thread(this).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning = false;
        // 回收bitmap
        for (int i = 0; i < mBitmapSparseArray.size(); i++) {
            if (mBitmapSparseArray.valueAt(i) != null) {
                mBitmapSparseArray.valueAt(i).recycle();
            }
        }
    }

    @Override
    public void run() {
        while (isRunning) {
            Canvas canvas = null;
            try {
                canvas = getHolder().lockCanvas();
                if (canvas != null) {
                    // 清屏~
                    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                    for (Heart heart : mHearts) {
                        if (mBitmapSparseArray.get(heart.getType()) == null) {
                            continue;
                        }
                        mMatrix.setTranslate(0, 0);
                        // 位移到x,y
                        mMatrix.postTranslate(heart.getX(), heart.getY());
                        // 缩放
                        // mMatrix.postScale()
                        // 画bitmap
                        canvas.drawBitmap(mBitmapSparseArray.get(heart.getType()), mMatrix, mPaint);
                        // 计算时间
                        if (heart.getT() < 1) {
                            heart.setT(heart.getT() + heart.getSpeed());
                            handleBezierXY(heart);
                        } else {
                            removeHeart(heart);
                        }
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "run: " + e.getMessage());
            } finally {
                if (canvas != null) {
                    getHolder().unlockCanvasAndPost(canvas);
                }
            }
        }
    }

    /**
     * 计算实时的点坐标
     *
     * @param heart
     */
    private void handleBezierXY(Heart heart) {
        // 三阶贝塞尔曲线函数
        // x = (float) (Math.pow((1 - t), 3) * start.x + 3 * t * Math.pow((1 - t), 2) * control1.x + 3 * Math.pow(t, 2) * (1 - t) * control2.x + Math.pow(t, 3) * end.x);
        // y = (float) (Math.pow((1 - t), 3) * start.y + 3 * t * Math.pow((1 - t), 2) * control1.y + 3 * Math.pow(t, 2) * (1 - t) * control2.y + Math.pow(t, 3) * end.y);
        float x = (float) (Math.pow((1 - heart.getT()), 3) * heart.getStartX() + 3 * heart.getT() * Math.pow((1 - heart.getT()), 2) * heart.getControl1X() + 3 * Math.pow(heart.getT(), 2) * (1 - heart.getT()) * heart.getControl2X() + Math.pow(heart.getT(), 3) * heart.getEndX());
        float y = (float) (Math.pow((1 - heart.getT()), 3) * heart.getStartY() + 3 * heart.getT() * Math.pow((1 - heart.getT()), 2) * heart.getControl1Y() + 3 * Math.pow(heart.getT(), 2) * (1 - heart.getT()) * heart.getControl2Y() + Math.pow(heart.getT(), 3) * heart.getEndY());
        heart.setX(x);
        heart.setY(y);
    }

    /**
     * 添加heart
     */
    public void addHeart() {
        Heart heart = new Heart();
        initHeart(heart);
        mHearts.add(heart);
    }

    /**
     * 添加heart
     *
     * @param type
     */
    public void addHeart(int type) {
        Heart heart = new Heart();
        initHeart(heart);
        heart.setType(type);
        mHearts.add(heart);
    }

    /**
     * 重置
     *
     * @param heart
     */
    private void initHeart(Heart heart) {
        heart.initStartAndEnd(mWidth, mHeight);
        heart.initControl(mWidth, mHeight);
        heart.initSpeed();
    }

    /**
     * 移除Heart
     *
     * @param heart
     */
    private void removeHeart(Heart heart) {
        mHearts.remove(heart);
    }
}

19 Source : CartProvider.java
with Apache License 2.0
from zxuu

/**
 * Created by <a href="http://www.cniao5.com">菜鸟窝</a>
 * 一个专业的Android开发在线教育平台
 */
public clreplaced CartProvider {

    public static final String CART_JSON = "cart_json";

    private SparseArray<ShoppingCart> datas = null;

    private Context mContext;

    public CartProvider(Context context) {
        mContext = context;
        // 存储到SparseArray
        datas = new SparseArray<>(10);
        // 从本地读入到内存
        listToSparse();
    }

    public void put(ShoppingCart cart) {
        // key
        ShoppingCart temp = datas.get(cart.getId().intValue());
        // 如果购物车里存在
        if (temp != null) {
            temp.setCount(temp.getCount() + 1);
        } else {
            temp = cart;
            temp.setCount(1);
        }
        datas.put(cart.getId().intValue(), temp);
        commit();
    }

    public void update(ShoppingCart cart) {
        datas.put(cart.getId().intValue(), cart);
        commit();
    }

    public void delete(ShoppingCart cart) {
        datas.delete(cart.getId().intValue());
        commit();
    }

    public List<ShoppingCart> getAll() {
        return getDataFromLocal();
    }

    public void commit() {
        List<ShoppingCart> carts = sparseToList();
        // 存储到本地
        PreferencesUtils.putString(mContext, CART_JSON, JSONUtil.toJSON(carts));
    }

    // SparseArray里的数据转换为List
    private List<ShoppingCart> sparseToList() {
        int size = datas.size();
        List<ShoppingCart> list = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            list.add(datas.valueAt(i));
        }
        return list;
    }

    // 保存到SparseArray
    private void listToSparse() {
        List<ShoppingCart> carts = getDataFromLocal();
        if (carts != null && carts.size() > 0) {
            for (ShoppingCart cart : carts) {
                datas.put(cart.getId().intValue(), cart);
            }
        }
    }

    public List<ShoppingCart> getDataFromLocal() {
        String json = PreferencesUtils.getString(mContext, CART_JSON);
        List<ShoppingCart> carts = null;
        if (json != null) {
            carts = JSONUtil.fromJson(json, new TypeToken<List<ShoppingCart>>() {
            }.getType());
        }
        return carts;
    }
}

19 Source : BaseViewHolder.java
with Apache License 2.0
from zxuu

public clreplaced BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    private SparseArray<View> views;

    protected BaseAdapter.OnItemClickListener mOnItemClickListener;

    public BaseViewHolder(View itemView, BaseAdapter.OnItemClickListener onItemClickListener) {
        super(itemView);
        itemView.setOnClickListener(this);
        this.mOnItemClickListener = onItemClickListener;
        this.views = new SparseArray<View>();
    }

    public TextView getTextView(int viewId) {
        return retrieveView(viewId);
    }

    public Button getButton(int viewId) {
        return retrieveView(viewId);
    }

    public ImageView getImageView(int viewId) {
        return retrieveView(viewId);
    }

    public View getView(int viewId) {
        return retrieveView(viewId);
    }

    protected <T extends View> T retrieveView(int viewId) {
        View view = views.get(viewId);
        if (view == null) {
            view = itemView.findViewById(viewId);
            views.put(viewId, view);
        }
        return (T) view;
    }

    @Override
    public void onClick(View v) {
        if (mOnItemClickListener != null) {
            mOnItemClickListener.onItemClick(v, getLayoutPosition());
        }
    }
}

19 Source : NatSessionManager.java
with GNU General Public License v3.0
from zxc111

public clreplaced NatSessionManager {

    static final int MAX_SESSION_COUNT = 60;

    static final long SESSION_TIMEOUT_NS = 60 * 1000000000L;

    static final SparseArray<NatSession> Sessions = new SparseArray<NatSession>();

    public static NatSession getSession(int portKey) {
        return Sessions.get(portKey);
    }

    public static int getSessionCount() {
        return Sessions.size();
    }

    static void clearExpiredSessions() {
        long now = System.nanoTime();
        for (int i = Sessions.size() - 1; i >= 0; i--) {
            NatSession session = Sessions.valueAt(i);
            if (now - session.LastNanoTime > SESSION_TIMEOUT_NS) {
                Sessions.removeAt(i);
            }
        }
    }

    public static NatSession createSession(int portKey, int remoteIP, short remotePort) {
        if (Sessions.size() > MAX_SESSION_COUNT) {
            // 清理过期的会话。
            clearExpiredSessions();
        }
        NatSession session = new NatSession();
        session.LastNanoTime = System.nanoTime();
        session.RemoteIP = remoteIP;
        session.RemotePort = remotePort;
        if (ProxyConfig.isFakeIP(remoteIP)) {
            session.RemoteHost = DnsProxy.reverseLookup(remoteIP);
        }
        if (session.RemoteHost == null) {
            session.RemoteHost = CommonMethods.ipIntToString(remoteIP);
        }
        Sessions.put(portKey, session);
        return session;
    }
}

19 Source : StickyRecyclerHeadersDecoration.java
with Apache License 2.0
from zuoweitan

public clreplaced StickyRecyclerHeadersDecoration extends RecyclerView.ItemDecoration {

    private final StickyRecyclerHeadersAdapter mAdapter;

    private final SparseArray<Rect> mHeaderRects = new SparseArray<>();

    private final HeaderProvider mHeaderProvider;

    private final OrientationProvider mOrientationProvider;

    private final HeaderPositionCalculator mHeaderPositionCalculator;

    private final HeaderRenderer mRenderer;

    private final DimensionCalculator mDimensionCalculator;

    /**
     * The following field is used as a buffer for internal calculations. Its sole purpose is to avoid
     * allocating new Rect every time we need one.
     */
    private final Rect mTempRect = new Rect();

    // TODO: Consider preplaceding in orientation to simplify orientation accounting within calculation
    public StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter) {
        this(adapter, new LinearLayoutOrientationProvider(), new DimensionCalculator());
    }

    private StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter, OrientationProvider orientationProvider, DimensionCalculator dimensionCalculator) {
        this(adapter, orientationProvider, dimensionCalculator, new HeaderRenderer(orientationProvider), new HeaderViewCache(adapter, orientationProvider));
    }

    private StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter, OrientationProvider orientationProvider, DimensionCalculator dimensionCalculator, HeaderRenderer headerRenderer, HeaderProvider headerProvider) {
        this(adapter, headerRenderer, orientationProvider, dimensionCalculator, headerProvider, new HeaderPositionCalculator(adapter, headerProvider, orientationProvider, dimensionCalculator));
    }

    private StickyRecyclerHeadersDecoration(StickyRecyclerHeadersAdapter adapter, HeaderRenderer headerRenderer, OrientationProvider orientationProvider, DimensionCalculator dimensionCalculator, HeaderProvider headerProvider, HeaderPositionCalculator headerPositionCalculator) {
        mAdapter = adapter;
        mHeaderProvider = headerProvider;
        mOrientationProvider = orientationProvider;
        mRenderer = headerRenderer;
        mDimensionCalculator = dimensionCalculator;
        mHeaderPositionCalculator = headerPositionCalculator;
    }

    @Override
    public void gereplacedemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.gereplacedemOffsets(outRect, view, parent, state);
        int itemPosition = parent.getChildAdapterPosition(view);
        if (itemPosition == RecyclerView.NO_POSITION) {
            return;
        }
        if (mHeaderPositionCalculator.hasNewHeader(itemPosition, mOrientationProvider.isReverseLayout(parent))) {
            View header = getHeaderView(parent, itemPosition);
            sereplacedemOffsetsForHeader(outRect, header, mOrientationProvider.getOrientation(parent));
        }
    }

    /**
     * Sets the offsets for the first item in a section to make room for the header view
     *
     * @param itemOffsets rectangle to define offsets for the item
     * @param header      view used to calculate offset for the item
     * @param orientation used to calculate offset for the item
     */
    private void sereplacedemOffsetsForHeader(Rect itemOffsets, View header, int orientation) {
        mDimensionCalculator.initMargins(mTempRect, header);
        if (orientation == LinearLayoutManager.VERTICAL) {
            itemOffsets.top = header.getHeight() + mTempRect.top + mTempRect.bottom;
        } else {
            itemOffsets.left = header.getWidth() + mTempRect.left + mTempRect.right;
        }
    }

    @Override
    public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(canvas, parent, state);
        final int childCount = parent.getChildCount();
        if (childCount <= 0 || mAdapter.gereplacedemCount() <= 0) {
            return;
        }
        for (int i = 0; i < childCount; i++) {
            View itemView = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(itemView);
            if (position == RecyclerView.NO_POSITION) {
                continue;
            }
            boolean hreplacedtickyHeader = mHeaderPositionCalculator.hreplacedtickyHeader(itemView, mOrientationProvider.getOrientation(parent), position);
            if (hreplacedtickyHeader || mHeaderPositionCalculator.hasNewHeader(position, mOrientationProvider.isReverseLayout(parent))) {
                View header = mHeaderProvider.getHeader(parent, position);
                // re-use existing Rect, if any.
                Rect headerOffset = mHeaderRects.get(position);
                if (headerOffset == null) {
                    headerOffset = new Rect();
                    mHeaderRects.put(position, headerOffset);
                }
                mHeaderPositionCalculator.initHeaderBounds(headerOffset, parent, header, itemView, hreplacedtickyHeader);
                mRenderer.drawHeader(parent, canvas, header, headerOffset);
            }
        }
    }

    /**
     * Gets the position of the header under the specified (x, y) coordinates.
     *
     * @param x x-coordinate
     * @param y y-coordinate
     * @return position of header, or -1 if not found
     */
    public int findHeaderPositionUnder(int x, int y) {
        for (int i = 0; i < mHeaderRects.size(); i++) {
            Rect rect = mHeaderRects.get(mHeaderRects.keyAt(i));
            if (rect.contains(x, y)) {
                return mHeaderRects.keyAt(i);
            }
        }
        return -1;
    }

    /**
     * Gets the header view for the replacedociated position.  If it doesn't exist yet, it will be
     * created, measured, and laid out.
     *
     * @param parent
     * @param position
     * @return Header view
     */
    public View getHeaderView(RecyclerView parent, int position) {
        return mHeaderProvider.getHeader(parent, position);
    }

    /**
     * Invalidates cached headers.  This does not invalidate the recyclerview, you should do that manually after
     * calling this method.
     */
    public void invalidateHeaders() {
        mHeaderProvider.invalidate();
        mHeaderRects.clear();
    }
}

19 Source : BaseAutoAdapter.java
with Apache License 2.0
from Zuluft

@SuppressWarnings({ "WeakerAccess" })
public abstract clreplaced BaseAutoAdapter<T extends IRenderer> extends RecyclerView.Adapter<AutoViewHolder> implements IAdapter<T> {

    private final AutoViewHolderFactory mAutoViewHolderFactory;

    private final Map<Clreplaced<? extends IRenderer>, PublishSubject> mItemViewClickBinding = new HashMap<>();

    private final Map<Clreplaced<? extends IRenderer>, Map<Integer, PublishSubject>> mChildViewsClickBinding = new HashMap<>();

    private final Map<Clreplaced<? extends IRenderer>, PublishSubject> mItemViewLongClickBinding = new HashMap<>();

    private final Map<Clreplaced<? extends IRenderer>, Map<Integer, PublishSubject>> mChildViewsLongClickBinding = new HashMap<>();

    private final SparseArray<Clreplaced<? extends IRenderer>> mLayoutRendererMapping = new SparseArray<>();

    private final List<ViewHolderCreationListener> mViewHolderCreationListeners = new ArrayList<>();

    public BaseAutoAdapter(final AutoViewHolderFactory autoViewHolderFactory) {
        this.mAutoViewHolderFactory = autoViewHolderFactory;
    }

    @SuppressWarnings("unused")
    public final void addViewHolderCreationListener(@NonNull final ViewHolderCreationListener viewHolderCreationListener) {
        mViewHolderCreationListeners.add(viewHolderCreationListener);
    }

    @NonNull
    @Override
    public AutoViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int layoutId) {
        AutoViewHolder viewHolder = mAutoViewHolderFactory.createViewHolder(parent, layoutId);
        Clreplaced rendererClreplaced = mLayoutRendererMapping.get(layoutId);
        final PublishSubject itemLongClickPublishSubject = mItemViewLongClickBinding.get(rendererClreplaced);
        if (itemLongClickPublishSubject != null) {
            viewHolder.getViewHolderOnLongClickObservable().subscribe(new Observer<AutoViewHolder>() {

                @Override
                public void onSubscribe(Disposable d) {
                    itemLongClickPublishSubject.onSubscribe(d);
                }

                @Override
                @SuppressWarnings("unchecked")
                public void onNext(AutoViewHolder autoViewHolder) {
                    int position = autoViewHolder.getAdapterPosition();
                    ItemInfo info = new ItemInfo(position, gereplacedem(position), autoViewHolder);
                    itemLongClickPublishSubject.onNext(info);
                }

                @SuppressWarnings("unchecked")
                @Override
                public void onError(Throwable e) {
                    itemLongClickPublishSubject.onNext(e);
                }

                @Override
                public void onComplete() {
                    itemLongClickPublishSubject.onComplete();
                }
            });
        }
        final PublishSubject itemClickPublishSubject = mItemViewClickBinding.get(rendererClreplaced);
        if (itemClickPublishSubject != null) {
            viewHolder.getViewHolderOnClickObservable().subscribe(new Observer<AutoViewHolder>() {

                @Override
                public void onSubscribe(Disposable d) {
                    itemClickPublishSubject.onSubscribe(d);
                }

                @SuppressWarnings("unchecked")
                @Override
                public void onNext(AutoViewHolder autoViewHolder) {
                    int position = autoViewHolder.getAdapterPosition();
                    ItemInfo info = new ItemInfo(position, gereplacedem(position), autoViewHolder);
                    itemClickPublishSubject.onNext(info);
                }

                @Override
                public void onError(Throwable e) {
                    itemClickPublishSubject.onError(e);
                }

                @Override
                public void onComplete() {
                    itemClickPublishSubject.onComplete();
                }
            });
        }
        final Map<Integer, PublishSubject> childViewsLongClickMap = mChildViewsLongClickBinding.get(rendererClreplaced);
        if (childViewsLongClickMap != null) {
            for (Map.Entry<Integer, PublishSubject> entry : childViewsLongClickMap.entrySet()) {
                final PublishSubject publishSubject = entry.getValue();
                viewHolder.getViewHolderOnChildLongClickObservable(entry.getKey()).subscribe(new Observer<AutoViewHolder>() {

                    @Override
                    public void onSubscribe(Disposable d) {
                        publishSubject.onSubscribe(d);
                    }

                    @SuppressWarnings("unchecked")
                    @Override
                    public void onNext(AutoViewHolder autoViewHolder) {
                        int position = autoViewHolder.getAdapterPosition();
                        ItemInfo info = new ItemInfo(position, gereplacedem(position), autoViewHolder);
                        publishSubject.onNext(info);
                    }

                    @Override
                    public void onError(Throwable e) {
                        publishSubject.onError(e);
                    }

                    @Override
                    public void onComplete() {
                        publishSubject.onComplete();
                    }
                });
            }
        }
        final Map<Integer, PublishSubject> childViewsClickMap = mChildViewsClickBinding.get(rendererClreplaced);
        if (childViewsClickMap != null) {
            for (Map.Entry<Integer, PublishSubject> entry : childViewsClickMap.entrySet()) {
                final PublishSubject publishSubject = entry.getValue();
                viewHolder.getViewHolderOnChildClickObservable(entry.getKey()).subscribe(new Observer<AutoViewHolder>() {

                    @Override
                    public void onSubscribe(Disposable d) {
                        publishSubject.onSubscribe(d);
                    }

                    @SuppressWarnings("unchecked")
                    @Override
                    public void onNext(AutoViewHolder autoViewHolder) {
                        int position = autoViewHolder.getAdapterPosition();
                        ItemInfo info = new ItemInfo(position, gereplacedem(position), autoViewHolder);
                        publishSubject.onNext(info);
                    }

                    @Override
                    public void onError(Throwable e) {
                        publishSubject.onError(e);
                    }

                    @Override
                    public void onComplete() {
                        publishSubject.onComplete();
                    }
                });
            }
        }
        for (ViewHolderCreationListener mViewHolderCreationListener : mViewHolderCreationListeners) {
            mViewHolderCreationListener.onViewHolderCreated(viewHolder);
        }
        return viewHolder;
    }

    public final <X extends AutoViewHolder, Y extends IRenderer<X>> PublishSubject<ItemInfo<Y, X>> clicks(@NonNull final Clreplaced<Y> clazz) {
        PublishSubject<ItemInfo<Y, X>> publishSubject = PublishSubject.create();
        mItemViewClickBinding.put(clazz, publishSubject);
        return publishSubject;
    }

    @SuppressLint("UseSparseArrays")
    public final <X extends AutoViewHolder, Y extends IRenderer<X>> PublishSubject<ItemInfo<Y, X>> clicks(@NonNull final Clreplaced<Y> clazz, @IdRes final int viewId) {
        PublishSubject<ItemInfo<Y, X>> publishSubject = PublishSubject.create();
        Map<Integer, PublishSubject> map = mChildViewsClickBinding.get(clazz);
        if (map == null) {
            map = new HashMap<>();
            mChildViewsClickBinding.put(clazz, map);
        }
        map.put(viewId, publishSubject);
        return publishSubject;
    }

    @SuppressWarnings("unused")
    public final <X extends AutoViewHolder, Y extends IRenderer<X>> PublishSubject<ItemInfo<Y, X>> longClicks(@NonNull final Clreplaced<Y> clazz) {
        PublishSubject<ItemInfo<Y, X>> publishSubject = PublishSubject.create();
        mItemViewLongClickBinding.put(clazz, publishSubject);
        return publishSubject;
    }

    @SuppressWarnings("unused")
    @SuppressLint("UseSparseArrays")
    public final <X extends AutoViewHolder, Y extends IRenderer<X>> PublishSubject<ItemInfo<Y, X>> longClicks(@NonNull final Clreplaced<Y> clazz, @IdRes final int viewId) {
        PublishSubject<ItemInfo<Y, X>> publishSubject = PublishSubject.create();
        Map<Integer, PublishSubject> map = mChildViewsLongClickBinding.get(clazz);
        if (map == null) {
            map = new HashMap<>();
            mChildViewsLongClickBinding.put(clazz, map);
        }
        map.put(viewId, publishSubject);
        return publishSubject;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onBindViewHolder(@NonNull final AutoViewHolder holder, final int position) {
        gereplacedem(position).apply(holder);
    }

    @Override
    @LayoutRes
    public int gereplacedemViewType(final int position) {
        final T item = gereplacedem(position);
        final int layoutId = mAutoViewHolderFactory.getLayoutId(gereplacedem(position));
        if (mLayoutRendererMapping.indexOfKey(layoutId) < 0) {
            mLayoutRendererMapping.put(layoutId, item.getClreplaced());
        }
        return layoutId;
    }
}

19 Source : BannerView.java
with GNU Affero General Public License v3.0
from zood

public clreplaced BannerView extends LinearLayout {

    private final SparseArray<ItemHolder> items = new SparseArray<>();

    public BannerView(Context context) {
        super(context);
        init();
    }

    public BannerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BannerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setOrientation(LinearLayout.VERTICAL);
        setLayoutTransition(new LayoutTransition());
    }

    @UiThread
    public void addItem(@NonNull String msg, @NonNull String action, int itemId, @NonNull ItemClickListener listener) {
        // Check if we already have a view for this item. If so, update it
        ItemHolder holder = items.get(itemId);
        if (holder != null) {
            holder.textView.setText(msg);
            holder.button.setText(action);
            holder.button.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    listener.onBannerItemClick(itemId);
                }
            });
            return;
        }
        // we don't have the view, so inflate a new one and add it
        ConstraintLayout itemView = (ConstraintLayout) LayoutInflater.from(getContext()).inflate(R.layout.banner_item, this, false);
        holder = new ItemHolder(itemView, itemId);
        holder.textView.setText(msg);
        holder.button.setText(action);
        holder.button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                listener.onBannerItemClick(itemId);
            }
        });
        items.put(itemId, holder);
        addView(itemView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    }

    @UiThread
    public void removeItem(int itemId) {
        int size = items.size();
        int i = 0;
        while (i < size) {
            ItemHolder holder = items.valueAt(i);
            if (holder.id == itemId) {
                removeView(holder.view);
                items.delete(holder.id);
                break;
            }
            i++;
        }
    }

    public interface ItemClickListener {

        @UiThread
        void onBannerItemClick(int id);
    }

    private clreplaced ItemHolder {

        final private ConstraintLayout view;

        final int id;

        final TextView textView;

        final MaterialButton button;

        ItemHolder(@NonNull ConstraintLayout view, int id) {
            this.view = view;
            this.id = id;
            textView = view.findViewById(R.id.message);
            button = view.findViewById(R.id.button);
        }
    }
}

19 Source : FriendsBarAdapter.java
with GNU Affero General Public License v3.0
from zood

public clreplaced FriendsBarAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static final int ADDFRIEND_ID = -4;

    private static final int DIVIDER_ID = -3;

    private static final int MARGIN_ID = -2;

    private ArrayList<RecyclerViewAdapterItem> items = new ArrayList<>();

    private ArrayList<FriendRecord> friends = new ArrayList<>();

    private SparseArray<FriendRecord> friendPositions = new SparseArray<>();

    @NonNull
    private final Listener listener;

    FriendsBarAdapter(@NonNull Listener l) {
        this.listener = l;
        setHreplacedtableIds(true);
    }

    @AnyThread
    void addFriend(final FriendRecord friend) {
        App.runOnUiThread(new UiRunnable() {

            @Override
            public void run() {
                _addFriend(friend);
            }
        });
    }

    @UiThread
    private void _addFriend(FriendRecord friend) {
        // check if we're replacing or adding the friend
        int idx = friends.indexOf(friend);
        if (idx == -1) {
            friends.add(friend);
        } else {
            friends.set(idx, friend);
        }
        rebuildItemsList();
        notifyDataSetChanged();
    }

    @Override
    public int gereplacedemCount() {
        return items.size();
    }

    @Override
    public long gereplacedemId(int position) {
        return items.get(position).id;
    }

    @Override
    public int gereplacedemViewType(int position) {
        return items.get(position).viewType;
    }

    @UiThread
    void onAvatarUpdated(@Nullable String username) {
        if (username == null) {
            return;
        }
        notifyDataSetChanged();
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        RecyclerViewAdapterItem item = items.get(position);
        if (holder instanceof AvatarViewHolder) {
            FriendRecord friend = friendPositions.get(position);
            if (friend == null) {
                throw new RuntimeException("Unable to find the friend with id " + item.id);
            }
            AvatarViewHolder h = (AvatarViewHolder) holder;
            Resources rsrcs = h.avatar.getResources();
            int imgSize = rsrcs.getDimensionPixelSize(R.dimen.forty);
            Context ctx = h.avatar.getContext();
            h.avatar.setUsername(friend.user.username);
            Picreplacedo.with(ctx).load(AvatarManager.getAvatar(ctx, friend.user.username)).resize(imgSize, imgSize).into(h.avatar);
        }
    }

    @Override
    @NonNull
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(viewType, parent, false);
        if (viewType == R.layout.friends_bar_friend) {
            final AvatarViewHolder h = new AvatarViewHolder(view);
            h.itemView.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    FriendRecord friend = friendPositions.get(h.getAdapterPosition());
                    if (friend == null) {
                        throw new RuntimeException("Unable to find friend at position " + h.getAdapterPosition());
                    }
                    listener.onFriendSelected(friend);
                }
            });
            return h;
        } else if (viewType == R.layout.friends_bar_add_friend) {
            final AddFriendViewHolder h = new AddFriendViewHolder(view);
            h.itemView.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    listener.onAddFriendAction();
                }
            });
            return h;
        }
        return new NothingViewHolder(view);
    }

    @UiThread
    private void rebuildItemsList() {
        items.clear();
        int position = 0;
        items.add(new RecyclerViewAdapterItem(R.layout.friends_bar_margin, MARGIN_ID));
        friendPositions.clear();
        for (FriendRecord f : friends) {
            position++;
            items.add(new RecyclerViewAdapterItem(R.layout.friends_bar_friend, f.id));
            friendPositions.put(position, f);
        }
        items.add(new RecyclerViewAdapterItem(R.layout.friends_bar_divider, DIVIDER_ID));
        items.add(new RecyclerViewAdapterItem(R.layout.friends_bar_add_friend, ADDFRIEND_ID));
    }

    @UiThread
    void removeFriend(long friendId) {
        for (int i = 0; i < friends.size(); i++) {
            if (friends.get(i).id == friendId) {
                friends.remove(i);
                break;
            }
        }
        rebuildItemsList();
        notifyDataSetChanged();
    }

    @AnyThread
    public void setFriends(final ArrayList<FriendRecord> friends) {
        App.runOnUiThread(new UiRunnable() {

            @Override
            public void run() {
                _setFriends(friends);
            }
        });
    }

    @UiThread
    private void _setFriends(ArrayList<FriendRecord> friends) {
        this.friends = friends;
        rebuildItemsList();
        notifyDataSetChanged();
    }

    private static clreplaced AddFriendViewHolder extends RecyclerView.ViewHolder {

        ImageView image;

        AddFriendViewHolder(View itemView) {
            super(itemView);
            image = itemView.findViewById(R.id.image);
            image.setOutlineProvider(new ViewOutlineProvider() {

                @Override
                public void getOutline(View view, Outline outline) {
                    outline.setRoundRect(0, 0, image.getWidth(), image.getHeight(), image.getWidth() / 2.0f);
                }
            });
            image.setClipToOutline(true);
        }
    }

    private static clreplaced AvatarViewHolder extends RecyclerView.ViewHolder {

        final AvatarView avatar;

        AvatarViewHolder(View itemView) {
            super(itemView);
            avatar = itemView.findViewById(R.id.avatar_image);
        }
    }

    private static clreplaced NothingViewHolder extends RecyclerView.ViewHolder {

        NothingViewHolder(View itemView) {
            super(itemView);
        }
    }

    public interface Listener {

        @UiThread
        void onAddFriendAction();

        @UiThread
        void onFriendSelected(@NonNull FriendRecord fr);
    }
}

19 Source : DecodeTask.java
with Apache License 2.0
from zjutkz

/**
 * Created by kangzhe on 16/10/20.
 */
public clreplaced DecodeTask extends DefaultTask {

    private static final String TAG = "DecodeTask";

    private static final int MAGIC_DEX = 0x0A786564;

    private static final int MAGIC_035 = 0x00353330;

    private static final int MAGIC_036 = 0x00363330;

    private static final int VALUE_BYTE = 0;

    private static final int VALUE_SHORT = 2;

    private static final int VALUE_CHAR = 3;

    private static final int VALUE_INT = 4;

    private static final int VALUE_LONG = 6;

    private static final int VALUE_FLOAT = 16;

    private static final int VALUE_DOUBLE = 17;

    private static final int VALUE_STRING = 23;

    private static final int VALUE_TYPE = 24;

    private static final int VALUE_FIELD = 25;

    private static final int VALUE_METHOD = 26;

    private static final int VALUE_ENUM = 27;

    private static final int VALUE_ARRAY = 28;

    private static final int VALUE_ANNOTATION = 29;

    private static final int VALUE_NULL = 30;

    private static final int VALUE_BOOLEAN = 31;

    private static int string_ids_size;

    private static int type_ids_size;

    private static int field_ids_size;

    private static int method_ids_size;

    private static int clreplaced_def_size;

    private static ByteBuffer stringId;

    private static ByteBuffer typeId;

    private static ByteBuffer protoId;

    private static ByteBuffer fieldId;

    private static ByteBuffer methodId;

    private static ByteBuffer clreplacedDef;

    private static ByteBuffer typeList;

    private static ByteBuffer stringData;

    private static ByteBuffer clreplacedData;

    private static ByteBuffer codeData;

    private static ByteBuffer annotationsDirectoryItem;

    private static ByteBuffer annotationSereplacedem;

    private static ByteBuffer annotationItem;

    private static ByteBuffer annotationSetRefList;

    private static SparseIntArray fieldAnnotationPositions = new SparseIntArray();

    private static SparseIntArray methodAnnotationPositions = new SparseIntArray();

    private static SparseIntArray paramAnnotationPositions = new SparseIntArray();

    private static SparseArray<Clreplaced> id2clreplaced = new SparseArray<>();

    private static List<Clreplaced> allClreplacedes = new ArrayList<>();

    private static List<Method> allMethods = new ArrayList<>();

    private static Map<String, Integer> name2Id = new HashMap<>();

    @Override
    public void doTask() {
        byte[] dexSrc = (byte[]) src;
        decodeDexFile(dexSrc);
    }

    private void decodeDexFile(byte[] src) {
        decodeDexFile(ByteBuffer.wrap(src));
    }

    private static void decodeDexFile(ByteBuffer buffer) {
        restore(buffer);
        buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
        // magic & version
        int magic = buffer.getInt();
        int version = buffer.getInt();
        if (!isDexFile(magic, version)) {
            Log.d(TAG, "Finish decoding,it is not a dex file!");
            return;
        }
        // skip checksum
        // skip signature
        // skip file_size
        // skip header_size 0x70
        // skip endian_tag
        // skip uint link_size
        // skip uint link_off
        // skip uint map_off
        skip(buffer, 4 + 20 + 4 + 4 + 4 + 4 + 4 + 4);
        string_ids_size = buffer.getInt();
        int string_ids_off = buffer.getInt();
        type_ids_size = buffer.getInt();
        int type_ids_off = buffer.getInt();
        int proto_ids_size = buffer.getInt();
        int proto_ids_off = buffer.getInt();
        field_ids_size = buffer.getInt();
        int field_ids_off = buffer.getInt();
        method_ids_size = buffer.getInt();
        int method_ids_off = buffer.getInt();
        clreplaced_def_size = buffer.getInt();
        int clreplaced_def_off = buffer.getInt();
        stringId = slice(buffer, string_ids_off, string_ids_size * 4);
        typeId = slice(buffer, type_ids_off, type_ids_size * 4);
        protoId = slice(buffer, proto_ids_off, proto_ids_size * 12);
        fieldId = slice(buffer, field_ids_off, field_ids_size * 8);
        methodId = slice(buffer, method_ids_off, method_ids_size * 8);
        clreplacedDef = slice(buffer, clreplaced_def_off, clreplaced_def_size * 32);
        restore(buffer);
        stringData = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        typeList = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        clreplacedData = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        codeData = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        annotationsDirectoryItem = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        annotationSereplacedem = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        annotationItem = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        annotationSetRefList = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
        preFetch();
    }

    private static void preFetch() {
        getAllClreplacedes();
        int clzSize = allClreplacedes.size();
        int methodSize = allMethods.size();
        Log.d(TAG, "There are " + clzSize + " clreplacedes with " + methodSize + " methods.");
    }

    private static boolean isDexFile(int magic, int version) {
        return magic == MAGIC_DEX && (version == MAGIC_035 || version == MAGIC_036);
    }

    public static List<Method> getAllMethodsInClreplaced(String clzName) {
        List<Method> allMethods = new ArrayList<>();
        Integer clzId = name2Id.get(clzName);
        if (clzId != null) {
            allMethods = getMethodNamesWithClzId(clzId);
        }
        return allMethods;
    }

    public static boolean hasMethod(String clzName, String methodName) {
        List<Method> allMethods = getAllMethodsInClreplaced(clzName);
        for (Method method : allMethods) {
            if (method.name.equals(methodName)) {
                return true;
            }
        }
        return false;
    }

    public static boolean hasClreplaced(String clzName) {
        if (name2Id.size() != 0) {
            return name2Id.containsKey(clzName);
        }
        getFileNames();
        return name2Id.containsKey(clzName);
    }

    private static ByteBuffer slice(ByteBuffer in, int offset, int length) {
        in.position(offset);
        ByteBuffer b = in.slice();
        b.limit(length);
        b.order(ByteOrder.LITTLE_ENDIAN);
        return b;
    }

    private static void restore(ByteBuffer buffer) {
        buffer.position(0);
    }

    private static void skip(ByteBuffer data, int pos) {
        data.position(data.position() + pos);
    }

    private static List<Method> getMethodNamesWithClzId(int clzId) {
        Clreplaced dest = id2clreplaced.get(clzId, null);
        List<Method> allMethods = new ArrayList<>();
        if (dest != null) {
            allMethods.addAll(dest.virtual_methods);
            allMethods.addAll(dest.direct_methods);
        }
        return allMethods;
    }

    public static Method getMethod(String clzName, String methodName) {
        Clreplaced destClz;
        Integer clzId = name2Id.get(clzName);
        if (clzId != null) {
            destClz = id2clreplaced.get(clzId, null);
            for (Method method : destClz.direct_methods) {
                if (method.name.equals(methodName)) {
                    return method;
                }
            }
            for (Method method : destClz.virtual_methods) {
                if (method.name.equals(methodName)) {
                    return method;
                }
            }
        }
        return null;
    }

    public static int getMethodCount() {
        if (allMethods != null) {
            return allMethods.size();
        }
        return 0;
    }

    public static Clreplaced getClreplaced(String clzName) {
        Integer clzId = name2Id.get(clzName);
        if (clzId != null) {
            return id2clreplaced.get(clzId, null);
        }
        return null;
    }

    public static int getClreplacedCount() {
        if (allClreplacedes != null) {
            return allClreplacedes.size();
        }
        return 0;
    }

    public static void dumpDex() {
        StringBuilder sb = new StringBuilder();
        sb.append("access_flag:" + "\n");
        sb.append(AccessFlag.dump());
        if (allClreplacedes != null) {
            for (Clreplaced clz : allClreplacedes) {
                sb.append(clz.dump());
            }
        }
        Log.d(TAG, sb.toString());
    }

    public static void dumpDex(String filePath) {
        StringBuilder sb = new StringBuilder();
        sb.append("access_flag:" + "\n");
        sb.append(AccessFlag.dump());
        if (allClreplacedes != null) {
            for (Clreplaced clz : allClreplacedes) {
                sb.append(clz.dump());
            }
        }
        try {
            File dump = mkFile(filePath);
            FileWriter writer = new FileWriter(dump);
            writer.write(sb.toString());
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static File mkFile(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
        }
        return file;
    }

    public static List<Method> getAllMethods() {
        if (allMethods.size() != 0) {
            return allMethods;
        }
        getAllClreplacedes();
        return allMethods;
    }

    public static void clearAllData() {
        allClreplacedes.clear();
        allMethods.clear();
        name2Id.clear();
    }

    public static List<Clreplaced> getAllClreplacedes() {
        if (allClreplacedes.size() != 0) {
            return allClreplacedes;
        }
        List<Clreplaced> clzs = new ArrayList<>(clreplaced_def_size);
        for (int cid = 0; cid < clreplaced_def_size; cid++) {
            Clreplaced clz = new Clreplaced();
            clreplacedDef.position(cid * 32);
            int clreplaced_idx = clreplacedDef.getInt();
            clz.clreplaced_name = getType(clreplaced_idx);
            clz.access_flags = clreplacedDef.getInt();
            clz.super_clreplaced_name = getType(clreplacedDef.getInt());
            clz.interfaces = getTypeList(clreplacedDef.getInt());
            clz.source_file_name = getString(clreplacedDef.getInt());
            int annotations_off = clreplacedDef.getInt();
            int clreplaced_data_off = clreplacedDef.getInt();
            int static_values_off = clreplacedDef.getInt();
            parseAnnotation(clz, annotations_off);
            getFieldsAndMethods(clz, clreplaced_data_off, static_values_off);
            if (!TextUtils.isEmpty(clz.source_file_name)) {
                replaceSourceFileName(clz);
                name2Id.put(clz.source_file_name.split("\\.")[0], clreplaced_idx);
            }
            id2clreplaced.append(clreplaced_idx, clz);
            clzs.add(clz);
        }
        for (Clreplaced clz : allClreplacedes) {
            if (!TextUtils.isEmpty(clz.super_clreplaced_name)) {
                clz.super_clreplaced = getClreplaced(clz.super_clreplaced_name);
            }
        }
        allClreplacedes = clzs;
        return clzs;
    }

    private static void parseAnnotation(Clreplaced clz, int annotations_off) {
        if (annotations_off != 0) {
            annotationsDirectoryItem.position(annotations_off);
            int clreplaced_annotations_off = annotationsDirectoryItem.getInt();
            int field_annotation_size = annotationsDirectoryItem.getInt();
            int method_annotation_size = annotationsDirectoryItem.getInt();
            int parameter_annotation_size = annotationsDirectoryItem.getInt();
            if (clreplaced_annotations_off != 0) {
                getAnnotationSereplacedem(clz, clreplaced_annotations_off);
            }
            for (int i = 0; i < field_annotation_size; i++) {
                int field_idx = annotationsDirectoryItem.getInt();
                int field_annotations_offset = annotationsDirectoryItem.getInt();
                fieldAnnotationPositions.put(field_idx, field_annotations_offset);
            }
            for (int i = 0; i < method_annotation_size; i++) {
                int method_idx = annotationsDirectoryItem.getInt();
                int method_annotation_offset = annotationsDirectoryItem.getInt();
                methodAnnotationPositions.put(method_idx, method_annotation_offset);
            }
            for (int i = 0; i < parameter_annotation_size; i++) {
                int method_idx = annotationsDirectoryItem.getInt();
                int parameter_annotation_offset = annotationsDirectoryItem.getInt();
                paramAnnotationPositions.put(method_idx, parameter_annotation_offset);
            }
        }
    }

    private static void getAnnotationSereplacedem(Object injected, int annotations_off) {
        if (annotations_off != 0) {
            ByteBuffer buffer = annotationSereplacedem;
            buffer.position(annotations_off);
            int size = buffer.getInt();
            for (int j = 0; j < size; j++) {
                int annotation_off = buffer.getInt();
                Annotation annotation = getAnnotation(annotation_off);
                if (injected instanceof Clreplaced) {
                    ((Clreplaced) injected).addAnnotation(annotation);
                } else if (injected instanceof Field) {
                    ((Field) injected).addAnnotation(annotation);
                } else if (injected instanceof Method) {
                    ((Method) injected).addMethodAnnotation(annotation);
                }
            }
        }
    }

    private static Annotation getAnnotation(int annotation_off) {
        ByteBuffer buffer = annotationItem;
        buffer.position(annotation_off);
        Annotation annotation = new Annotation();
        int visibility = 0xFF & buffer.get();
        int type_idx = readULeb128(buffer);
        int size = readULeb128(buffer);
        String type = getType(type_idx);
        annotation.visibility = visibility;
        annotation.name = type;
        for (int i = 0; i < size; i++) {
            AnnotationElement element = new AnnotationElement();
            int name_idx = readULeb128(buffer);
            String name = getString(name_idx);
            Object value = readEncodedValue(buffer);
            element.name = name;
            element.value = value;
            annotation.addElement(element);
        }
        return annotation;
    }

    private static Object readEncodedValue(ByteBuffer in) {
        int b = 0xFF & in.get();
        int type = b & 0x1f;
        switch(type) {
            case VALUE_BYTE:
                return new Byte((byte) readIntBits(in, b));
            case VALUE_SHORT:
                return new Short((short) readIntBits(in, b));
            case VALUE_INT:
                return new Integer((int) readIntBits(in, b));
            case VALUE_LONG:
                return new Long(readIntBits(in, b));
            case VALUE_CHAR:
                return new Character((char) readUIntBits(in, b));
            case VALUE_STRING:
                return getString((int) readUIntBits(in, b));
            case VALUE_FLOAT:
                return Float.intBitsToFloat((int) (readFloatBits(in, b) >> 32));
            case VALUE_DOUBLE:
                return Double.longBitsToDouble(readFloatBits(in, b));
            case VALUE_NULL:
                return null;
            case VALUE_BOOLEAN:
                {
                    return new Boolean(((b >> 5) & 0x3) != 0);
                }
            case VALUE_ENUM:
                {
                    return getField((int) readUIntBits(in, b), -1);
                }
            // TODO: 16/10/23 support array
            /*case VALUE_ARRAY: {
                return getEncodedArray(in);
            }*/
            default:
                return null;
        }
    }

    private static Object[] getEncodedArray(ByteBuffer in) {
        int size = readULeb128(in);
        Object[] constant = new Object[size];
        for (int i = 0; i < size; i++) {
            constant[i] = readEncodedValue(in);
        }
        return constant;
    }

    private static void replaceSourceFileName(Clreplaced clz) {
        if (clz.clreplaced_name.contains("$")) {
            String outerClz = clz.source_file_name.split("\\.")[0];
            String[] maybeMore = clz.clreplaced_name.split("\\$");
            String innerClz = "";
            for (int i = 1; i < maybeMore.length; i++) {
                if (i == 1) {
                    innerClz = maybeMore[i];
                } else {
                    innerClz = innerClz + "$" + maybeMore[i];
                }
            }
            // exclude ";"
            innerClz = innerClz.substring(0, innerClz.length() - 1);
            clz.source_file_name = outerClz + "$" + innerClz + ".java";
        }
    }

    private static void getFieldsAndMethods(Clreplaced clz, int clreplaced_data_off, int static_values_off) {
        if (clreplaced_data_off != 0) {
            ByteBuffer buffer = clreplacedData;
            buffer.position(clreplaced_data_off);
            int static_fields = readULeb128(buffer);
            int instance_fields = readULeb128(buffer);
            int direct_methods = readULeb128(buffer);
            int virtual_methods = readULeb128(buffer);
            List<Field> staticFields = new ArrayList<>();
            List<Field> instanceFields = new ArrayList<>();
            List<Method> directMethods = new ArrayList<>();
            List<Method> virtualMethods = new ArrayList<>();
            int lastField = 0;
            for (int i = 0; i < static_fields; i++) {
                lastField = findFields(buffer, lastField, staticFields);
            }
            lastField = 0;
            for (int i = 0; i < instance_fields; i++) {
                lastField = findFields(buffer, lastField, instanceFields);
            }
            int lastMethod = 0;
            for (int i = 0; i < direct_methods; i++) {
                lastMethod = findMethods(buffer, lastMethod, directMethods);
            }
            lastMethod = 0;
            for (int i = 0; i < virtual_methods; i++) {
                lastMethod = findMethods(buffer, lastMethod, virtualMethods);
            }
            clz.static_fields = staticFields;
            clz.instance_fields = instanceFields;
            clz.direct_methods = directMethods;
            clz.virtual_methods = virtualMethods;
            allMethods.addAll(directMethods);
            allMethods.addAll(virtualMethods);
        }
    }

    private static int findMethods(ByteBuffer buffer, int lastMethod, List<Method> methods) {
        if (methods == null) {
            methods = new ArrayList<>();
        }
        int diff = readULeb128(buffer);
        // TODO: 16/10/21 support code item
        int access_flags = readULeb128(buffer);
        int code_off = readULeb128(buffer);
        int method_id = lastMethod + diff;
        methods.add(getMethod(method_id, access_flags, code_off));
        return method_id;
    }

    private static Method getMethod(int id, int access_flags, int offset) {
        methodId.position(id * 8);
        int clreplaced_idx = methodId.getShort();
        int proto_idx = 0xFFFF & methodId.getShort();
        int name_idx = methodId.getInt();
        String clzName = getType(clreplaced_idx);
        List<String> parameterTypes;
        String returnType;
        protoId.position(proto_idx * 12 + 4);
        int return_type_idx = protoId.getInt();
        int parameters_off = protoId.getInt();
        returnType = getType(return_type_idx);
        parameterTypes = getTypeList(parameters_off);
        Method method = new Method(clzName, parameterTypes, returnType, getString(name_idx), access_flags);
        Integer method_annotation_offset = methodAnnotationPositions.get(id);
        getAnnotationSereplacedem(method, method_annotation_offset);
        Integer parameter_annotation_offset = paramAnnotationPositions.get(id);
        getAnnotationSetRefList(method, parameter_annotation_offset);
        return method;
    }

    private static void getAnnotationSetRefList(Method method, Integer parameter_annotation_offset) {
        if (parameter_annotation_offset != 0) {
            ByteBuffer buffer = annotationSetRefList;
            buffer.position(parameter_annotation_offset);
            int size = buffer.getInt();
            for (int j = 0; j < size; j++) {
                int param_annotation_offset = buffer.getInt();
                if (param_annotation_offset == 0) {
                    continue;
                }
                getAnnotationSereplacedem(method, param_annotation_offset);
            }
        }
    }

    private static int findFields(ByteBuffer buffer, int lastField, List<Field> fields) {
        if (fields == null) {
            fields = new ArrayList<>();
        }
        int diff = readULeb128(buffer);
        int field_access_flags = readULeb128(buffer);
        int field_id = lastField + diff;
        fields.add(getField(field_id, field_access_flags));
        return field_id;
    }

    private static Field getField(int id, int field_access_flags) {
        Field field = new Field();
        fieldId.position(id * 8);
        skip(fieldId, 2);
        int type_idx = 0xFFFF & fieldId.getShort();
        int name_idx = fieldId.getInt();
        String type = getType(type_idx);
        String name = getString(name_idx);
        Integer annotation_offset = fieldAnnotationPositions.get(id);
        getAnnotationSereplacedem(field, annotation_offset);
        field.type = type;
        field.name = name;
        field.access_flag = field_access_flags;
        return field;
    }

    private static void getFileNames() {
        ByteBuffer buffer = clreplacedDef;
        restore(buffer);
        for (int cid = 0; cid < clreplaced_def_size; cid++) {
            int clreplaced_idx = buffer.getInt();
            // skip access_flags
            // skip superclreplaced_idx
            // skip interfaces_off
            skip(buffer, 4 + 4 + 4);
            int source_file_idx = buffer.getInt();
            // skip annotations_off
            // skip clreplaced_data_off
            // skip static_values_off
            skip(buffer, 4 + 4 + 4);
            String fileName = getString(source_file_idx);
            if (!TextUtils.isEmpty(fileName)) {
                String clzName = fileName.split("\\.")[0];
                name2Id.put(clzName.trim(), clreplaced_idx);
            }
        }
    }

    private static List<String> getTypeList(int offset) {
        if (offset == 0) {
            return new ArrayList<>();
        }
        typeList.position(offset);
        int size = typeList.getInt();
        List<String> types = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            types.add(getType(0xFFFF & typeList.getShort()));
        }
        return types;
    }

    private static String getType(int id) {
        if (id == -1) {
            return null;
        }
        return getString(typeId.getInt(id * 4));
    }

    private static String getString(int id) {
        if (id == -1) {
            return null;
        }
        int offset = stringId.getInt(id * 4);
        stringData.position(offset);
        int length = readULeb128(stringData);
        try {
            StringBuilder buff = new StringBuilder(length);
            return UTF8.decode(stringData, buff).trim();
        } catch (UTFDataFormatException e) {
            e.printStackTrace();
            return "";
        }
    }

    private static int readULeb128(ByteBuffer in) {
        int value = 0;
        int count = 0;
        int b = in.get();
        while ((b & 0x80) != 0) {
            value |= (b & 0x7f) << count;
            count += 7;
            b = in.get();
        }
        value |= (b & 0x7f) << count;
        return value;
    }

    private static long readIntBits(ByteBuffer in, int before) {
        int length = ((before >> 5) & 0x7) + 1;
        long value = 0;
        for (int j = 0; j < length; j++) {
            value |= ((long) (0xFF & in.get())) << (j * 8);
        }
        int shift = (8 - length) * 8;
        return value << shift >> shift;
    }

    private static long readUIntBits(ByteBuffer in, int before) {
        int length = ((before >> 5) & 0x7) + 1;
        long value = 0;
        for (int j = 0; j < length; j++) {
            value |= ((long) (0xFF & in.get())) << (j * 8);
        }
        return value;
    }

    private static long readFloatBits(ByteBuffer in, int before) {
        int bytes = ((before >> 5) & 0x7) + 1;
        long result = 0L;
        for (int i = 0; i < bytes; ++i) {
            result |= ((long) (0xFF & in.get())) << (i * 8);
        }
        result <<= (8 - bytes) * 8;
        return result;
    }
}

19 Source : SavedState.java
with Apache License 2.0
from Zhuinden

/**
 * A container for the view hierarchy state and an optional Bundle.
 *
 * A {@link SavedState} represents the state of the screen that is bound to a given key.
 */
public clreplaced SavedState {

    private Object key;

    private SparseArray<Parcelable> viewHierarchyState;

    private StateBundle bundle;

    private StateBundle viewBundle;

    private SavedState() {
    }

    @Nonnull
    public Object getKey() {
        return key;
    }

    @Nonnull
    public SparseArray<Parcelable> getViewHierarchyState() {
        return viewHierarchyState;
    }

    public void setViewHierarchyState(SparseArray<Parcelable> viewHierarchyState) {
        this.viewHierarchyState = viewHierarchyState;
    }

    @Nullable
    public StateBundle getBundle() {
        return bundle;
    }

    @Nullable
    StateBundle getViewBundle() {
        return viewBundle;
    }

    public void setBundle(@Nullable StateBundle bundle) {
        // should be non-null
        this.bundle = bundle;
    }

    void setViewBundle(@Nullable StateBundle viewBundle) {
        this.viewBundle = viewBundle;
    }

    public static Builder builder() {
        return new Builder();
    }

    /**
     * A builder clreplaced that allows creating SavedState instances.
     *
     * Keys are not optional.
     */
    public static clreplaced Builder {

        private Object key;

        private SparseArray<Parcelable> viewHierarchyState = new SparseArray<>();

        private StateBundle bundle = new StateBundle();

        private StateBundle viewBundle;

        Builder() {
        }

        public Builder setKey(@Nonnull Object key) {
            if (key == null) {
                throw new IllegalArgumentException("Key cannot be null");
            }
            this.key = key;
            return this;
        }

        public Builder setViewHierarchyState(@Nonnull SparseArray<Parcelable> viewHierarchyState) {
            if (viewHierarchyState == null) {
                throw new IllegalArgumentException("Provided sparse array for view hierarchy state cannot be null");
            }
            this.viewHierarchyState = viewHierarchyState;
            return this;
        }

        public Builder setBundle(@Nullable StateBundle bundle) {
            // should be non-null
            this.bundle = bundle;
            return this;
        }

        Builder setViewBundle(@Nullable StateBundle viewBundle) {
            this.viewBundle = viewBundle;
            return this;
        }

        public SavedState build() {
            if (key == null) {
                throw new IllegalStateException("You cannot create a SavedState without replacedociating a Key with it.");
            }
            SavedState savedState = new SavedState();
            savedState.key = key;
            savedState.viewHierarchyState = viewHierarchyState;
            savedState.bundle = bundle;
            savedState.viewBundle = viewBundle;
            return savedState;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof SavedState)) {
            return false;
        }
        return ((SavedState) obj).getKey().equals(this.key);
    }

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

19 Source : ParcelledState.java
with Apache License 2.0
from Zhuinden

/**
 * Created by Owner on 2017. 02. 28..
 */
clreplaced ParcelledState implements Parcelable {

    Parcelable parcelableKey;

    SparseArray<Parcelable> viewHierarchyState;

    StateBundle bundle;

    StateBundle viewBundle;

    ParcelledState() {
    }

    protected ParcelledState(Parcel in) {
        parcelableKey = in.readParcelable(getClreplaced().getClreplacedLoader());
        // noinspection unchecked
        viewHierarchyState = in.readSparseArray(getClreplaced().getClreplacedLoader());
        boolean hasBundle = in.readByte() > 0;
        if (hasBundle) {
            bundle = in.readParcelable(getClreplaced().getClreplacedLoader());
        }
        boolean hasViewBundle = in.readByte() > 0;
        if (hasViewBundle) {
            viewBundle = in.readParcelable(getClreplaced().getClreplacedLoader());
        }
    }

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

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

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

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeParcelable(parcelableKey, flags);
        // noinspection unchecked
        SparseArray<Object> sparseArray = (SparseArray) viewHierarchyState;
        dest.writeSparseArray(sparseArray);
        dest.writeByte(bundle != null ? (byte) 0x01 : 0x00);
        if (bundle != null) {
            dest.writeParcelable(bundle, 0);
        }
        dest.writeByte(viewBundle != null ? (byte) 0x01 : 0x00);
        if (viewBundle != null) {
            dest.writeParcelable(viewBundle, 0);
        }
    }
}

19 Source : ParcelledState.java
with Apache License 2.0
from Zhuinden

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeParcelable(parcelableKey, flags);
    // noinspection unchecked
    SparseArray<Object> sparseArray = (SparseArray) viewHierarchyState;
    dest.writeSparseArray(sparseArray);
    dest.writeByte(bundle != null ? (byte) 0x01 : 0x00);
    if (bundle != null) {
        dest.writeParcelable(bundle, 0);
    }
    dest.writeByte(viewBundle != null ? (byte) 0x01 : 0x00);
    if (viewBundle != null) {
        dest.writeParcelable(viewBundle, 0);
    }
}

19 Source : BaseViewHolder.java
with Apache License 2.0
from zhpanvip

/**
 * <pre>
 *   Created by zhpan on 2020/4/5.
 *   Attention:Don't use {@link RecyclerView.ViewHolder#getAdapterPosition}
 *   method to get position,this method will return a fake position.
 * </pre>
 */
@SuppressWarnings("unused")
public clreplaced BaseViewHolder<T> extends RecyclerView.ViewHolder {

    private final SparseArray<View> mViews = new SparseArray<>();

    public BaseViewHolder(@NonNull View itemView) {
        super(itemView);
    }

    /**
     * @deprecated bind data in adapter please.
     */
    @Deprecated
    public void bindData(T data, int position, int pageSize) {
    }

    @SuppressWarnings("unchecked")
    public <V extends View> V findViewById(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = itemView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (V) view;
    }

    public void setText(int viewId, CharSequence text) {
        View view = findViewById(viewId);
        if (view instanceof TextView) {
            ((TextView) view).setText(text);
        }
    }

    public void setText(int viewId, @StringRes int textId) {
        View view = findViewById(viewId);
        if (view instanceof TextView) {
            ((TextView) view).setText(textId);
        }
    }

    public void setTextColor(int viewId, @ColorInt int colorId) {
        View view = findViewById(viewId);
        if (view instanceof TextView) {
            ((TextView) view).setTextColor(colorId);
        }
    }

    public void setTextColorRes(@IdRes int viewId, @ColorRes int colorRes) {
        View view = findViewById(viewId);
        if (view instanceof TextView) {
            ((TextView) view).setTextColor(ContextCompat.getColor(itemView.getContext(), colorRes));
        }
    }

    public void setOnClickListener(int viewId, View.OnClickListener clickListener) {
        findViewById(viewId).setOnClickListener(clickListener);
    }

    public void setBackgroundResource(int viewId, @DrawableRes int resId) {
        findViewById(viewId).setBackgroundResource(resId);
    }

    public void setBackgroundColor(int viewId, @ColorInt int colorId) {
        findViewById(viewId).setBackgroundColor(colorId);
    }

    public void setImageResource(@IdRes int viewId, @DrawableRes int resId) {
        View view = findViewById(viewId);
        if (view instanceof ImageView) {
            ((ImageView) view).setImageResource(resId);
        }
    }

    public void setImageDrawable(@IdRes int viewId, Drawable drawable) {
        View view = findViewById(viewId);
        if (view instanceof ImageView) {
            ((ImageView) view).setImageDrawable(drawable);
        }
    }

    public void setImageBitmap(@IdRes int viewId, Bitmap bitmap) {
        ImageView view = findViewById(viewId);
        view.setImageBitmap(bitmap);
    }

    public void setVisibility(@IdRes int resId, @Visibility int visibility) {
        findViewById(resId).setVisibility(visibility);
    }
}

19 Source : PRouterV4.java
with Apache License 2.0
from zhouhuandev

/**
 * 把OnActivityResult方式转换为Callback方式的空Fragment(V4兼容包)
 *
 * Created by XiaoFeng on 2018/9/5.
 */
public clreplaced PRouterV4 extends Fragment {

    private SparseArray<PLauncher.Callback> mCallbacks = new SparseArray<>();

    private Random mCodeGenerator = new Random();

    public PRouterV4() {
    // Required empty public constructor
    }

    public static PRouterV4 newInstance() {
        return new PRouterV4();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    public void startActivityForResult(Intent intent, PLauncher.Callback callback) {
        int requestCode = makeRequestCode();
        mCallbacks.put(requestCode, callback);
        startActivityForResult(intent, requestCode);
    }

    /**
     * 随机生成唯一的requestCode,最多尝试10次
     *
     * @return
     */
    private int makeRequestCode() {
        int requestCode;
        int tryCount = 0;
        do {
            requestCode = mCodeGenerator.nextInt(0x0000FFFF);
            tryCount++;
        } while (mCallbacks.indexOfKey(requestCode) >= 0 && tryCount < 10);
        return requestCode;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        PLauncher.Callback callback = mCallbacks.get(requestCode);
        mCallbacks.remove(requestCode);
        if (callback != null) {
            callback.onActivityResult(resultCode, data);
        }
    }
}

19 Source : PRouter.java
with Apache License 2.0
from zhouhuandev

/**
 * 把OnActivityResult方式转换为Callback方式的空Fragment(标准SDK)
 *
 * Created by XiaoFeng on 2018/9/5.
 */
public clreplaced PRouter extends Fragment {

    private SparseArray<PLauncher.Callback> mCallbacks = new SparseArray<>();

    private Random mCodeGenerator = new Random();

    public PRouter() {
    // Required empty public constructor
    }

    public static PRouter newInstance() {
        return new PRouter();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    public void startActivityForResult(Intent intent, PLauncher.Callback callback) {
        int requestCode = makeRequestCode();
        mCallbacks.put(requestCode, callback);
        startActivityForResult(intent, requestCode);
    }

    /**
     * 随机生成唯一的requestCode,最多尝试10次
     *
     * @return
     */
    private int makeRequestCode() {
        int requestCode;
        int tryCount = 0;
        do {
            requestCode = mCodeGenerator.nextInt(0x0000FFFF);
            tryCount++;
        } while (mCallbacks.indexOfKey(requestCode) >= 0 && tryCount < 10);
        return requestCode;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        PLauncher.Callback callback = mCallbacks.get(requestCode);
        mCallbacks.remove(requestCode);
        if (callback != null) {
            callback.onActivityResult(resultCode, data);
        }
    }
}

19 Source : RecycleViewHolder.java
with Apache License 2.0
from zhonglikui

/**
 * RecycleView使用的ViewHolder
 * Created by zhong on 2017/4/1.
 */
public clreplaced RecycleViewHolder extends RecyclerView.ViewHolder {

    private SparseArray<View> mViews;

    private View mConvertView;

    public RecycleViewHolder(Context context, View itemView, ViewGroup parent) {
        super(itemView);
        mConvertView = itemView;
        mViews = new SparseArray<>();
    }

    public static RecycleViewHolder get(Context context, ViewGroup parent, int layoutId) {
        View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        return new RecycleViewHolder(context, itemView, parent);
    }

    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

    /**
     * @return 返回convertView
     */
    public View getConvertView() {
        return mConvertView;
    }
}

19 Source : ListViewHolder.java
with Apache License 2.0
from zhonglikui

/**
 * Created by zhong on 2015/10/12.
 * BaseListAdapter的辅助工具类
 */
public clreplaced ListViewHolder {

    private final View mConvertView;

    private final SparseArray<View> mViews;

    /**
     * 初始化ViewHolder
     *
     * @param context       Context
     * @param convertViewId item的layout
     */
    private ListViewHolder(Context context, int convertViewId) {
        mViews = new SparseArray<>();
        mConvertView = View.inflate(context, convertViewId, null);
        mConvertView.setTag(this);
    }

    /**
     * 获取ViewHolder对象
     *
     * @param convertView layout
     * @return ViewHolder
     */
    static ListViewHolder get(Context context, View convertView, int converViewId) {
        if (convertView == null) {
            return new ListViewHolder(context, converViewId);
        } else {
            return (ListViewHolder) convertView.getTag();
        }
    }

    /**
     * 通过控件的id获取相对应的控件
     *
     * @param viewId 需要查找的View的id
     * @param <T>    View的类型
     * @return 查找的结果
     */
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

    /**
     * @return 返回convertView
     */
    View getConvertView() {
        return mConvertView;
    }
}

19 Source : PreviewPagerAdapter.java
with MIT License
from zhongjhATC

public clreplaced PreviewPagerAdapter extends FragmentPagerAdapter {

    private ArrayList<MultiMedia> mItems = new ArrayList<>();

    private SparseArray<Fragment> fragments;

    private OnPrimaryItemSetListener mListener;

    public PreviewPagerAdapter(FragmentManager manager, OnPrimaryItemSetListener listener) {
        super(manager);
        mListener = listener;
        fragments = new SparseArray<>(getCount());
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        fragments.put(position, fragment);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
        fragments.remove(position);
    }

    public Fragment getFragment(int position) {
        return fragments.get(position);
    }

    @Override
    public Fragment gereplacedem(int position) {
        return PreviewItemFragment.newInstance(mItems.get(position));
    }

    @Override
    public int getCount() {
        return mItems.size();
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
        if (mListener != null) {
            mListener.onPrimaryItemSet(position);
        }
    }

    public MultiMedia getMediaItem(int position) {
        return mItems.get(position);
    }

    public void setMediaItem(int position, MultiMedia multiMedia) {
        mItems.set(position, multiMedia);
    }

    public void addAll(List<MultiMedia> items) {
        mItems.addAll(items);
    }

    public ArrayList<MultiMedia> getmItems() {
        return mItems;
    }

    interface OnPrimaryItemSetListener {

        void onPrimaryItemSet(int position);
    }
}

19 Source : UiSelector.java
with MIT License
from ZhongAnTech

/**
 * Specifies the elements in the layout hierarchy for tests to target, filtered
 * by properties such as text value, content-description, clreplaced name, and state
 * information. You can also target an element by its location in a layout
 * hierarchy.
 * @since API Level 16
 */
public clreplaced UiSelector {

    static final int SELECTOR_NIL = 0;

    static final int SELECTOR_TEXT = 1;

    static final int SELECTOR_START_TEXT = 2;

    static final int SELECTOR_CONTAINS_TEXT = 3;

    static final int SELECTOR_CLreplaced = 4;

    static final int SELECTOR_DESCRIPTION = 5;

    static final int SELECTOR_START_DESCRIPTION = 6;

    static final int SELECTOR_CONTAINS_DESCRIPTION = 7;

    static final int SELECTOR_INDEX = 8;

    static final int SELECTOR_INSTANCE = 9;

    static final int SELECTOR_ENABLED = 10;

    static final int SELECTOR_FOCUSED = 11;

    static final int SELECTOR_FOCUSABLE = 12;

    static final int SELECTOR_SCROLLABLE = 13;

    static final int SELECTOR_CLICKABLE = 14;

    static final int SELECTOR_CHECKED = 15;

    static final int SELECTOR_SELECTED = 16;

    static final int SELECTOR_ID = 17;

    static final int SELECTOR_PACKAGE_NAME = 18;

    static final int SELECTOR_CHILD = 19;

    static final int SELECTOR_CONTAINER = 20;

    static final int SELECTOR_PATTERN = 21;

    static final int SELECTOR_PARENT = 22;

    static final int SELECTOR_COUNT = 23;

    static final int SELECTOR_LONG_CLICKABLE = 24;

    static final int SELECTOR_TEXT_REGEX = 25;

    static final int SELECTOR_CLreplaced_REGEX = 26;

    static final int SELECTOR_DESCRIPTION_REGEX = 27;

    static final int SELECTOR_PACKAGE_NAME_REGEX = 28;

    static final int SELECTOR_RESOURCE_ID = 29;

    static final int SELECTOR_CHECKABLE = 30;

    static final int SELECTOR_RESOURCE_ID_REGEX = 31;

    private SparseArray<Object> mSelectorAttributes = new SparseArray<Object>();

    /**
     * @since API Level 16
     */
    public UiSelector() {
    }

    UiSelector(UiSelector selector) {
        mSelectorAttributes = selector.cloneSelector().mSelectorAttributes;
    }

    /**
     * @since API Level 17
     */
    protected UiSelector cloneSelector() {
        UiSelector ret = new UiSelector();
        ret.mSelectorAttributes = mSelectorAttributes.clone();
        if (hasChildSelector())
            ret.mSelectorAttributes.put(SELECTOR_CHILD, new UiSelector(getChildSelector()));
        if (hasParentSelector())
            ret.mSelectorAttributes.put(SELECTOR_PARENT, new UiSelector(getParentSelector()));
        if (hasPatternSelector())
            ret.mSelectorAttributes.put(SELECTOR_PATTERN, new UiSelector(getPatternSelector()));
        return ret;
    }

    static UiSelector patternBuilder(UiSelector selector) {
        if (!selector.hasPatternSelector()) {
            return new UiSelector().patternSelector(selector);
        }
        return selector;
    }

    static UiSelector patternBuilder(UiSelector container, UiSelector pattern) {
        return new UiSelector(new UiSelector().containerSelector(container).patternSelector(pattern));
    }

    /**
     * Set the search criteria to match the visible text displayed
     * in a widget (for example, the text label to launch an app).
     *
     * The text for the element must match exactly with the string in your input
     * argument. Matching is case-sensitive.
     *
     * @param text Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector text(String text) {
        if (text == null) {
            throw new IllegalArgumentException("text cannot be null");
        }
        return buildSelector(SELECTOR_TEXT, text);
    }

    /**
     * Set the search criteria to match the visible text displayed in a layout
     * element, using a regular expression.
     *
     * The text in the widget must match exactly with the string in your
     * input argument.
     *
     * @param regex a regular expression
     * @return UiSelector with the specified search criteria
     * @since API Level 17
     */
    public UiSelector textMatches(String regex) {
        if (regex == null) {
            throw new IllegalArgumentException("regex cannot be null");
        }
        return buildSelector(SELECTOR_TEXT_REGEX, Pattern.compile(regex));
    }

    /**
     * Set the search criteria to match visible text in a widget that is
     * prefixed by the text parameter.
     *
     * The matching is case-insensitive.
     *
     * @param text Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector textStartsWith(String text) {
        if (text == null) {
            throw new IllegalArgumentException("text cannot be null");
        }
        return buildSelector(SELECTOR_START_TEXT, text);
    }

    /**
     * Set the search criteria to match the visible text in a widget
     * where the visible text must contain the string in your input argument.
     *
     * The matching is case-sensitive.
     *
     * @param text Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector textContains(String text) {
        if (text == null) {
            throw new IllegalArgumentException("text cannot be null");
        }
        return buildSelector(SELECTOR_CONTAINS_TEXT, text);
    }

    /**
     * Set the search criteria to match the clreplaced property
     * for a widget (for example, "android.widget.Button").
     *
     * @param clreplacedName Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector clreplacedName(String clreplacedName) {
        if (clreplacedName == null) {
            throw new IllegalArgumentException("clreplacedName cannot be null");
        }
        return buildSelector(SELECTOR_CLreplaced, clreplacedName);
    }

    /**
     * Set the search criteria to match the clreplaced property
     * for a widget, using a regular expression.
     *
     * @param regex a regular expression
     * @return UiSelector with the specified search criteria
     * @since API Level 17
     */
    public UiSelector clreplacedNameMatches(String regex) {
        if (regex == null) {
            throw new IllegalArgumentException("regex cannot be null");
        }
        return buildSelector(SELECTOR_CLreplaced_REGEX, Pattern.compile(regex));
    }

    /**
     * Set the search criteria to match the clreplaced property
     * for a widget (for example, "android.widget.Button").
     *
     * @param type type
     * @return UiSelector with the specified search criteria
     * @since API Level 17
     */
    public <T> UiSelector clreplacedName(Clreplaced<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("type cannot be null");
        }
        return buildSelector(SELECTOR_CLreplaced, type.getName());
    }

    /**
     * Set the search criteria to match the content-description
     * property for a widget.
     *
     * The content-description is typically used
     * by the Android Accessibility framework to
     * provide an audio prompt for the widget when
     * the widget is selected. The content-description
     * for the widget must match exactly
     * with the string in your input argument.
     *
     * Matching is case-sensitive.
     *
     * @param desc Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector description(String desc) {
        if (desc == null) {
            throw new IllegalArgumentException("desc cannot be null");
        }
        return buildSelector(SELECTOR_DESCRIPTION, desc);
    }

    /**
     * Set the search criteria to match the content-description
     * property for a widget.
     *
     * The content-description is typically used
     * by the Android Accessibility framework to
     * provide an audio prompt for the widget when
     * the widget is selected. The content-description
     * for the widget must match exactly
     * with the string in your input argument.
     *
     * @param regex a regular expression
     * @return UiSelector with the specified search criteria
     * @since API Level 17
     */
    public UiSelector descriptionMatches(String regex) {
        if (regex == null) {
            throw new IllegalArgumentException("regex cannot be null");
        }
        return buildSelector(SELECTOR_DESCRIPTION_REGEX, Pattern.compile(regex));
    }

    /**
     * Set the search criteria to match the content-description
     * property for a widget.
     *
     * The content-description is typically used
     * by the Android Accessibility framework to
     * provide an audio prompt for the widget when
     * the widget is selected. The content-description
     * for the widget must start
     * with the string in your input argument.
     *
     * Matching is case-insensitive.
     *
     * @param desc Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector descriptionStartsWith(String desc) {
        if (desc == null) {
            throw new IllegalArgumentException("desc cannot be null");
        }
        return buildSelector(SELECTOR_START_DESCRIPTION, desc);
    }

    /**
     * Set the search criteria to match the content-description
     * property for a widget.
     *
     * The content-description is typically used
     * by the Android Accessibility framework to
     * provide an audio prompt for the widget when
     * the widget is selected. The content-description
     * for the widget must contain
     * the string in your input argument.
     *
     * Matching is case-insensitive.
     *
     * @param desc Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector descriptionContains(String desc) {
        if (desc == null) {
            throw new IllegalArgumentException("desc cannot be null");
        }
        return buildSelector(SELECTOR_CONTAINS_DESCRIPTION, desc);
    }

    /**
     * Set the search criteria to match the given resource ID.
     *
     * @param id Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 18
     */
    public UiSelector resourceId(String id) {
        if (id == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        return buildSelector(SELECTOR_RESOURCE_ID, id);
    }

    /**
     * Set the search criteria to match the resource ID
     * of the widget, using a regular expression.
     *
     * @param regex a regular expression
     * @return UiSelector with the specified search criteria
     * @since API Level 18
     */
    public UiSelector resourceIdMatches(String regex) {
        if (regex == null) {
            throw new IllegalArgumentException("regex cannot be null");
        }
        return buildSelector(SELECTOR_RESOURCE_ID_REGEX, Pattern.compile(regex));
    }

    /**
     * Set the search criteria to match the widget by its node
     * index in the layout hierarchy.
     *
     * The index value must be 0 or greater.
     *
     * Using the index can be unreliable and should only
     * be used as a last resort for matching. Instead,
     * consider using the {@link #instance(int)} method.
     *
     * @param index Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector index(final int index) {
        return buildSelector(SELECTOR_INDEX, index);
    }

    /**
     * Set the search criteria to match the
     * widget by its instance number.
     *
     * The instance value must be 0 or greater, where
     * the first instance is 0.
     *
     * For example, to simulate a user click on
     * the third image that is enabled in a UI screen, you
     * could specify a a search criteria where the instance is
     * 2, the {@link #clreplacedName(String)} matches the image
     * widget clreplaced, and {@link #enabled(boolean)} is true.
     * The code would look like this:
     * <code>
     * new UiSelector().clreplacedName("android.widget.ImageView")
     *    .enabled(true).instance(2);
     * </code>
     *
     * @param instance Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector instance(final int instance) {
        return buildSelector(SELECTOR_INSTANCE, instance);
    }

    /**
     * Set the search criteria to match widgets that are enabled.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector enabled(boolean val) {
        return buildSelector(SELECTOR_ENABLED, val);
    }

    /**
     * Set the search criteria to match widgets that have focus.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector focused(boolean val) {
        return buildSelector(SELECTOR_FOCUSED, val);
    }

    /**
     * Set the search criteria to match widgets that are focusable.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector focusable(boolean val) {
        return buildSelector(SELECTOR_FOCUSABLE, val);
    }

    /**
     * Set the search criteria to match widgets that are scrollable.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector scrollable(boolean val) {
        return buildSelector(SELECTOR_SCROLLABLE, val);
    }

    /**
     * Set the search criteria to match widgets that
     * are currently selected.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector selected(boolean val) {
        return buildSelector(SELECTOR_SELECTED, val);
    }

    /**
     * Set the search criteria to match widgets that
     * are currently checked (usually for checkboxes).
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector checked(boolean val) {
        return buildSelector(SELECTOR_CHECKED, val);
    }

    /**
     * Set the search criteria to match widgets that are clickable.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector clickable(boolean val) {
        return buildSelector(SELECTOR_CLICKABLE, val);
    }

    /**
     * Set the search criteria to match widgets that are checkable.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 18
     */
    public UiSelector checkable(boolean val) {
        return buildSelector(SELECTOR_CHECKABLE, val);
    }

    /**
     * Set the search criteria to match widgets that are long-clickable.
     *
     * Typically, using this search criteria alone is not useful.
     * You should also include additional criteria, such as text,
     * content-description, or the clreplaced name for a widget.
     *
     * If no other search criteria is specified, and there is more
     * than one matching widget, the first widget in the tree
     * is selected.
     *
     * @param val Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 17
     */
    public UiSelector longClickable(boolean val) {
        return buildSelector(SELECTOR_LONG_CLICKABLE, val);
    }

    /**
     * Adds a child UiSelector criteria to this selector.
     *
     * Use this selector to narrow the search scope to
     * child widgets under a specific parent widget.
     *
     * @param selector
     * @return UiSelector with this added search criterion
     * @since API Level 16
     */
    public UiSelector childSelector(UiSelector selector) {
        if (selector == null) {
            throw new IllegalArgumentException("selector cannot be null");
        }
        return buildSelector(SELECTOR_CHILD, selector);
    }

    private UiSelector patternSelector(UiSelector selector) {
        return buildSelector(SELECTOR_PATTERN, selector);
    }

    private UiSelector containerSelector(UiSelector selector) {
        return buildSelector(SELECTOR_CONTAINER, selector);
    }

    /**
     * Adds a child UiSelector criteria to this selector which is used to
     * start search from the parent widget.
     *
     * Use this selector to narrow the search scope to
     * sibling widgets as well all child widgets under a parent.
     *
     * @param selector
     * @return UiSelector with this added search criterion
     * @since API Level 16
     */
    public UiSelector fromParent(UiSelector selector) {
        if (selector == null) {
            throw new IllegalArgumentException("selector cannot be null");
        }
        return buildSelector(SELECTOR_PARENT, selector);
    }

    /**
     * Set the search criteria to match the package name
     * of the application that contains the widget.
     *
     * @param name Value to match
     * @return UiSelector with the specified search criteria
     * @since API Level 16
     */
    public UiSelector packageName(String name) {
        if (name == null) {
            throw new IllegalArgumentException("name cannot be null");
        }
        return buildSelector(SELECTOR_PACKAGE_NAME, name);
    }

    /**
     * Set the search criteria to match the package name
     * of the application that contains the widget.
     *
     * @param regex a regular expression
     * @return UiSelector with the specified search criteria
     * @since API Level 17
     */
    public UiSelector packageNameMatches(String regex) {
        if (regex == null) {
            throw new IllegalArgumentException("regex cannot be null");
        }
        return buildSelector(SELECTOR_PACKAGE_NAME_REGEX, Pattern.compile(regex));
    }

    /**
     * Building a UiSelector always returns a new UiSelector and never modifies the
     * existing UiSelector being used.
     */
    private UiSelector buildSelector(int selectorId, Object selectorValue) {
        UiSelector selector = new UiSelector(this);
        if (selectorId == SELECTOR_CHILD || selectorId == SELECTOR_PARENT)
            selector.getLastSubSelector().mSelectorAttributes.put(selectorId, selectorValue);
        else
            selector.mSelectorAttributes.put(selectorId, selectorValue);
        return selector;
    }

    /**
     * Selectors may have a hierarchy defined by specifying child nodes to be matched.
     * It is not necessary that every selector have more than one level. A selector
     * can also be a single level referencing only one node. In such cases the return
     * it null.
     *
     * @return a child selector if one exists. Else null if this selector does not
     * reference child node.
     */
    UiSelector getChildSelector() {
        UiSelector selector = (UiSelector) mSelectorAttributes.get(UiSelector.SELECTOR_CHILD, null);
        if (selector != null)
            return new UiSelector(selector);
        return null;
    }

    UiSelector getPatternSelector() {
        UiSelector selector = (UiSelector) mSelectorAttributes.get(UiSelector.SELECTOR_PATTERN, null);
        if (selector != null)
            return new UiSelector(selector);
        return null;
    }

    UiSelector getContainerSelector() {
        UiSelector selector = (UiSelector) mSelectorAttributes.get(UiSelector.SELECTOR_CONTAINER, null);
        if (selector != null)
            return new UiSelector(selector);
        return null;
    }

    UiSelector getParentSelector() {
        UiSelector selector = (UiSelector) mSelectorAttributes.get(UiSelector.SELECTOR_PARENT, null);
        if (selector != null)
            return new UiSelector(selector);
        return null;
    }

    int getInstance() {
        return getInt(UiSelector.SELECTOR_INSTANCE);
    }

    String getString(int criterion) {
        return (String) mSelectorAttributes.get(criterion, null);
    }

    boolean getBoolean(int criterion) {
        return (Boolean) mSelectorAttributes.get(criterion, false);
    }

    int getInt(int criterion) {
        return (Integer) mSelectorAttributes.get(criterion, 0);
    }

    Pattern getPattern(int criterion) {
        return (Pattern) mSelectorAttributes.get(criterion, null);
    }

    boolean isMatchFor(AccessibilityNodeInfo node, int index) {
        int size = mSelectorAttributes.size();
        for (int x = 0; x < size; x++) {
            CharSequence s = null;
            int criterion = mSelectorAttributes.keyAt(x);
            switch(criterion) {
                case UiSelector.SELECTOR_INDEX:
                    if (index != this.getInt(criterion))
                        return false;
                    break;
                case UiSelector.SELECTOR_CHECKED:
                    if (node.isChecked() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_CLreplaced:
                    s = node.getClreplacedName();
                    if (s == null || !s.toString().contentEquals(getString(criterion))) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_CLreplaced_REGEX:
                    s = node.getClreplacedName();
                    if (s == null || !getPattern(criterion).matcher(s).matches()) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_CLICKABLE:
                    if (node.isClickable() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_CHECKABLE:
                    if (node.isCheckable() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_LONG_CLICKABLE:
                    if (node.isLongClickable() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_CONTAINS_DESCRIPTION:
                    s = node.getContentDescription();
                    if (s == null || !s.toString().toLowerCase().contains(getString(criterion).toLowerCase())) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_START_DESCRIPTION:
                    s = node.getContentDescription();
                    if (s == null || !s.toString().toLowerCase().startsWith(getString(criterion).toLowerCase())) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_DESCRIPTION:
                    s = node.getContentDescription();
                    if (s == null || !s.toString().contentEquals(getString(criterion))) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_DESCRIPTION_REGEX:
                    s = node.getContentDescription();
                    if (s == null || !getPattern(criterion).matcher(s).matches()) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_CONTAINS_TEXT:
                    s = node.getText();
                    if (s == null || !s.toString().toLowerCase().contains(getString(criterion).toLowerCase())) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_START_TEXT:
                    s = node.getText();
                    if (s == null || !s.toString().toLowerCase().startsWith(getString(criterion).toLowerCase())) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_TEXT:
                    s = node.getText();
                    if (s == null || !s.toString().contentEquals(getString(criterion))) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_TEXT_REGEX:
                    s = node.getText();
                    if (s == null || !getPattern(criterion).matcher(s).matches()) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_ENABLED:
                    if (node.isEnabled() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_FOCUSABLE:
                    if (node.isFocusable() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_FOCUSED:
                    if (node.isFocused() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_ID:
                    // TODO: do we need this for AccessibilityNodeInfo.id?
                    break;
                case UiSelector.SELECTOR_PACKAGE_NAME:
                    s = node.getPackageName();
                    if (s == null || !s.toString().contentEquals(getString(criterion))) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_PACKAGE_NAME_REGEX:
                    s = node.getPackageName();
                    if (s == null || !getPattern(criterion).matcher(s).matches()) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_SCROLLABLE:
                    if (node.isScrollable() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_SELECTED:
                    if (node.isSelected() != getBoolean(criterion)) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_RESOURCE_ID:
                    s = node.getViewIdResourceName();
                    if (s == null || !s.toString().contentEquals(getString(criterion))) {
                        return false;
                    }
                    break;
                case UiSelector.SELECTOR_RESOURCE_ID_REGEX:
                    s = node.getViewIdResourceName();
                    if (s == null || !getPattern(criterion).matcher(s).matches()) {
                        return false;
                    }
                    break;
            }
        }
        return matchOrUpdateInstance();
    }

    private boolean matchOrUpdateInstance() {
        int currentSelectorCounter = 0;
        int currentSelectorInstance = 0;
        // matched attributes - now check for matching instance number
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_INSTANCE) >= 0) {
            currentSelectorInstance = (Integer) mSelectorAttributes.get(UiSelector.SELECTOR_INSTANCE);
        }
        // instance is required. Add count if not already counting
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_COUNT) >= 0) {
            currentSelectorCounter = (Integer) mSelectorAttributes.get(UiSelector.SELECTOR_COUNT);
        }
        // Verify
        if (currentSelectorInstance == currentSelectorCounter) {
            return true;
        }
        // Update count
        if (currentSelectorInstance > currentSelectorCounter) {
            mSelectorAttributes.put(UiSelector.SELECTOR_COUNT, ++currentSelectorCounter);
        }
        return false;
    }

    /**
     * Leaf selector indicates no more child or parent selectors
     * are declared in the this selector.
     * @return true if is leaf.
     */
    boolean isLeaf() {
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) < 0 && mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) < 0) {
            return true;
        }
        return false;
    }

    boolean hasChildSelector() {
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) < 0) {
            return false;
        }
        return true;
    }

    boolean hasPatternSelector() {
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PATTERN) < 0) {
            return false;
        }
        return true;
    }

    boolean hasContainerSelector() {
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CONTAINER) < 0) {
            return false;
        }
        return true;
    }

    boolean hasParentSelector() {
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) < 0) {
            return false;
        }
        return true;
    }

    /**
     * Returns the deepest selector in the chain of possible sub selectors.
     * A chain of selector is created when either of {@link UiSelector#childSelector(UiSelector)}
     * or {@link UiSelector#fromParent(UiSelector)} are used once or more in the construction of
     * a selector.
     * @return last UiSelector in chain
     */
    private UiSelector getLastSubSelector() {
        if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_CHILD) >= 0) {
            UiSelector child = (UiSelector) mSelectorAttributes.get(UiSelector.SELECTOR_CHILD);
            if (child.getLastSubSelector() == null) {
                return child;
            }
            return child.getLastSubSelector();
        } else if (mSelectorAttributes.indexOfKey(UiSelector.SELECTOR_PARENT) >= 0) {
            UiSelector parent = (UiSelector) mSelectorAttributes.get(UiSelector.SELECTOR_PARENT);
            if (parent.getLastSubSelector() == null) {
                return parent;
            }
            return parent.getLastSubSelector();
        }
        return this;
    }

    @Override
    public String toString() {
        return dumpToString(true);
    }

    String dumpToString(boolean all) {
        StringBuilder builder = new StringBuilder();
        builder.append(UiSelector.clreplaced.getSimpleName() + "[");
        final int criterionCount = mSelectorAttributes.size();
        for (int i = 0; i < criterionCount; i++) {
            if (i > 0) {
                builder.append(", ");
            }
            final int criterion = mSelectorAttributes.keyAt(i);
            switch(criterion) {
                case SELECTOR_TEXT:
                    builder.append("TEXT=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_TEXT_REGEX:
                    builder.append("TEXT_REGEX=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_START_TEXT:
                    builder.append("START_TEXT=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CONTAINS_TEXT:
                    builder.append("CONTAINS_TEXT=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CLreplaced:
                    builder.append("CLreplaced=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CLreplaced_REGEX:
                    builder.append("CLreplaced_REGEX=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_DESCRIPTION:
                    builder.append("DESCRIPTION=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_DESCRIPTION_REGEX:
                    builder.append("DESCRIPTION_REGEX=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_START_DESCRIPTION:
                    builder.append("START_DESCRIPTION=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CONTAINS_DESCRIPTION:
                    builder.append("CONTAINS_DESCRIPTION=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_INDEX:
                    builder.append("INDEX=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_INSTANCE:
                    builder.append("INSTANCE=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_ENABLED:
                    builder.append("ENABLED=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_FOCUSED:
                    builder.append("FOCUSED=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_FOCUSABLE:
                    builder.append("FOCUSABLE=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_SCROLLABLE:
                    builder.append("SCROLLABLE=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CLICKABLE:
                    builder.append("CLICKABLE=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CHECKABLE:
                    builder.append("CHECKABLE=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_LONG_CLICKABLE:
                    builder.append("LONG_CLICKABLE=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CHECKED:
                    builder.append("CHECKED=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_SELECTED:
                    builder.append("SELECTED=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_ID:
                    builder.append("ID=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_CHILD:
                    if (all)
                        builder.append("CHILD=").append(mSelectorAttributes.valueAt(i));
                    else
                        builder.append("CHILD[..]");
                    break;
                case SELECTOR_PATTERN:
                    if (all)
                        builder.append("PATTERN=").append(mSelectorAttributes.valueAt(i));
                    else
                        builder.append("PATTERN[..]");
                    break;
                case SELECTOR_CONTAINER:
                    if (all)
                        builder.append("CONTAINER=").append(mSelectorAttributes.valueAt(i));
                    else
                        builder.append("CONTAINER[..]");
                    break;
                case SELECTOR_PARENT:
                    if (all)
                        builder.append("PARENT=").append(mSelectorAttributes.valueAt(i));
                    else
                        builder.append("PARENT[..]");
                    break;
                case SELECTOR_COUNT:
                    builder.append("COUNT=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_PACKAGE_NAME:
                    builder.append("PACKAGE NAME=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_PACKAGE_NAME_REGEX:
                    builder.append("PACKAGE_NAME_REGEX=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_RESOURCE_ID:
                    builder.append("RESOURCE_ID=").append(mSelectorAttributes.valueAt(i));
                    break;
                case SELECTOR_RESOURCE_ID_REGEX:
                    builder.append("RESOURCE_ID_REGEX=").append(mSelectorAttributes.valueAt(i));
                    break;
                default:
                    builder.append("UNDEFINED=" + criterion + " ").append(mSelectorAttributes.valueAt(i));
            }
        }
        builder.append("]");
        return builder.toString();
    }
}

19 Source : SugarAdapter.java
with Apache License 2.0
from zhihu

@SuppressWarnings({ "unused", "WeakerAccess" })
public final clreplaced SugarAdapter extends RecyclerView.Adapter<SugarHolder> {

    private static final String TAG = "SugarAdapter";

    public static final clreplaced Builder {

        private List<?> mList;

        private SparseArray<Container> mContainerArray;

        private boolean mPreInflate;

        @NonNull
        public static Builder with(@NonNull List<?> list) {
            return new Builder(list);
        }

        private Builder(@NonNull List<?> list) {
            mList = list;
            mContainerArray = new SparseArray<>();
        }

        @NonNull
        public <SH extends SugarHolder> Builder add(@NonNull Clreplaced<SH> holderClreplaced) {
            return add(holderClreplaced, null);
        }

        @NonNull
        public <SH extends SugarHolder> Builder add(@NonNull Clreplaced<SH> holderClreplaced, @Nullable SugarHolder.OnCreatedCallback<SH> callback) {
            ContainerDelegate delegate = Sugar.INSTANCE.getContainerDelegate();
            Clreplaced dataClreplaced = delegate.getDataClreplaced(holderClreplaced);
            int layoutRes = delegate.getLayoutRes(holderClreplaced);
            if (layoutRes == 0) {
                throw new IllegalStateException(holderClreplaced.getCanonicalName() + " must have an annotation @Layout(R.layout.*)");
            }
            mContainerArray.put(holderClreplaced.hashCode(), new Container(holderClreplaced, dataClreplaced, layoutRes, callback));
            return this;
        }

        @NonNull
        public <SH extends SugarHolder> Builder preInflate(boolean enable) {
            mPreInflate = enable;
            return this;
        }

        @NonNull
        public SugarAdapter build() {
            if (mContainerArray.size() <= 0) {
                throw new IllegalStateException("must add at least one Clreplaced<? extends SugarHolder>");
            }
            return new SugarAdapter(mList, mContainerArray, mPreInflate);
        }
    }

    public interface ExtraDelegate {

        void onAttachedToRecyclerView(@NonNull RecyclerView view);

        void onDetachedFromRecyclerView(@NonNull RecyclerView view);
    }

    public interface PreInflateListener {

        void onPreInflateExecuted(@LayoutRes int layoutRes);

        void onPreInflateConsumed(@LayoutRes int layoutRes, boolean fallback);
    }

    public static abstract clreplaced Dispatcher<T> {

        // return null to use default rule
        @Nullable
        public abstract Clreplaced<? extends SugarHolder> dispatch(@NonNull T data);

        // https://stackoverflow.com/q/3437897
        @Deprecated
        @NonNull
        private Clreplaced<T> ofType() {
            try {
                // noinspection ConstantConditions
                String clreplacedName = ((ParameterizedType) getClreplaced().getGenericSuperclreplaced()).getActualTypeArguments()[0].toString().split(" ")[1];
                // noinspection unchecked
                return (Clreplaced<T>) Clreplaced.forName(clreplacedName);
            } catch (@NonNull Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static abstract clreplaced SugarHolderListener<SH extends SugarHolder> {

        private Clreplaced<SH> mSugarHolderClreplaced = ofType();

        // https://stackoverflow.com/q/3437897
        @NonNull
        private Clreplaced<SH> ofType() {
            try {
                // noinspection ConstantConditions
                String clreplacedName = ((ParameterizedType) getClreplaced().getGenericSuperclreplaced()).getActualTypeArguments()[0].toString().split(" ")[1];
                // noinspection unchecked
                return (Clreplaced<SH>) Clreplaced.forName(clreplacedName);
            } catch (@NonNull Exception e) {
                throw new RuntimeException(e);
            }
        }

        private boolean isInstance(@Nullable Object object) {
            return mSugarHolderClreplaced.isInstance(object);
        }

        public void onSugarHolderCreated(@NonNull SH holder) {
        }

        public void onSugarHolderBindData(@NonNull SH holder) {
        }

        public void onSugarHolderViewAttachedToWindow(@NonNull SH holder) {
        }

        public void onSugarHolderViewDetachedFromWindow(@NonNull SH holder) {
        }

        public void onSugarHolderViewRecycled(@NonNull SH holder) {
        }
    }

    private List<?> mList;

    private SparseArray<Container> mContainerArray;

    private Map<Clreplaced<?>, Dispatcher<?>> mDispatcherMap;

    private List<ExtraDelegate> mExtraDelegateList;

    private List<PreInflateListener> mPreInflateListenerList;

    private List<SugarHolderListener<?>> mSugarHolderListenerList;

    private MessageQueue.IdleHandler mPreInflateHandler;

    private SparseArray<View> mPreInflateArray;

    private SugarAdapter(@NonNull List<?> list, @NonNull SparseArray<Container> containerArray, boolean preInflate) {
        mList = list;
        mContainerArray = containerArray;
        mDispatcherMap = new HashMap<>();
        mExtraDelegateList = new ArrayList<>();
        mPreInflateListenerList = new ArrayList<>();
        mSugarHolderListenerList = new ArrayList<>();
        if (preInflate) {
            mPreInflateArray = new SparseArray<>();
            for (int i = 0; i < mContainerArray.size(); i++) {
                int key = mContainerArray.keyAt(i);
                Container container = mContainerArray.get(key);
                mPreInflateArray.put(container.getLayoutRes(), null);
            }
        }
    }

    // <editor-fold desc="Dispatcher">
    @Deprecated
    @NonNull
    public <T> SugarAdapter addDispatcher(@NonNull Dispatcher<T> dispatcher) {
        return addDispatcher(dispatcher.ofType(), dispatcher);
    }

    @NonNull
    public <T> SugarAdapter addDispatcher(@NonNull Clreplaced<T> clazz, @NonNull Dispatcher<T> dispatcher) {
        if (mDispatcherMap.containsKey(clazz)) {
            Log.d(TAG, "addDispatcher repeated" + ", SugarAdapter already has a dispatcher of " + clazz.getCanonicalName() + ", new dispatcher will cover the old one.");
        }
        mDispatcherMap.put(clazz, dispatcher);
        return this;
    }

    @Deprecated
    @NonNull
    public <T> SugarAdapter removeDispatcher(@NonNull Dispatcher<T> dispatcher) {
        return removeDispatcher(dispatcher.ofType());
    }

    @NonNull
    public <T> SugarAdapter removeDispatcher(@NonNull Clreplaced<T> clazz) {
        mDispatcherMap.remove(clazz);
        return this;
    }

    @NonNull
    public SugarAdapter clearDispatcher() {
        mDispatcherMap.clear();
        return this;
    }

    // </editor-fold>
    // <editor-fold desc="ExtraDelegate">
    @NonNull
    public SugarAdapter addExtraDelegate(@NonNull ExtraDelegate delegate) {
        if (!mExtraDelegateList.contains(delegate)) {
            mExtraDelegateList.add(delegate);
        }
        return this;
    }

    @NonNull
    public SugarAdapter removeExtraDelegate(@NonNull ExtraDelegate delegate) {
        mExtraDelegateList.remove(delegate);
        return this;
    }

    @NonNull
    public SugarAdapter clearExtraDelegate() {
        mExtraDelegateList.clear();
        return this;
    }

    // </editor-fold>
    // <editor-fold desc="PreInflateListener">
    @NonNull
    public SugarAdapter addPreInflateListener(@NonNull PreInflateListener listener) {
        if (!mPreInflateListenerList.contains(listener)) {
            mPreInflateListenerList.add(listener);
        }
        return this;
    }

    @NonNull
    public SugarAdapter removePreInflateListener(@NonNull PreInflateListener listener) {
        mPreInflateListenerList.remove(listener);
        return this;
    }

    @NonNull
    public SugarAdapter clearPreInflateListener() {
        mPreInflateListenerList.clear();
        return this;
    }

    @NonNull
    public SugarAdapter clearPreInflateViews() {
        if (mPreInflateArray != null) {
            mPreInflateArray.clear();
        }
        return this;
    }

    // </editor-fold>
    // <editor-fold desc="SugarHolderListener">
    @SuppressWarnings("UnusedReturnValue")
    @NonNull
    public <SH extends SugarHolder> SugarAdapter addSugarHolderListener(@NonNull SugarHolderListener<SH> listener) {
        if (!mSugarHolderListenerList.contains(listener)) {
            mSugarHolderListenerList.add(listener);
        }
        return this;
    }

    @NonNull
    public SugarAdapter removeSugarHolderListener(@NonNull SugarHolderListener<?> listener) {
        mSugarHolderListenerList.remove(listener);
        return this;
    }

    @NonNull
    public SugarAdapter clearSugarHolderListener() {
        mSugarHolderListenerList.clear();
        return this;
    }

    // </editor-fold>
    @NonNull
    public List<?> getList() {
        return mList;
    }

    @Override
    public int gereplacedemCount() {
        return mList.size();
    }

    @SuppressWarnings({ "ConstantConditions", "unchecked" })
    @Override
    public int gereplacedemViewType(@IntRange(from = 0) int position) {
        Object data = mList.get(position);
        Clreplaced<? extends SugarHolder> holderClreplaced = null;
        if (mDispatcherMap.containsKey(data.getClreplaced())) {
            Dispatcher dispatcher = mDispatcherMap.get(data.getClreplaced());
            holderClreplaced = dispatcher.dispatch(data);
        }
        if (holderClreplaced != null) {
            int key = holderClreplaced.hashCode();
            if (mContainerArray.indexOfKey(key) < 0) {
                throw new RuntimeException("gereplacedemViewType() failed, holder: " + holderClreplaced.getCanonicalName() + ", please make sure you have added it when build SugarAdapter.");
            }
            mContainerArray.get(key).setData(data);
            return key;
        }
        for (int i = 0; i < mContainerArray.size(); i++) {
            int key = mContainerArray.keyAt(i);
            Container container = mContainerArray.get(key);
            if (container.getDataClreplaced() == data.getClreplaced()) {
                container.setData(data);
                return key;
            }
        }
        throw new RuntimeException("gereplacedemViewType() failed, data: " + data.getClreplaced().getCanonicalName() + ", please make sure you have replacedociated it with a Clreplaced<? extends SugarHolder>");
    }

    @SuppressWarnings("unchecked")
    @Override
    @NonNull
    public SugarHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Container container = mContainerArray.get(viewType);
        try {
            View view = null;
            int layoutRes = container.getLayoutRes();
            if (mPreInflateArray != null) {
                view = mPreInflateArray.get(layoutRes);
                // preInflate the layoutRes when next MainThread idle in case for needed
                mPreInflateArray.put(layoutRes, null);
                for (PreInflateListener listener : mPreInflateListenerList) {
                    if (listener != null) {
                        listener.onPreInflateConsumed(layoutRes, view == null);
                    }
                }
            }
            if (view == null) {
                view = inflateView(layoutRes, parent);
            }
            SugarHolder holder = container.getHolderClreplaced().getDeclaredConstructor(View.clreplaced).newInstance(view);
            holder.setAdapter(this);
            // makes SugarHolder#getData non-null
            holder.setData(container.getData());
            SugarHolder.OnCreatedCallback callback = container.getCallback();
            if (callback != null) {
                callback.onCreated(holder);
            }
            holder.getLifecycleRegistry().handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
            for (SugarHolderListener listener : mSugarHolderListenerList) {
                if (listener.isInstance(holder)) {
                    listener.onSugarHolderCreated(holder);
                }
            }
            return holder;
        } catch (@NonNull Exception e) {
            Log.e(TAG, "onCreateViewHolder failed, holder: " + container.getHolderClreplaced().getCanonicalName());
            throw new RuntimeException(e);
        }
    }

    @NonNull
    private View inflateView(@LayoutRes int layoutRes, @NonNull ViewGroup parent) {
        return LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false);
    }

    @Override
    public void onBindViewHolder(@NonNull SugarHolder holder, int position, @NonNull List<Object> payloads) {
        onBindViewHolderInternal(holder, position, payloads);
    }

    @Override
    public void onBindViewHolder(@NonNull SugarHolder holder, int position) {
        onBindViewHolderInternal(holder, position, null);
    }

    @SuppressWarnings("unchecked")
    private void onBindViewHolderInternal(@NonNull SugarHolder holder, int position, @Nullable List<Object> payloads) {
        Object data = mList.get(position);
        // double check
        holder.setData(data);
        if (payloads == null || payloads.isEmpty()) {
            holder.onBindData(data, Collections.emptyList());
        } else {
            holder.onBindData(data, payloads);
        }
        holder.getLifecycleRegistry().handleLifecycleEvent(Lifecycle.Event.ON_START);
        for (SugarHolderListener listener : mSugarHolderListenerList) {
            if (listener.isInstance(holder)) {
                listener.onSugarHolderBindData(holder);
            }
        }
    }

    @Override
    public void onViewAttachedToWindow(@NonNull SugarHolder holder) {
    // holder.onViewAttachedToWindow();
    }

    @Override
    public void onViewDetachedFromWindow(@NonNull SugarHolder holder) {
    // holder.onViewDetachedFromWindow();
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onViewRecycled(@NonNull SugarHolder holder) {
        holder.onViewRecycled();
        holder.getLifecycleRegistry().handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
        for (SugarHolderListener listener : mSugarHolderListenerList) {
            if (listener.isInstance(holder)) {
                listener.onSugarHolderViewRecycled(holder);
            }
        }
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView view) {
        // preInflate XML when MainThread idle
        if (mPreInflateArray != null && mPreInflateHandler == null) {
            mPreInflateHandler = () -> {
                for (int i = 0; i < mPreInflateArray.size(); i++) {
                    int layoutRes = mPreInflateArray.keyAt(i);
                    if (mPreInflateArray.get(layoutRes) == null) {
                        mPreInflateArray.put(layoutRes, inflateView(layoutRes, view));
                        for (PreInflateListener listener : mPreInflateListenerList) {
                            if (listener != null) {
                                listener.onPreInflateExecuted(layoutRes);
                            }
                        }
                        // only one at a time, avoid blocking MainThread
                        break;
                    }
                }
                return true;
            };
            Looper.myQueue().addIdleHandler(mPreInflateHandler);
        }
        for (ExtraDelegate delegate : mExtraDelegateList) {
            if (delegate != null) {
                delegate.onAttachedToRecyclerView(view);
            }
        }
    }

    @Override
    public void onDetachedFromRecyclerView(@NonNull RecyclerView view) {
        if (mPreInflateHandler != null) {
            Looper.myQueue().removeIdleHandler(mPreInflateHandler);
            mPreInflateHandler = null;
        }
        for (ExtraDelegate delegate : mExtraDelegateList) {
            if (delegate != null) {
                delegate.onDetachedFromRecyclerView(view);
            }
        }
    }

    @SuppressWarnings("unchecked")
    protected void onSugarHolderViewAttachedToWindow(@NonNull SugarHolder holder) {
        for (SugarHolderListener listener : mSugarHolderListenerList) {
            if (listener.isInstance(holder)) {
                listener.onSugarHolderViewAttachedToWindow(holder);
            }
        }
    }

    @SuppressWarnings("unchecked")
    protected void onSugarHolderViewDetachedFromWindow(@NonNull SugarHolder holder) {
        for (SugarHolderListener listener : mSugarHolderListenerList) {
            if (listener.isInstance(holder)) {
                listener.onSugarHolderViewDetachedFromWindow(holder);
            }
        }
    }

    @Override
    public boolean onFailedToRecycleView(@NonNull SugarHolder holder) {
        return holder.onFailedToRecycleView();
    }
}

19 Source : Notification.java
with MIT License
from zhangyd-c

/**
 * Wrapper clreplaced around OS notification clreplaced. Handles basic operations
 * like show, delete, cancel for a single local notification instance.
 */
public final clreplaced Notification {

    // Used to differ notifications by their life cycle state
    public enum Type {

        ALL, SCHEDULED, TRIGGERED
    }

    // Extra key for the id
    public static final String EXTRA_ID = "NOTIFICATION_ID";

    // Extra key for the update flag
    public static final String EXTRA_UPDATE = "NOTIFICATION_UPDATE";

    // Key for private preferences
    static final String PREF_KEY_ID = "NOTIFICATION_ID";

    // Key for private preferences
    private static final String PREF_KEY_PID = "NOTIFICATION_PID";

    // Cache for the builder instances
    private static SparseArray<NotificationCompat.Builder> cache = null;

    // Application context preplaceded by constructor
    private final Context context;

    // Notification options preplaceded by JS
    private final Options options;

    // Builder with full configuration
    private final NotificationCompat.Builder builder;

    /**
     * Constructor
     *
     * @param context Application context.
     * @param options Parsed notification options.
     * @param builder Pre-configured notification builder.
     */
    Notification(Context context, Options options, NotificationCompat.Builder builder) {
        this.context = context;
        this.options = options;
        this.builder = builder;
    }

    /**
     * Constructor
     *
     * @param context Application context.
     * @param options Parsed notification options.
     */
    public Notification(Context context, Options options) {
        this.context = context;
        this.options = options;
        this.builder = null;
    }

    /**
     * Get application context.
     */
    public Context getContext() {
        return context;
    }

    /**
     * Get notification options.
     */
    public Options getOptions() {
        return options;
    }

    /**
     * Get notification ID.
     */
    public int getId() {
        return options.getId();
    }

    /**
     * If it's a repeating notification.
     */
    private boolean isRepeating() {
        return getOptions().getTrigger().has("every");
    }

    /**
     * Notification type can be one of triggered or scheduled.
     */
    public Type getType() {
        Manager mgr = Manager.getInstance(context);
        StatusBarNotification[] toasts = mgr.getActiveNotifications();
        int id = getId();
        for (StatusBarNotification toast : toasts) {
            if (toast.getId() == id) {
                return Type.TRIGGERED;
            }
        }
        return Type.SCHEDULED;
    }

    /**
     * Schedule the local notification.
     *
     * @param request Set of notification options.
     * @param receiver Receiver to handle the trigger event.
     */
    void schedule(Request request, Clreplaced<?> receiver) {
        List<Pair<Date, Intent>> intents = new ArrayList<Pair<Date, Intent>>();
        Set<String> ids = new ArraySet<String>();
        AlarmManager mgr = getAlarmMgr();
        cancelScheduledAlarms();
        do {
            Date date = request.getTriggerDate();
            if (date == null)
                continue;
            Intent intent = new Intent(context, receiver).setAction(PREF_KEY_ID + request.getIdentifier()).putExtra(Notification.EXTRA_ID, options.getId()).putExtra(Request.EXTRA_OCCURRENCE, request.getOccurrence());
            ids.add(intent.getAction());
            intents.add(new Pair<Date, Intent>(date, intent));
        } while (request.moveNext());
        if (intents.isEmpty()) {
            unpersist();
            return;
        }
        persist(ids);
        if (!options.isInfiniteTrigger()) {
            Intent last = intents.get(intents.size() - 1).second;
            last.putExtra(Request.EXTRA_LAST, true);
        }
        for (Pair<Date, Intent> pair : intents) {
            Date date = pair.first;
            long time = date.getTime();
            Intent intent = pair.second;
            if (!date.after(new Date()) && trigger(intent, receiver))
                continue;
            PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, FLAG_CANCEL_CURRENT);
            try {
                switch(options.getPriority()) {
                    case IMPORTANCE_MIN:
                        mgr.setExact(RTC, time, pi);
                        break;
                    case IMPORTANCE_MAX:
                        if (SDK_INT >= M) {
                            mgr.setExactAndAllowWhileIdle(RTC_WAKEUP, time, pi);
                        } else {
                            mgr.setExact(RTC, time, pi);
                        }
                        break;
                    default:
                        mgr.setExact(RTC_WAKEUP, time, pi);
                        break;
                }
            } catch (Exception ignore) {
            // Samsung devices have a known bug where a 500 alarms limit
            // can crash the app
            }
        }
    }

    /**
     * Trigger local notification specified by options.
     *
     * @param intent The intent to broadcast.
     * @param cls    The broadcast clreplaced.
     *
     * @return false if the receiver could not be invoked.
     */
    private boolean trigger(Intent intent, Clreplaced<?> cls) {
        BroadcastReceiver receiver;
        try {
            receiver = (BroadcastReceiver) cls.newInstance();
        } catch (InstantiationException e) {
            return false;
        } catch (IllegalAccessException e) {
            return false;
        }
        receiver.onReceive(context, intent);
        return true;
    }

    /**
     * Clear the local notification without canceling repeating alarms.
     */
    public void clear() {
        getNotMgr().cancel(getId());
        if (isRepeating())
            return;
        unpersist();
    }

    /**
     * Cancel the local notification.
     */
    public void cancel() {
        cancelScheduledAlarms();
        unpersist();
        getNotMgr().cancel(getId());
        clearCache();
    }

    /**
     * Cancel the scheduled future local notification.
     *
     * Create an intent that looks similar, to the one that was registered
     * using schedule. Making sure the notification id in the action is the
     * same. Now we can search for such an intent using the 'getService'
     * method and cancel it.
     */
    private void cancelScheduledAlarms() {
        SharedPreferences prefs = getPrefs(PREF_KEY_PID);
        String id = options.getIdentifier();
        Set<String> actions = prefs.getStringSet(id, null);
        if (actions == null)
            return;
        for (String action : actions) {
            Intent intent = new Intent(action);
            PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
            if (pi != null) {
                getAlarmMgr().cancel(pi);
            }
        }
    }

    /**
     * Present the local notification to user.
     */
    public void show() {
        if (builder == null)
            return;
        if (options.isWithProgressBar()) {
            cacheBuilder();
        }
        grantPermissionToPlaySoundFromExternal();
        getNotMgr().notify(getId(), builder.build());
    }

    /**
     * Update the notification properties.
     *
     * @param updates  The properties to update.
     * @param receiver Receiver to handle the trigger event.
     */
    void update(JSONObject updates, Clreplaced<?> receiver) {
        mergeJSONObjects(updates);
        persist(null);
        if (getType() != Type.TRIGGERED)
            return;
        Intent intent = new Intent(context, receiver).setAction(PREF_KEY_ID + options.getId()).putExtra(Notification.EXTRA_ID, options.getId()).putExtra(Notification.EXTRA_UPDATE, true);
        trigger(intent, receiver);
    }

    /**
     * Encode options to JSON.
     */
    public String toString() {
        JSONObject dict = options.getDict();
        JSONObject json = new JSONObject();
        try {
            json = new JSONObject(dict.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return json.toString();
    }

    /**
     * Persist the information of this notification to the Android Shared
     * Preferences. This will allow the application to restore the notification
     * upon device reboot, app restart, retrieve notifications, aso.
     *
     * @param ids List of intent actions to persist.
     */
    private void persist(Set<String> ids) {
        String id = options.getIdentifier();
        SharedPreferences.Editor editor;
        editor = getPrefs(PREF_KEY_ID).edit();
        editor.putString(id, options.toString());
        editor.apply();
        if (ids == null)
            return;
        editor = getPrefs(PREF_KEY_PID).edit();
        editor.putStringSet(id, ids);
        editor.apply();
    }

    /**
     * Remove the notification from the Android shared Preferences.
     */
    private void unpersist() {
        String[] keys = { PREF_KEY_ID, PREF_KEY_PID };
        String id = options.getIdentifier();
        SharedPreferences.Editor editor;
        for (String key : keys) {
            editor = getPrefs(key).edit();
            editor.remove(id);
            editor.apply();
        }
    }

    /**
     * Since Android 7 the app will crash if an external process has no
     * permission to access the referenced sound file.
     */
    private void grantPermissionToPlaySoundFromExternal() {
        if (builder == null)
            return;
        String sound = builder.getExtras().getString(Options.EXTRA_SOUND);
        Uri soundUri = Uri.parse(sound);
        context.grantUriPermission("com.android.systemui", soundUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }

    /**
     * Merge two JSON objects.
     */
    private void mergeJSONObjects(JSONObject updates) {
        JSONObject dict = options.getDict();
        Iterator it = updates.keys();
        while (it.hasNext()) {
            try {
                String key = (String) it.next();
                dict.put(key, updates.opt(key));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Caches the builder instance so it can be used later.
     */
    private void cacheBuilder() {
        if (cache == null) {
            cache = new SparseArray<NotificationCompat.Builder>();
        }
        cache.put(getId(), builder);
    }

    /**
     * Find the cached builder instance.
     *
     * @param key The key under where to look for the builder.
     *
     * @return null if no builder instance could be found.
     */
    static NotificationCompat.Builder getCachedBuilder(int key) {
        return (cache != null) ? cache.get(key) : null;
    }

    /**
     * Caches the builder instance so it can be used later.
     */
    private void clearCache() {
        if (cache != null) {
            cache.delete(getId());
        }
    }

    /**
     * Shared private preferences for the application.
     */
    private SharedPreferences getPrefs(String key) {
        return context.getSharedPreferences(key, Context.MODE_PRIVATE);
    }

    /**
     * Notification manager for the application.
     */
    private NotificationManager getNotMgr() {
        return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    }

    /**
     * Alarm manager for the application.
     */
    private AlarmManager getAlarmMgr() {
        return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    }
}

19 Source : PendingRequests.java
with MIT License
from zhangyd-c

/**
 * Holds pending runtime permission requests
 */
clreplaced PendingRequests {

    private int currentReqId = 0;

    private SparseArray<Request> requests = new SparseArray<Request>();

    /**
     * Creates a request and adds it to the array of pending requests. Each created request gets a
     * unique result code for use with requestPermission()
     * @param rawArgs           The raw arguments preplaceded to the plugin
     * @param action            The action this request corresponds to (get file, etc.)
     * @param callbackContext   The CallbackContext for this plugin call
     * @return                  The request code that can be used to retrieve the Request object
     */
    public synchronized int createRequest(String rawArgs, int action, CallbackContext callbackContext) {
        Request req = new Request(rawArgs, action, callbackContext);
        requests.put(req.requestCode, req);
        return req.requestCode;
    }

    /**
     * Gets the request corresponding to this request code and removes it from the pending requests
     * @param requestCode   The request code for the desired request
     * @return              The request corresponding to the given request code or null if such a
     *                      request is not found
     */
    public synchronized Request getAndRemove(int requestCode) {
        Request result = requests.get(requestCode);
        requests.remove(requestCode);
        return result;
    }

    /**
     * Holds the options and CallbackContext for a call made to the plugin.
     */
    public clreplaced Request {

        // Unique int used to identify this request in any Android permission callback
        private int requestCode;

        // Action to be performed after permission request result
        private int action;

        // Raw arguments preplaceded to plugin
        private String rawArgs;

        // The callback context for this plugin request
        private CallbackContext callbackContext;

        private Request(String rawArgs, int action, CallbackContext callbackContext) {
            this.rawArgs = rawArgs;
            this.action = action;
            this.callbackContext = callbackContext;
            this.requestCode = currentReqId++;
        }

        public int getAction() {
            return this.action;
        }

        public String getRawArgs() {
            return rawArgs;
        }

        public CallbackContext getCallbackContext() {
            return callbackContext;
        }
    }
}

19 Source : CallbackMap.java
with MIT License
from zhangyd-c

/**
 * Provides a collection that maps unique request codes to CordovaPlugins and Integers.
 * Used to ensure that when plugins make requests for runtime permissions, those requests do not
 * collide with requests from other plugins that use the same request code value.
 */
public clreplaced CallbackMap {

    private int currentCallbackId = 0;

    private SparseArray<Pair<CordovaPlugin, Integer>> callbacks;

    public CallbackMap() {
        this.callbacks = new SparseArray<Pair<CordovaPlugin, Integer>>();
    }

    /**
     * Stores a CordovaPlugin and request code and returns a new unique request code to use
     * in a permission request.
     *
     * @param receiver      The plugin that is making the request
     * @param requestCode   The original request code used by the plugin
     * @return              A unique request code that can be used to retrieve this callback
     *                      with getAndRemoveCallback()
     */
    public synchronized int registerCallback(CordovaPlugin receiver, int requestCode) {
        int mappedId = this.currentCallbackId++;
        callbacks.put(mappedId, new Pair<CordovaPlugin, Integer>(receiver, requestCode));
        return mappedId;
    }

    /**
     * Retrieves and removes a callback stored in the map using the mapped request code
     * obtained from registerCallback()
     *
     * @param mappedId      The request code obtained from registerCallback()
     * @return              The CordovaPlugin and orignal request code that correspond to the
     *                      given mappedCode
     */
    public synchronized Pair<CordovaPlugin, Integer> getAndRemoveCallback(int mappedId) {
        Pair<CordovaPlugin, Integer> callback = callbacks.get(mappedId);
        callbacks.remove(mappedId);
        return callback;
    }
}

19 Source : ServerInterface.java
with Apache License 2.0
from zhangke3016

/**
 * @author zk
 * @date 创建时间:2019/2/1
 * @Description:
 * @other 修改历史:
 */
public clreplaced ServerInterface {

    private Clreplaced<?> interfaceClreplaced;

    private final SparseArray<IPCMethod> codeToInterfaceMethod;

    private final Map<Method, IPCMethod> methodToIPCMethodMap;

    public ServerInterface(Clreplaced<?> interfaceClreplaced) {
        this.interfaceClreplaced = interfaceClreplaced;
        Method[] methods = interfaceClreplaced.getMethods();
        codeToInterfaceMethod = new SparseArray<>(methods.length);
        methodToIPCMethodMap = new HashMap<>(methods.length);
        for (int i = 0; i < methods.length; i++) {
            int code = Binder.FIRST_CALL_TRANSACTION + i;
            IPCMethod ipcMethod = new IPCMethod(code, methods[i], interfaceClreplaced.getName());
            codeToInterfaceMethod.put(code, ipcMethod);
            methodToIPCMethodMap.put(methods[i], ipcMethod);
        }
    }

    public Clreplaced<?> getInterfaceClreplaced() {
        return interfaceClreplaced;
    }

    public String getInterfaceName() {
        return interfaceClreplaced.getName();
    }

    public IPCMethod getIPCMethod(int code) {
        return codeToInterfaceMethod.get(code);
    }

    public IPCMethod getIPCMethod(Method method) {
        return methodToIPCMethodMap.get(method);
    }
}

19 Source : Constants.java
with Apache License 2.0
from zhangjianli

public final clreplaced Constants {

    public static final int MSG_START_ACTIVITY = 1;

    public static final int MSG_LIFECYCLE = 2;

    public static final int MSG_MESSAGE = 3;

    public static final int LIFECYCLE_CREATED = 1;

    public static final int LIFECYCLE_STARTED = 2;

    public static final int LIFECYCLE_RESUMED = 3;

    public static final int LIFECYCLE_PAUSED = 4;

    public static final int LIFECYCLE_STOPPED = 5;

    public static final int LIFECYCLE_DESTROYED = 6;

    public static final int LIFECYCLE_STATE_SAVED = 7;

    public static final int COLOR_NORMAL = Color.parseColor("#27C47A");

    public static final int COLOR_WARNING = Color.parseColor("#ED4337");

    public static final int COLOR_INFO = Color.parseColor("#222222");

    public static final SparseArray<String> sActivityThreadMsgMap = new SparseArray<>();

    static {
        sActivityThreadMsgMap.put(100, "LAUNCH_ACTIVITY");
        sActivityThreadMsgMap.put(101, "PAUSE_ACTIVITY");
        sActivityThreadMsgMap.put(102, "PAUSE_ACTIVITY_FINISHING");
        sActivityThreadMsgMap.put(103, "STOP_ACTIVITY_SHOW");
        sActivityThreadMsgMap.put(104, "STOP_ACTIVITY_HIDE");
        sActivityThreadMsgMap.put(105, "SHOW_WINDOW");
        sActivityThreadMsgMap.put(106, "HIDE_WINDOW");
        sActivityThreadMsgMap.put(107, "RESUME_ACTIVITY");
        sActivityThreadMsgMap.put(108, "SEND_RESULT");
        sActivityThreadMsgMap.put(109, "DESTROY_ACTIVITY");
        sActivityThreadMsgMap.put(110, "BIND_APPLICATION");
        sActivityThreadMsgMap.put(111, "EXIT_APPLICATION");
        sActivityThreadMsgMap.put(112, "NEW_INTENT");
        sActivityThreadMsgMap.put(113, "RECEIVER");
        sActivityThreadMsgMap.put(114, "CREATE_SERVICE");
        sActivityThreadMsgMap.put(115, "SERVICE_ARGS");
        sActivityThreadMsgMap.put(116, "STOP_SERVICE");
        sActivityThreadMsgMap.put(118, "CONFIGURATION_CHANGED");
        sActivityThreadMsgMap.put(119, "CLEAN_UP_CONTEXT");
        sActivityThreadMsgMap.put(120, "GC_WHEN_IDLE");
        sActivityThreadMsgMap.put(121, "BIND_SERVICE");
        sActivityThreadMsgMap.put(122, "UNBIND_SERVICE");
        sActivityThreadMsgMap.put(123, "DUMP_SERVICE");
        sActivityThreadMsgMap.put(124, "LOW_MEMORY");
        sActivityThreadMsgMap.put(125, "ACTIVITY_CONFIGURATION_CHANGED");
        sActivityThreadMsgMap.put(126, "RELAUNCH_ACTIVITY");
        sActivityThreadMsgMap.put(127, "PROFILER_CONTROL");
        sActivityThreadMsgMap.put(128, "CREATE_BACKUP_AGENT");
        sActivityThreadMsgMap.put(129, "DESTROY_BACKUP_AGENT");
        sActivityThreadMsgMap.put(130, "SUICIDE");
        sActivityThreadMsgMap.put(131, "REMOVE_PROVIDER");
        sActivityThreadMsgMap.put(132, "ENABLE_JIT");
        sActivityThreadMsgMap.put(133, "DISPATCH_PACKAGE_BROADCAST");
        sActivityThreadMsgMap.put(134, "SCHEDULE_CRASH");
        sActivityThreadMsgMap.put(135, "DUMP_HEAP");
        sActivityThreadMsgMap.put(136, "DUMP_ACTIVITY");
        sActivityThreadMsgMap.put(137, "SLEEPING");
        sActivityThreadMsgMap.put(138, "SET_CORE_SETTINGS");
        sActivityThreadMsgMap.put(139, "UPDATE_PACKAGE_COMPATIBILITY_INFO");
        sActivityThreadMsgMap.put(140, "TRIM_MEMORY");
        sActivityThreadMsgMap.put(141, "DUMP_PROVIDER");
        sActivityThreadMsgMap.put(142, "UNSTABLE_PROVIDER_DIED");
        sActivityThreadMsgMap.put(143, "REQUEST_replacedIST_CONTEXT_EXTRAS");
        sActivityThreadMsgMap.put(144, "TRANSLUCENT_CONVERSION_COMPLETE");
        sActivityThreadMsgMap.put(145, "INSTALL_PROVIDER");
        sActivityThreadMsgMap.put(146, "ON_NEW_ACTIVITY_OPTIONS");
        sActivityThreadMsgMap.put(147, "CANCEL_VISIBLE_BEHIND");
        sActivityThreadMsgMap.put(148, "BACKGROUND_VISIBLE_BEHIND_CHANGED");
        sActivityThreadMsgMap.put(149, "ENTER_ANIMATION_COMPLETE");
        sActivityThreadMsgMap.put(150, "START_BINDER_TRACKING");
        sActivityThreadMsgMap.put(151, "STOP_BINDER_TRACKING_AND_DUMP");
        sActivityThreadMsgMap.put(152, "MULTI_WINDOW_MODE_CHANGED");
        sActivityThreadMsgMap.put(153, "PICTURE_IN_PICTURE_MODE_CHANGED");
        sActivityThreadMsgMap.put(154, "LOCAL_VOICE_INTERACTION_STARTED");
        sActivityThreadMsgMap.put(155, "ATTACH_AGENT");
        sActivityThreadMsgMap.put(156, "APPLICATION_INFO_CHANGED");
        sActivityThreadMsgMap.put(157, "ACTIVITY_MOVED_TO_DISPLAY");
    }

    public static final SparseArray<String> sViewRootImplMsgMap = new SparseArray<>();

    static {
        sViewRootImplMsgMap.put(1, "MSG_INVALIDATE");
        sViewRootImplMsgMap.put(2, "MSG_INVALIDATE_RECT");
        sViewRootImplMsgMap.put(3, "MSG_DIE");
        sViewRootImplMsgMap.put(4, "MSG_RESIZED");
        sViewRootImplMsgMap.put(5, "MSG_RESIZED_REPORT");
        sViewRootImplMsgMap.put(6, "MSG_WINDOW_FOCUS_CHANGED");
        sViewRootImplMsgMap.put(7, "MSG_DISPATCH_INPUT_EVENT");
        sViewRootImplMsgMap.put(8, "MSG_DISPATCH_APP_VISIBILITY");
        sViewRootImplMsgMap.put(9, "MSG_DISPATCH_GET_NEW_SURFACE");
        sViewRootImplMsgMap.put(11, "MSG_DISPATCH_KEY_FROM_IME");
        sViewRootImplMsgMap.put(12, "MSG_FINISH_INPUT_CONNECTION");
        sViewRootImplMsgMap.put(13, "MSG_CHECK_FOCUS");
        sViewRootImplMsgMap.put(14, "MSG_CLOSE_SYSTEM_DIALOGS");
        sViewRootImplMsgMap.put(15, "MSG_DISPATCH_DRAG_EVENT");
        sViewRootImplMsgMap.put(16, "MSG_DISPATCH_DRAG_LOCATION_EVENT");
        sViewRootImplMsgMap.put(17, "MSG_DISPATCH_SYSTEM_UI_VISIBILITY");
        sViewRootImplMsgMap.put(18, "MSG_UPDATE_CONFIGURATION");
        sViewRootImplMsgMap.put(19, "MSG_PROCESS_INPUT_EVENTS");
        sViewRootImplMsgMap.put(21, "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST");
        sViewRootImplMsgMap.put(22, "MSG_INVALIDATE_WORLD");
        sViewRootImplMsgMap.put(23, "MSG_WINDOW_MOVED");
        sViewRootImplMsgMap.put(24, "MSG_SYNTHESIZE_INPUT_EVENT");
        sViewRootImplMsgMap.put(25, "MSG_DISPATCH_WINDOW_SHOWN");
        sViewRootImplMsgMap.put(26, "MSG_DISPATCH_WINDOW_ANIMATION_STOPPED");
        sViewRootImplMsgMap.put(27, "MSG_DISPATCH_WINDOW_ANIMATION_STARTED");
    }

    private Constants() {
    }
}

19 Source : FragmentViewPagerActivity.java
with Apache License 2.0
from zguop

/**
 * auth aboom
 * date 2019-12-28
 */
public clreplaced FragmentViewPagerActivity extends AppCompatActivity {

    public static final int TAB_TEST1 = R.id.test1;

    public static final int TAB_TEST2 = R.id.test2;

    public static final int TAB_TEST3 = R.id.test3;

    private SparseArray<View> tabView = new SparseArray<>();

    private View selectedButton;

    private int currentTag;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        StatusBarUtil.setStatusBarColor(this, Color.WHITE);
        int currentTag = getIntent().getIntExtra("currentTag", TAB_TEST1);
        setContentView(R.layout.activity_fvp);
        binding();
        clickTab(tabView.get(currentTag));
    }

    private void clickTab(View view) {
        if (selectedButton != null) {
            selectedButton.setSelected(Boolean.FALSE);
        }
        selectedButton = view;
        selectedButton.setSelected(Boolean.TRUE);
        selectFragment(view.getId());
    }

    private void binding() {
        tabView.put(TAB_TEST1, findViewById(TAB_TEST1));
        tabView.put(TAB_TEST2, findViewById(TAB_TEST2));
        tabView.put(TAB_TEST3, findViewById(TAB_TEST3));
        for (int i = 0; i < tabView.size(); i++) {
            tabView.get(tabView.keyAt(i)).setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    clickTab(v);
                }
            });
        }
    }

    private void selectFragment(int tag) {
        FragmentManager supportFragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = supportFragmentManager.beginTransaction();
        if (tag == currentTag) {
            return;
        }
        Fragment currentFragment = supportFragmentManager.findFragmentByTag(String.valueOf(currentTag));
        if (currentFragment != null) {
            transaction.hide(currentFragment);
        }
        Fragment fragment = supportFragmentManager.findFragmentByTag(String.valueOf(tag));
        if (fragment == null) {
            transaction.add(R.id.main_content, getFragment(tag), String.valueOf(tag));
        } else {
            transaction.show(fragment);
        }
        currentTag = tag;
        transaction.commitAllowingStateLoss();
    }

    @NonNull
    private Fragment getFragment(int tag) {
        switch(tag) {
            case TAB_TEST1:
                return new Test1Fragment();
            case TAB_TEST2:
                return new Test2Fragment();
            case TAB_TEST3:
                return new Test3Fragment();
        }
        return new Test1Fragment();
    }
}

19 Source : AdapterItemUtil.java
with Apache License 2.0
from zaihuishou

/**
 * creater: zaihuishou
 * create time: 7/13/16.
 * email:[email protected]
 * collect item type
 */
public clreplaced AdapterItemUtil {

    private SparseArray<Object> typeSArr = new SparseArray<>();

    /**
     * @param type item type
     * @return int type of object corresponding
     */
    public int getIntType(Object type) {
        int index = typeSArr.indexOfValue(type);
        if (index == -1) {
            index = typeSArr.size();
            typeSArr.put(index, type);
        }
        return index;
    }
}

19 Source : AdapterItemUtil.java
with Apache License 2.0
from zaihuishou

/**
 * creater: zaihuishou
 * create time: 7/13/16.
 * email:[email protected]
 */
public clreplaced AdapterItemUtil {

    private SparseArray<Object> typeSArr = new SparseArray<>();

    /**
     * @param type item的类型
     * @return 通过object类型的type来得到int类型的type
     */
    public int getIntType(Object type) {
        int index = typeSArr.indexOfValue(type);
        if (index == -1) {
            index = typeSArr.size();
            // 如果没用这个type,就存入这个type
            typeSArr.put(index, type);
        }
        return index;
    }
}

19 Source : TvContractUtils.java
with Apache License 2.0
from zaclimon

/**
 * Static helper methods for working with {@link android.media.tv.TvContract}.
 */
public final clreplaced TvContractUtils {

    /**
     * Indicates that no source type has been defined for this video yet
     */
    public static final int SOURCE_TYPE_INVALID = -1;

    /**
     * Indicates that the video will use MPEG-DASH (Dynamic Adaptive Streaming over HTTP) for
     * playback.
     */
    public static final int SOURCE_TYPE_MPEG_DASH = 0;

    /**
     * Indicates that the video will use SS (Smooth Streaming) for playback.
     */
    public static final int SOURCE_TYPE_SS = 1;

    /**
     * Indicates that the video will use HLS (HTTP Live Streaming) for playback.
     */
    public static final int SOURCE_TYPE_HLS = 2;

    /**
     * Indicates that the video will use HTTP Progressive for playback.
     */
    public static final int SOURCE_TYPE_HTTP_PROGRESSIVE = 3;

    private static final String TAG = "TvContractUtils";

    private static final boolean DEBUG = false;

    private static final SparseArray<String> VIDEO_HEIGHT_TO_FORMAT_MAP = new SparseArray<>();

    static {
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(480, TvContract.Channels.VIDEO_FORMAT_480P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(576, TvContract.Channels.VIDEO_FORMAT_576P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(720, TvContract.Channels.VIDEO_FORMAT_720P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(1080, TvContract.Channels.VIDEO_FORMAT_1080P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(2160, TvContract.Channels.VIDEO_FORMAT_2160P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(4320, TvContract.Channels.VIDEO_FORMAT_4320P);
    }

    private static void insertUrl(Context context, Uri contentUri, URL sourceUrl) {
        if (DEBUG) {
            Log.d(TAG, "Inserting " + sourceUrl + " to " + contentUri);
        }
        InputStream is = null;
        OutputStream os = null;
        try {
            is = sourceUrl.openStream();
            os = context.getContentResolver().openOutputStream(contentUri);
            copy(is, os);
        } catch (IOException ioe) {
            Log.e(TAG, "Failed to write " + sourceUrl + "  to " + contentUri, ioe);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                // Ignore exception.
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                // Ignore exception.
                }
            }
        }
    }

    private static void copy(InputStream is, OutputStream os) throws IOException {
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
    }

    /**
     * Parses a string of comma-separated ratings into an array of {@link TvContentRating}.
     *
     * @param commaSeparatedRatings String containing various ratings, separated by commas.
     * @return An array of TvContentRatings.
     * @hide
     */
    public static TvContentRating[] stringToContentRatings(String commaSeparatedRatings) {
        if (TextUtils.isEmpty(commaSeparatedRatings)) {
            return null;
        }
        String[] ratings = commaSeparatedRatings.split("\\s*,\\s*");
        TvContentRating[] contentRatings = new TvContentRating[ratings.length];
        for (int i = 0; i < contentRatings.length; ++i) {
            contentRatings[i] = TvContentRating.unflattenFromString(ratings[i]);
        }
        return contentRatings;
    }

    /**
     * Flattens an array of {@link TvContentRating} into a String to be inserted into a database.
     *
     * @param contentRatings An array of TvContentRatings.
     * @return A comma-separated String of ratings.
     * @hide
     */
    public static String contentRatingsToString(TvContentRating[] contentRatings) {
        if (contentRatings == null || contentRatings.length == 0) {
            return null;
        }
        final String DELIMITER = ",";
        StringBuilder ratings = new StringBuilder(contentRatings[0].flattenToString());
        for (int i = 1; i < contentRatings.length; ++i) {
            ratings.append(DELIMITER);
            ratings.append(contentRatings[i].flattenToString());
        }
        return ratings.toString();
    }

    private TvContractUtils() {
    }

    /**
     * AsyncTask to insert logos.
     */
    public static clreplaced InsertLogosTask extends AsyncTask<Map<Uri, String>, Void, Void> {

        private final Context mContext;

        public InsertLogosTask(Context context) {
            mContext = context;
        }

        @Override
        public Void doInBackground(Map<Uri, String>... logosList) {
            for (Map<Uri, String> logos : logosList) {
                for (Uri uri : logos.keySet()) {
                    try {
                        insertUrl(mContext, uri, new URL(logos.get(uri)));
                    } catch (MalformedURLException e) {
                        Log.e(TAG, "Can't load " + logos.get(uri), e);
                    }
                }
            }
            return null;
        }
    }
}

19 Source : EpgSyncJobService.java
with Apache License 2.0
from zaclimon

/**
 * Service to handle callbacks from JobScheduler. This service will be called by the system to
 * update the EPG with channels and programs periodically.
 *
 * <p>You can extend this clreplaced and add it your app by including it in your app's
 * AndroidManfiest.xml:
 *
 * <pre>
 *      <service
 *          android:name=".SampleJobService"
 *          android:permission="android.permission.BIND_JOB_SERVICE"
 *          android:exported="true" />
 * </pre>
 *
 * You will need to implement several methods in your EpgSyncJobService to return your content.
 *
 * <p>To start periodically syncing data, call {@link #setUpPeriodicSync(Context, String,
 * ComponentName, long, long)}.
 *
 * <p>To sync manually, call {@link #requestImmediateSync(Context, String, long, ComponentName)}.
 */
public abstract clreplaced EpgSyncJobService extends JobService {

    private static final String TAG = "EpgSyncJobService";

    private static final boolean DEBUG = false;

    /**
     * The action that will be broadcast when the job service's status changes.
     */
    public static final String ACTION_SYNC_STATUS_CHANGED = EpgSyncJobService.clreplaced.getPackage().getName() + ".ACTION_SYNC_STATUS_CHANGED";

    /**
     * The key representing the component name for the app's TvInputService.
     */
    public static final String BUNDLE_KEY_INPUT_ID = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_input_id";

    /**
     * The key representing the number of channels that have been scanned and populated in the EPG.
     */
    public static final String BUNDLE_KEY_CHANNELS_SCANNED = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_channels_scanned";

    /**
     * The key representing the total number of channels for this input.
     */
    public static final String BUNDLE_KEY_CHANNEL_COUNT = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_channel_count";

    /**
     * The key representing the most recently scanned channel display name.
     */
    public static final String BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NAME = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_scanned_channel_display_name";

    /**
     * The key representing the most recently scanned channel display number.
     */
    public static final String BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NUMBER = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_scanned_channel_display_number";

    /**
     * The key representing the error that occurred during an EPG sync
     */
    public static final String BUNDLE_KEY_ERROR_REASON = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_error_reason";

    /**
     * The name for the {@link android.content.SharedPreferences} file used for storing syncing
     * metadata.
     */
    public static final String PREFERENCE_EPG_SYNC = EpgSyncJobService.clreplaced.getPackage().getName() + ".preference_epg_sync";

    /**
     * The status of the job service when syncing has begun.
     */
    public static final String SYNC_STARTED = "sync_started";

    /**
     * The status of the job service when a channel has been scanned and the EPG for that channel
     * has been populated.
     */
    public static final String SYNC_SCANNED = "sync_scanned";

    /**
     * The status of the job service when syncing has completed.
     */
    public static final String SYNC_FINISHED = "sync_finished";

    /**
     * The status of the job when a problem occurs during syncing. A {@link #SYNC_FINISHED}
     * broadcast will still be sent when the service is done. This status can be used to identify
     * specific issues in your EPG sync.
     */
    public static final String SYNC_ERROR = "sync_error";

    /**
     * The key corresponding to the job service's status.
     */
    public static final String SYNC_STATUS = "sync_status";

    /**
     * Indicates that the EPG sync was canceled before being completed.
     */
    public static final int ERROR_EPG_SYNC_CANCELED = 1;

    /**
     * Indicates that the input id was not defined and the EPG sync cannot complete.
     */
    public static final int ERROR_INPUT_ID_NULL = 2;

    /**
     * Indicates that no programs were found.
     */
    public static final int ERROR_NO_PROGRAMS = 3;

    /**
     * Indicates that no channels were found.
     */
    public static final int ERROR_NO_CHANNELS = 4;

    /**
     * Indicates an error occurred when updating programs in the database
     */
    public static final int ERROR_DATABASE_INSERT = 5;

    /**
     * Subclreplacedes start their custom error numbers with this value
     */
    public static final int ERROR_START_CUSTOM = 1000;

    /**
     * The default period between full EPG syncs, one day.
     */
    // 12 hour
    private static final long DEFAULT_SYNC_PERIOD_MILLIS = 1000 * 60 * 60 * 12;

    // 1 Hour
    private static final long DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS = 1000 * 60 * 60;

    // 48 Hour
    private static final long DEFAULT_PERIODIC_EPG_DURATION_MILLIS = 1000 * 60 * 60 * 48;

    private static final int PERIODIC_SYNC_JOB_ID = 0;

    private static final int REQUEST_SYNC_JOB_ID = 1;

    private static final int BATCH_OPERATION_COUNT = 100;

    // 1 second
    private static final long OVERRIDE_DEADLINE_MILLIS = 1000;

    private static final String BUNDLE_KEY_SYNC_PERIOD = "bundle_key_sync_period";

    private static final ExecutorService SINGLE_THREAD_EXECUTOR = Executors.newSingleThreadExecutor();

    private final SparseArray<EpgSyncTask> mTaskArray = new SparseArray<>();

    private static final Object mContextLock = new Object();

    private Context mContext;

    /**
     * Returns the channels that your app contains.
     *
     * @return The list of channels for your app.
     */
    public abstract List<Channel> getChannels() throws EpgSyncException;

    /**
     * Returns the programs that will appear for each channel.
     *
     * @param channelUri The Uri corresponding to the channel.
     * @param channel The channel your programs will appear on.
     * @param startMs The starting time in milliseconds since the epoch to generate programs. If
     *     your program starts before this starting time, it should be be included.
     * @param endMs The ending time in milliseconds since the epoch to generate programs. If your
     *     program starts before this ending time, it should be be included.
     * @return A list of programs for a given channel.
     */
    public abstract List<Program> getProgramsForChannel(Uri channelUri, Channel channel, long startMs, long endMs) throws EpgSyncException;

    @Override
    public void onCreate() {
        super.onCreate();
        if (DEBUG) {
            Log.d(TAG, "Created EpgSyncJobService");
        }
        synchronized (mContextLock) {
            if (mContext == null) {
                mContext = getApplicationContext();
            }
        }
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        if (DEBUG) {
            Log.d(TAG, "onStartJob(" + params.getJobId() + ")");
        }
        // Broadcast status
        Intent intent = createSyncStartedIntent(params.getExtras().getString(BUNDLE_KEY_INPUT_ID));
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
        EpgSyncTask epgSyncTask = new EpgSyncTask(params);
        synchronized (mTaskArray) {
            mTaskArray.put(params.getJobId(), epgSyncTask);
        }
        // Run the task on a single threaded custom executor in order not to block the AsyncTasks
        // running on application side.
        epgSyncTask.executeOnExecutor(SINGLE_THREAD_EXECUTOR);
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        synchronized (mTaskArray) {
            int jobId = params.getJobId();
            EpgSyncTask epgSyncTask = mTaskArray.get(jobId);
            if (epgSyncTask != null) {
                epgSyncTask.cancel(true);
                mTaskArray.delete(params.getJobId());
            }
        }
        return false;
    }

    /**
     * Returns {@code true} if the {@code oldProgram} program is the same as the {@code newProgram}
     * program but should update metadata. This updates the database instead of deleting and
     * inserting a new program to keep the user's intent, eg. recording this program.
     */
    public boolean shouldUpdateProgramMetadata(Program oldProgram, Program newProgram) {
        // NOTE: Here, we update the old program if it has the same replacedle and overlaps with the
        // new program. The test logic is just an example and you can modify this. E.g. check
        // whether the both programs have the same program ID if your EPG supports any ID for
        // the programs.
        return oldProgram.getreplacedle().equals(newProgram.getreplacedle()) && oldProgram.getStartTimeUtcMillis() <= newProgram.getEndTimeUtcMillis() && newProgram.getStartTimeUtcMillis() <= oldProgram.getEndTimeUtcMillis();
    }

    /**
     * Send the job to JobScheduler.
     */
    private static void scheduleJob(Context context, JobInfo job) {
        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        int result = jobScheduler.schedule(job);
        if (DEBUG) {
            Log.d(TAG, "Scheduling result is " + result);
        }
    }

    /**
     * Initializes a job that will periodically update the app's channels and programs with a
     * default period of 24 hours.
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param jobServiceComponent The {@link EpgSyncJobService} component name that will run.
     */
    public static void setUpPeriodicSync(Context context, String inputId, ComponentName jobServiceComponent) {
        setUpPeriodicSync(context, inputId, jobServiceComponent, DEFAULT_SYNC_PERIOD_MILLIS, DEFAULT_PERIODIC_EPG_DURATION_MILLIS);
    }

    /**
     * Initializes a job that will periodically update the app's channels and programs.
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param jobServiceComponent The {@link EpgSyncJobService} component name that will run.
     * @param fullSyncPeriod The period between when the job will run a full background sync in
     *     milliseconds.
     * @param syncDuration The duration of EPG content to fetch in milliseconds. For a manual sync,
     *     this should be relatively short. For a background sync this should be long.
     */
    public static void setUpPeriodicSync(Context context, String inputId, ComponentName jobServiceComponent, long fullSyncPeriod, long syncDuration) {
        if (jobServiceComponent.getClreplaced().isreplacedignableFrom(EpgSyncJobService.clreplaced)) {
            throw new IllegalArgumentException("This clreplaced does not extend EpgSyncJobService");
        }
        PersistableBundle persistableBundle = new PersistableBundle();
        persistableBundle.putString(EpgSyncJobService.BUNDLE_KEY_INPUT_ID, inputId);
        persistableBundle.putLong(EpgSyncJobService.BUNDLE_KEY_SYNC_PERIOD, syncDuration);
        JobInfo.Builder builder = new JobInfo.Builder(PERIODIC_SYNC_JOB_ID, jobServiceComponent);
        JobInfo jobInfo = builder.setExtras(persistableBundle).setPeriodic(fullSyncPeriod).setPersisted(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
        scheduleJob(context, jobInfo);
        if (DEBUG) {
            Log.d(TAG, "Job has been scheduled for every " + fullSyncPeriod + "ms");
        }
    }

    /**
     * Manually requests a job to run now to retrieve EPG content for the next hour.
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param jobServiceComponent The {@link EpgSyncJobService} clreplaced that will run.
     */
    public static void requestImmediateSync(Context context, String inputId, ComponentName jobServiceComponent) {
        requestImmediateSync(context, inputId, DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS, jobServiceComponent);
    }

    /**
     * Manually requests a job to run now.
     *
     * <p>To check the current status of the sync, register a {@link
     * android.content.BroadcastReceiver} with an {@link android.content.IntentFilter} which checks
     * for the action {@link #ACTION_SYNC_STATUS_CHANGED}.
     *
     * <p>The sync status is an extra parameter in the {@link Intent} with key {@link #SYNC_STATUS}.
     * The sync status is either {@link #SYNC_STARTED} or {@link #SYNC_FINISHED}.
     *
     * <p>Check that the value of {@link #BUNDLE_KEY_INPUT_ID} matches your {@link
     * android.media.tv.TvInputService}. If you're calling this from your setup activity, you can
     * get the extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     *
     * <p>
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param syncDuration The duration of EPG content to fetch in milliseconds. For a manual sync,
     *     this should be relatively short. For a background sync this should be long.
     * @param jobServiceComponent The {@link EpgSyncJobService} clreplaced that will run.
     */
    public static void requestImmediateSync(Context context, String inputId, long syncDuration, ComponentName jobServiceComponent) {
        if (jobServiceComponent.getClreplaced().isreplacedignableFrom(EpgSyncJobService.clreplaced)) {
            throw new IllegalArgumentException("This clreplaced does not extend EpgSyncJobService");
        }
        PersistableBundle persistableBundle = new PersistableBundle();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            persistableBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
            persistableBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
        }
        persistableBundle.putString(EpgSyncJobService.BUNDLE_KEY_INPUT_ID, inputId);
        persistableBundle.putLong(EpgSyncJobService.BUNDLE_KEY_SYNC_PERIOD, syncDuration);
        JobInfo.Builder builder = new JobInfo.Builder(REQUEST_SYNC_JOB_ID, jobServiceComponent);
        JobInfo jobInfo = builder.setExtras(persistableBundle).setOverrideDeadline(EpgSyncJobService.OVERRIDE_DEADLINE_MILLIS).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
        scheduleJob(context, jobInfo);
        if (DEBUG) {
            Log.d(TAG, "Single job scheduled");
        }
    }

    /**
     * Cancels all pending jobs.
     *
     * @param context Application's context.
     */
    public static void cancelAllSyncRequests(Context context) {
        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobScheduler.cancelAll();
    }

    /**
     * @hide
     */
    public clreplaced EpgSyncTask extends AsyncTask<Void, Void, Void> {

        private final JobParameters params;

        private String mInputId;

        public EpgSyncTask(JobParameters params) {
            this.params = params;
        }

        @Override
        public Void doInBackground(Void... voids) {
            PersistableBundle extras = params.getExtras();
            mInputId = extras.getString(BUNDLE_KEY_INPUT_ID);
            if (mInputId == null) {
                broadcastError(ERROR_INPUT_ID_NULL);
                return null;
            }
            if (isCancelled()) {
                broadcastError(ERROR_EPG_SYNC_CANCELED);
                return null;
            }
            List<Channel> tvChannels;
            try {
                tvChannels = getChannels();
            } catch (EpgSyncException e) {
                broadcastError(e.getReason());
                return null;
            }
            ModelUtils.updateChannels(mContext, mInputId, tvChannels, new OnChannelDeletedCallback() {

                @Override
                public void onChannelDeleted(long rowId) {
                    SharedPreferences.Editor editor = mContext.getSharedPreferences(Constants.PREFERENCES_FILE_KEY, Context.MODE_PRIVATE).edit();
                    editor.remove(Constants.SHARED_PREFERENCES_KEY_LAST_CHANNEL_AD_PLAY + rowId);
                    editor.apply();
                }
            });
            LongSparseArray<Channel> channelMap = ModelUtils.buildChannelMap(mContext.getContentResolver(), mInputId);
            if (channelMap == null) {
                broadcastError(ERROR_NO_CHANNELS);
                return null;
            }
            // Default to one hour sync
            long durationMs = extras.getLong(BUNDLE_KEY_SYNC_PERIOD, DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS);
            long startMs = System.currentTimeMillis();
            long endMs = startMs + durationMs;
            ChangeCount runningChangeCount = new ChangeCount();
            for (int i = 0; i < channelMap.size(); ++i) {
                Uri channelUri = TvContract.buildChannelUri(channelMap.keyAt(i));
                if (isCancelled()) {
                    broadcastError(ERROR_EPG_SYNC_CANCELED);
                    return null;
                }
                List<Program> programs;
                try {
                    programs = getProgramsForChannel(channelUri, channelMap.valueAt(i), startMs, endMs);
                } catch (EpgSyncException e) {
                    broadcastError(e.getReason());
                    return null;
                }
                if (programs != null) {
                    if (DEBUG) {
                        Log.d(TAG, programs.toString());
                    }
                    for (int index = 0; index < programs.size(); index++) {
                        if (programs.get(index).getChannelId() == -1) {
                            // Automatically set the channel id if not set
                            programs.set(index, new Program.Builder(programs.get(index)).setChannelId(channelMap.valueAt(i).getId()).build());
                        }
                    }
                    // Double check if the job is cancelled, so that this task can be finished faster
                    // after cancel() is called.
                    if (isCancelled()) {
                        broadcastError(ERROR_EPG_SYNC_CANCELED);
                        return null;
                    }
                    updatePrograms(channelUri, programs, runningChangeCount);
                }
                Intent intent = createSyncScannedIntent(mInputId, i + 1, channelMap.size(), channelMap.valueAt(i).getDisplayName(), channelMap.valueAt(i).getDisplayNumber());
                LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
            }
            Log.i(TAG, mInputId + " synced " + runningChangeCount.total + " programs. Deleted " + runningChangeCount.deleteCount + " updated " + runningChangeCount.updateCount + " added " + runningChangeCount.addCount);
            return null;
        }

        @Override
        public void onPostExecute(Void success) {
            finishEpgSync(params);
        }

        @Override
        public void onCancelled(Void ignore) {
            finishEpgSync(params);
        }

        private void finishEpgSync(JobParameters jobParams) {
            if (DEBUG) {
                Log.d(TAG, "taskFinished(" + jobParams.getJobId() + ")");
            }
            mTaskArray.delete(jobParams.getJobId());
            jobFinished(jobParams, false);
            if (DEBUG) {
                Log.d(TAG, "Send out broadcast");
            }
            Intent intent = createSyncFinishedIntent(jobParams.getExtras().getString(BUNDLE_KEY_INPUT_ID));
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
        }

        private void broadcastError(int reason) {
            Intent intent = createSyncErrorIntent(mInputId, reason);
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
        }

        /**
         * Returns a list of programs for the given time range.
         *
         * @param channel The {@link Channel} for the programs to return.
         * @param programs The feed fetched from cloud.
         * @param startTimeMs The start time of the range requested.
         * @param endTimeMs The end time of the range requested.
         * @return A list of programs for the channel within the specifed range. They may be
         * repeated.
         * @hide
         */
        @VisibleForTesting
        public List<Program> getPrograms(Channel channel, List<Program> programs, long startTimeMs, long endTimeMs) {
            if (startTimeMs > endTimeMs) {
                throw new IllegalArgumentException("Start time must be before end time");
            }
            List<Program> programForGivenTime = new ArrayList<>();
            if (channel.getInternalProviderData() != null && !channel.getInternalProviderData().isRepeatable()) {
                for (Program program : programs) {
                    if (program.getStartTimeUtcMillis() <= endTimeMs && program.getEndTimeUtcMillis() >= startTimeMs) {
                        programForGivenTime.add(new Program.Builder(program).setChannelId(channel.getId()).build());
                    }
                }
                return programForGivenTime;
            }
            // If repeat-programs is on, schedule the programs sequentially in a loop. To make every
            // device play the same program in a given channel and time, we replacedumes the loop started
            // from the epoch time.
            long totalDurationMs = 0;
            for (Program program : programs) {
                totalDurationMs += (program.getEndTimeUtcMillis() - program.getStartTimeUtcMillis());
            }
            if (totalDurationMs <= 0) {
                throw new IllegalArgumentException("The duration of all programs must be greater " + "than 0ms.");
            }
            long programStartTimeMs = startTimeMs - startTimeMs % totalDurationMs;
            int i = 0;
            final int programCount = programs.size();
            while (programStartTimeMs < endTimeMs) {
                Program programInfo = programs.get(i++ % programCount);
                long programEndTimeMs = programStartTimeMs + totalDurationMs;
                if (programInfo.getEndTimeUtcMillis() > -1 && programInfo.getStartTimeUtcMillis() > -1) {
                    programEndTimeMs = programStartTimeMs + (programInfo.getEndTimeUtcMillis() - programInfo.getStartTimeUtcMillis());
                }
                if (programEndTimeMs < startTimeMs) {
                    programStartTimeMs = programEndTimeMs;
                    continue;
                }
                // Shift advertisement time to match current program time.
                InternalProviderData updateInternalProviderData = programInfo.getInternalProviderData();
                shiftAdsTimeWithProgram(updateInternalProviderData, programInfo.getStartTimeUtcMillis(), programStartTimeMs);
                programForGivenTime.add(new Program.Builder(programInfo).setChannelId(channel.getId()).setStartTimeUtcMillis(programStartTimeMs).setEndTimeUtcMillis(programEndTimeMs).setInternalProviderData(updateInternalProviderData).build());
                programStartTimeMs = programEndTimeMs;
            }
            return programForGivenTime;
        }

        /**
         * Shift advertisement time to match program playback time. For channels with repeated program,
         * the time for current program may vary from what it was defined previously.
         *
         * @param oldProgramStartTimeMs Outdated program start time.
         * @param newProgramStartTimeMs Updated program start time.
         */
        private void shiftAdsTimeWithProgram(InternalProviderData internalProviderData, long oldProgramStartTimeMs, long newProgramStartTimeMs) {
            if (internalProviderData == null) {
                return;
            }
            long timeShift = newProgramStartTimeMs - oldProgramStartTimeMs;
            List<Advertisement> oldAds = internalProviderData.getAds();
            List<Advertisement> newAds = new ArrayList<>();
            for (Advertisement oldAd : oldAds) {
                newAds.add(new Advertisement.Builder(oldAd).setStartTimeUtcMillis(oldAd.getStartTimeUtcMillis() + timeShift).setStopTimeUtcMillis(oldAd.getStopTimeUtcMillis() + timeShift).build());
            }
            internalProviderData.setAds(newAds);
        }

        /**
         * Updates the system database, TvProvider, with the given programs.
         *
         * <p>If there is any overlap between the given and existing programs, the existing ones
         * will be updated with the given ones if they have the same replacedle or replaced.
         *
         * @param channelUri The channel where the program info will be added.
         * @param newPrograms A list of {@link Program} instances which includes program
         *     information.
         */
        private void updatePrograms(Uri channelUri, List<Program> newPrograms, ChangeCount runningChangeCount) {
            final int fetchedProgramsCount = newPrograms.size();
            runningChangeCount.total += fetchedProgramsCount;
            if (fetchedProgramsCount == 0) {
                broadcastError(ERROR_NO_PROGRAMS);
                return;
            }
            List<Program> oldPrograms = ModelUtils.getPrograms(mContext.getContentResolver(), channelUri);
            Program firstNewProgram = newPrograms.get(0);
            int oldProgramsIndex = 0;
            int newProgramsIndex = 0;
            // Skip the past programs. They will be automatically removed by the system.
            for (Program program : oldPrograms) {
                if (program.getEndTimeUtcMillis() < System.currentTimeMillis() || program.getEndTimeUtcMillis() < firstNewProgram.getStartTimeUtcMillis()) {
                    oldProgramsIndex++;
                } else {
                    break;
                }
            }
            // Compare the new programs with old programs one by one and update/delete the old one
            // or insert new program if there is no matching program in the database.
            ArrayList<ContentProviderOperation> ops = new ArrayList<>();
            if (isCancelled()) {
                return;
            }
            while (newProgramsIndex < fetchedProgramsCount) {
                Program oldProgram = oldProgramsIndex < oldPrograms.size() ? oldPrograms.get(oldProgramsIndex) : null;
                Program newProgram = newPrograms.get(newProgramsIndex);
                boolean addNewProgram = false;
                if (oldProgram != null) {
                    if (oldProgram.equals(newProgram)) {
                        // Exact match. No need to update. Move on to the next programs.
                        oldProgramsIndex++;
                        newProgramsIndex++;
                    } else if (shouldUpdateProgramMetadata(oldProgram, newProgram)) {
                        // Partial match. Update the old program with the new one.
                        // NOTE: Use 'update' in this case instead of 'insert' and 'delete'. There
                        // could be application specific settings which belong to the old program.
                        ops.add(ContentProviderOperation.newUpdate(TvContract.buildProgramUri(oldProgram.getId())).withValues(newProgram.toContentValues()).build());
                        runningChangeCount.updateCount++;
                        oldProgramsIndex++;
                        newProgramsIndex++;
                    } else if (oldProgram.getEndTimeUtcMillis() < newProgram.getEndTimeUtcMillis()) {
                        // No match. Remove the old program first to see if the next program in
                        // {@code oldPrograms} partially matches the new program.
                        ops.add(ContentProviderOperation.newDelete(TvContract.buildProgramUri(oldProgram.getId())).build());
                        runningChangeCount.deleteCount++;
                        oldProgramsIndex++;
                    } else {
                        // No match. The new program does not match any of the old programs. Insert
                        // it as a new program.
                        addNewProgram = true;
                        newProgramsIndex++;
                    }
                } else {
                    // No old programs. Just insert new programs.
                    addNewProgram = true;
                    newProgramsIndex++;
                }
                if (addNewProgram) {
                    ops.add(ContentProviderOperation.newInsert(TvContract.Programs.CONTENT_URI).withValues(newProgram.toContentValues()).build());
                    runningChangeCount.addCount++;
                }
                // Throttle the batch operation not to cause TransactionTooLargeException.
                if (ops.size() > BATCH_OPERATION_COUNT || newProgramsIndex >= fetchedProgramsCount) {
                    try {
                        mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
                    } catch (RemoteException | OperationApplicationException e) {
                        Log.e(TAG, "Failed to insert programs.", e);
                        broadcastError(ERROR_DATABASE_INSERT);
                        return;
                    }
                    ops.clear();
                }
            }
        }
    }

    @VisibleForTesting
    public static Intent createSyncStartedIntent(String inputId) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(SYNC_STATUS, SYNC_STARTED);
        return intent;
    }

    @VisibleForTesting
    public static Intent createSyncScannedIntent(String inputId, int channelsScanned, int channelCount, String displayName, String displayNumber) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_CHANNELS_SCANNED, channelsScanned);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_CHANNEL_COUNT, channelCount);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NAME, displayName);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NUMBER, displayNumber);
        intent.putExtra(EpgSyncJobService.SYNC_STATUS, EpgSyncJobService.SYNC_SCANNED);
        return intent;
    }

    @VisibleForTesting
    public static Intent createSyncFinishedIntent(String inputId) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(SYNC_STATUS, SYNC_FINISHED);
        return intent;
    }

    @VisibleForTesting
    public static Intent createSyncErrorIntent(String inputId, int reason) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(SYNC_STATUS, SYNC_ERROR);
        intent.putExtra(BUNDLE_KEY_ERROR_REASON, reason);
        return intent;
    }

    /**
     * Propagates the reason for an EpgSync failure.
     */
    public static clreplaced EpgSyncException extends Exception {

        private final int reason;

        /**
         * Create EpgSyncException with the given {@code reason}.
         *
         * <p>This {@link EpgSyncJobService} sends reason such as {@link #ERROR_EPG_SYNC_CANCELED},
         * {@link #ERROR_DATABASE_INSERT}, etc. Clreplacedes that extend the {@code EpgSyncJobService},
         * should use custom reasons that start at {@link #ERROR_START_CUSTOM}.
         *
         * @param reason The reason sync failed.
         */
        public EpgSyncException(int reason) {
            this.reason = reason;
        }

        public int getReason() {
            return reason;
        }
    }

    /**
     * Struct to hold change counts
     */
    private static clreplaced ChangeCount {

        long total = 0;

        long deleteCount = 0;

        long updateCount = 0;

        long addCount = 0;
    }
}

19 Source : ProviderTvFragment.java
with Apache License 2.0
from zaclimon

/**
 * Main fragment used for the Android TV variant of the application
 *
 * @author zaclimon
 * Creation date: 20/06/17
 */
public abstract clreplaced ProviderTvFragment extends BrowseSupportFragment {

    private ArrayObjectAdapter mRowsAdapter;

    private SparseArray<RowsSupportFragment> mFragmentSparseArray;

    /**
     * Gets the application name
     *
     * @return the application name
     */
    protected abstract String getAppName();

    /**
     * Returns a map containing one or multiple {@link RowsSupportFragment} alongside their respective
     * header replacedle(s).
     *
     * @return the list of RowsFragment mapped by replacedle
     */
    protected abstract Map<String, RowsSupportFragment> getFragmentMap();

    protected abstract Clreplaced<? extends ProviderSearchActivity> getSearchActivity();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            mFragmentSparseArray = new SparseArray<>();
            setupUI();
            showRows();
            getMainFragmentRegistry().registerFragment(PageRow.clreplaced, new TvFragmentFactory());
            if (getSearchActivity() != null) {
                TypedValue value = new TypedValue();
                TypedArray array = getActivity().obtainStyledAttributes(value.data, new int[] { android.R.attr.colorAccent });
                setSearchAffordanceColor(array.getColor(0, 0));
                setOnSearchClickedListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View view) {
                        Intent intent = new Intent(getActivity(), getSearchActivity());
                        startActivity(intent);
                    }
                });
                array.recycle();
            }
        }
    }

    /**
     * Sets the user interface (UI) for the Fragment.
     */
    private void setupUI() {
        setreplacedle(getAppName());
        setHeadersState(HEADERS_ENABLED);
        setHeadersTransitionOnBackEnabled(true);
    }

    /**
     * Shows the different rows of the Fragment.
     */
    private void showRows() {
        Map<String, RowsSupportFragment> tempMap = getFragmentMap();
        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
        int i = 0;
        for (Map.Entry<String, RowsSupportFragment> entry : tempMap.entrySet()) {
            HeaderItem header = new HeaderItem(i, entry.getKey());
            PageRow row = new PageRow(header);
            mRowsAdapter.add(row);
            mFragmentSparseArray.append(i, entry.getValue());
            i++;
        }
        setAdapter(mRowsAdapter);
    }

    /**
     * Private clreplaced acting as a Fragment factory in order to implement custom fragments
     * into Leanback.
     *
     * @author zaclimon
     * Creation date: 02/07/17
     */
    private clreplaced TvFragmentFactory extends FragmentFactory {

        @Override
        public Fragment createFragment(Object row) {
            Row tempRow = (Row) row;
            Fragment fragment = mFragmentSparseArray.get((int) tempRow.getId());
            if (fragment != null) {
                return (fragment);
            } else {
                throw new IllegalArgumentException("Invalid row: " + row);
            }
        }
    }
}

19 Source : TvContractUtils.java
with GNU General Public License v3.0
from zaclimon

/**
 * Static helper methods for working with {@link android.media.tv.TvContract}.
 */
public final clreplaced TvContractUtils {

    /**
     * Indicates that no source type has been defined for this video yet
     */
    public static final int SOURCE_TYPE_INVALID = -1;

    /**
     * Indicates that the video will use MPEG-DASH (Dynamic Adaptive Streaming over HTTP) for
     * playback.
     */
    public static final int SOURCE_TYPE_MPEG_DASH = 0;

    /**
     * Indicates that the video will use SS (Smooth Streaming) for playback.
     */
    public static final int SOURCE_TYPE_SS = 1;

    /**
     * Indicates that the video will use HLS (HTTP Live Streaming) for playback.
     */
    public static final int SOURCE_TYPE_HLS = 2;

    /**
     * Indicates that the video will use HTTP Progressive for playback.
     */
    public static final int SOURCE_TYPE_HTTP_PROGRESSIVE = 3;

    private static final String TAG = "TvContractUtils";

    private static final boolean DEBUG = false;

    private static final SparseArray<String> VIDEO_HEIGHT_TO_FORMAT_MAP = new SparseArray<>();

    static {
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(480, TvContract.Channels.VIDEO_FORMAT_480P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(576, TvContract.Channels.VIDEO_FORMAT_576P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(720, TvContract.Channels.VIDEO_FORMAT_720P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(1080, TvContract.Channels.VIDEO_FORMAT_1080P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(2160, TvContract.Channels.VIDEO_FORMAT_2160P);
        VIDEO_HEIGHT_TO_FORMAT_MAP.put(4320, TvContract.Channels.VIDEO_FORMAT_4320P);
    }

    private static void insertUrl(Context context, Uri contentUri, URL sourceUrl) {
        if (DEBUG) {
            Log.d(TAG, "Inserting " + sourceUrl + " to " + contentUri);
        }
        InputStream is = null;
        OutputStream os = null;
        try {
            is = sourceUrl.openStream();
            os = context.getContentResolver().openOutputStream(contentUri);
            if (is != null && os != null) {
                copy(is, os);
            }
        } catch (IOException ioe) {
            Log.e(TAG, "Failed to write " + sourceUrl + "  to " + contentUri, ioe);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                // Ignore exception.
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                // Ignore exception.
                }
            }
        }
    }

    private static void copy(InputStream is, OutputStream os) throws IOException {
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
    }

    /**
     * Parses a string of comma-separated ratings into an array of {@link TvContentRating}.
     *
     * @param commaSeparatedRatings String containing various ratings, separated by commas.
     * @return An array of TvContentRatings.
     * @hide
     */
    public static TvContentRating[] stringToContentRatings(String commaSeparatedRatings) {
        if (TextUtils.isEmpty(commaSeparatedRatings)) {
            return null;
        }
        String[] ratings = commaSeparatedRatings.split("\\s*,\\s*");
        TvContentRating[] contentRatings = new TvContentRating[ratings.length];
        for (int i = 0; i < contentRatings.length; ++i) {
            contentRatings[i] = TvContentRating.unflattenFromString(ratings[i]);
        }
        return contentRatings;
    }

    /**
     * Flattens an array of {@link TvContentRating} into a String to be inserted into a database.
     *
     * @param contentRatings An array of TvContentRatings.
     * @return A comma-separated String of ratings.
     * @hide
     */
    public static String contentRatingsToString(TvContentRating[] contentRatings) {
        if (contentRatings == null || contentRatings.length == 0) {
            return null;
        }
        final String DELIMITER = ",";
        StringBuilder ratings = new StringBuilder(contentRatings[0].flattenToString());
        for (int i = 1; i < contentRatings.length; ++i) {
            ratings.append(DELIMITER);
            ratings.append(contentRatings[i].flattenToString());
        }
        return ratings.toString();
    }

    private TvContractUtils() {
    }

    /**
     * AsyncTask to insert logos.
     */
    public static clreplaced InsertLogosTask extends AsyncTask<Map<Uri, String>, Void, Void> {

        private final Context mContext;

        public InsertLogosTask(Context context) {
            mContext = context;
        }

        @Override
        public Void doInBackground(Map<Uri, String>... logosList) {
            for (Map<Uri, String> logos : logosList) {
                for (Uri uri : logos.keySet()) {
                    try {
                        insertUrl(mContext, uri, new URL(logos.get(uri)));
                    } catch (MalformedURLException e) {
                        Log.e(TAG, "Can't load " + logos.get(uri), e);
                    }
                }
            }
            return null;
        }
    }
}

19 Source : EpgSyncJobService.java
with GNU General Public License v3.0
from zaclimon

/**
 * Service to handle callbacks from JobScheduler. This service will be called by the system to
 * update the EPG with channels and programs periodically.
 *
 * <p>You can extend this clreplaced and add it your app by including it in your app's
 * AndroidManfiest.xml:
 *
 * <pre>
 *      <service
 *          android:name=".SampleJobService"
 *          android:permission="android.permission.BIND_JOB_SERVICE"
 *          android:exported="true" />
 * </pre>
 *
 * You will need to implement several methods in your EpgSyncJobService to return your content.
 *
 * <p>To start periodically syncing data, call {@link #setUpPeriodicSync(Context, String,
 * ComponentName, long, long)}.
 *
 * <p>To sync manually, call {@link #requestImmediateSync(Context, String, long, ComponentName)}.
 */
public abstract clreplaced EpgSyncJobService extends JobService {

    private static final String TAG = "EpgSyncJobService";

    private static final boolean DEBUG = false;

    /**
     * The action that will be broadcast when the job service's status changes.
     */
    public static final String ACTION_SYNC_STATUS_CHANGED = EpgSyncJobService.clreplaced.getPackage().getName() + ".ACTION_SYNC_STATUS_CHANGED";

    /**
     * The key representing the component name for the app's TvInputService.
     */
    public static final String BUNDLE_KEY_INPUT_ID = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_input_id";

    /**
     * The key representing the number of channels that have been scanned and populated in the EPG.
     */
    public static final String BUNDLE_KEY_CHANNELS_SCANNED = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_channels_scanned";

    /**
     * The key representing the total number of channels for this input.
     */
    public static final String BUNDLE_KEY_CHANNEL_COUNT = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_channel_count";

    /**
     * The key representing the most recently scanned channel display name.
     */
    public static final String BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NAME = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_scanned_channel_display_name";

    /**
     * The key representing the most recently scanned channel display number.
     */
    public static final String BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NUMBER = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_scanned_channel_display_number";

    /**
     * The key representing the error that occurred during an EPG sync
     */
    public static final String BUNDLE_KEY_ERROR_REASON = EpgSyncJobService.clreplaced.getPackage().getName() + ".bundle_key_error_reason";

    /**
     * The name for the {@link android.content.SharedPreferences} file used for storing syncing
     * metadata.
     */
    public static final String PREFERENCE_EPG_SYNC = EpgSyncJobService.clreplaced.getPackage().getName() + ".preference_epg_sync";

    /**
     * The status of the job service when syncing has begun.
     */
    public static final String SYNC_STARTED = "sync_started";

    /**
     * The status of the job service when a channel has been scanned and the EPG for that channel
     * has been populated.
     */
    public static final String SYNC_SCANNED = "sync_scanned";

    /**
     * The status of the job service when syncing has completed.
     */
    public static final String SYNC_FINISHED = "sync_finished";

    /**
     * The status of the job when a problem occurs during syncing. A {@link #SYNC_FINISHED}
     * broadcast will still be sent when the service is done. This status can be used to identify
     * specific issues in your EPG sync.
     */
    public static final String SYNC_ERROR = "sync_error";

    /**
     * The key corresponding to the job service's status.
     */
    public static final String SYNC_STATUS = "sync_status";

    /**
     * Indicates that the EPG sync was canceled before being completed.
     */
    public static final int ERROR_EPG_SYNC_CANCELED = 1;

    /**
     * Indicates that the input id was not defined and the EPG sync cannot complete.
     */
    public static final int ERROR_INPUT_ID_NULL = 2;

    /**
     * Indicates that no programs were found.
     */
    public static final int ERROR_NO_PROGRAMS = 3;

    /**
     * Indicates that no channels were found.
     */
    public static final int ERROR_NO_CHANNELS = 4;

    /**
     * Indicates an error occurred when updating programs in the database
     */
    public static final int ERROR_DATABASE_INSERT = 5;

    /**
     * Subclreplacedes start their custom error numbers with this value
     */
    public static final int ERROR_START_CUSTOM = 1000;

    /**
     * The default period between full EPG syncs, one day.
     */
    // 12 hour
    private static final long DEFAULT_SYNC_PERIOD_MILLIS = 1000 * 60 * 60 * 12;

    // 1 Hour
    private static final long DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS = 1000 * 60 * 60;

    // 48 Hour
    private static final long DEFAULT_PERIODIC_EPG_DURATION_MILLIS = 1000 * 60 * 60 * 48;

    private static final int PERIODIC_SYNC_JOB_ID = 0;

    private static final int REQUEST_SYNC_JOB_ID = 1;

    private static final int BATCH_OPERATION_COUNT = 100;

    // 1 second
    private static final long OVERRIDE_DEADLINE_MILLIS = 1000;

    private static final String BUNDLE_KEY_SYNC_PERIOD = "bundle_key_sync_period";

    private static final ExecutorService SINGLE_THREAD_EXECUTOR = Executors.newSingleThreadExecutor();

    private final SparseArray<EpgSyncTask> mTaskArray = new SparseArray<>();

    private static final Object mContextLock = new Object();

    private Context mContext;

    /**
     * Returns the channels that your app contains.
     *
     * @return The list of channels for your app.
     */
    public abstract List<Channel> getChannels() throws EpgSyncException;

    /**
     * Returns the programs that will appear for each channel.
     *
     * @param channelUri The Uri corresponding to the channel.
     * @param channel The channel your programs will appear on.
     * @param startMs The starting time in milliseconds since the epoch to generate programs. If
     *     your program starts before this starting time, it should be be included.
     * @param endMs The ending time in milliseconds since the epoch to generate programs. If your
     *     program starts before this ending time, it should be be included.
     * @return A list of programs for a given channel.
     */
    public abstract List<Program> getProgramsForChannel(Uri channelUri, Channel channel, long startMs, long endMs) throws EpgSyncException;

    @Override
    public void onCreate() {
        super.onCreate();
        if (DEBUG) {
            Log.d(TAG, "Created EpgSyncJobService");
        }
        synchronized (mContextLock) {
            if (mContext == null) {
                mContext = getApplicationContext();
            }
        }
    }

    @Override
    public boolean onStartJob(JobParameters params) {
        if (DEBUG) {
            Log.d(TAG, "onStartJob(" + params.getJobId() + ")");
        }
        // Broadcast status
        Intent intent = createSyncStartedIntent(params.getExtras().getString(BUNDLE_KEY_INPUT_ID));
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
        EpgSyncTask epgSyncTask = new EpgSyncTask(params);
        synchronized (mTaskArray) {
            mTaskArray.put(params.getJobId(), epgSyncTask);
        }
        // Run the task on a single threaded custom executor in order not to block the AsyncTasks
        // running on application side.
        epgSyncTask.executeOnExecutor(SINGLE_THREAD_EXECUTOR);
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        synchronized (mTaskArray) {
            int jobId = params.getJobId();
            EpgSyncTask epgSyncTask = mTaskArray.get(jobId);
            if (epgSyncTask != null) {
                epgSyncTask.cancel(true);
                mTaskArray.delete(params.getJobId());
            }
        }
        return false;
    }

    /**
     * Returns {@code true} if the {@code oldProgram} program is the same as the {@code newProgram}
     * program but should update metadata. This updates the database instead of deleting and
     * inserting a new program to keep the user's intent, eg. recording this program.
     */
    public boolean shouldUpdateProgramMetadata(Program oldProgram, Program newProgram) {
        // NOTE: Here, we update the old program if it has the same replacedle and overlaps with the
        // new program. The test logic is just an example and you can modify this. E.g. check
        // whether the both programs have the same program ID if your EPG supports any ID for
        // the programs.
        return oldProgram.getreplacedle().equals(newProgram.getreplacedle()) && oldProgram.getStartTimeUtcMillis() <= newProgram.getEndTimeUtcMillis() && newProgram.getStartTimeUtcMillis() <= oldProgram.getEndTimeUtcMillis();
    }

    /**
     * Send the job to JobScheduler.
     */
    private static void scheduleJob(Context context, JobInfo job) {
        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        int result = jobScheduler.schedule(job);
        if (DEBUG) {
            Log.d(TAG, "Scheduling result is " + result);
        }
    }

    /**
     * Initializes a job that will periodically update the app's channels and programs with a
     * default period of 24 hours.
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param jobServiceComponent The {@link EpgSyncJobService} component name that will run.
     */
    public static void setUpPeriodicSync(Context context, String inputId, ComponentName jobServiceComponent) {
        setUpPeriodicSync(context, inputId, jobServiceComponent, DEFAULT_SYNC_PERIOD_MILLIS, DEFAULT_PERIODIC_EPG_DURATION_MILLIS);
    }

    /**
     * Initializes a job that will periodically update the app's channels and programs.
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param jobServiceComponent The {@link EpgSyncJobService} component name that will run.
     * @param fullSyncPeriod The period between when the job will run a full background sync in
     *     milliseconds.
     * @param syncDuration The duration of EPG content to fetch in milliseconds. For a manual sync,
     *     this should be relatively short. For a background sync this should be long.
     */
    public static void setUpPeriodicSync(Context context, String inputId, ComponentName jobServiceComponent, long fullSyncPeriod, long syncDuration) {
        if (jobServiceComponent.getClreplaced().isreplacedignableFrom(EpgSyncJobService.clreplaced)) {
            throw new IllegalArgumentException("This clreplaced does not extend EpgSyncJobService");
        }
        PersistableBundle persistableBundle = new PersistableBundle();
        persistableBundle.putString(EpgSyncJobService.BUNDLE_KEY_INPUT_ID, inputId);
        persistableBundle.putLong(EpgSyncJobService.BUNDLE_KEY_SYNC_PERIOD, syncDuration);
        JobInfo.Builder builder = new JobInfo.Builder(PERIODIC_SYNC_JOB_ID, jobServiceComponent);
        JobInfo jobInfo = builder.setExtras(persistableBundle).setPeriodic(fullSyncPeriod).setPersisted(true).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
        scheduleJob(context, jobInfo);
        if (DEBUG) {
            Log.d(TAG, "Job has been scheduled for every " + fullSyncPeriod + "ms");
        }
    }

    /**
     * Manually requests a job to run now to retrieve EPG content for the next hour.
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param jobServiceComponent The {@link EpgSyncJobService} clreplaced that will run.
     */
    public static void requestImmediateSync(Context context, String inputId, ComponentName jobServiceComponent) {
        requestImmediateSync(context, inputId, DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS, jobServiceComponent);
    }

    /**
     * Manually requests a job to run now.
     *
     * <p>To check the current status of the sync, register a {@link
     * android.content.BroadcastReceiver} with an {@link android.content.IntentFilter} which checks
     * for the action {@link #ACTION_SYNC_STATUS_CHANGED}.
     *
     * <p>The sync status is an extra parameter in the {@link Intent} with key {@link #SYNC_STATUS}.
     * The sync status is either {@link #SYNC_STARTED} or {@link #SYNC_FINISHED}.
     *
     * <p>Check that the value of {@link #BUNDLE_KEY_INPUT_ID} matches your {@link
     * android.media.tv.TvInputService}. If you're calling this from your setup activity, you can
     * get the extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     *
     * <p>
     *
     * @param context Application's context.
     * @param inputId Component name for the app's TvInputService. This can be received through an
     *     Intent extra parameter {@link TvInputInfo#EXTRA_INPUT_ID}.
     * @param syncDuration The duration of EPG content to fetch in milliseconds. For a manual sync,
     *     this should be relatively short. For a background sync this should be long.
     * @param jobServiceComponent The {@link EpgSyncJobService} clreplaced that will run.
     */
    public static void requestImmediateSync(Context context, String inputId, long syncDuration, ComponentName jobServiceComponent) {
        if (jobServiceComponent.getClreplaced().isreplacedignableFrom(EpgSyncJobService.clreplaced)) {
            throw new IllegalArgumentException("This clreplaced does not extend EpgSyncJobService");
        }
        PersistableBundle persistableBundle = new PersistableBundle();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            persistableBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
            persistableBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
        }
        persistableBundle.putString(EpgSyncJobService.BUNDLE_KEY_INPUT_ID, inputId);
        persistableBundle.putLong(EpgSyncJobService.BUNDLE_KEY_SYNC_PERIOD, syncDuration);
        JobInfo.Builder builder = new JobInfo.Builder(REQUEST_SYNC_JOB_ID, jobServiceComponent);
        JobInfo jobInfo = builder.setExtras(persistableBundle).setOverrideDeadline(EpgSyncJobService.OVERRIDE_DEADLINE_MILLIS).setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
        scheduleJob(context, jobInfo);
        if (DEBUG) {
            Log.d(TAG, "Single job scheduled");
        }
    }

    /**
     * Cancels all pending jobs.
     *
     * @param context Application's context.
     */
    public static void cancelAllSyncRequests(Context context) {
        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobScheduler.cancelAll();
    }

    /**
     * @hide
     */
    public clreplaced EpgSyncTask extends AsyncTask<Void, Void, Void> {

        private final JobParameters params;

        private String mInputId;

        public EpgSyncTask(JobParameters params) {
            this.params = params;
        }

        @Override
        public Void doInBackground(Void... voids) {
            PersistableBundle extras = params.getExtras();
            mInputId = extras.getString(BUNDLE_KEY_INPUT_ID);
            if (mInputId == null) {
                broadcastError(ERROR_INPUT_ID_NULL);
                return null;
            }
            if (isCancelled()) {
                broadcastError(ERROR_EPG_SYNC_CANCELED);
                return null;
            }
            List<Channel> tvChannels;
            try {
                tvChannels = getChannels();
            } catch (EpgSyncException e) {
                broadcastError(e.getReason());
                return null;
            }
            ModelUtils.updateChannels(mContext, mInputId, tvChannels, new OnChannelDeletedCallback() {

                @Override
                public void onChannelDeleted(long rowId) {
                    SharedPreferences.Editor editor = mContext.getSharedPreferences(Constants.PREFERENCES_FILE_KEY, Context.MODE_PRIVATE).edit();
                    editor.remove(Constants.SHARED_PREFERENCES_KEY_LAST_CHANNEL_AD_PLAY + rowId);
                    editor.apply();
                }
            });
            LongSparseArray<Channel> channelMap = ModelUtils.buildChannelMap(mContext.getContentResolver(), mInputId);
            if (channelMap == null) {
                broadcastError(ERROR_NO_CHANNELS);
                return null;
            }
            // Default to one hour sync
            long durationMs = extras.getLong(BUNDLE_KEY_SYNC_PERIOD, DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS);
            long startMs = System.currentTimeMillis();
            long endMs = startMs + durationMs;
            ChangeCount runningChangeCount = new ChangeCount();
            for (int i = 0; i < channelMap.size(); ++i) {
                Uri channelUri = TvContract.buildChannelUri(channelMap.keyAt(i));
                if (isCancelled()) {
                    broadcastError(ERROR_EPG_SYNC_CANCELED);
                    return null;
                }
                List<Program> programs;
                try {
                    programs = getProgramsForChannel(channelUri, channelMap.valueAt(i), startMs, endMs);
                } catch (EpgSyncException e) {
                    broadcastError(e.getReason());
                    return null;
                }
                if (programs != null) {
                    if (DEBUG) {
                        Log.d(TAG, programs.toString());
                    }
                    for (int index = 0; index < programs.size(); index++) {
                        if (programs.get(index).getChannelId() == -1) {
                            // Automatically set the channel id if not set
                            programs.set(index, new Program.Builder(programs.get(index)).setChannelId(channelMap.valueAt(i).getId()).build());
                        }
                    }
                    // Double check if the job is cancelled, so that this task can be finished faster
                    // after cancel() is called.
                    if (isCancelled()) {
                        broadcastError(ERROR_EPG_SYNC_CANCELED);
                        return null;
                    }
                    updatePrograms(channelUri, programs, runningChangeCount);
                }
                Intent intent = createSyncScannedIntent(mInputId, i + 1, channelMap.size(), channelMap.valueAt(i).getDisplayName(), channelMap.valueAt(i).getDisplayNumber());
                LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
            }
            Log.i(TAG, mInputId + " synced " + runningChangeCount.total + " programs. Deleted " + runningChangeCount.deleteCount + " updated " + runningChangeCount.updateCount + " added " + runningChangeCount.addCount);
            return null;
        }

        @Override
        public void onPostExecute(Void success) {
            finishEpgSync(params);
        }

        @Override
        public void onCancelled(Void ignore) {
            finishEpgSync(params);
        }

        private void finishEpgSync(JobParameters jobParams) {
            if (DEBUG) {
                Log.d(TAG, "taskFinished(" + jobParams.getJobId() + ")");
            }
            mTaskArray.delete(jobParams.getJobId());
            jobFinished(jobParams, false);
            if (DEBUG) {
                Log.d(TAG, "Send out broadcast");
            }
            Intent intent = createSyncFinishedIntent(jobParams.getExtras().getString(BUNDLE_KEY_INPUT_ID));
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
        }

        private void broadcastError(int reason) {
            Intent intent = createSyncErrorIntent(mInputId, reason);
            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
        }

        /**
         * Returns a list of programs for the given time range.
         *
         * @param channel The {@link Channel} for the programs to return.
         * @param programs The feed fetched from cloud.
         * @param startTimeMs The start time of the range requested.
         * @param endTimeMs The end time of the range requested.
         * @return A list of programs for the channel within the specifed range. They may be
         * repeated.
         * @hide
         */
        @VisibleForTesting
        public List<Program> getPrograms(Channel channel, List<Program> programs, long startTimeMs, long endTimeMs) {
            if (startTimeMs > endTimeMs) {
                throw new IllegalArgumentException("Start time must be before end time");
            }
            List<Program> programForGivenTime = new ArrayList<>();
            if (channel.getInternalProviderData() != null && !channel.getInternalProviderData().isRepeatable()) {
                for (Program program : programs) {
                    if (program.getStartTimeUtcMillis() <= endTimeMs && program.getEndTimeUtcMillis() >= startTimeMs) {
                        programForGivenTime.add(new Program.Builder(program).setChannelId(channel.getId()).build());
                    }
                }
                return programForGivenTime;
            }
            // If repeat-programs is on, schedule the programs sequentially in a loop. To make every
            // device play the same program in a given channel and time, we replacedumes the loop started
            // from the epoch time.
            long totalDurationMs = 0;
            for (Program program : programs) {
                totalDurationMs += (program.getEndTimeUtcMillis() - program.getStartTimeUtcMillis());
            }
            if (totalDurationMs <= 0) {
                throw new IllegalArgumentException("The duration of all programs must be greater " + "than 0ms.");
            }
            long programStartTimeMs = startTimeMs - startTimeMs % totalDurationMs;
            int i = 0;
            final int programCount = programs.size();
            while (programStartTimeMs < endTimeMs) {
                Program programInfo = programs.get(i++ % programCount);
                long programEndTimeMs = programStartTimeMs + totalDurationMs;
                if (programInfo.getEndTimeUtcMillis() > -1 && programInfo.getStartTimeUtcMillis() > -1) {
                    programEndTimeMs = programStartTimeMs + (programInfo.getEndTimeUtcMillis() - programInfo.getStartTimeUtcMillis());
                }
                if (programEndTimeMs < startTimeMs) {
                    programStartTimeMs = programEndTimeMs;
                    continue;
                }
                // Shift advertisement time to match current program time.
                InternalProviderData updateInternalProviderData = programInfo.getInternalProviderData();
                shiftAdsTimeWithProgram(updateInternalProviderData, programInfo.getStartTimeUtcMillis(), programStartTimeMs);
                programForGivenTime.add(new Program.Builder(programInfo).setChannelId(channel.getId()).setStartTimeUtcMillis(programStartTimeMs).setEndTimeUtcMillis(programEndTimeMs).setInternalProviderData(updateInternalProviderData).build());
                programStartTimeMs = programEndTimeMs;
            }
            return programForGivenTime;
        }

        /**
         * Shift advertisement time to match program playback time. For channels with repeated program,
         * the time for current program may vary from what it was defined previously.
         *
         * @param oldProgramStartTimeMs Outdated program start time.
         * @param newProgramStartTimeMs Updated program start time.
         */
        private void shiftAdsTimeWithProgram(InternalProviderData internalProviderData, long oldProgramStartTimeMs, long newProgramStartTimeMs) {
            if (internalProviderData == null) {
                return;
            }
            long timeShift = newProgramStartTimeMs - oldProgramStartTimeMs;
            List<Advertisement> oldAds = internalProviderData.getAds();
            List<Advertisement> newAds = new ArrayList<>();
            for (Advertisement oldAd : oldAds) {
                newAds.add(new Advertisement.Builder(oldAd).setStartTimeUtcMillis(oldAd.getStartTimeUtcMillis() + timeShift).setStopTimeUtcMillis(oldAd.getStopTimeUtcMillis() + timeShift).build());
            }
            internalProviderData.setAds(newAds);
        }

        /**
         * Updates the system database, TvProvider, with the given programs.
         *
         * <p>If there is any overlap between the given and existing programs, the existing ones
         * will be updated with the given ones if they have the same replacedle or replaced.
         *
         * @param channelUri The channel where the program info will be added.
         * @param newPrograms A list of {@link Program} instances which includes program
         *     information.
         */
        private void updatePrograms(Uri channelUri, List<Program> newPrograms, ChangeCount runningChangeCount) {
            final int fetchedProgramsCount = newPrograms.size();
            runningChangeCount.total += fetchedProgramsCount;
            if (fetchedProgramsCount == 0) {
                broadcastError(ERROR_NO_PROGRAMS);
                return;
            }
            List<Program> oldPrograms = ModelUtils.getPrograms(mContext.getContentResolver(), channelUri);
            Program firstNewProgram = newPrograms.get(0);
            int oldProgramsIndex = 0;
            int newProgramsIndex = 0;
            // Skip the past programs. They will be automatically removed by the system.
            for (Program program : oldPrograms) {
                if (program.getEndTimeUtcMillis() < System.currentTimeMillis() || program.getEndTimeUtcMillis() < firstNewProgram.getStartTimeUtcMillis()) {
                    oldProgramsIndex++;
                } else {
                    break;
                }
            }
            // Compare the new programs with old programs one by one and update/delete the old one
            // or insert new program if there is no matching program in the database.
            ArrayList<ContentProviderOperation> ops = new ArrayList<>();
            if (isCancelled()) {
                return;
            }
            while (newProgramsIndex < fetchedProgramsCount) {
                Program oldProgram = oldProgramsIndex < oldPrograms.size() ? oldPrograms.get(oldProgramsIndex) : null;
                Program newProgram = newPrograms.get(newProgramsIndex);
                boolean addNewProgram = false;
                if (oldProgram != null && newProgram != null) {
                    if (oldProgram.equals(newProgram)) {
                        // Exact match. No need to update. Move on to the next programs.
                        oldProgramsIndex++;
                        newProgramsIndex++;
                    } else if (shouldUpdateProgramMetadata(oldProgram, newProgram)) {
                        // Partial match. Update the old program with the new one.
                        // NOTE: Use 'update' in this case instead of 'insert' and 'delete'. There
                        // could be application specific settings which belong to the old program.
                        ops.add(ContentProviderOperation.newUpdate(TvContract.buildProgramUri(oldProgram.getId())).withValues(newProgram.toContentValues()).build());
                        runningChangeCount.updateCount++;
                        oldProgramsIndex++;
                        newProgramsIndex++;
                    } else if (oldProgram.getEndTimeUtcMillis() < newProgram.getEndTimeUtcMillis()) {
                        // No match. Remove the old program first to see if the next program in
                        // {@code oldPrograms} partially matches the new program.
                        ops.add(ContentProviderOperation.newDelete(TvContract.buildProgramUri(oldProgram.getId())).build());
                        runningChangeCount.deleteCount++;
                        oldProgramsIndex++;
                    } else {
                        // No match. The new program does not match any of the old programs. Insert
                        // it as a new program.
                        addNewProgram = true;
                        newProgramsIndex++;
                    }
                } else {
                    // No old programs. Just insert new programs.
                    addNewProgram = true;
                    newProgramsIndex++;
                }
                if (addNewProgram) {
                    ops.add(ContentProviderOperation.newInsert(TvContract.Programs.CONTENT_URI).withValues(newProgram.toContentValues()).build());
                    runningChangeCount.addCount++;
                }
                // Throttle the batch operation not to cause TransactionTooLargeException.
                if (ops.size() > BATCH_OPERATION_COUNT || newProgramsIndex >= fetchedProgramsCount) {
                    try {
                        mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
                    } catch (RemoteException | OperationApplicationException e) {
                        Log.e(TAG, "Failed to insert programs.", e);
                        broadcastError(ERROR_DATABASE_INSERT);
                        return;
                    }
                    ops.clear();
                }
            }
        }
    }

    @VisibleForTesting
    public static Intent createSyncStartedIntent(String inputId) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(SYNC_STATUS, SYNC_STARTED);
        return intent;
    }

    @VisibleForTesting
    public static Intent createSyncScannedIntent(String inputId, int channelsScanned, int channelCount, String displayName, String displayNumber) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_CHANNELS_SCANNED, channelsScanned);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_CHANNEL_COUNT, channelCount);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NAME, displayName);
        intent.putExtra(EpgSyncJobService.BUNDLE_KEY_SCANNED_CHANNEL_DISPLAY_NUMBER, displayNumber);
        intent.putExtra(EpgSyncJobService.SYNC_STATUS, EpgSyncJobService.SYNC_SCANNED);
        return intent;
    }

    @VisibleForTesting
    public static Intent createSyncFinishedIntent(String inputId) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(SYNC_STATUS, SYNC_FINISHED);
        return intent;
    }

    @VisibleForTesting
    public static Intent createSyncErrorIntent(String inputId, int reason) {
        Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED);
        intent.putExtra(BUNDLE_KEY_INPUT_ID, inputId);
        intent.putExtra(SYNC_STATUS, SYNC_ERROR);
        intent.putExtra(BUNDLE_KEY_ERROR_REASON, reason);
        return intent;
    }

    /**
     * Propagates the reason for an EpgSync failure.
     */
    public static clreplaced EpgSyncException extends Exception {

        private final int reason;

        /**
         * Create EpgSyncException with the given {@code reason}.
         *
         * <p>This {@link EpgSyncJobService} sends reason such as {@link #ERROR_EPG_SYNC_CANCELED},
         * {@link #ERROR_DATABASE_INSERT}, etc. Clreplacedes that extend the {@code EpgSyncJobService},
         * should use custom reasons that start at {@link #ERROR_START_CUSTOM}.
         *
         * @param reason The reason sync failed.
         */
        public EpgSyncException(int reason) {
            this.reason = reason;
        }

        public int getReason() {
            return reason;
        }
    }

    /**
     * Struct to hold change counts
     */
    private static clreplaced ChangeCount {

        long total = 0;

        long deleteCount = 0;

        long updateCount = 0;

        long addCount = 0;
    }
}

19 Source : USBVendorId.java
with Apache License 2.0
from z-jc

public clreplaced USBVendorId {

    private static final SparseArray<String> IDS = new SparseArray<String>();

    public static String vendorName(final int vendor_id) {
        return IDS.get(vendor_id);
    }

    static {
        IDS.put(10006, "YUEN DA ELECTRONIC PRODUCTS FACTORY");
        IDS.put(10013, "Gionee Communication Equipment Co., Ltd. ShenZhen");
        IDS.put(10022, "Universal Electronics Inc. (dba: TVIEW)");
        IDS.put(1003, "Atmel Corporation");
        IDS.put(1006, "Mitsumi");
        IDS.put(1008, "HP Inc.");
        IDS.put(10112, "M31 Technology Corp.");
        IDS.put(10113, "Liteconn Co., Ltd.");
        IDS.put(10121, "Suzhou WEIJU Electronics Technology Co., Ltd.");
        IDS.put(10144, "Mondokey Limited");
        IDS.put(10149, "Advantest Corporation");
        IDS.put(10150, "iRobot Corporation");
        IDS.put(1020, "Elitegroup Computer Systems");
        IDS.put(1021, "Xilinx Inc.");
        IDS.put(10226, "Sibridge Tech.");
        IDS.put(1026, "ALi Corporation");
        IDS.put(1027, "Future Technology Devices International Limited");
        IDS.put(10275, "Dongguan Jiumutong Industry Co., Ltd.");
        IDS.put(10289, "Power Integrations");
        IDS.put(10291, "Oculus VR, Inc.");
        IDS.put(10300, "HIGH TEK HARNESS ENTERPRISE CO., LTD.");
        IDS.put(10316, "Full in Hope Co., Ltd.");
        IDS.put(1032, "Quanta Computer Inc.");
        IDS.put(10329, "Viconn Technology (HK) Co., Ltd.");
        IDS.put(1033, "NEC Corporation");
        IDS.put(1035, "Weltrend Semiconductor");
        IDS.put(1037, "VIA Technologies, Inc.");
        IDS.put(10374, "Seeed Technology Co., Ltd.");
        IDS.put(10375, "Specwerkz");
        IDS.put(1038, "MCCI Corporation");
        IDS.put(10398, "Esselte Leitz GmbH & Co. KG");
        IDS.put(10406, "E-SEEK Inc.");
        IDS.put(1041, "BUFFALO INC.");
        IDS.put(10423, "Pleora Technologies Inc.");
        IDS.put(10431, "Vitetech Int'l Co., Ltd.");
        IDS.put(1044, "Giga-Byte Technology Co., Ltd.");
        IDS.put(10446, "Changzhou Shi Wujin Miqi East Electronic Co., Ltd.");
        IDS.put(10457, "Shenzhen Ourconn Technology Co., Ltd.");
        IDS.put(10458, "G.SKILL Int'l Enterprice Co., Ltd.");
        IDS.put(1046, "Nuvoton Technology Corp.");
        IDS.put(10466, "Surplus Electronic Technology Co., Ltd.");
        IDS.put(10470, "BIAMP SYSTEMS");
        IDS.put(10509, "IBCONN Technologies (Shenzhen) Co., Ltd.");
        IDS.put(10510, "Fugoo Inc.");
        IDS.put(10519, "Pan Xin Precision Electronics Co., Ltd.");
        IDS.put(10530, "Dongguan Digi-in Digital Technology Co., Ltd.");
        IDS.put(1054, "Creative Labs");
        IDS.put(10540, "GENUSION, Inc.");
        IDS.put(10544, "Ineda Systems Inc.");
        IDS.put(10545, "Jolla Ltd.");
        IDS.put(10546, "Peraso Technologies, Inc.");
        IDS.put(10549, "Nanjing Magewell Electronics Co., Ltd.");
        IDS.put(10560, "Shenzhen Yiwanda Electronics Co., Ltd.");
        IDS.put(1057, "Nokia Corporation");
        IDS.put(10575, "Dollar Connection Ltd.");
        IDS.put(10595, "BIO-key International, Inc.");
        IDS.put(1060, "Microchip-SMSC");
        IDS.put(10603, "Xacti Corporation");
        IDS.put(10615, "Shenzhen Zowee Technology Co., Ltd.");
        IDS.put(10643, "ADPlaus Technology Limited");
        IDS.put(10646, "Unwired Technology");
        IDS.put(1065, "Cirrus Logic Inc.");
        IDS.put(10657, "Union Electric Plug & Connector Corp.");
        IDS.put(10674, "Canova Tech");
        IDS.put(10685, "Silicon Works");
        IDS.put(10695, "HANRICO ANFU ELECTRONICS CO., LTD.");
        IDS.put(10700, "Kodak Alaris");
        IDS.put(10702, "JGR Optics Inc.");
        IDS.put(10703, "Richtek Technology Corporation");
        IDS.put(10705, "Binatone Electronics Int. Ltd.");
        IDS.put(1071, "Molex Inc.");
        IDS.put(10715, "Shenzhen iBoard Technology Co., Ltd.");
        IDS.put(10719, "SMIT(HK) Limited");
        IDS.put(1072, "Fujitsu Component Limited");
        IDS.put(10725, "Dongguan Kechenda Electronic Technology Co., Ltd.");
        IDS.put(10726, "Fengshun Peiying Electro-Acoustic Co., Ltd.");
        IDS.put(10744, "MD ELEKTRONIK GmbH");
        IDS.put(10749, "Bad Elf, LLC");
        IDS.put(10770, "Vreo Limited");
        IDS.put(10772, "Kanex");
        IDS.put(10781, "Oxford Nanopore Technologies");
        IDS.put(10782, "Obsidian Technology");
        IDS.put(10783, "Lucent Trans Electronics Co., Ltd.");
        IDS.put(10784, "GUOGUANG GROUP CO., LTD.");
        IDS.put(10788, "CNPLUS");
        IDS.put(10789, "Fourstar Group");
        IDS.put(10790, "Tragant International Co., Ltd.");
        IDS.put(10791, "DongGuan LianGang Optoelectronic Technology Co., Ltd.");
        IDS.put(10797, "Atrust Computer Corp.");
        IDS.put(10798, "VIA Alliance Semiconductor Co., Ltd.");
        IDS.put(10799, "BSUN Electronics Co., Ltd.");
        IDS.put(1080, "Advanced Micro Devices");
        IDS.put(10807, "RTD Embedded Technologies, Inc.");
        IDS.put(10816, "Shenzhen Choseal Industrial Co., Ltd.");
        IDS.put(10817, "Canyon Semiconductor");
        IDS.put(10818, "Spectra7 Microsystems Corp.");
        IDS.put(10821, "Meizu Technology Co., Ltd.");
        IDS.put(10822, "Hubei Yingtong Telecommunication Cable Inc.");
        IDS.put(10829, "Wilder Technologies");
        IDS.put(10837, "Diodes Inc.");
        IDS.put(10846, "DuPont");
        IDS.put(1085, "Lexmark International Inc.");
        IDS.put(10852, "Zhejiang Songcheng Electronics Co., Ltd.");
        IDS.put(10859, "VSN Mobil");
        IDS.put(10875, "Bellwether Electronic Corp.");
        IDS.put(10878, "VAIO Corporation");
        IDS.put(10879, "Perixx Computer GmbH");
        IDS.put(10885, "HANK ELECTRONICS CO., LTD");
        IDS.put(10892, "Sonnet Technologies, Inc.");
        IDS.put(10893, "Keysight Technologies Inc.");
        IDS.put(10895, "Manutronics Vietnam Joint Stock Company");
        IDS.put(10900, "G2 Touch Co., Ltd.");
        IDS.put(10902, "Micromax Informatics Ltd");
        IDS.put(10910, "SEIKO SOLUTIONS Inc.");
        IDS.put(10912, "Casco Products Corp.");
        IDS.put(10922, "Virtium Technology, Inc.");
        IDS.put(10923, "Field and Company LLC, dba Leef USA");
        IDS.put(10928, "GM Global Technology Operations LLC");
        IDS.put(10931, "Key Asic Inc.");
        IDS.put(10943, "Revolabs, Inc.");
        IDS.put(10945, "Lattice Semiconductor Corp");
        IDS.put(10947, "Foshan Nanhai Saga Audio Equipment Co., Ltd.");
        IDS.put(10957, "Silergy Corp.");
        IDS.put(10963, "Shenzhen Hali-Power Industrial Co., Ltd.");
        IDS.put(10971, "I-PEX (Dai-ichi Seiko)");
        IDS.put(10973, "SEE-PLUS INDUSTRIAL LTD.");
        IDS.put(10990, "Adapt-IP Company");
        IDS.put(10997, "Libratone A/S");
        IDS.put(10999, "Shenzhen Hazens Automotive Electronics (SZ) Co., Ltd.");
        IDS.put(11000, "Jiangsu Toppower Automotive Electronics Co., Ltd.");
        IDS.put(11001, "Drapho Electronics Technology Co., Ltd.");
        IDS.put(1102, "Alps Electric Co., Ltd.");
        IDS.put(11022, "Le Shi Zhi Xin Electronic Technology (Tian Jin) Limited");
        IDS.put(11024, "Cardiac Insight, Inc.");
        IDS.put(11028, "EverPro Technologies Company, Ltd.");
        IDS.put(11029, "Rosenberger Hochfrequenztechnik");
        IDS.put(11035, "Dongguan City Sanji Electronics Co., Ltd.");
        IDS.put(11037, "Lintes Technology Co., Ltd.");
        IDS.put(11039, "KinnexA, Inc.");
        IDS.put(11042, "Metra Electronics Corp.");
        IDS.put(11044, "KeepKey, LLC");
        IDS.put(11047, "FluxData Incorporated");
        IDS.put(1105, "Texas Instruments");
        IDS.put(11061, "replacedem Technology Co., Ltd.");
        IDS.put(11062, "Dongguan City Jianghan Electronics Co., Ltd.");
        IDS.put(11063, "Huizhou Desay SV Automotive Co., Ltd.");
        IDS.put(11064, "Ningbo Rixing Electronics Co., Ltd.");
        IDS.put(11069, "GuangDong YuanFeng Automotive Electroics Co., Ltd.");
        IDS.put(11080, "Sounding Audio Industrial Limited");
        IDS.put(11082, "Yueqing Huaxin Electronic Co., Ltd.");
        IDS.put(11098, "Universal Audio, Inc.");
        IDS.put(11111, "Lifesize, Inc.");
        IDS.put(11123, "Pioneer DJ Corporation");
        IDS.put(11124, "Embedded Intelligence, Inc.");
        IDS.put(11125, "New Matter");
        IDS.put(11126, "Shanghai Wingtech Electronic Technology Co., Ltd.");
        IDS.put(11127, "Epiphan Systems Inc.");
        IDS.put(11130, "Spin Master Far East Ltd.");
        IDS.put(11131, "Gigaset Digital Technology (Shenzhen) Co., Ltd.");
        IDS.put(11132, "Noveltek Semiconductor Corp.");
        IDS.put(11139, "Silicon Line GmbH");
        IDS.put(11140, "Ever Win International Corp.");
        IDS.put(11144, "Socionext Inc.");
        IDS.put(11145, "Ugreen Group Limited");
        IDS.put(11146, "Shanghai Pateo Electronic Equipment Mfg. Co., Ltd.");
        IDS.put(1115, "Renesas Electronics Corp.");
        IDS.put(11154, "i-BLADES, Inc.");
        IDS.put(11155, "Altia Systems Inc.");
        IDS.put(11156, "ShenZhen Baoyuanda Electronics Co., Ltd.");
        IDS.put(11157, "iST - Integrated Service Technology Inc.");
        IDS.put(11158, "HYUNDAI MOBIS Co., Ltd.");
        IDS.put(11161, "360fly, Inc.");
        IDS.put(11162, "HUIZHOU CHENG SHUO HARDWARE PLASTIC CO., LTD.");
        IDS.put(11163, "Zhongshan Aute Electronics Technology Co., Ltd.");
        IDS.put(11164, "Guangdong King Link Industrial Co., Ltd.");
        IDS.put(11167, "Scietera Technologies, Inc.");
        IDS.put(11168, "InVue Security Products");
        IDS.put(11169, "I-Sheng Electric Wire & Cable Co., Ltd.");
        IDS.put(11170, "China Daheng Group Inc Beijing Image Vision Tech Branch");
        IDS.put(11171, "Shenzhen FeiTianXia Technology Ltd.");
        IDS.put(11172, "Shenzhen HengJia New Energy Auto Part Co., Ltd.");
        IDS.put(11175, "77 Elektronika Kft.");
        IDS.put(11176, "YUDU EASON ELECTRONIC CO., LTD.");
        IDS.put(1118, "Microsoft Corporation");
        IDS.put(11181, "XIN JI (SHENZHEN) COMPUTER PARTS CO., LTD.");
        IDS.put(11189, "Silk ID Systems");
        IDS.put(11190, "3D Imaging & Simulations Corp. (3DISC)");
        IDS.put(11191, "Dongguan ChengXiang Industrial Co., Ltd.");
        IDS.put(11192, "OCC (Zhuhai) Electronic Co., Ltd.");
        IDS.put(11194, "Sinseader Electronic Co., Ltd.");
        IDS.put(11195, "DONGGUAN YELLOWKNIFE Industrial Co., Ltd.");
        IDS.put(11197, "RF Creations Ltd.");
        IDS.put(11198, "Chengyi Semiconductors (Shanghai) Co., Ltd.");
        IDS.put(11199, "Shenzhen Shinning Electronic Co., Ltd.");
        IDS.put(11200, "Shenzhen WFD Electronics Co., Ltd.");
        IDS.put(11201, "Dongguan Sino Syncs Industrial Co., Ltd.");
        IDS.put(11202, "JNTC Co., Ltd.");
        IDS.put(11208, "DONGGUAN POLIXIN ELECTRIC CO., LTD.");
        IDS.put(11209, "Tama Electric (Suzhou) Co., Ltd.");
        IDS.put(1121, "Primax Electronics");
        IDS.put(11210, "Exvision, Inc.");
        IDS.put(11216, "mophie, LLC");
        IDS.put(11219, "Dongguan ULT-unite electronic technology co., LTD");
        IDS.put(11220, "JL Audio, Inc.");
        IDS.put(11221, "Cable Matters Inc.");
        IDS.put(11222, "CoroWare, Inc.");
        IDS.put(11229, "Charm Sciences Inc.");
        IDS.put(1123, "EATON");
        IDS.put(11230, "Pickering Interfaces Limited");
        IDS.put(11231, "Hangzhou Hikvision Digital Technology Co., Ltd.");
        IDS.put(11232, "FULLINK ELECTRONICS TECHNOLOGY (SZ) LTD");
        IDS.put(11233, "AutoChips Inc.");
        IDS.put(11234, "Electric Connector Technology Co., Ltd.");
        IDS.put(11237, "LELTEK");
        IDS.put(11238, "Dongguan KaiWin Electronics Co., Ltd.");
        IDS.put(11239, "BEFS Co., Ltd.");
        IDS.put(11240, "Archisite, Inc.");
        IDS.put(11241, "Magneti Marelli S.p.A Electr BL");
        IDS.put(11246, "Ventev Mobile");
        IDS.put(11247, "Quanta Storage Inc.");
        IDS.put(11248, "Tech-Top Technology Limited");
        IDS.put(11253, "Shenzhen YOOBAO Technology Co., Ltd.");
        IDS.put(11254, "Shenzhen Sinotek Technology Co., Ltd.");
        IDS.put(11255, "KEYW");
        IDS.put(11256, "Visual Land Inc.");
        IDS.put(11264, "MEEM SL Ltd");
        IDS.put(11265, "Dongguan Arin Electronics Technology Co., Ltd.");
        IDS.put(11266, "DongGuan City JianNuo Electronics Co., Ltd.");
        IDS.put(11268, "Shenzhen XOX Electronics Co., Ltd.");
        IDS.put(11269, "Protop International Inc.");
        IDS.put(11270, "Microsemi Semiconductor (US) Inc.");
        IDS.put(11271, "Webcloak LLC");
        IDS.put(11272, "INVECAS INC.");
        IDS.put(11274, "ATANS Technology Inc.");
        IDS.put(11275, "Triple Win Precision Technology Co., Ltd.");
        IDS.put(11276, "IC Realtech");
        IDS.put(11277, "Embrava Pty Ltd");
        IDS.put(1128, "Wieson Technologies Co., Ltd.");
        IDS.put(11280, "Sinotronics Co., Ltd.");
        IDS.put(11281, "ALLBEST ELECTRONICS TECHNOLOGY CO., LTD.");
        IDS.put(11282, "Shenzhen Xin Kai Feng Electronics Factory");
        IDS.put(11283, "MOST WELL Technology Corp.");
        IDS.put(11284, "Buffalo Memory Co., Ltd.");
        IDS.put(11285, "Xentris Wireless");
        IDS.put(11286, "Priferential Accessories Ltd");
        IDS.put(11289, "Sunlike Technology Co., Ltd.");
        IDS.put(11290, "Young Fast Optoelectronics Co., Ltd.");
        IDS.put(11291, "ISAW Camera Inc");
        IDS.put(11298, "Qanba USA, LLC");
        IDS.put(11299, "Super Micro Computer Inc.");
        IDS.put(11302, "Micromax International Corporation");
        IDS.put(11304, "Granite River Labs replacedan Ltd.");
        IDS.put(11305, "Coagent Enterprise Limited");
        IDS.put(11306, "LEIA Inc.");
        IDS.put(11309, "Shenzhen Ebull Technology Limited");
        IDS.put(1131, "American Megatrends");
        IDS.put(11310, "Hualun Technology Co., Ltd.");
        IDS.put(11311, "Sensel, Inc.");
        IDS.put(11319, "Shenzhen Adition Audio Science & Technology Co., Ltd.");
        IDS.put(11320, "Goldenconn Electronics Technology (Suzhou) Co., Ltd.");
        IDS.put(11321, "JIB Electronics Technology Co., Ltd.");
        IDS.put(11322, "Changzhou Shinco Automotive Electronics Co., Ltd.");
        IDS.put(11323, "Shenzhen Hangsheng Electronics Corp., Ltd.");
        IDS.put(11324, "Beartooth Radio, Inc.");
        IDS.put(11325, "Audience, A Knowles Company");
        IDS.put(11327, "Nextbit Systems, Inc.");
        IDS.put(11328, "Leadtrend");
        IDS.put(11329, "Adaptertek Technology Co., Ltd.");
        IDS.put(1133, "Logitech Inc.");
        IDS.put(11330, "Feature Integration Technology Inc.");
        IDS.put(11331, "Avegant Corporation");
        IDS.put(11335, "Chunghsin International Electronics Co., Ltd.");
        IDS.put(11336, "Delphi Electrical Centers (Shanghai) Co., Ltd.");
        IDS.put(11341, "VVETEK DOO");
        IDS.put(11347, "Huizhou Foryou General Electronics Co., Ltd.");
        IDS.put(11348, "LifeWatch Technologies Ltd.");
        IDS.put(11349, "Magicleap");
        IDS.put(11355, "Dongguan City Shenglan Electronics Co., LTD.");
        IDS.put(11356, "Neusoft Corporation");
        IDS.put(11357, "SIP Simya Electronics Technology Co., Ltd.");
        IDS.put(11358, "GNSD Automotive Co., Ltd.");
        IDS.put(11359, "YOODS Co., Ltd.");
        IDS.put(11360, "Sirin Mobile Technologies AG");
        IDS.put(11361, "Jadmam Corporation dba: Boytone");
        IDS.put(11373, "Gibson Innovations");
        IDS.put(11374, "Shen Zhen Xian Shuo Technology Co. LTD");
        IDS.put(11375, "PST Eletronica LTDA");
        IDS.put(11376, "PERI, Inc.");
        IDS.put(11377, "Bozhou BoTong Information Technology Co., Ltd.");
        IDS.put(11383, "Profindustry GmbH");
        IDS.put(11384, "BRAGI GmbH");
        IDS.put(11385, "WAWGD, Inc. (DBA: Foresight Sports)");
        IDS.put(11390, "Dongguan Allpreplaced Electronic Co., Ltd.");
        IDS.put(11391, "SHENZHEN D-VITEC INDUSTRIAL CO., LTD.");
        IDS.put(11392, "motomobile AG");
        IDS.put(11393, "Indie Semiconductor");
        IDS.put(11397, "Audientes");
        IDS.put(11403, "Huizhou Dehong Technology Co., Ltd.");
        IDS.put(11404, "PowerCenter Technology Limited");
        IDS.put(11405, "Mizco International, Inc.");
        IDS.put(11408, "I. AM. PLUS, LLC");
        IDS.put(11409, "Corigine, Inc.");
        IDS.put(11410, "Ningbo Yinzhou Shengke Electronics Co., Ltd.");
        IDS.put(11417, "Prusa Research s.r.o.");
        IDS.put(11423, "e-Smart Systems Pvt. Ltd.");
        IDS.put(11424, "Leagtech Jiangxi Electronic Co., Ltd.");
        IDS.put(11425, "Dongguan Yujia Electronics Technology Co., Ltd.");
        IDS.put(11426, "GuangZhou MingPing Electronics Technology");
        IDS.put(11427, "DJI Technology Co., Ltd.");
        IDS.put(11428, "Shenzhen Alex Technology Co., Ltd.");
        IDS.put(11433, "JITS TECHNOLOGY CO., LIMITED");
        IDS.put(11434, "LIVV Brand llc");
        IDS.put(11444, "Ava Enterprises, Inc. dba: Boss Audio Systems");
        IDS.put(11448, "Shenzhen Sydixon Electronic Technology Co., Ltd.");
        IDS.put(11449, "On-Bright Electronics (Shanghai) Co., Ltd.");
        IDS.put(11450, "Dongguan Puxu Industrial Co., Ltd.");
        IDS.put(11451, "Shenzhen Soling Indusrtial Co., Ltd.");
        IDS.put(11453, "EGGCYTE, INC.");
        IDS.put(11455, "Donggguan Yuhua Electronic Co., Ltd.");
        IDS.put(11456, "Hangzhou Zero Zero Technology Co., Ltd.");
        IDS.put(11462, "Prodigy Technovations Pvt Ltd");
        IDS.put(11463, "EmergiTech, Inc");
        IDS.put(11464, "Hewlett Packard Enterprise");
        IDS.put(11465, "Monolithic Power Systems Inc.");
        IDS.put(11467, "USB Memory Direct");
        IDS.put(11468, "Silicon Mitus Inc.");
        IDS.put(11472, "Technics Global Electronics & JCE Co., Ltd.");
        IDS.put(11478, "Immersive Media");
        IDS.put(11479, "Cosemi Technologies Inc.");
        IDS.put(11481, "Cambrionix Ltd");
        IDS.put(11482, "CXUN Co. Ltd.");
        IDS.put(11483, "China Tsp Inc");
        IDS.put(11490, "Yanfeng Visteon (Chongqing) Automotive Electronics Co");
        IDS.put(11491, "Alcorlink Corp.");
        IDS.put(11492, "ISBC Ltd.");
        IDS.put(11493, "InX8 Inc dba: AKiTiO");
        IDS.put(11494, "SDAN Tecchnology Co., Ltd.");
        IDS.put(11495, "Lemobile Information Technology (Beijing) Co., Ltd.");
        IDS.put(11496, "GongGuan HWX Electronic Technology Co., Ltd.");
        IDS.put(11497, "Suzhu Jingshi Electronic Technology Co., Ltd.");
        IDS.put(11498, "Zhong Shan City Richsound Electronic Industrial Ltd.");
        IDS.put(11499, "Dongguang Kangbang Electronics Co., Ltd.");
        IDS.put(1151, "Plantronics, Inc.");
        IDS.put(1154, "Kyocera Corporation");
        IDS.put(1155, "STMicroelectronics");
        IDS.put(1161, "Foxconn / Hon Hai");
        IDS.put(1165, "ITE Tech Inc.");
        IDS.put(1177, "Yamaha Corporation");
        IDS.put(1188, "Hitachi, Ltd.");
        IDS.put(1191, "Visioneer");
        IDS.put(1193, "Canon Inc.");
        IDS.put(1200, "Nikon Corporation");
        IDS.put(1201, "Pan International");
        IDS.put(1204, "Cypress Semiconductor");
        IDS.put(1205, "ROHM Co., Ltd.");
        IDS.put(1207, "Compal Electronics, Inc.");
        IDS.put(1208, "Seiko Epson Corp.");
        IDS.put(1211, "I-O Data Device, Inc.");
        IDS.put(1221, "Fujitsu Ltd.");
        IDS.put(1227, "FUJIFILM Corporation");
        IDS.put(1238, "Mentor Graphics");
        IDS.put(1240, "Microchip Technology Inc.");
        IDS.put(1241, "Holtek Semiconductor, Inc.");
        IDS.put(1242, "Panasonic Corporation");
        IDS.put(1245, "Sharp Corporation");
        IDS.put(1250, "Exar Corporation");
        IDS.put(1254, "Identiv, Inc.");
        IDS.put(1256, "Samsung Electronics Co., Ltd.");
        IDS.put(1260, "Tokyo Electron Device Limited");
        IDS.put(1266, "Chicony Electronics Co., Ltd.");
        IDS.put(1271, "Newnex Technology Corp.");
        IDS.put(1273, "Brother Industries, Ltd.");
        IDS.put(1276, "SUNPLUS TECHNOLOGY CO., LTD.");
        IDS.put(1278, "PFU Limited");
        IDS.put(1281, "Fujikura/DDK");
        IDS.put(1282, "Acer, Inc.");
        IDS.put(1287, "Hosiden Corporation");
        IDS.put(1293, "Belkin International, Inc.");
        IDS.put(1300, "FCI Electronics");
        IDS.put(1302, "Longwell Electronics/Longwell Company");
        IDS.put(1305, "Star Micronics Co., LTD");
        IDS.put(1309, "American Power Conversion");
        IDS.put(1314, "ACON, Advanced-Connectek, Inc.");
        IDS.put(1343, "Synopsys, Inc.");
        IDS.put(1356, "Sony Corporation");
        IDS.put(1360, "Fuji Xerox Co., Ltd.");
        IDS.put(1367, "ATEN International Co. Ltd.");
        IDS.put(1369, "Cadence Design Systems, Inc.");
        IDS.put(1386, "WACOM Co., Ltd.");
        IDS.put(1389, "EIZO Corporation");
        IDS.put(1390, "Elecom Co., Ltd.");
        IDS.put(1394, "Conexant Systems, Inc.");
        IDS.put(1398, "BAFO/Quality Computer Accessories");
        IDS.put(1403, "Y-E Data, Inc.");
        IDS.put(1404, "AVM GmbH");
        IDS.put(1410, "Roland Corporation");
        IDS.put(1412, "RATOC Systems, Inc.");
        IDS.put(1419, "Infineon Technologies");
        IDS.put(1423, "Alcor Micro, Corp.");
        IDS.put(1424, "OMRON Corporation");
        IDS.put(1447, "Bose Corporation");
        IDS.put(1449, "OmniVision Technologies, Inc.");
        IDS.put(1452, "Apple");
        IDS.put(1453, "Y.C. Cable U.S.A., Inc");
        IDS.put(14627, "National Instruments");
        IDS.put(1470, "Tyco Electronics Corp., a TE Connectivity Ltd. company");
        IDS.put(1473, "MegaChips Corporation");
        IDS.put(1478, "Qualcomm, Inc");
        IDS.put(1480, "Foxlink/Cheng Uei Precision Industry Co., Ltd.");
        IDS.put(1482, "Ricoh Company Ltd.");
        IDS.put(1498, "Microtek International Inc.");
        IDS.put(1504, "Symbol Technologies");
        IDS.put(1507, "Genesys Logic, Inc.");
        IDS.put(1509, "Fuji Electric Co., Ltd.");
        IDS.put(1525, "Unixtar Technology Inc.");
        IDS.put(1529, "Datalogic ADC");
        IDS.put(1535, "LeCroy Corporation");
        IDS.put(1539, "Novatek Microelectronics Corp.");
        IDS.put(1545, "SMK Manufacturing Inc.");
        IDS.put(1551, "Joinsoon Electronics Mfg. Co., Ltd.");
        IDS.put(1555, "TransAct Technologies Incorporated");
        IDS.put(1561, "Seiko Instruments Inc.");
        IDS.put(1582, "JPC/MAIN SUPER Inc.");
        IDS.put(1583, "Sin Sheng Terminal & Machine Inc.");
        IDS.put(1593, "Chrontel, Inc.");
        IDS.put(1611, "replacedog Devices, Inc. Development Tools");
        IDS.put(1612, "Ji-Haw Industrial Co., Ltd");
        IDS.put(1614, "Suyin Corporation");
        IDS.put(1621, "Space Shuttle Hi-Tech Co.,Ltd.");
        IDS.put(1622, "Glory Mark Electronic Ltd.");
        IDS.put(1623, "Tekcon Electronics Corp.");
        IDS.put(1624, "Sigma Designs, Inc.");
        IDS.put(1631, "Good Way Technology Co., Ltd. & GWC technology Inc");
        IDS.put(1632, "TSAY-E (BVI) International Inc.");
        IDS.put(1633, "Hamamatsu Photonics K.K.");
        IDS.put(1642, "Total Technologies, Ltd.");
        IDS.put(1659, "Prolific Technology, Inc.");
        IDS.put(16700, "Dell Inc.");
        IDS.put(1680, "Golden Bridge Electech Inc.");
        IDS.put(1689, "Tektronix, Inc.");
        IDS.put(1690, "Askey Computer Corporation");
        IDS.put(1709, "Greatland Electronics Taiwan Ltd.");
        IDS.put(1710, "Eurofins Digital Testing Belgium");
        IDS.put(1720, "Pixela Corporation");
        IDS.put(1724, "Oki Data Corporation");
        IDS.put(1727, "Leoco Corporation");
        IDS.put(1732, "Bizlink Technology, Inc.");
        IDS.put(1736, "SIIG, Inc.");
        IDS.put(1747, "Mitsubishi Electric Corporation");
        IDS.put(1758, "Heisei Technology Co., Ltd.");
        IDS.put(1802, "Oki Electric Industry Co., Ltd.");
        IDS.put(1805, "Comoss Electronic Co., Ltd.");
        IDS.put(1809, "Magic Control Technology Corp.");
        IDS.put(1816, "Imation Corp.");
        IDS.put(1838, "Sunix Co., Ltd.");
        IDS.put(1846, "Lorom Industrial Co., Ltd.");
        IDS.put(1848, "Mad Catz, Inc.");
        IDS.put(1899, "HID Global GmbH");
        IDS.put(1901, "Denso Corporation");
        IDS.put(1913, "Fairchild Semiconductor");
        IDS.put(1921, "SanDisk Corporation");
        IDS.put(1937, "Copartner Technology Corporation");
        IDS.put(1954, "National Technical Systems");
        IDS.put(1971, "Plustek, Inc.");
        IDS.put(1972, "OLYMPUS CORPORATION");
        IDS.put(1975, "TIME Interconnect Ltd.");
        IDS.put(1994, "AVerMedia Technologies, Inc.");
        IDS.put(1999, "Casio Computer Co., Ltd.");
        IDS.put(2015, "David Electronics Company, Ltd.");
        IDS.put(2039, "Century Corporation");
        IDS.put(2058, "Evermuch Technology Co., Ltd.");
        IDS.put(2101, "Action Star Enterprise Co., Ltd.");
        IDS.put(2112, "Argosy Research Inc.");
        IDS.put(2122, "Wipro Limited");
        IDS.put(2159, "MEC IMEX INC/HPT");
        IDS.put(2205, "Icron Technologies Corporation");
        IDS.put(2247, "TAI TWUN ENTERPRISE CO., LTD.");
        IDS.put(2276, "Pioneer Corporation");
        IDS.put(2278, "Gemalto SA");
        IDS.put(2310, "FARADAY Technology Corp.");
        IDS.put(2313, "Audio-Technica Corp.");
        IDS.put(2316, "Silicon Motion, Inc. - Taiwan");
        IDS.put(2334, "Garmin International");
        IDS.put(2352, "Toshiba Corporation");
        IDS.put(2362, "Pixart Imaging, Inc.");
        IDS.put(2363, "Plextor LLC");
        IDS.put(2366, "J.S.T. Mfg. Co., Ltd.");
        IDS.put(2385, "Kingston Technology Company");
        IDS.put(2389, "NVIDIA");
        IDS.put(2395, "Medialogic Corporation");
        IDS.put(2397, "Polycom, Inc.");
        IDS.put(2468, "Contech Research, Inc.");
        IDS.put(2472, "Lin Shiung Enterprise Co., Ltd.");
        IDS.put(2475, "replacedan Cash Machine Co., Ltd.");
        IDS.put(2498, "NISCA Corporation");
        IDS.put(2511, "Electronics Testing Center, Taiwan");
        IDS.put(2522, "A-FOUR TECH CO., LTD.");
        IDS.put(2555, "Altera");
        IDS.put(2578, "Cambridge Silicon Radio Ltd.");
        IDS.put(2583, "HOYA Corporation");
        IDS.put(2631, "Hirose Electric Co., Ltd.");
        IDS.put(2636, "COMPUTEX Co., Ltd.");
        IDS.put(2640, "Mimaki Engineering Co., Ltd.");
        IDS.put(2652, "Broadcom Corp.");
        IDS.put(2667, "Green House Co., Ltd.");
        IDS.put(2702, "replacedan Aviation Electronics Industry Ltd. (JAE)");
        IDS.put(2727, "Wincor Nixdorf GmbH & Co KG");
        IDS.put(2733, "Rohde & Schwarz GmbH & Co. KG");
        IDS.put(2787, "Allion Labs, Inc.");
        IDS.put(2821, "ASUSTek Computer Inc.");
        IDS.put(2849, "Yokogawa Electric Corporation");
        IDS.put(2851, "Pan-Asia Electronics Co., Ltd.");
        IDS.put(2894, "Musical Electronics Ltd.");
        IDS.put(2907, "Anritsu Corporation");
        IDS.put(2922, "Maxim Integrated Products");
        IDS.put(2965, "ASIX Electronics Corporation");
        IDS.put(2967, "O2Micro, Inc.");
        IDS.put(3010, "Seagate Technology LLC");
        IDS.put(3034, "Realtek Semiconductor Corp.");
        IDS.put(3035, "Ericsson AB");
        IDS.put(3044, "Elka International Ltd.");
        IDS.put(3056, "Pace Micro Technology PLC");
        IDS.put(3108, "Taiyo Yuden Co., Ltd.");
        IDS.put(3129, "Aeroflex");
        IDS.put(3132, "Radius Co., Ltd.");
        IDS.put(3141, "Sonix Technology Co., Ltd.");
        IDS.put(3158, "Billion Bright (HK) Corporation Limited");
        IDS.put(3161, "Dong Guan Shinko Wire Co., Ltd.");
        IDS.put(3170, "Chant Sincere Co., Ltd");
        IDS.put(3190, "Solid State System Co., Ltd.");
        IDS.put(3209, "Honda Tsushin Kogyo Co., Ltd");
        IDS.put(3245, "Motorola Solutions");
        IDS.put(3255, "Singatron Enterprise Co. Ltd.");
        IDS.put(3268, "emsys Embedded Systems GmbH");
        IDS.put(32902, "Intel Corporation");
        IDS.put(3294, "Z-Com INC.");
        IDS.put(3313, "e-CONN ELECTRONIC CO., LTD.");
        IDS.put(3314, "ENE Technology Inc.");
        IDS.put(3351, "NALTEC, Inc.");
        IDS.put(3402, "NF Corporation");
        IDS.put(3403, "Grape Systems Inc.");
        IDS.put(3409, "Volex (Asia) Pte Ltd");
        IDS.put(3425, "MEILU ELECTRONICS (SHENZHEN) CO., LTD.");
        IDS.put(3441, "Hirakawa Hewtech Corp.");
        IDS.put(3452, "Taiwan Line Tek Electronic Co., Ltd.");
        IDS.put(3463, "Dolby Laboratories Inc.");
        IDS.put(3468, "C-MEDIA ELECTRONICS INC.");
        IDS.put(3472, "Sure-Fire Electrical Corporation");
        IDS.put(3495, "IOGEAR, Inc.");
        IDS.put(3504, "Micro-Star International Co., Ltd.");
        IDS.put(3537, "Contek Electronics Co., Ltd.");
        IDS.put(3540, "Custom Engineering SPA");
        IDS.put(3641, "Smart Modular Technologies, Inc.");
        IDS.put(3658, "Shenzhen Bao Hing Electric Wire & Cable Mfr. Co.");
        IDS.put(3673, "Bourns, Inc.");
        IDS.put(3690, "Megawin Technology Co., Ltd.");
        IDS.put(3698, "Hsi-Chin Electronics Co., Ltd.");
        IDS.put(3714, "Ching Tai Electric Wire & Cable Co., Ltd.");
        IDS.put(3724, "Well Force Electronic Co., Ltd");
        IDS.put(3725, "MediaTek Inc.");
        IDS.put(3728, "CRU");
        IDS.put(3744, "Ours Technology Inc.");
        IDS.put(3762, "Y-S ELECTRONIC CO., LTD.");
        IDS.put(3778, "Sweetray Industrial Ltd.");
        IDS.put(3779, "Axell Corporation");
        IDS.put(3782, "InnoVISION Multimedia Limited");
        IDS.put(3790, "TaiSol Electronics Co., Ltd.");
        IDS.put(3812, "Sunrich Technology (H.K.) Ltd.");
        IDS.put(3868, "Funai Electric Co., Ltd.");
        IDS.put(3873, "IOI Technology Corporation");
        IDS.put(3890, "YFC-BonEagle Electric Co., Ltd.");
        IDS.put(3896, "Nien-Yi Industrial Corp.");
        IDS.put(3916, "WORLDWIDE CABLE OPTO CORP.");
        IDS.put(3923, "Taiyo Cable (Dongguan) Co. Ltd.");
        IDS.put(3924, "Kawai Musical Instruments Mfg. Co., Ltd.");
        IDS.put(3936, "GuangZhou Chief Tech Electronic Technology Co. Ltd.");
        IDS.put(3944, "UQUEST, LTD.");
        IDS.put(3991, "CviLux Corporation");
        IDS.put(4003, "Chief Land Electronic Co., Ltd.");
        IDS.put(4046, "Sony Mobile Communications");
        IDS.put(4087, "CHI SHING COMPUTER ACCESSORIES CO., LTD.");
        IDS.put(4096, "Speed Tech Corp.");
        IDS.put(4100, "LG Electronics Inc.");
        IDS.put(4101, "Apacer Technology Inc.");
        IDS.put(4134, "Newly Corporation");
        IDS.put(4168, "Targus Group International");
        IDS.put(4172, "AMCO TEC International Inc.");
        IDS.put(4183, "ON Semiconductor");
        IDS.put(4184, "Western Digital Technologies, Inc.");
        IDS.put(4227, "CANON ELECTRONICS INC.");
        IDS.put(4235, "Grand-tek Technology Co., Ltd.");
        IDS.put(4236, "Robert Bosch GmbH");
        IDS.put(4238, "Lotes Co., Ltd.");
        IDS.put(4266, "Cables To Go");
        IDS.put(4267, "Universal Global Scientific Industrial Co., Ltd.");
        IDS.put(4292, "Silicon Laboratories, Inc.");
        IDS.put(4301, "Kycon Inc.");
        IDS.put(4362, "Moxa Inc.");
        IDS.put(4370, "Golden Bright (Sichuan) Electronic Technology Co Ltd");
        IDS.put(4382, "VSO ELECTRONICS CO., LTD.");
        IDS.put(4398, "Master Hill Electric Wire and Cable Co., Ltd.");
        IDS.put(4477, "Santa Electronic Inc.");
        IDS.put(4505, "Sierra Wireless Inc.");
        IDS.put(4522, "GlobalMedia Group, LLC");
        IDS.put(4528, "ATECH FLASH TECHNOLOGY");
        IDS.put(4643, "SKYCABLE ENTERPRISE CO., LTD.");
        IDS.put(4703, "ADATA Technology Co., Ltd.");
        IDS.put(4716, "Aristocrat Technologies");
        IDS.put(4717, "Bel Stewart");
        IDS.put(4742, "MARVELL SEMICONDUCTOR, INC.");
        IDS.put(4756, "RISO KAGAKU CORP.");
        IDS.put(4792, "Zhejiang Xinya Electronic Technology Co., Ltd.");
        IDS.put(4817, "Huawei Technologies Co., Ltd.");
        IDS.put(4823, "Better Holdings (HK) Limited");
        IDS.put(4907, "Konica Minolta, Inc.");
        IDS.put(4925, "Jasco Products Company");
        IDS.put(4989, "Pericom Semiconductor Corp.");
        IDS.put(5008, "TomTom International B.V.");
        IDS.put(5075, "AzureWave Technologies, Inc.");
        IDS.put(5117, "Initio Corporation");
        IDS.put(5118, "Phison Electronics Corp.");
        IDS.put(5134, "Telechips, Inc.");
        IDS.put(5145, "ABILITY ENTERPRISE CO., LTD.");
        IDS.put(5148, "Leviton Manufacturing");
        IDS.put(5271, "Panstrong Company Ltd.");
        IDS.put(5293, "CTK Corporation");
        IDS.put(5296, "StarTech.com Ltd.");
        IDS.put(5376, "Ellisys");
        IDS.put(5404, "VeriSilicon Holdings Co., Ltd.");
        IDS.put(5421, "JMicron Technology Corp.");
        IDS.put(5422, "HLDS (Hitachi-LG Data Storage, Inc.)");
        IDS.put(5440, "Phihong Technology Co., Ltd.");
        IDS.put(5451, "PNY Technologies Inc.");
        IDS.put(5453, "Rapid Conn, Connect County Holdings Bhd");
        IDS.put(5454, "D & M Holdings, Inc.");
        IDS.put(5480, "Sunf Pu Technology Co., Ltd");
        IDS.put(5488, "ALLTOP TECHNOLOGY CO., LTD.");
        IDS.put(5510, "Palconn Technology Co., Ltd.");
        IDS.put(5528, "Kunshan Guoji Electronics Co., Ltd.");
        IDS.put(5546, "DongGuan Ya Lian Electronics Co., Ltd.");
        IDS.put(5645, "Samtec");
        IDS.put(5694, "HongLin Electronics Co., Ltd.");
        IDS.put(5753, "Total Phase");
        IDS.put(5766, "ZOOM Corporation");
        IDS.put(5836, "silex technology, Inc.");
        IDS.put(5946, "F. Hoffmann-La Roche AG");
        IDS.put(5960, "MQP Electronics Ltd.");
        IDS.put(5964, "ASMedia Technology Inc.");
        IDS.put(5998, "UD electronic corp.");
        IDS.put(6001, "Shenzhen Alex Connector Co., Ltd.");
        IDS.put(6002, "System Level Solutions, Inc.");
        IDS.put(6018, "Spreadtrum Hong Kong Limited");
        IDS.put(6024, "ShenZhen Litkconn Technology Co., Ltd.");
        IDS.put(6053, "Advanced Connection Technology Inc.");
        IDS.put(6095, "Hip Hing Cable & Plug Mfy. Ltd.");
        IDS.put(6121, "DisplayLink (UK) Ltd.");
        IDS.put(6127, "Lenovo");
        IDS.put(6133, "K.K. Rocky");
        IDS.put(6160, "Wanshih Electronic Co., Ltd.");
        IDS.put(6185, "Dongguan YuQiu Electronics Co., Ltd.");
        IDS.put(6193, "Gwo Jinn Industries Co., Ltd.");
        IDS.put(6297, "Linkiss Co., Ltd.");
        IDS.put(6353, "Google Inc.");
        IDS.put(6394, "Kuang Ying Computer Equipment Co., Ltd.");
        IDS.put(6421, "Nordic Semiconductor ASA");
        IDS.put(6448, "Shenzhen Xianhe Technology Co., Ltd.");
        IDS.put(6449, "Ningbo Broad Telecommunication Co., Ltd.");
        IDS.put(6470, "Irisguard UK Ltd");
        IDS.put(6473, "Lab126");
        IDS.put(6481, "Hyperstone GmbH");
        IDS.put(6487, "BIOS Corporation");
        IDS.put(6626, "Solomon Systech Limited");
        IDS.put(6639, "Pak Heng Technology (Shenzhen) Co., Ltd.");
        IDS.put(6655, "Best Buy China Ltd.");
        IDS.put(6666, "USB-IF non-workshop");
        IDS.put(6709, "Artesyn Technologies Inc.");
        IDS.put(6720, "TERMINUS TECHNOLOGY INC.");
        IDS.put(6766, "Global Unichip Corp.");
        IDS.put(6786, "Proconn Technology Co., Ltd.");
        IDS.put(6794, "Simula Technology Inc.");
        IDS.put(6795, "SGS Taiwan Ltd.");
        IDS.put(6830, "Johnson Component & Equipments Co., Ltd.");
        IDS.put(6834, "Allied Vision Technologies GmbH");
        IDS.put(6859, "Salcomp Plc");
        IDS.put(6865, "Desan Wire Co., Ltd.");
        IDS.put(6944, "MStar Semiconductor, Inc.");
        IDS.put(6984, "Plastron Precision Co., Ltd.");
        IDS.put(7013, "The Hong Kong Standards and Testing Centre Ltd.");
        IDS.put(7048, "ShenMing Electron (Dong Guan) Co., Ltd.");
        IDS.put(7086, "Vuzix Corporation");
        IDS.put(7108, "Ford Motor Co.");
        IDS.put(7118, "Contac Cable Industrial Limited");
        IDS.put(7119, "Sunplus Innovation Technology Inc.");
        IDS.put(7120, "Hangzhou Riyue Electronics Co., Ltd.");
        IDS.put(7158, "Orient Semiconductor Electronics, Ltd.");
        IDS.put(7207, "SHENZHEN DNS INDUSTRIES CO., LTD.");
        IDS.put(7217, "LS Mtron Ltd.");
        IDS.put(7229, "NONIN MEDICAL INC.");
        IDS.put(7275, "Philips & Lite-ON Digital Solutions Corporation");
        IDS.put(7310, "ASTRON INTERNATIONAL CORP.");
        IDS.put(7320, "ALPINE ELECTRONICS, INC.");
        IDS.put(7347, "Aces Electronics Co., Ltd.");
        IDS.put(7348, "OPEX CORPORATION");
        IDS.put(7390, "Telecommunications Technology replacedociation (TTA)");
        IDS.put(7434, "Visteon Corporation");
        IDS.put(7465, "Horng Tong Enterprise Co., Ltd.");
        IDS.put(7501, "Pegatron Corporation");
        IDS.put(7516, "Fresco Logic Inc.");
        IDS.put(7529, "Walta Electronic Co., Ltd.");
        IDS.put(7543, "Yueqing Changling Electronic Instrument Corp., Ltd.");
        IDS.put(7584, "Parade Technologies, Inc.");
        IDS.put(7647, "L&T Technology Services");
        IDS.put(7649, "Actions Microelectronics Co., Ltd.");
        IDS.put(7666, "China Telecommunication Technology Labs - Terminals");
        IDS.put(7668, "SHEN ZHEN FORMAN PRECISION INDUSTRY CO., LTD.");
        IDS.put(7682, "GLOBEMASTER TECHNOLOGIES CO., LTD.");
        IDS.put(7696, "Point Grey Research Inc.");
        IDS.put(7751, "HUNG TA H.T.ENTERPRISE CO., LTD.");
        IDS.put(7758, "Etron Technology, Inc.");
        IDS.put(7795, "COMLINK ELECTRONICS CO., LTD.");
        IDS.put(7818, "HIBEST Electronic (DongGuan) Co., Ltd.");
        IDS.put(7825, "Other World Computing");
        IDS.put(7863, "WIN WIN PRECISION INDUSTRIAL CO., LTD.");
        IDS.put(7879, "Gefen Inc.");
        IDS.put(7881, "MOSER BAER INDIA LIMITED");
        IDS.put(7898, "AIRTIES WIRELESS NETWORKS");
        IDS.put(7956, "Astoria Networks GmbH");
        IDS.put(7969, "Scosche Industries");
        IDS.put(7976, "Cal-Comp Electronics & Communications");
        IDS.put(7977, "replacedogix Semiconductor, Inc.");
        IDS.put(7989, "Amphenol ShouhMin Industry (ShenZhen) Co., Ltd");
        IDS.put(7996, "Chang Yang Electronics Company Ltd.");
        IDS.put(8073, "Dongguan Goldconn Electronics Co., Ltd.");
        IDS.put(8074, "Morning Star Industrial Co., Ltd.");
        IDS.put(8117, "Unify Software and Solutions GmbH & Co. KG");
        IDS.put(8137, "NXP Semiconductors");
        IDS.put(8181, "Changzhou Wujin BEST Electronic Cables Co., Ltd.");
        IDS.put(8205, "Belkin Electronic (Changzhou) Co., Ltd.");
        IDS.put(8220, "Freeport Resources Enterprises Corp.");
        IDS.put(8222, "Qingdao Haier Telecom Co., Ltd.");
        IDS.put(8284, "Shenzhen Tronixin Electronics Co., Ltd.");
        IDS.put(8294, "Unicorn Electronics Components Co., Ltd.");
        IDS.put(8334, "Luxshare-ICT");
        IDS.put(8341, "CE LINK LIMITED");
        IDS.put(8342, "Microconn Electronic Co., Ltd.");
        IDS.put(8367, "Shenzhen CARVE Electronics Co., Ltd.");
        IDS.put(8382, "BURY GmbH & Co. KG");
        IDS.put(8384, "FENGHUA KINGSUN CO., LTD.");
        IDS.put(8386, "Sumitomo Electric Ind., Ltd., Optical Comm. R&D Lab");
        IDS.put(8439, "XIMEA s.r.o.");
        IDS.put(8457, "VIA Labs, Inc.");
        IDS.put(8492, "Shenzhen Linoya Electronic Co., Ltd.");
        IDS.put(8494, "Amphenol replacedembleTech (Xiamen) Co., Ltd.");
        IDS.put(8524, "Y Soft Corporation");
        IDS.put(8550, "JVC KENWOOD Corporation");
        IDS.put(8564, "Transcend Information, Inc.");
        IDS.put(8566, "TMC/Allion Test Labs");
        IDS.put(8613, "Genesis Technology USA, Inc.");
        IDS.put(8627, "Dongguan Teconn Electronics Technology Co., Ltd.");
        IDS.put(8644, "Netcom Technology (HK) Limited");
        IDS.put(8659, "Compupack Technology Co., Ltd.");
        IDS.put(8667, "G-Max Technology Co., Ltd.");
        IDS.put(8679, "Sagemcom Broadband SAS");
        IDS.put(8695, "Wuerth-Elektronik eiSos GmbH & Co. KG");
        IDS.put(8707, "Shin Shin Co., Ltd.");
        IDS.put(8709, "3eYamaichi Electronics Co., Ltd.");
        IDS.put(8710, "Wiretek International Investment Ltd.");
        IDS.put(8711, "Fuzhou Rockchip Electronics Co., Ltd.");
        IDS.put(8752, "Plugable Technologies");
        IDS.put(8756, "T-CONN PRECISION CORPORATION");
        IDS.put(8831, "Granite River Labs");
        IDS.put(8842, "Hotron Precision Electronic Ind. Corp.");
        IDS.put(8875, "Trigence Semiconductor, Inc.");
        IDS.put(8888, "Motorola Mobility Inc.");
        IDS.put(8904, "Karming Electronic (Shenzhen) Co., Ltd.");
        IDS.put(8981, "Avery Design Systems, Inc.");
        IDS.put(8993, "iKingdom Corp. (d.b.a. iConnectivity)");
        IDS.put(9051, "KangXiang Electronic Co., Ltd.");
        IDS.put(9068, "ZheJiang Chunsheng Electronics Co., Ltd.");
        IDS.put(9130, "DOK (HK) Trading Limited");
        IDS.put(9132, "Marunix Electron Limited");
        IDS.put(9165, "Avconn Precise Connector Co., Ltd.");
        IDS.put(9184, "BitifEye Digital Test Solutions GmbH");
        IDS.put(9205, "Speed Conn Co., Ltd.");
        IDS.put(9222, "INSIDE Secure");
        IDS.put(9292, "Minebea Co., Ltd.");
        IDS.put(9299, "BAANTO");
        IDS.put(9338, "Suzhou Jutze Technologies Co., Ltd");
        IDS.put(9355, "DONGGUAN SYNCONN PRECISION INDUSTRY CO. LTD.");
        IDS.put(9382, "Shenzhen Pangngai Industrial Co., Ltd.");
        IDS.put(9422, "Shenzhen Deren Electronic Co., Ltd.");
        IDS.put(9424, "Smith Micro Software, Inc.");
        IDS.put(9453, "ZEN FACTORY GROUP (ASIA) LTD.");
        IDS.put(9481, "Chain-In Electronic Co., Ltd.");
        IDS.put(9514, "SUZHOU KELI TECHNOLOGY DEVELOPMENT CO., LTD.");
        IDS.put(9515, "TOP Exacreplacedude Industry (ShenZhen) Co., Ltd.");
        IDS.put(9525, "ShenZhen Hogend Precision Technology Co., Ltd.");
        IDS.put(9527, "Norel Systems Ltd.");
        IDS.put(9556, "replacedA ABLOY AB");
        IDS.put(9575, "DongGuan LongTao Electronic Co., Ltd.");
        IDS.put(9577, "DongGuan City MingJi Electronics Co., Ltd.");
        IDS.put(9589, "Weida Hi-Tech Co., Ltd.");
        IDS.put(9593, "Dongguan Wisechamp Electronic Co., Ltd.");
        IDS.put(9613, "Sequans Communications");
        IDS.put(9636, "ALGOLTEK, INC.");
        IDS.put(9651, "DongGuan Elinke Industrial Co., Ltd.");
        IDS.put(9679, "Corning Optical Communications LLC");
        IDS.put(9714, "Dongguan Jinyue Electronics Co., Ltd.");
        IDS.put(9723, "RICOH IMAGING COMPANY, LTD.");
        IDS.put(9742, "DongGuan HYX Industrial Co., Ltd.");
        IDS.put(9753, "Advanced Silicon SA");
        IDS.put(9756, "EISST Limited");
        IDS.put(9771, "YTOP Electronics Technical (Kunshan) Co., Ltd.");
        IDS.put(9841, "Innovative Logic");
        IDS.put(9842, "GoPro");
        IDS.put(9846, "Basler AG");
        IDS.put(9851, "Palpilot International Corp.");
        IDS.put(9896, "UNIREX CORPORATION");
        IDS.put(9917, "Integral Memory Plc.");
        IDS.put(9973, "Morning Star Digital Connector Co., Ltd.");
        IDS.put(9984, "MITACHI CO., LTD.");
        IDS.put(9999, "HGST, a Western Digital Company");
    }
}

19 Source : USBMonitor.java
with Apache License 2.0
from z-jc

public final clreplaced USBMonitor {

    // TODO set false on production
    private static final boolean DEBUG = false;

    private static final String TAG = "USBMonitor";

    private static final String ACTION_USB_PERMISSION_BASE = "com.serenegiant.USB_PERMISSION.";

    private final String ACTION_USB_PERMISSION = ACTION_USB_PERMISSION_BASE + hashCode();

    public static final String ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";

    /**
     * openしているUsbControlBlock
     */
    private final ConcurrentHashMap<UsbDevice, UsbControlBlock> mCtrlBlocks = new ConcurrentHashMap<UsbDevice, UsbControlBlock>();

    private final SparseArray<WeakReference<UsbDevice>> mHasPermissions = new SparseArray<WeakReference<UsbDevice>>();

    private final WeakReference<Context> mWeakContext;

    private final UsbManager mUsbManager;

    private final OnDeviceConnectListener mOnDeviceConnectListener;

    private PendingIntent mPermissionIntent = null;

    private List<DeviceFilter> mDeviceFilters = new ArrayList<DeviceFilter>();

    /**
     * コールバックをワーカースレッドで呼び出すためのハンドラー
     */
    private final Handler mAsyncHandler;

    private volatile boolean destroyed;

    /**
     * USB機器の状態変更時のコールバックリスナー
     */
    public interface OnDeviceConnectListener {

        /**
         * called when device attached
         * @param device
         */
        public void onAttach(UsbDevice device);

        /**
         * called when device dettach(after onDisconnect)
         * @param device
         */
        public void onDettach(UsbDevice device);

        /**
         * called after device opend
         * @param device
         * @param ctrlBlock
         * @param createNew
         */
        public void onConnect(UsbDevice device, UsbControlBlock ctrlBlock, boolean createNew);

        /**
         * called when USB device removed or its power off (this callback is called after device closing)
         * @param device
         * @param ctrlBlock
         */
        public void onDisconnect(UsbDevice device, UsbControlBlock ctrlBlock);

        /**
         * called when canceled or could not get permission from user
         * @param device
         */
        public void onCancel(UsbDevice device);
    }

    public USBMonitor(final Context context, final OnDeviceConnectListener listener) {
        if (DEBUG)
            Log.v(TAG, "USBMonitor:Constructor");
        if (listener == null)
            throw new IllegalArgumentException("OnDeviceConnectListener should not null.");
        mWeakContext = new WeakReference<Context>(context);
        mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        mOnDeviceConnectListener = listener;
        mAsyncHandler = HandlerThreadHandler.createHandler(TAG);
        destroyed = false;
        if (DEBUG)
            Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager);
    }

    /**
     * Release all related resources,
     * never reuse again
     */
    public void destroy() {
        if (DEBUG)
            Log.i(TAG, "destroy:");
        unregister();
        if (!destroyed) {
            destroyed = true;
            // モニターしているUSB機器を全てcloseする
            final Set<UsbDevice> keys = mCtrlBlocks.keySet();
            if (keys != null) {
                UsbControlBlock ctrlBlock;
                try {
                    for (final UsbDevice key : keys) {
                        ctrlBlock = mCtrlBlocks.remove(key);
                        if (ctrlBlock != null) {
                            ctrlBlock.close();
                        }
                    }
                } catch (final Exception e) {
                    Log.e(TAG, "destroy:", e);
                }
            }
            mCtrlBlocks.clear();
            try {
                mAsyncHandler.getLooper().quit();
            } catch (final Exception e) {
                Log.e(TAG, "destroy:", e);
            }
        }
    }

    /**
     * register BroadcastReceiver to monitor USB events
     * @throws IllegalStateException
     */
    public synchronized void register() throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        if (mPermissionIntent == null) {
            if (DEBUG)
                Log.i(TAG, "register:");
            final Context context = mWeakContext.get();
            if (context != null) {
                mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
                final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
                // ACTION_USB_DEVICE_ATTACHED never comes on some devices so it should not be added here
                filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
                context.registerReceiver(mUsbReceiver, filter);
            }
            // start connection check
            mDeviceCounts = 0;
            mAsyncHandler.postDelayed(mDeviceCheckRunnable, 1000);
        }
    }

    /**
     * unregister BroadcastReceiver
     * @throws IllegalStateException
     */
    public synchronized void unregister() throws IllegalStateException {
        // 接続チェック用Runnableを削除
        mDeviceCounts = 0;
        if (!destroyed) {
            mAsyncHandler.removeCallbacks(mDeviceCheckRunnable);
        }
        if (mPermissionIntent != null) {
            // if (DEBUG) Log.i(TAG, "unregister:");
            final Context context = mWeakContext.get();
            try {
                if (context != null) {
                    context.unregisterReceiver(mUsbReceiver);
                }
            } catch (final Exception e) {
                Log.w(TAG, e);
            }
            mPermissionIntent = null;
        }
    }

    public synchronized boolean isRegistered() {
        return !destroyed && (mPermissionIntent != null);
    }

    /**
     * set device filter
     * @param filter
     * @throws IllegalStateException
     */
    public void setDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        mDeviceFilters.clear();
        mDeviceFilters.add(filter);
    }

    /**
     * デバイスフィルターを追加
     * @param filter
     * @throws IllegalStateException
     */
    public void addDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        mDeviceFilters.add(filter);
    }

    /**
     * デバイスフィルターを削除
     * @param filter
     * @throws IllegalStateException
     */
    public void removeDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        mDeviceFilters.remove(filter);
    }

    /**
     * set device filters
     * @param filters
     * @throws IllegalStateException
     */
    public void setDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        mDeviceFilters.clear();
        mDeviceFilters.addAll(filters);
    }

    /**
     * add device filters
     * @param filters
     * @throws IllegalStateException
     */
    public void addDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        mDeviceFilters.addAll(filters);
    }

    /**
     * remove device filters
     * @param filters
     */
    public void removeDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        mDeviceFilters.removeAll(filters);
    }

    /**
     * return the number of connected USB devices that matched device filter
     * @return
     * @throws IllegalStateException
     */
    public int getDeviceCount() throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        return getDeviceList().size();
    }

    /**
     * return device list, return empty list if no device matched
     * @return
     * @throws IllegalStateException
     */
    public List<UsbDevice> getDeviceList() throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        return getDeviceList(mDeviceFilters);
    }

    /**
     * return device list, return empty list if no device matched
     * @param filters
     * @return
     * @throws IllegalStateException
     */
    public List<UsbDevice> getDeviceList(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        final List<UsbDevice> result = new ArrayList<UsbDevice>();
        if (deviceList != null) {
            if ((filters == null) || filters.isEmpty()) {
                result.addAll(deviceList.values());
            } else {
                for (final UsbDevice device : deviceList.values()) {
                    for (final DeviceFilter filter : filters) {
                        if ((filter != null) && filter.matches(device)) {
                            // when filter matches
                            if (!filter.isExclude) {
                                result.add(device);
                            }
                            break;
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * return device list, return empty list if no device matched
     * @param filter
     * @return
     * @throws IllegalStateException
     */
    public List<UsbDevice> getDeviceList(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        final List<UsbDevice> result = new ArrayList<UsbDevice>();
        if (deviceList != null) {
            for (final UsbDevice device : deviceList.values()) {
                if ((filter == null) || (filter.matches(device) && !filter.isExclude)) {
                    result.add(device);
                }
            }
        }
        return result;
    }

    /**
     * get USB device list, without filter
     * @return
     * @throws IllegalStateException
     */
    public Iterator<UsbDevice> getDevices() throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        Iterator<UsbDevice> iterator = null;
        final HashMap<String, UsbDevice> list = mUsbManager.getDeviceList();
        if (list != null)
            iterator = list.values().iterator();
        return iterator;
    }

    /**
     * output device list to LogCat
     */
    public final void dumpDevices() {
        final HashMap<String, UsbDevice> list = mUsbManager.getDeviceList();
        if (list != null) {
            final Set<String> keys = list.keySet();
            if (keys != null && keys.size() > 0) {
                final StringBuilder sb = new StringBuilder();
                for (final String key : keys) {
                    final UsbDevice device = list.get(key);
                    final int num_interface = device != null ? device.getInterfaceCount() : 0;
                    sb.setLength(0);
                    for (int i = 0; i < num_interface; i++) {
                        sb.append(String.format(Locale.US, "interface%d:%s", i, device.getInterface(i).toString()));
                    }
                    Log.i(TAG, "key=" + key + ":" + device + ":" + sb.toString());
                }
            } else {
                Log.i(TAG, "no device");
            }
        } else {
            Log.i(TAG, "no device");
        }
    }

    /**
     * return whether the specific Usb device has permission
     * @param device
     * @return true: 指定したUsbDeviceにパーミッションがある
     * @throws IllegalStateException
     */
    public final boolean hasPermission(final UsbDevice device) throws IllegalStateException {
        if (destroyed)
            throw new IllegalStateException("already destroyed");
        return updatePermission(device, device != null && mUsbManager.hasPermission(device));
    }

    /**
     * 内部で保持しているパーミッション状態を更新
     * @param device
     * @param hasPermission
     * @return hasPermission
     */
    private boolean updatePermission(final UsbDevice device, final boolean hasPermission) {
        final int deviceKey = getDeviceKey(device, true);
        synchronized (mHasPermissions) {
            if (hasPermission) {
                if (mHasPermissions.get(deviceKey) == null) {
                    mHasPermissions.put(deviceKey, new WeakReference<UsbDevice>(device));
                }
            } else {
                mHasPermissions.remove(deviceKey);
            }
        }
        return hasPermission;
    }

    /**
     * request permission to access to USB device
     * @param device
     * @return true if fail to request permission
     */
    public synchronized boolean requestPermission(final UsbDevice device) {
        // if (DEBUG) Log.v(TAG, "requestPermission:device=" + device);
        boolean result = false;
        if (isRegistered()) {
            if (device != null) {
                if (mUsbManager.hasPermission(device)) {
                    // call onConnect if app already has permission
                    processConnect(device);
                } else {
                    try {
                        // パーミッションがなければ要求する
                        mUsbManager.requestPermission(device, mPermissionIntent);
                    } catch (final Exception e) {
                        // Android5.1.xのGALAXY系でandroid.permission.sec.MDM_APP_MGMTという意味不明の例外生成するみたい
                        Log.w(TAG, e);
                        processCancel(device);
                        result = true;
                    }
                }
            } else {
                processCancel(device);
                result = true;
            }
        } else {
            processCancel(device);
            result = true;
        }
        return result;
    }

    /**
     * 指定したUsbDeviceをopenする
     * @param device
     * @return
     * @throws SecurityException パーミッションがなければSecurityExceptionを投げる
     */
    public UsbControlBlock openDevice(final UsbDevice device) throws SecurityException {
        if (hasPermission(device)) {
            UsbControlBlock result = mCtrlBlocks.get(device);
            if (result == null) {
                // この中でopenDeviceする
                result = new UsbControlBlock(USBMonitor.this, device);
                mCtrlBlocks.put(device, result);
            }
            return result;
        } else {
            throw new SecurityException("has no permission");
        }
    }

    /**
     * BroadcastReceiver for USB permission
     */
    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            if (destroyed)
                return;
            final String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                // when received the result of requesting USB permission
                synchronized (USBMonitor.this) {
                    final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if (device != null) {
                            // get permission, call onConnect
                            processConnect(device);
                        }
                    } else {
                        // failed to get permission
                        processCancel(device);
                    }
                }
            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                updatePermission(device, hasPermission(device));
                processAttach(device);
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                // when device removed
                final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (device != null) {
                    UsbControlBlock ctrlBlock = mCtrlBlocks.remove(device);
                    if (ctrlBlock != null) {
                        // cleanup
                        ctrlBlock.close();
                    }
                    mDeviceCounts = 0;
                    processDettach(device);
                }
            }
        }
    };

    /**
     * number of connected & detected devices
     */
    private volatile int mDeviceCounts = 0;

    /**
     * periodically check connected devices and if it changed, call onAttach
     */
    private final Runnable mDeviceCheckRunnable = new Runnable() {

        @Override
        public void run() {
            if (destroyed)
                return;
            final List<UsbDevice> devices = getDeviceList();
            final int n = devices.size();
            final int hasPermissionCounts;
            final int m;
            synchronized (mHasPermissions) {
                hasPermissionCounts = mHasPermissions.size();
                mHasPermissions.clear();
                for (final UsbDevice device : devices) {
                    hasPermission(device);
                }
                m = mHasPermissions.size();
            }
            if ((n > mDeviceCounts) || (m > hasPermissionCounts)) {
                mDeviceCounts = n;
                if (mOnDeviceConnectListener != null) {
                    for (int i = 0; i < n; i++) {
                        final UsbDevice device = devices.get(i);
                        mAsyncHandler.post(new Runnable() {

                            @Override
                            public void run() {
                                mOnDeviceConnectListener.onAttach(device);
                            }
                        });
                    }
                }
            }
            // confirm every 2 seconds
            mAsyncHandler.postDelayed(this, 2000);
        }
    };

    /**
     * open specific USB device
     * @param device
     */
    private final void processConnect(final UsbDevice device) {
        if (destroyed)
            return;
        updatePermission(device, true);
        mAsyncHandler.post(new Runnable() {

            @Override
            public void run() {
                if (DEBUG)
                    Log.v(TAG, "processConnect:device=" + device);
                UsbControlBlock ctrlBlock;
                final boolean createNew;
                ctrlBlock = mCtrlBlocks.get(device);
                if (ctrlBlock == null) {
                    ctrlBlock = new UsbControlBlock(USBMonitor.this, device);
                    mCtrlBlocks.put(device, ctrlBlock);
                    createNew = true;
                } else {
                    createNew = false;
                }
                if (mOnDeviceConnectListener != null) {
                    mOnDeviceConnectListener.onConnect(device, ctrlBlock, createNew);
                }
            }
        });
    }

    private final void processCancel(final UsbDevice device) {
        if (destroyed)
            return;
        if (DEBUG)
            Log.v(TAG, "processCancel:");
        updatePermission(device, false);
        if (mOnDeviceConnectListener != null) {
            mAsyncHandler.post(new Runnable() {

                @Override
                public void run() {
                    mOnDeviceConnectListener.onCancel(device);
                }
            });
        }
    }

    private final void processAttach(final UsbDevice device) {
        if (destroyed)
            return;
        if (DEBUG)
            Log.v(TAG, "processAttach:");
        if (mOnDeviceConnectListener != null) {
            mAsyncHandler.post(new Runnable() {

                @Override
                public void run() {
                    mOnDeviceConnectListener.onAttach(device);
                }
            });
        }
    }

    private final void processDettach(final UsbDevice device) {
        if (destroyed)
            return;
        if (DEBUG)
            Log.v(TAG, "processDettach:");
        if (mOnDeviceConnectListener != null) {
            mAsyncHandler.post(new Runnable() {

                @Override
                public void run() {
                    mOnDeviceConnectListener.onDettach(device);
                }
            });
        }
    }

    /**
     * USB機器毎の設定保存用にデバイスキー名を生成する。
     * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成
     * 同種の製品だと同じキー名になるので注意
     * @param device nullなら空文字列を返す
     * @return
     */
    public static final String getDeviceKeyName(final UsbDevice device) {
        return getDeviceKeyName(device, null, false);
    }

    /**
     * USB機器毎の設定保存用にデバイスキー名を生成する。
     * useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意
     * @param device
     * @param useNewAPI
     * @return
     */
    public static final String getDeviceKeyName(final UsbDevice device, final boolean useNewAPI) {
        return getDeviceKeyName(device, null, useNewAPI);
    }

    /**
     * USB機器毎の設定保存用にデバイスキー名を生成する。この機器名をHashMapのキーにする
     * UsbDeviceがopenしている時のみ有効
     * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成
     * serialがnullや空文字でなければserialを含めたデバイスキー名を生成する
     * useNewAPI=trueでAPIレベルを満たしていればマニュファクチャ名, バージョン, コンフィギュレーションカウントも使う
     * @param device nullなら空文字列を返す
     * @param serial	UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得
     * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による)
     * @return
     */
    @SuppressLint("NewApi")
    public static final String getDeviceKeyName(final UsbDevice device, final String serial, final boolean useNewAPI) {
        if (device == null)
            return "";
        final StringBuilder sb = new StringBuilder();
        // API >= 12
        sb.append(device.getVendorId());
        // API >= 12
        sb.append("#");
        // API >= 12
        sb.append(device.getProductId());
        // API >= 12
        sb.append("#");
        // API >= 12
        sb.append(device.getDeviceClreplaced());
        // API >= 12
        sb.append("#");
        // API >= 12
        sb.append(device.getDeviceSubclreplaced());
        // API >= 12
        sb.append("#");
        // API >= 12
        sb.append(device.getDeviceProtocol());
        if (!TextUtils.isEmpty(serial)) {
            sb.append("#");
            sb.append(serial);
        }
        if (useNewAPI && BuildCheck.isAndroid5()) {
            sb.append("#");
            if (TextUtils.isEmpty(serial)) {
                // API >= 21
                sb.append(device.getSerialNumber());
                // API >= 21
                sb.append("#");
            }
            // API >= 21
            sb.append(device.getManufacturerName());
            // API >= 21
            sb.append("#");
            // API >= 21
            sb.append(device.getConfigurationCount());
            // API >= 21
            sb.append("#");
            if (BuildCheck.isMarshmallow()) {
                // API >= 23
                sb.append(device.getVersion());
                // API >= 23
                sb.append("#");
            }
        }
        // if (DEBUG) Log.v(TAG, "getDeviceKeyName:" + sb.toString());
        return sb.toString();
    }

    /**
     * デバイスキーを整数として取得
     * getDeviceKeyNameで得られる文字列のhasCodeを取得
     * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成
     * 同種の製品だと同じデバイスキーになるので注意
     * @param device nullなら0を返す
     * @return
     */
    public static final int getDeviceKey(final UsbDevice device) {
        return device != null ? getDeviceKeyName(device, null, false).hashCode() : 0;
    }

    /**
     * デバイスキーを整数として取得
     * getDeviceKeyNameで得られる文字列のhasCodeを取得
     * useNewAPI=falseで同種の製品だと同じデバイスキーになるので注意
     * @param device
     * @param useNewAPI
     * @return
     */
    public static final int getDeviceKey(final UsbDevice device, final boolean useNewAPI) {
        return device != null ? getDeviceKeyName(device, null, useNewAPI).hashCode() : 0;
    }

    /**
     * デバイスキーを整数として取得
     * getDeviceKeyNameで得られる文字列のhasCodeを取得
     * serialがnullでuseNewAPI=falseで同種の製品だと同じデバイスキーになるので注意
     * @param device nullなら0を返す
     * @param serial UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得
     * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による)
     * @return
     */
    public static final int getDeviceKey(final UsbDevice device, final String serial, final boolean useNewAPI) {
        return device != null ? getDeviceKeyName(device, serial, useNewAPI).hashCode() : 0;
    }

    public static clreplaced UsbDeviceInfo {

        public String usb_version;

        public String manufacturer;

        public String product;

        public String version;

        public String serial;

        private void clear() {
            usb_version = manufacturer = product = version = serial = null;
        }

        @Override
        public String toString() {
            return String.format("UsbDevice:usb_version=%s,manufacturer=%s,product=%s,version=%s,serial=%s", usb_version != null ? usb_version : "", manufacturer != null ? manufacturer : "", product != null ? product : "", version != null ? version : "", serial != null ? serial : "");
        }
    }

    private static final int USB_DIR_OUT = 0;

    private static final int USB_DIR_IN = 0x80;

    private static final int USB_TYPE_MASK = (0x03 << 5);

    private static final int USB_TYPE_STANDARD = (0x00 << 5);

    private static final int USB_TYPE_CLreplaced = (0x01 << 5);

    private static final int USB_TYPE_VENDOR = (0x02 << 5);

    private static final int USB_TYPE_RESERVED = (0x03 << 5);

    private static final int USB_RECIP_MASK = 0x1f;

    private static final int USB_RECIP_DEVICE = 0x00;

    private static final int USB_RECIP_INTERFACE = 0x01;

    private static final int USB_RECIP_ENDPOINT = 0x02;

    private static final int USB_RECIP_OTHER = 0x03;

    private static final int USB_RECIP_PORT = 0x04;

    private static final int USB_RECIP_RPIPE = 0x05;

    private static final int USB_REQ_GET_STATUS = 0x00;

    private static final int USB_REQ_CLEAR_FEATURE = 0x01;

    private static final int USB_REQ_SET_FEATURE = 0x03;

    private static final int USB_REQ_SET_ADDRESS = 0x05;

    private static final int USB_REQ_GET_DESCRIPTOR = 0x06;

    private static final int USB_REQ_SET_DESCRIPTOR = 0x07;

    private static final int USB_REQ_GET_CONFIGURATION = 0x08;

    private static final int USB_REQ_SET_CONFIGURATION = 0x09;

    private static final int USB_REQ_GET_INTERFACE = 0x0A;

    private static final int USB_REQ_SET_INTERFACE = 0x0B;

    private static final int USB_REQ_SYNCH_FRAME = 0x0C;

    private static final int USB_REQ_SET_SEL = 0x30;

    private static final int USB_REQ_SET_ISOCH_DELAY = 0x31;

    private static final int USB_REQ_SET_ENCRYPTION = 0x0D;

    private static final int USB_REQ_GET_ENCRYPTION = 0x0E;

    private static final int USB_REQ_RPIPE_ABORT = 0x0E;

    private static final int USB_REQ_SET_HANDSHAKE = 0x0F;

    private static final int USB_REQ_RPIPE_RESET = 0x0F;

    private static final int USB_REQ_GET_HANDSHAKE = 0x10;

    private static final int USB_REQ_SET_CONNECTION = 0x11;

    private static final int USB_REQ_SET_SECURITY_DATA = 0x12;

    private static final int USB_REQ_GET_SECURITY_DATA = 0x13;

    private static final int USB_REQ_SET_WUSB_DATA = 0x14;

    private static final int USB_REQ_LOOPBACK_DATA_WRITE = 0x15;

    private static final int USB_REQ_LOOPBACK_DATA_READ = 0x16;

    private static final int USB_REQ_SET_INTERFACE_DS = 0x17;

    // 0x10
    private static final int USB_REQ_STANDARD_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE);

    // 0x90
    private static final int USB_REQ_STANDARD_DEVICE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE);

    // 0x11
    private static final int USB_REQ_STANDARD_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE);

    // 0x91
    private static final int USB_REQ_STANDARD_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE);

    // 0x12
    private static final int USB_REQ_STANDARD_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT);

    // 0x92
    private static final int USB_REQ_STANDARD_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT);

    // 0x20
    private static final int USB_REQ_CS_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLreplaced | USB_RECIP_DEVICE);

    // 0xa0
    private static final int USB_REQ_CS_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLreplaced | USB_RECIP_DEVICE);

    // 0x21
    private static final int USB_REQ_CS_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLreplaced | USB_RECIP_INTERFACE);

    // 0xa1
    private static final int USB_REQ_CS_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLreplaced | USB_RECIP_INTERFACE);

    // 0x22
    private static final int USB_REQ_CS_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLreplaced | USB_RECIP_ENDPOINT);

    // 0xa2
    private static final int USB_REQ_CS_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLreplaced | USB_RECIP_ENDPOINT);

    // 0x40
    private static final int USB_REQ_VENDER_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLreplaced | USB_RECIP_DEVICE);

    // 0xc0
    private static final int USB_REQ_VENDER_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLreplaced | USB_RECIP_DEVICE);

    // 0x41
    private static final int USB_REQ_VENDER_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLreplaced | USB_RECIP_INTERFACE);

    // 0xc1
    private static final int USB_REQ_VENDER_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLreplaced | USB_RECIP_INTERFACE);

    // 0x42
    private static final int USB_REQ_VENDER_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLreplaced | USB_RECIP_ENDPOINT);

    // 0xc2
    private static final int USB_REQ_VENDER_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLreplaced | USB_RECIP_ENDPOINT);

    private static final int USB_DT_DEVICE = 0x01;

    private static final int USB_DT_CONFIG = 0x02;

    private static final int USB_DT_STRING = 0x03;

    private static final int USB_DT_INTERFACE = 0x04;

    private static final int USB_DT_ENDPOINT = 0x05;

    private static final int USB_DT_DEVICE_QUALIFIER = 0x06;

    private static final int USB_DT_OTHER_SPEED_CONFIG = 0x07;

    private static final int USB_DT_INTERFACE_POWER = 0x08;

    private static final int USB_DT_OTG = 0x09;

    private static final int USB_DT_DEBUG = 0x0a;

    private static final int USB_DT_INTERFACE_replacedOCIATION = 0x0b;

    private static final int USB_DT_SECURITY = 0x0c;

    private static final int USB_DT_KEY = 0x0d;

    private static final int USB_DT_ENCRYPTION_TYPE = 0x0e;

    private static final int USB_DT_BOS = 0x0f;

    private static final int USB_DT_DEVICE_CAPABILITY = 0x10;

    private static final int USB_DT_WIRELESS_ENDPOINT_COMP = 0x11;

    private static final int USB_DT_WIRE_ADAPTER = 0x21;

    private static final int USB_DT_RPIPE = 0x22;

    private static final int USB_DT_CS_RADIO_CONTROL = 0x23;

    private static final int USB_DT_PIPE_USAGE = 0x24;

    private static final int USB_DT_SS_ENDPOINT_COMP = 0x30;

    private static final int USB_DT_CS_DEVICE = (USB_TYPE_CLreplaced | USB_DT_DEVICE);

    private static final int USB_DT_CS_CONFIG = (USB_TYPE_CLreplaced | USB_DT_CONFIG);

    private static final int USB_DT_CS_STRING = (USB_TYPE_CLreplaced | USB_DT_STRING);

    private static final int USB_DT_CS_INTERFACE = (USB_TYPE_CLreplaced | USB_DT_INTERFACE);

    private static final int USB_DT_CS_ENDPOINT = (USB_TYPE_CLreplaced | USB_DT_ENDPOINT);

    private static final int USB_DT_DEVICE_SIZE = 18;

    /**
     * 指定したIDのStringディスクリプタから文字列を取得する。取得できなければnull
     * @param connection
     * @param id
     * @param languageCount
     * @param languages
     * @return
     */
    private static String getString(final UsbDeviceConnection connection, final int id, final int languageCount, final byte[] languages) {
        final byte[] work = new byte[256];
        String result = null;
        for (int i = 1; i <= languageCount; i++) {
            int ret = connection.controlTransfer(// USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE
            USB_REQ_STANDARD_DEVICE_GET, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | id, languages[i], work, 256, 0);
            if ((ret > 2) && (work[0] == ret) && (work[1] == USB_DT_STRING)) {
                // skip first two bytes(bLength & bDescriptorType), and copy the rest to the string
                try {
                    result = new String(work, 2, ret - 2, "UTF-16LE");
                    if (!"Љ".equals(result)) {
                        // 変なゴミが返ってくる時がある
                        break;
                    } else {
                        result = null;
                    }
                } catch (final UnsupportedEncodingException e) {
                // ignore
                }
            }
        }
        return result;
    }

    /**
     * ベンダー名・製品名・バージョン・シリアルを取得する
     * @param device
     * @return
     */
    public UsbDeviceInfo getDeviceInfo(final UsbDevice device) {
        return updateDeviceInfo(mUsbManager, device, null);
    }

    /**
     * ベンダー名・製品名・バージョン・シリアルを取得する
     * #updateDeviceInfo(final UsbManager, final UsbDevice, final UsbDeviceInfo)のヘルパーメソッド
     * @param context
     * @param device
     * @return
     */
    public static UsbDeviceInfo getDeviceInfo(final Context context, final UsbDevice device) {
        return updateDeviceInfo((UsbManager) context.getSystemService(Context.USB_SERVICE), device, new UsbDeviceInfo());
    }

    /**
     * ベンダー名・製品名・バージョン・シリアルを取得する
     * @param manager
     * @param device
     * @param _info
     * @return
     */
    @TargetApi(Build.VERSION_CODES.M)
    public static UsbDeviceInfo updateDeviceInfo(final UsbManager manager, final UsbDevice device, final UsbDeviceInfo _info) {
        final UsbDeviceInfo info = _info != null ? _info : new UsbDeviceInfo();
        info.clear();
        if (device != null) {
            if (BuildCheck.isLollipop()) {
                info.manufacturer = device.getManufacturerName();
                info.product = device.getProductName();
                info.serial = device.getSerialNumber();
            }
            if (BuildCheck.isMarshmallow()) {
                info.usb_version = device.getVersion();
            }
            if ((manager != null) && manager.hasPermission(device)) {
                final UsbDeviceConnection connection = manager.openDevice(device);
                if (connection == null) {
                    return null;
                }
                final byte[] desc = connection.getRawDescriptors();
                if (TextUtils.isEmpty(info.usb_version)) {
                    info.usb_version = String.format("%x.%02x", ((int) desc[3] & 0xff), ((int) desc[2] & 0xff));
                }
                if (TextUtils.isEmpty(info.version)) {
                    info.version = String.format("%x.%02x", ((int) desc[13] & 0xff), ((int) desc[12] & 0xff));
                }
                if (TextUtils.isEmpty(info.serial)) {
                    info.serial = connection.getSerial();
                }
                final byte[] languages = new byte[256];
                int languageCount = 0;
                // controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout)
                try {
                    int result = connection.controlTransfer(// USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE
                    USB_REQ_STANDARD_DEVICE_GET, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0, 0, languages, 256, 0);
                    if (result > 0) {
                        languageCount = (result - 2) / 2;
                    }
                    if (languageCount > 0) {
                        if (TextUtils.isEmpty(info.manufacturer)) {
                            info.manufacturer = getString(connection, desc[14], languageCount, languages);
                        }
                        if (TextUtils.isEmpty(info.product)) {
                            info.product = getString(connection, desc[15], languageCount, languages);
                        }
                        if (TextUtils.isEmpty(info.serial)) {
                            info.serial = getString(connection, desc[16], languageCount, languages);
                        }
                    }
                } finally {
                    connection.close();
                }
            }
            if (TextUtils.isEmpty(info.manufacturer)) {
                info.manufacturer = USBVendorId.vendorName(device.getVendorId());
            }
            if (TextUtils.isEmpty(info.manufacturer)) {
                info.manufacturer = String.format("%04x", device.getVendorId());
            }
            if (TextUtils.isEmpty(info.product)) {
                info.product = String.format("%04x", device.getProductId());
            }
        }
        return info;
    }

    /**
     * control clreplaced
     * never reuse the instance when it closed
     */
    public static final clreplaced UsbControlBlock implements Cloneable {

        private final WeakReference<USBMonitor> mWeakMonitor;

        private final WeakReference<UsbDevice> mWeakDevice;

        protected UsbDeviceConnection mConnection;

        protected final UsbDeviceInfo mInfo;

        private final int mBusNum;

        private final int mDevNum;

        private final SparseArray<SparseArray<UsbInterface>> mInterfaces = new SparseArray<SparseArray<UsbInterface>>();

        /**
         * this clreplaced needs permission to access USB device before constructing
         * @param monitor
         * @param device
         */
        private UsbControlBlock(final USBMonitor monitor, final UsbDevice device) {
            if (DEBUG)
                Log.i(TAG, "UsbControlBlock:constructor");
            mWeakMonitor = new WeakReference<USBMonitor>(monitor);
            mWeakDevice = new WeakReference<UsbDevice>(device);
            mConnection = monitor.mUsbManager.openDevice(device);
            mInfo = updateDeviceInfo(monitor.mUsbManager, device, null);
            final String name = device.getDeviceName();
            final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null;
            int busnum = 0;
            int devnum = 0;
            if (v != null) {
                busnum = Integer.parseInt(v[v.length - 2]);
                devnum = Integer.parseInt(v[v.length - 1]);
            }
            mBusNum = busnum;
            mDevNum = devnum;
            // if (DEBUG) {
            if (mConnection != null) {
                final int desc = mConnection.getFileDescriptor();
                final byte[] rawDesc = mConnection.getRawDescriptors();
                Log.i(TAG, String.format(Locale.US, "name=%s,desc=%d,busnum=%d,devnum=%d,rawDesc=", name, desc, busnum, devnum) + rawDesc);
            } else {
                Log.e(TAG, "could not connect to device " + name);
            }
        // }
        }

        /**
         * copy constructor
         * @param src
         * @throws IllegalStateException
         */
        private UsbControlBlock(final UsbControlBlock src) throws IllegalStateException {
            final USBMonitor monitor = src.getUSBMonitor();
            final UsbDevice device = src.getDevice();
            if (device == null) {
                throw new IllegalStateException("device may already be removed");
            }
            mConnection = monitor.mUsbManager.openDevice(device);
            if (mConnection == null) {
                throw new IllegalStateException("device may already be removed or have no permission");
            }
            mInfo = updateDeviceInfo(monitor.mUsbManager, device, null);
            mWeakMonitor = new WeakReference<USBMonitor>(monitor);
            mWeakDevice = new WeakReference<UsbDevice>(device);
            mBusNum = src.mBusNum;
            mDevNum = src.mDevNum;
        // FIXME USBMonitor.mCtrlBlocksに追加する(今はHashMapなので追加すると置き換わってしまうのでだめ, ListかHashMapにListをぶら下げる?)
        }

        /**
         * duplicate by clone
         * need permission
         * USBMonitor never handle cloned UsbControlBlock, you should release it after using it.
         * @return
         * @throws CloneNotSupportedException
         */
        @Override
        public UsbControlBlock clone() throws CloneNotSupportedException {
            final UsbControlBlock ctrlblock;
            try {
                ctrlblock = new UsbControlBlock(this);
            } catch (final IllegalStateException e) {
                throw new CloneNotSupportedException(e.getMessage());
            }
            return ctrlblock;
        }

        public USBMonitor getUSBMonitor() {
            return mWeakMonitor.get();
        }

        public final UsbDevice getDevice() {
            return mWeakDevice.get();
        }

        /**
         * get device name
         * @return
         */
        public String getDeviceName() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getDeviceName() : "";
        }

        /**
         * get device id
         * @return
         */
        public int getDeviceId() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getDeviceId() : 0;
        }

        /**
         * get device key string
         * @return same value if the devices has same vendor id, product id, device clreplaced, device subclreplaced and device protocol
         */
        public String getDeviceKeyName() {
            return USBMonitor.getDeviceKeyName(mWeakDevice.get());
        }

        /**
         * get device key string
         * @param useNewAPI if true, try to use serial number
         * @return
         * @throws IllegalStateException
         */
        public String getDeviceKeyName(final boolean useNewAPI) throws IllegalStateException {
            if (useNewAPI)
                checkConnection();
            return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, useNewAPI);
        }

        /**
         * get device key
         * @return
         * @throws IllegalStateException
         */
        public int getDeviceKey() throws IllegalStateException {
            checkConnection();
            return USBMonitor.getDeviceKey(mWeakDevice.get());
        }

        /**
         * get device key
         * @param useNewAPI if true, try to use serial number
         * @return
         * @throws IllegalStateException
         */
        public int getDeviceKey(final boolean useNewAPI) throws IllegalStateException {
            if (useNewAPI)
                checkConnection();
            return USBMonitor.getDeviceKey(mWeakDevice.get(), mInfo.serial, useNewAPI);
        }

        /**
         * get device key string
         * if device has serial number, use it
         * @return
         */
        public String getDeviceKeyNameWithSerial() {
            return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, false);
        }

        /**
         * get device key
         * if device has serial number, use it
         * @return
         */
        public int getDeviceKeyWithSerial() {
            return getDeviceKeyNameWithSerial().hashCode();
        }

        /**
         * get UsbDeviceConnection
         * @return
         */
        public synchronized UsbDeviceConnection getConnection() {
            return mConnection;
        }

        /**
         * get file descriptor to access USB device
         * @return
         * @throws IllegalStateException
         */
        public synchronized int getFileDescriptor() throws IllegalStateException {
            checkConnection();
            return mConnection.getFileDescriptor();
        }

        /**
         * get raw descriptor for the USB device
         * @return
         * @throws IllegalStateException
         */
        public synchronized byte[] getRawDescriptors() throws IllegalStateException {
            checkConnection();
            return mConnection.getRawDescriptors();
        }

        /**
         * get vendor id
         * @return
         */
        public int getVenderId() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getVendorId() : 0;
        }

        /**
         * get product id
         * @return
         */
        public int getProductId() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getProductId() : 0;
        }

        /**
         * get version string of USB
         * @return
         */
        public String getUsbVersion() {
            return mInfo.usb_version;
        }

        /**
         * get manufacture
         * @return
         */
        public String getManufacture() {
            return mInfo.manufacturer;
        }

        /**
         * get product name
         * @return
         */
        public String getProductName() {
            return mInfo.product;
        }

        /**
         * get version
         * @return
         */
        public String getVersion() {
            return mInfo.version;
        }

        /**
         * get serial number
         * @return
         */
        public String getSerial() {
            return mInfo.serial;
        }

        public int getBusNum() {
            return mBusNum;
        }

        public int getDevNum() {
            return mDevNum;
        }

        /**
         * get interface
         * @param interface_id
         * @throws IllegalStateException
         */
        public synchronized UsbInterface getInterface(final int interface_id) throws IllegalStateException {
            return getInterface(interface_id, 0);
        }

        /**
         * get interface
         * @param interface_id
         * @param altsetting
         * @return
         * @throws IllegalStateException
         */
        public synchronized UsbInterface getInterface(final int interface_id, final int altsetting) throws IllegalStateException {
            checkConnection();
            SparseArray<UsbInterface> intfs = mInterfaces.get(interface_id);
            if (intfs == null) {
                intfs = new SparseArray<UsbInterface>();
                mInterfaces.put(interface_id, intfs);
            }
            UsbInterface intf = intfs.get(altsetting);
            if (intf == null) {
                final UsbDevice device = mWeakDevice.get();
                final int n = device.getInterfaceCount();
                for (int i = 0; i < n; i++) {
                    final UsbInterface temp = device.getInterface(i);
                    if ((temp.getId() == interface_id) && (temp.getAlternateSetting() == altsetting)) {
                        intf = temp;
                        break;
                    }
                }
                if (intf != null) {
                    intfs.append(altsetting, intf);
                }
            }
            return intf;
        }

        /**
         * open specific interface
         * @param intf
         */
        public synchronized void claimInterface(final UsbInterface intf) {
            claimInterface(intf, true);
        }

        public synchronized void claimInterface(final UsbInterface intf, final boolean force) {
            checkConnection();
            mConnection.claimInterface(intf, force);
        }

        /**
         * close interface
         * @param intf
         * @throws IllegalStateException
         */
        public synchronized void releaseInterface(final UsbInterface intf) throws IllegalStateException {
            checkConnection();
            final SparseArray<UsbInterface> intfs = mInterfaces.get(intf.getId());
            if (intfs != null) {
                final int index = intfs.indexOfValue(intf);
                intfs.removeAt(index);
                if (intfs.size() == 0) {
                    mInterfaces.remove(intf.getId());
                }
            }
            mConnection.releaseInterface(intf);
        }

        /**
         * Close device
         * This also close interfaces if they are opened in Java side
         */
        public synchronized void close() {
            if (DEBUG)
                Log.i(TAG, "UsbControlBlock#close:");
            if (mConnection != null) {
                final int n = mInterfaces.size();
                for (int i = 0; i < n; i++) {
                    final SparseArray<UsbInterface> intfs = mInterfaces.valueAt(i);
                    if (intfs != null) {
                        final int m = intfs.size();
                        for (int j = 0; j < m; j++) {
                            final UsbInterface intf = intfs.valueAt(j);
                            mConnection.releaseInterface(intf);
                        }
                        intfs.clear();
                    }
                }
                mInterfaces.clear();
                mConnection.close();
                mConnection = null;
                final USBMonitor monitor = mWeakMonitor.get();
                if (monitor != null) {
                    if (monitor.mOnDeviceConnectListener != null) {
                        monitor.mOnDeviceConnectListener.onDisconnect(mWeakDevice.get(), UsbControlBlock.this);
                    }
                    monitor.mCtrlBlocks.remove(getDevice());
                }
            }
        }

        @Override
        public boolean equals(final Object o) {
            if (o == null)
                return false;
            if (o instanceof UsbControlBlock) {
                final UsbDevice device = ((UsbControlBlock) o).getDevice();
                return device == null ? mWeakDevice.get() == null : device.equals(mWeakDevice.get());
            } else if (o instanceof UsbDevice) {
                return o.equals(mWeakDevice.get());
            }
            return super.equals(o);
        }

        // @Override
        // protected void finalize() throws Throwable {
        // /			close();
        // super.finalize();
        // }
        private synchronized void checkConnection() throws IllegalStateException {
            if (mConnection == null) {
                throw new IllegalStateException("already closed");
            }
        }
    }
}

19 Source : StringAdapter.java
with GNU General Public License v3.0
from z-chu

private SparseArray<ArrayList<String>> getSectionData(int section, PageProperty property) {
    SparseArray<ArrayList<String>> pages = null;
    if (map == null) {
        map = new LruCache<>(3);
        pages = loadPages(getPageSource(section), property.textPaint, property.visibleHeight, property.visibleWidth, property.intervalSize, property.paragraphSize);
        map.put(section, pages);
        mPageProperty = property;
    } else {
        if (mPageProperty != null && mPageProperty.equals(property)) {
            pages = map.get(section);
        }
        if (pages == null) {
            pages = loadPages(getPageSource(section), property.textPaint, property.visibleHeight, property.visibleWidth, property.intervalSize, property.paragraphSize);
            map.put(section, pages);
            mPageProperty = property;
        }
    }
    return pages;
}

19 Source : StringAdapter.java
with GNU General Public License v3.0
from z-chu

public static SparseArray<ArrayList<String>> loadPages(String source, Paint textPaint, int visibleHeight, int visibleWidth, int intervalSize, int paragraphSize) {
    SparseArray<ArrayList<String>> pageArray = new SparseArray<>();
    List<String> lines = new ArrayList<>();
    if (source != null && source.length() > 0) {
        String[] split = source.split("\n");
        // 剩余高度
        int rHeight = visibleHeight + intervalSize + paragraphSize;
        for (String paragraph : split) {
            boolean hasContent = false;
            // 如果只有换行符,那么就不执行
            if (StringUtils.isBlank(paragraph))
                continue;
            // 重置段落
            paragraph = StringUtils.halfToFull("  " + paragraph + "\n");
            paragraph = StringUtils.trimBeforeReplace(paragraph, "  ");
            while (paragraph.length() > 0) {
                // 测量一行占用的字节数
                int count = textPaint.breakText(paragraph, true, visibleWidth, null);
                String subStr = paragraph.substring(0, count);
                String trim = subStr.trim();
                if (trim.length() > 0 && !trim.equals("\n") && !trim.equals("\r\n") && !StringUtils.isBlank(trim)) {
                    // 重置剩余距离
                    rHeight -= (textPaint.getTextSize() + intervalSize);
                    // 达到行数要求,创建Page
                    if (rHeight < 0) {
                        // 创建Page
                        pageArray.put(pageArray.size(), new ArrayList<>(lines));
                        // 重置Lines
                        lines.clear();
                        rHeight = visibleHeight;
                        continue;
                    }
                    // 将一行字节,存储到lines中
                    lines.add(subStr);
                    hasContent = true;
                }
                // 裁剪
                paragraph = paragraph.substring(count);
            }
            if (lines.size() > 0 && hasContent) {
                rHeight -= paragraphSize;
            }
        }
        if (lines.size() != 0) {
            pageArray.put(pageArray.size(), new ArrayList<>(lines));
            // 重置Lines
            lines.clear();
        }
    }
    return pageArray;
}

19 Source : ReadAdapter.java
with GNU General Public License v3.0
from z-chu

/**
 * Created by Chu on 2017/8/15.
 */
public clreplaced ReadAdapter extends StringAdapter {

    private SparseArray<BookSectionContent> bookArray;

    private List<BookSectionItem> mBookSectionItems;

    public ReadAdapter() {
        bookArray = new SparseArray<>();
    }

    public ReadAdapter(List<BookSectionItem> bookSectionItems) {
        bookArray = new SparseArray<>();
        mBookSectionItems = bookSectionItems;
    }

    @Override
    protected String getPageSource(int section) {
        BookSectionContent sectionContent = bookArray.get(section);
        return sectionContent != null ? bookArray.get(section).getContent() : null;
    }

    @Override
    public int getSectionCount() {
        return bookArray.size();
    }

    @Override
    public String getSectionName(int section) {
        BookSectionContent sectionContent = bookArray.get(section);
        return sectionContent != null ? bookArray.get(section).getSectionName() : null;
    }

    @Override
    public boolean hasNextSection(int currentSection) {
        return bookArray.get(currentSection + 1) != null;
    }

    @Override
    public boolean hasPreviousSection(int currentSection) {
        return bookArray.get(currentSection - 1) != null;
    }

    public void addData(int section, BookSectionContent content) {
        bookArray.put(section, content);
    }

    public boolean hreplacedection(int section) {
        return bookArray.get(section) != null;
    }
}

19 Source : DisplayUtil.java
with GNU General Public License v3.0
from ywwynm

/**
 * Created by ywwynm on 2015/6/28.
 * A helper clreplaced to get necessary screen information and update UI with color.
 */
public clreplaced DisplayUtil {

    public static final String TAG = "DisplayUtil";

    private DisplayUtil() {
    }

    public static float getScreenDensity(Context context) {
        return context.getResources().getDisplayMetrics().density;
    }

    @SuppressLint("NewApi")
    public static Point getDisplaySize(Context context) {
        Point screen = new Point();
        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        if (!DeviceUtil.hasLollipopApi()) {
            display.getSize(screen);
        } else {
            // Content can overlay Navigation Bar above Lollipop.
            display.getRealSize(screen);
        }
        return screen;
    }

    // Get physical screen size of phone/tablet.
    public static Point getScreenSize(Context context) {
        Point realScreen = new Point();
        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        if (DeviceUtil.hasJellyBeanMR1Api()) {
            display.getRealSize(realScreen);
        } else {
            try {
                Method mGetRawH = Display.clreplaced.getMethod("getRawHeight");
                Method mGetRawW = Display.clreplaced.getMethod("getRawWidth");
                realScreen.x = (Integer) mGetRawW.invoke(display);
                realScreen.y = (Integer) mGetRawH.invoke(display);
            } catch (Exception e) {
                display.getSize(realScreen);
                Log.e(TAG, "Cannot use reflection to get real screen size. " + "Returned size may be wrong.");
            }
        }
        return realScreen;
    }

    public static boolean isTablet(Context context) {
        // improved on 2016/5/11~
        return context.getResources().getBoolean(R.bool.isTablet);
    }

    public static int getStatusbarHeight(Context context) {
        Resources resources = context.getResources();
        int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            return resources.getDimensionPixelSize(resourceId);
        } else
            return 0;
    }

    public static boolean hasNavigationBar(Context context) {
        // improved on 2016/11/21
        boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
        boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
        boolean con1 = !hasMenuKey && !hasBackKey;
        Resources resources = context.getResources();
        int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
        boolean con2 = id > 0 && resources.getBoolean(id);
        boolean con3;
        Point displaySize = new Point();
        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        display.getSize(displaySize);
        Point screenSize = getScreenSize(context);
        if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            con3 = displaySize.y != screenSize.y;
        } else {
            con3 = displaySize.x != screenSize.x;
        }
        return con1 || con2 || con3;
    }

    public static int getNavigationBarHeight(Context context) {
        // improved on 2016/11/21
        int res1 = 0;
        Resources resources = context.getResources();
        int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            res1 = resources.getDimensionPixelSize(resourceId);
        }
        int res2;
        Point displaySize = new Point();
        Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        display.getSize(displaySize);
        Point screenSize = getScreenSize(context);
        if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            res2 = screenSize.y - displaySize.y;
        } else {
            res2 = screenSize.x - displaySize.x;
        }
        return Math.max(res1, res2);
    }

    // This method has a sexy history~
    // Someday if you see this code again, wish that your dream had come true
    public static int getRandomColor(Context context) {
        int[] colors = context.getResources().getIntArray(R.array.thing);
        return colors[new Random().nextInt(colors.length)];
    }

    public static int getColorIndex(int color, Context context) {
        int[] colors = context.getResources().getIntArray(R.array.thing);
        for (int i = 0; i < colors.length; i++) {
            if (colors[i] == color) {
                return i;
            }
        }
        return -1;
    }

    public static int getDarkColor(int color, Context context) {
        int[] colorsDark = context.getResources().getIntArray(R.array.thing_dark);
        int index = getColorIndex(color, context);
        if (index != -1) {
            return colorsDark[index];
        } else
            return 0;
    }

    public static int getLightColor(int color, Context context) {
        int[] colorsLight = context.getResources().getIntArray(R.array.thing_light);
        int index = getColorIndex(color, context);
        if (index != -1) {
            return colorsLight[index];
        } else
            return 0;
    }

    public static int getTransparentColor(int color, int alpha) {
        int red = Color.red(color);
        int green = Color.green(color);
        int blue = Color.blue(color);
        return Color.argb(alpha, red, green, blue);
    }

    /**
     * Play drawer toggle animation(from drawer to arrow and vice versa).
     * @param d the {@link DrawerArrowDrawable} object to play toggle animation.
     */
    public static void playDrawerToggleAnim(final DrawerArrowDrawable d) {
        float start = d.getProgress();
        float end = Math.abs(start - 1);
        ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
        offsetAnimator.setDuration(300);
        offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float progress = (Float) animation.getAnimatedValue();
                d.setProgress(progress);
            }
        });
        offsetAnimator.start();
    }

    /**
     * Set backgroundTint to {@link View} across all targeting platform level.
     * @param view the {@link View} to tint.
     * @param color color used to tint.
     */
    public static void tintView(View view, int color) {
        final Drawable d = view.getBackground();
        Drawable.ConstantState constantState = d.getConstantState();
        if (constantState == null)
            return;
        final Drawable nd = constantState.newDrawable();
        nd.setColorFilter(AppCompatDrawableManager.getPorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN));
        view.setBackground(nd);
    // Drawable wrappedDrawable = DrawableCompat.wrap(view.getBackground().mutate());
    // DrawableCompat.setTint(wrappedDrawable, color);
    // view.setBackground(wrappedDrawable);
    // ViewCompat.setBackgroundTintList(view, ColorStateList.valueOf(color));
    }

    public static void expandLayoutToStatusBarAboveLollipop(Activity activity) {
        if (DeviceUtil.hasLollipopApi()) {
            View decor = activity.getWindow().getDecorView();
            decor.setSystemUiVisibility(decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        }
    }

    public static void expandLayoutToFullscreenAboveLollipop(Activity activity) {
        if (DeviceUtil.hasLollipopApi()) {
            View decor = activity.getWindow().getDecorView();
            decor.setSystemUiVisibility(decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
        }
    }

    public static void expandStatusBarViewAboveKitkat(View statusBar) {
        if (DeviceUtil.hasKitKatApi()) {
            final int height = getStatusbarHeight(statusBar.getContext());
            ViewGroup.LayoutParams vlp = statusBar.getLayoutParams();
            vlp.height = height;
            statusBar.requestLayout();
        }
    }

    public static void darkStatusBar(Activity activity) {
        Window window = activity.getWindow();
        if (DeviceUtil.hasMarshmallowApi()) {
            View decor = window.getDecorView();
            decor.setSystemUiVisibility(decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        }
        darkStatusBarForMIUI(window);
        darkStatusBarForFlyme(window);
    }

    public static void cancelDarkStatusBar(Activity activity) {
        Window window = activity.getWindow();
        if (DeviceUtil.hasMarshmallowApi()) {
            View decor = window.getDecorView();
            decor.setSystemUiVisibility(decor.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        }
    }

    private static void darkStatusBarForMIUI(Window window) {
        Clreplaced<? extends Window> clazz = window.getClreplaced();
        try {
            Clreplaced<?> layoutParams = Clreplaced.forName("android.view.MiuiWindowManager$LayoutParams");
            Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
            int darkModeFlag = field.getInt(layoutParams);
            Method extraFlagField = clazz.getMethod("setExtraFlags", int.clreplaced, int.clreplaced);
            extraFlagField.invoke(window, darkModeFlag, darkModeFlag);
        } catch (Exception ignored) {
        }
    }

    private static void darkStatusBarForFlyme(Window window) {
        try {
            WindowManager.LayoutParams lp = window.getAttributes();
            Field darkFlag = WindowManager.LayoutParams.clreplaced.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
            Field meizuFlags = WindowManager.LayoutParams.clreplaced.getDeclaredField("meizuFlags");
            darkFlag.setAccessible(true);
            meizuFlags.setAccessible(true);
            int bit = darkFlag.getInt(null);
            int value = meizuFlags.getInt(lp);
            value |= bit;
            meizuFlags.setInt(lp, value);
            window.setAttributes(lp);
        } catch (Exception ignored) {
        }
    }

    public static boolean isInMultiWindow(Activity activity) {
        if (DeviceUtil.hasNougatApi()) {
            return activity.isInMultiWindowMode();
        }
        return false;
    }

    /**
     * Set color of handlers appearing when user is selecting content of {@link EditText}.
     * @param editText handlers of which {@link EditText} should be set to {@param color}.
     * @param color color to set for handlers.
     */
    public static void setSelectionHandlersColor(EditText editText, int color) {
        try {
            final Clreplaced<?> cTextView = TextView.clreplaced;
            final Field fhlRes = cTextView.getDeclaredField("mTextSelectHandleLeftRes");
            final Field fhrRes = cTextView.getDeclaredField("mTextSelectHandleRightRes");
            final Field fhcRes = cTextView.getDeclaredField("mTextSelectHandleRes");
            fhlRes.setAccessible(true);
            fhrRes.setAccessible(true);
            fhcRes.setAccessible(true);
            int hlRes = fhlRes.getInt(editText);
            int hrRes = fhrRes.getInt(editText);
            int hcRes = fhcRes.getInt(editText);
            final Field fEditor = TextView.clreplaced.getDeclaredField("mEditor");
            fEditor.setAccessible(true);
            final Object editor = fEditor.get(editText);
            final Clreplaced<?> cEditor = editor.getClreplaced();
            final Field fSelectHandleL = cEditor.getDeclaredField("mSelectHandleLeft");
            final Field fSelectHandleR = cEditor.getDeclaredField("mSelectHandleRight");
            final Field fSelectHandleC = cEditor.getDeclaredField("mSelectHandleCenter");
            fSelectHandleL.setAccessible(true);
            fSelectHandleR.setAccessible(true);
            fSelectHandleC.setAccessible(true);
            Drawable selectHandleL = ContextCompat.getDrawable(editText.getContext(), hlRes);
            Drawable selectHandleR = ContextCompat.getDrawable(editText.getContext(), hrRes);
            Drawable selectHandleC = ContextCompat.getDrawable(editText.getContext(), hcRes);
            selectHandleL.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
            selectHandleR.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
            selectHandleC.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
            fSelectHandleL.set(editor, selectHandleL);
            fSelectHandleR.set(editor, selectHandleR);
            fSelectHandleC.set(editor, selectHandleC);
        } catch (Exception ignored) {
        }
    }

    public static int getThingCardWidth(Context context) {
        int span = 2;
        Resources res = context.getResources();
        float density = res.getDisplayMetrics().density;
        if (res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            span++;
        }
        if (isTablet(context)) {
            span++;
        }
        int basePadding;
        if (!DeviceUtil.hasLollipopApi()) {
            basePadding = (int) (density * 4);
        } else {
            basePadding = (int) (density * 6);
        }
        return (res.getDisplayMetrics().widthPixels - basePadding * 2 * (span + 1)) / span;
    }

    private static SparseArray<StateListDrawable> sSldMap;

    // private static HashMap<Integer, StateListDrawable> sSldMap;
    public static void setRippleColorForCardView(CardView cardView, int color) {
        if (DeviceUtil.hasLollipopApi()) {
            RippleDrawable rp = (RippleDrawable) cardView.getForeground();
            rp.setColor(ColorStateList.valueOf(color));
        } else {
            if (sSldMap == null) {
                sSldMap = new SparseArray<>();
            }
            StateListDrawable sld = sSldMap.get(color);
            if (sld == null) {
                sld = new StateListDrawable();
                sld.addState(new int[] { android.R.attr.state_pressed }, new ColorDrawable(color));
                sld.addState(new int[] { -android.R.attr.state_pressed }, new ColorDrawable(Color.TRANSPARENT));
                sSldMap.put(color, sld);
            }
            cardView.setForeground(sld);
        }
    }

    public static void setSeekBarColor(SeekBar seekBar, int color) {
        if (DeviceUtil.hasLollipopApi()) {
            seekBar.setProgressTintList(ColorStateList.valueOf(color));
        } else {
            seekBar.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
        }
        seekBar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN);
    }

    public static void setButtonColor(Button button, int color) {
        button.getBackground().setColorFilter(color, PorterDuff.Mode.MULTIPLY);
    }

    public static void setCheckBoxColor(AppCompatCheckBox checkBox, int accentColor) {
        setCheckBoxColor(checkBox, ContextCompat.getColor(checkBox.getContext(), R.color.black_54), accentColor);
    }

    public static void setCheckBoxColor(AppCompatCheckBox checkBox, int uncheckedColor, int checkedColor) {
        ColorStateList colorStateList = new ColorStateList(new int[][] { // unchecked
        new int[] { -android.R.attr.state_checked }, // checked
        new int[] { android.R.attr.state_checked } }, new int[] { uncheckedColor, checkedColor });
        checkBox.setSupportButtonTintList(colorStateList);
    }

    public static int getCursorY(EditText et) {
        int pos = et.getSelectionStart();
        Layout layout = et.getLayout();
        int line = layout.getLineForOffset(pos);
        int baseline = layout.getLineBaseline(line);
        int ascent = layout.getLineAscent(line);
        return baseline + ascent;
    }
}

19 Source : EverythingDoneBaseActivity.java
with GNU General Public License v3.0
from ywwynm

/**
 * Created by ywwynm on 2015/6/4.
 * A base Activity clreplaced to reduce same codes in different subclreplacedes.
 */
public abstract clreplaced EverythingDoneBaseActivity extends AppCompatActivity {

    public static final String TAG = "EverythingDoneBaseActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Call this before setContentView so that NavigationView can update its language correctly.
        LocaleUtil.changeLanguage();
        beforeSetContentView();
        setContentView(getLayoutResource());
        beforeInit();
        init();
    }

    @SuppressWarnings("unchecked")
    protected final <T extends View> T f(@IdRes int id) {
        return (T) findViewById(id);
    }

    @SuppressWarnings("unchecked")
    protected final <T extends View> T f(View v, @IdRes int id) {
        return (T) v.findViewById(id);
    }

    protected void beforeSetContentView() {
    }

    @LayoutRes
    protected abstract int getLayoutResource();

    protected void beforeInit() {
    }

    protected void init() {
        initMembers();
        findViews();
        initUI();
        setActionbar();
        setEvents();
    }

    protected abstract void initMembers();

    protected abstract void findViews();

    protected abstract void initUI();

    protected abstract void setActionbar();

    protected abstract void setEvents();

    private SparseArray<PermissionCallback> mCallbacks;

    public void doWithPermissionChecked(@NonNull PermissionCallback permissionCallback, int requestCode, String... permissions) {
        if (DeviceUtil.hasMarshmallowApi()) {
            if (mCallbacks == null) {
                mCallbacks = new SparseArray<>();
            }
            for (String permission : permissions) {
                int pg = ContextCompat.checkSelfPermission(this, permission);
                if (pg != PackageManager.PERMISSION_GRANTED) {
                    mCallbacks.put(requestCode, permissionCallback);
                    ActivityCompat.requestPermissions(this, permissions, requestCode);
                    return;
                }
            }
        }
        permissionCallback.onGranted();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        PermissionCallback callback = mCallbacks.get(requestCode);
        if (callback != null) {
            for (int grantResult : grantResults) {
                if (grantResult != PackageManager.PERMISSION_GRANTED) {
                    callback.onDenied();
                    return;
                }
            }
            callback.onGranted();
        }
    }
}

19 Source : LoadingRendererFactory.java
with Apache License 2.0
from Yuphee

public final clreplaced LoadingRendererFactory {

    private static final SparseArray<Clreplaced<? extends LoadingRenderer>> LOADING_RENDERERS = new SparseArray<>();

    static {
        // circle rotate
        // LOADING_RENDERERS.put(0, MaterialLoadingRenderer.clreplaced);
        // LOADING_RENDERERS.put(1, LevelLoadingRenderer.clreplaced);
        // LOADING_RENDERERS.put(2, WhorlLoadingRenderer.clreplaced);
        // LOADING_RENDERERS.put(3, GearLoadingRenderer.clreplaced);
        // //circle jump
        // LOADING_RENDERERS.put(4, SwapLoadingRenderer.clreplaced);
        // LOADING_RENDERERS.put(5, GuardLoadingRenderer.clreplaced);
        // LOADING_RENDERERS.put(6, DanceLoadingRenderer.clreplaced);
        // LOADING_RENDERERS.put(7, CollisionLoadingRenderer.clreplaced);
        // //scenery
        // LOADING_RENDERERS.put(8, DayNightLoadingRenderer.clreplaced);
        LOADING_RENDERERS.put(9, ElectricFanLoadingRenderer.clreplaced);
    // animal
    // LOADING_RENDERERS.put(10, FishLoadingRenderer.clreplaced);
    // LOADING_RENDERERS.put(11, GhostsEyeLoadingRenderer.clreplaced);
    // //goods
    // LOADING_RENDERERS.put(12, BalloonLoadingRenderer.clreplaced);
    // LOADING_RENDERERS.put(13, WaterBottleLoadingRenderer.clreplaced);
    // //shape change
    // LOADING_RENDERERS.put(14, CircleBroodLoadingRenderer.clreplaced);
    // LOADING_RENDERERS.put(15, CoolWaitLoadingRenderer.clreplaced);
    }

    private LoadingRendererFactory() {
    }

    public static LoadingRenderer createLoadingRenderer(Context context, int loadingRendererId) throws Exception {
        Clreplaced<?> loadingRendererClazz = LOADING_RENDERERS.get(loadingRendererId);
        Constructor<?>[] constructors = loadingRendererClazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            Clreplaced<?>[] parameterTypes = constructor.getParameterTypes();
            if (parameterTypes != null && parameterTypes.length == 1 && parameterTypes[0].equals(Context.clreplaced)) {
                constructor.setAccessible(true);
                return (LoadingRenderer) constructor.newInstance(context);
            }
        }
        throw new InstantiationException();
    }
}

19 Source : ExternalViewerButton.java
with Apache License 2.0
from Yuloran

/**
 * This is a custom image button that launches an external viewer. It changes its
 * image resource based on the current viewer type (photosphere, refocus, etc).
 * Also, it tracks whether it is shown by tracking the visibility change of all
 * its ancestors, and keep the visibility of the clings that are registered to the
 * button in sync.
 */
public clreplaced ExternalViewerButton extends ImageButton {

    private static final Log.Tag TAG = new Log.Tag("ExtViewerButton");

    private int mState = CameraAppUI.BottomPanel.VIEWER_NONE;

    private final SparseArray<Cling> mClingMap;

    public ExternalViewerButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        mClingMap = new SparseArray<Cling>();
        updateClingVisibility();
    }

    @Override
    protected void onVisibilityChanged(View v, int visibility) {
        super.onVisibilityChanged(v, visibility);
        if (mClingMap == null) {
            return;
        }
        updateClingVisibility();
    }

    /**
     * Sets cling of the given viewer type for external viewer button.
     */
    public void setClingForViewer(int viewerType, Cling cling) {
        if (cling == null) {
            Log.w(TAG, "Cannot set a null cling for viewer");
            return;
        }
        mClingMap.put(viewerType, cling);
        cling.setReferenceView(this);
    }

    /**
     * Clears cling of the given viewer type for external viewer button.
     */
    public void clearClingForViewer(int viewerType) {
        Cling cling = mClingMap.get(viewerType);
        if (cling == null) {
            Log.w(TAG, "Cling does not exist for the given viewer type: " + viewerType);
        }
        cling.setReferenceView(null);
        mClingMap.remove(viewerType);
    }

    /**
     * Returns a cling for the specified viewer type.
     */
    public Cling getClingForViewer(int viewerType) {
        return mClingMap.get(viewerType);
    }

    /**
     * Sets the current state of the button, which affects the visibility and image
     * resource of the button.
     */
    public void setState(int state) {
        mState = state;
        int newVisibility;
        if (state == CameraAppUI.BottomPanel.VIEWER_NONE) {
            newVisibility = View.GONE;
        } else {
            setImageResource(getViewButtonResource(state));
            newVisibility = View.VISIBLE;
        }
        if (newVisibility != getVisibility()) {
            setVisibility(newVisibility);
        } else if (newVisibility == View.VISIBLE) {
            // If visibility has changed, cling visibility was updated already,
            // so only need to update it when visibility has not changed.
            updateClingVisibility();
        }
    }

    /**
     * Sets all the clings to be invisible.
     */
    public void hideClings() {
        for (int i = 0; i < mClingMap.size(); i++) {
            mClingMap.valueAt(i).setVisibility(View.INVISIBLE);
        }
    }

    /**
     * Gets the image resource for a specific state.
     */
    private int getViewButtonResource(int state) {
        switch(state) {
            case CameraAppUI.BottomPanel.VIEWER_REFOCUS:
                return R.drawable.ic_refocus_normal;
            case CameraAppUI.BottomPanel.VIEWER_PHOTO_SPHERE:
                return R.drawable.ic_view_photosphere;
            default:
                return R.drawable.ic_control_play;
        }
    }

    /**
     * Updates the visibility of clings based on whether the button is currently
     * shown.
     */
    public void updateClingVisibility() {
        hideClings();
        if (isShown()) {
            Cling cling = mClingMap.get(mState);
            if (cling != null) {
                cling.adjustPosition();
                cling.setVisibility(View.VISIBLE);
            }
        }
    }
}

19 Source : SettingsUtil.java
with Apache License 2.0
from Yuloran

/**
 * Utility functions around camera settings.
 */
public clreplaced SettingsUtil {

    /**
     * Returns the maximum video recording duration (in milliseconds).
     */
    public static int getMaxVideoDuration(Context context) {
        // in milliseconds, 0 means unlimited.
        int duration = 0;
        try {
            duration = context.getResources().getInteger(R.integer.max_video_recording_length);
        } catch (Resources.NotFoundException ex) {
        }
        return duration;
    }

    /**
     * The selected Camera sizes.
     */
    public static clreplaced SelectedPictureSizes {

        public Size large;

        public Size medium;

        public Size small;

        /**
         * This takes a string preference describing the desired resolution and
         * returns the camera size it represents. <br/>
         * It supports historical values of SIZE_LARGE, SIZE_MEDIUM, and
         * SIZE_SMALL as well as resolutions separated by an x i.e. "1024x576" <br/>
         * If it fails to parse the string, it will return the old SIZE_LARGE
         * value.
         *
         * @param sizeSetting    the preference string to convert to a size
         * @param supportedSizes all possible camera sizes that are supported
         * @return the size that this setting represents
         */
        public Size getFromSetting(String sizeSetting, List<Size> supportedSizes) {
            if (SIZE_LARGE.equals(sizeSetting)) {
                return large;
            } else if (SIZE_MEDIUM.equals(sizeSetting)) {
                return medium;
            } else if (SIZE_SMALL.equals(sizeSetting)) {
                return small;
            } else if (sizeSetting != null && sizeSetting.split("x").length == 2) {
                Size desiredSize = sizeFromSettingString(sizeSetting);
                if (supportedSizes.contains(desiredSize)) {
                    return desiredSize;
                }
            }
            return large;
        }

        @Override
        public String toString() {
            return "SelectedPictureSizes: " + large + ", " + medium + ", " + small;
        }
    }

    /**
     * The selected {@link CamcorderProfile} qualities.
     */
    public static clreplaced SelectedVideoQualities {

        public int large = -1;

        public int medium = -1;

        public int small = -1;

        public int getFromSetting(String sizeSetting) {
            // Sanitize the value to be either small, medium or large. Default
            // to the latter.
            if (!SIZE_SMALL.equals(sizeSetting) && !SIZE_MEDIUM.equals(sizeSetting)) {
                sizeSetting = SIZE_LARGE;
            }
            if (SIZE_LARGE.equals(sizeSetting)) {
                return large;
            } else if (SIZE_MEDIUM.equals(sizeSetting)) {
                return medium;
            } else {
                return small;
            }
        }
    }

    private static final Log.Tag TAG = new Log.Tag("SettingsUtil");

    /**
     * Enable debug output.
     */
    private static final boolean DEBUG = false;

    private static final String SIZE_LARGE = "large";

    private static final String SIZE_MEDIUM = "medium";

    private static final String SIZE_SMALL = "small";

    /**
     * The ideal "medium" picture size is 50% of "large".
     */
    private static final float MEDIUM_RELATIVE_PICTURE_SIZE = 0.5f;

    /**
     * The ideal "small" picture size is 25% of "large".
     */
    private static final float SMALL_RELATIVE_PICTURE_SIZE = 0.25f;

    /**
     * Video qualities sorted by size.
     */
    public static int[] sVideoQualities = new int[] { CamcorderProfile.QUALITY_2160P, CamcorderProfile.QUALITY_1080P, CamcorderProfile.QUALITY_720P, CamcorderProfile.QUALITY_480P, CamcorderProfile.QUALITY_CIF, CamcorderProfile.QUALITY_QVGA, CamcorderProfile.QUALITY_QCIF };

    public static SparseArray<SelectedPictureSizes> sCachedSelectedPictureSizes = new SparseArray<SelectedPictureSizes>(2);

    public static SparseArray<SelectedVideoQualities> sCachedSelectedVideoQualities = new SparseArray<SelectedVideoQualities>(2);

    /**
     * Based on the selected size, this method returns the matching concrete
     * resolution.
     *
     * @param sizeSetting The setting selected by the user. One of "large",
     *                    "medium, "small".
     * @param supported   The list of supported resolutions.
     * @param cameraId    This is used for caching the results for finding the
     *                    different sizes.
     */
    public static Size getPhotoSize(String sizeSetting, List<Size> supported, int cameraId) {
        if (ResolutionUtil.NEXUS_5_LARGE_16_BY_9.equals(sizeSetting)) {
            return ResolutionUtil.NEXUS_5_LARGE_16_BY_9_SIZE;
        }
        Size selectedSize = getCameraPictureSize(sizeSetting, supported, cameraId);
        return selectedSize;
    }

    /**
     * Based on the selected size (large, medium or small), and the list of
     * supported resolutions, this method selects and returns the best matching
     * picture size.
     *
     * @param sizeSetting The setting selected by the user. One of "large",
     *                    "medium, "small".
     * @param supported   The list of supported resolutions.
     * @param cameraId    This is used for caching the results for finding the
     *                    different sizes.
     * @return The selected size.
     */
    private static Size getCameraPictureSize(String sizeSetting, List<Size> supported, int cameraId) {
        return getSelectedCameraPictureSizes(supported, cameraId).getFromSetting(sizeSetting, supported);
    }

    /**
     * Based on the list of supported resolutions, this method selects the ones
     * that shall be selected for being 'large', 'medium' and 'small'.
     *
     * @return It's guaranteed that all three sizes are filled. If less than
     * three sizes are supported, the selected sizes might contain
     * duplicates.
     */
    static SelectedPictureSizes getSelectedCameraPictureSizes(List<Size> supported, int cameraId) {
        List<Size> supportedCopy = new LinkedList<Size>(supported);
        if (sCachedSelectedPictureSizes.get(cameraId) != null) {
            return sCachedSelectedPictureSizes.get(cameraId);
        }
        if (supportedCopy == null) {
            return null;
        }
        SelectedPictureSizes selectedSizes = new SelectedPictureSizes();
        // Sort supported sizes by total pixel count, descending.
        Collections.sort(supportedCopy, new Comparator<Size>() {

            @Override
            public int compare(Size lhs, Size rhs) {
                int leftArea = lhs.width() * lhs.height();
                int rightArea = rhs.width() * rhs.height();
                return rightArea - leftArea;
            }
        });
        if (DEBUG) {
            Log.d(TAG, "Supported Sizes:");
            for (Size size : supportedCopy) {
                Log.d(TAG, " --> " + size.width() + "x" + size.height() + "  " + ((size.width() * size.height()) / 1000000f) + " - " + (size.width() / (float) size.height()));
            }
        }
        // Large size is always the size with the most pixels reported.
        selectedSizes.large = supportedCopy.remove(0);
        // If possible we want to find medium and small sizes with the same
        // aspect ratio as 'large'.
        final float targetAspectRatio = selectedSizes.large.width() / (float) selectedSizes.large.height();
        // Create a list of sizes with the same aspect ratio as "large" which we
        // will search in primarily.
        ArrayList<Size> aspectRatioMatches = new ArrayList<Size>();
        for (Size size : supportedCopy) {
            float aspectRatio = size.width() / (float) size.height();
            // Allow for small rounding errors in aspect ratio.
            if (Math.abs(aspectRatio - targetAspectRatio) < 0.01) {
                aspectRatioMatches.add(size);
            }
        }
        // If we have at least two more resolutions that match the 'large'
        // aspect ratio, use that list to find small and medium sizes. If not,
        // use the full list with any aspect ratio.
        final List<Size> searchList = (aspectRatioMatches.size() >= 2) ? aspectRatioMatches : supportedCopy;
        // Edge cases: If there are no further supported resolutions, use the
        // only one we have.
        // If there is only one remaining, use it for small and medium. If there
        // are two, use the two for small and medium.
        // These edge cases should never happen on a real device, but might
        // happen on test devices and emulators.
        if (searchList.isEmpty()) {
            Log.w(TAG, "Only one supported resolution.");
            selectedSizes.medium = selectedSizes.large;
            selectedSizes.small = selectedSizes.large;
        } else if (searchList.size() == 1) {
            Log.w(TAG, "Only two supported resolutions.");
            selectedSizes.medium = searchList.get(0);
            selectedSizes.small = searchList.get(0);
        } else if (searchList.size() == 2) {
            Log.w(TAG, "Exactly three supported resolutions.");
            selectedSizes.medium = searchList.get(0);
            selectedSizes.small = searchList.get(1);
        } else {
            // Based on the large pixel count, determine the target pixel count
            // for medium and small.
            final int largePixelCount = selectedSizes.large.width() * selectedSizes.large.height();
            final int mediumTargetPixelCount = (int) (largePixelCount * MEDIUM_RELATIVE_PICTURE_SIZE);
            final int smallTargetPixelCount = (int) (largePixelCount * SMALL_RELATIVE_PICTURE_SIZE);
            int mediumSizeIndex = findClosestSize(searchList, mediumTargetPixelCount);
            int smallSizeIndex = findClosestSize(searchList, smallTargetPixelCount);
            // If the selected sizes are the same, move the small size one down
            // or
            // the medium size one up.
            if (searchList.get(mediumSizeIndex).equals(searchList.get(smallSizeIndex))) {
                if (smallSizeIndex < (searchList.size() - 1)) {
                    smallSizeIndex += 1;
                } else {
                    mediumSizeIndex -= 1;
                }
            }
            selectedSizes.medium = searchList.get(mediumSizeIndex);
            selectedSizes.small = searchList.get(smallSizeIndex);
        }
        sCachedSelectedPictureSizes.put(cameraId, selectedSizes);
        return selectedSizes;
    }

    /**
     * Determines the video quality for large/medium/small for the given camera.
     * Returns the one matching the given setting. Defaults to 'large' of the
     * qualitySetting does not match either large. medium or small.
     *
     * @param qualitySetting One of 'large', 'medium', 'small'.
     * @param cameraId       The ID of the camera for which to get the quality
     *                       setting.
     * @return The CamcorderProfile quality setting.
     */
    public static int getVideoQuality(String qualitySetting, int cameraId) {
        return getSelectedVideoQualities(cameraId).getFromSetting(qualitySetting);
    }

    static SelectedVideoQualities getSelectedVideoQualities(int cameraId) {
        if (sCachedSelectedVideoQualities.get(cameraId) != null) {
            return sCachedSelectedVideoQualities.get(cameraId);
        }
        // Go through the sizes in descending order, see if they are supported,
        // and set large/medium/small accordingly.
        // If no quality is supported at all, the first call to
        // getNextSupportedQuality will throw an exception.
        // If only one quality is supported, then all three selected qualities
        // will be the same.
        int largeIndex = getNextSupportedVideoQualityIndex(cameraId, -1);
        int mediumIndex = getNextSupportedVideoQualityIndex(cameraId, largeIndex);
        int smallIndex = getNextSupportedVideoQualityIndex(cameraId, mediumIndex);
        SelectedVideoQualities selectedQualities = new SelectedVideoQualities();
        selectedQualities.large = sVideoQualities[largeIndex];
        selectedQualities.medium = sVideoQualities[mediumIndex];
        selectedQualities.small = sVideoQualities[smallIndex];
        sCachedSelectedVideoQualities.put(cameraId, selectedQualities);
        return selectedQualities;
    }

    /**
     * Starting from 'start' this method returns the next supported video
     * quality.
     */
    private static int getNextSupportedVideoQualityIndex(int cameraId, int start) {
        for (int i = start + 1; i < sVideoQualities.length; ++i) {
            if (isVideoQualitySupported(sVideoQualities[i]) && CamcorderProfile.hasProfile(cameraId, sVideoQualities[i])) {
                // We found a new supported quality.
                return i;
            }
        }
        // Failed to find another supported quality.
        if (start < 0 || start >= sVideoQualities.length) {
            // This means we couldn't find any supported quality.
            throw new IllegalArgumentException("Could not find supported video qualities.");
        }
        // We previously found a larger supported size. In this edge case, just
        // return the same index as the previous size.
        return start;
    }

    /**
     * @return Whether the given {@link CamcorderProfile} is supported on the
     * current device/OS version.
     */
    private static boolean isVideoQualitySupported(int videoQuality) {
        // 4k is only supported on L or higher but some devices falsely report
        // to have support for it on K, see b/18172081.
        if (!ApiHelper.isLOrHigher() && videoQuality == CamcorderProfile.QUALITY_2160P) {
            return false;
        }
        return true;
    }

    /**
     * Returns the index of the size within the given list that is closest to
     * the given target pixel count.
     */
    private static int findClosestSize(List<Size> sortedSizes, int targetPixelCount) {
        int closestMatchIndex = 0;
        int closestMatchPixelCountDiff = Integer.MAX_VALUE;
        for (int i = 0; i < sortedSizes.size(); ++i) {
            Size size = sortedSizes.get(i);
            int pixelCountDiff = Math.abs((size.width() * size.height()) - targetPixelCount);
            if (pixelCountDiff < closestMatchPixelCountDiff) {
                closestMatchIndex = i;
                closestMatchPixelCountDiff = pixelCountDiff;
            }
        }
        return closestMatchIndex;
    }

    private static final String SIZE_SETTING_STRING_DIMENSION_DELIMITER = "x";

    /**
     * This is used to serialize a size to a string for storage in settings
     *
     * @param size The size to serialize.
     * @return the string to be saved in preferences
     */
    public static String sizeToSettingString(Size size) {
        return size.width() + SIZE_SETTING_STRING_DIMENSION_DELIMITER + size.height();
    }

    /**
     * This parses a setting string and returns the representative size.
     *
     * @param sizeSettingString The string that stored in settings to represent a size.
     * @return the represented Size.
     */
    public static Size sizeFromSettingString(String sizeSettingString) {
        if (sizeSettingString == null) {
            return null;
        }
        String[] parts = sizeSettingString.split(SIZE_SETTING_STRING_DIMENSION_DELIMITER);
        if (parts.length != 2) {
            return null;
        }
        try {
            int width = Integer.parseInt(parts[0]);
            int height = Integer.parseInt(parts[1]);
            return new Size(width, height);
        } catch (NumberFormatException ex) {
            return null;
        }
    }

    /**
     * Updates an AlertDialog.Builder to explain what it means to enable
     * location on captures.
     */
    public static AlertDialog.Builder getFirstTimeLocationAlertBuilder(AlertDialog.Builder builder, Callback<Boolean> callback) {
        if (callback == null) {
            return null;
        }
        getLocationAlertBuilder(builder, callback).setMessage(R.string.remember_location_prompt);
        return builder;
    }

    /**
     * Updates an AlertDialog.Builder for choosing whether to include location
     * on captures.
     */
    public static AlertDialog.Builder getLocationAlertBuilder(AlertDialog.Builder builder, final Callback<Boolean> callback) {
        if (callback == null) {
            return null;
        }
        builder.setreplacedle(R.string.remember_location_replacedle).setPositiveButton(R.string.remember_location_yes, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int arg1) {
                callback.onCallback(true);
            }
        }).setNegativeButton(R.string.remember_location_no, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int arg1) {
                callback.onCallback(false);
            }
        });
        return builder;
    }

    /**
     * Gets the first (lowest-indexed) camera matching the given criterion.
     *
     * @param facing Either {@link CAMERA_FACING_BACK}, {@link CAMERA_FACING_FRONT}, or some other
     *               implementation of {@link CameraDeviceSelector}.
     * @return The ID of the first camera matching the supplied criterion, or
     * -1, if no camera meeting the specification was found.
     */
    public static int getCameraId(CameraDeviceInfo info, CameraDeviceSelector chooser) {
        if (info == null) {
            return -1;
        }
        int numCameras = info.getNumberOfCameras();
        for (int i = 0; i < numCameras; ++i) {
            CameraDeviceInfo.Characteristics props = info.getCharacteristics(i);
            if (props == null) {
                // Skip this device entry
                continue;
            }
            if (chooser.useCamera(props)) {
                return i;
            }
        }
        return -1;
    }

    public static interface CameraDeviceSelector {

        /**
         * Given the static characteristics of a specific camera device, decide whether it is the
         * one we will use.
         *
         * @param info The static characteristics of a device.
         * @return Whether we're electing to use this particular device.
         */
        public boolean useCamera(CameraDeviceInfo.Characteristics info);
    }

    public static final CameraDeviceSelector CAMERA_FACING_BACK = new CameraDeviceSelector() {

        @Override
        public boolean useCamera(CameraDeviceInfo.Characteristics info) {
            return info.isFacingBack();
        }
    };

    public static final CameraDeviceSelector CAMERA_FACING_FRONT = new CameraDeviceSelector() {

        @Override
        public boolean useCamera(CameraDeviceInfo.Characteristics info) {
            return info.isFacingFront();
        }
    };
}

19 Source : ModuleManagerImpl.java
with Apache License 2.0
from Yuloran

/**
 * A clreplaced which implements {@link com.android.camera.app.ModuleManager}.
 */
public clreplaced ModuleManagerImpl implements ModuleManager {

    private static final Log.Tag TAG = new Log.Tag("ModuleManagerImpl");

    private final SparseArray<ModuleAgent> mRegisteredModuleAgents = new SparseArray<ModuleAgent>(2);

    private int mDefaultModuleId = MODULE_INDEX_NONE;

    public ModuleManagerImpl() {
    }

    @Override
    public void registerModule(ModuleAgent agent) {
        if (agent == null) {
            throw new NullPointerException("Registering a null ModuleAgent.");
        }
        final int moduleId = agent.getModuleId();
        if (moduleId == MODULE_INDEX_NONE) {
            throw new IllegalArgumentException("ModuleManager: The module ID can not be " + "MODULE_INDEX_NONE");
        }
        if (mRegisteredModuleAgents.get(moduleId) != null) {
            throw new IllegalArgumentException("Module ID is registered already:" + moduleId);
        }
        mRegisteredModuleAgents.put(moduleId, agent);
    }

    @Override
    public boolean unregisterModule(int moduleId) {
        if (mRegisteredModuleAgents.get(moduleId) == null) {
            return false;
        }
        mRegisteredModuleAgents.delete(moduleId);
        if (moduleId == mDefaultModuleId) {
            mDefaultModuleId = -1;
        }
        return true;
    }

    @Override
    public List<ModuleAgent> getRegisteredModuleAgents() {
        List<ModuleAgent> agents = new ArrayList<ModuleAgent>();
        for (int i = 0; i < mRegisteredModuleAgents.size(); i++) {
            agents.add(mRegisteredModuleAgents.valueAt(i));
        }
        return agents;
    }

    @Override
    public List<Integer> getSupportedModeIndexList() {
        List<Integer> modeIndexList = new ArrayList<Integer>();
        for (int i = 0; i < mRegisteredModuleAgents.size(); i++) {
            modeIndexList.add(mRegisteredModuleAgents.keyAt(i));
        }
        return modeIndexList;
    }

    @Override
    public boolean setDefaultModuleIndex(int moduleId) {
        if (mRegisteredModuleAgents.get(moduleId) != null) {
            mDefaultModuleId = moduleId;
            return true;
        }
        return false;
    }

    @Override
    public int getDefaultModuleIndex() {
        return mDefaultModuleId;
    }

    @Override
    public ModuleAgent getModuleAgent(int moduleId) {
        ModuleAgent agent = mRegisteredModuleAgents.get(moduleId);
        if (agent == null) {
            return mRegisteredModuleAgents.get(mDefaultModuleId);
        }
        return agent;
    }

    @Override
    public int getQuickSwitchToModuleId(int moduleId, SettingsManager settingsManager, Context context) {
        final int photoModuleId = context.getResources().getInteger(R.integer.camera_mode_photo);
        final int videoModuleId = context.getResources().getInteger(R.integer.camera_mode_video);
        int quickSwitchTo = moduleId;
        if (moduleId == photoModuleId || moduleId == context.getResources().getInteger(R.integer.camera_mode_gcam)) {
            // Quick switch from camera to video.
            quickSwitchTo = videoModuleId;
        } else if (moduleId == videoModuleId) {
            // Quick switch from video to last used camera (i.e. simple camera or hdr+)
            quickSwitchTo = settingsManager.getInteger(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_MODULE_LAST_USED);
        }
        if (mRegisteredModuleAgents.get(quickSwitchTo) != null) {
            return quickSwitchTo;
        } else {
            return moduleId;
        }
    }
}

19 Source : MediaItemsLoader.java
with Apache License 2.0
from yuchuangu85

/**
 * Returns all MediaItems in a MediaSet, wrapping them in a cursor to appear
 * like a PhotoSetLoader
 */
public clreplaced MediaItemsLoader extends AsyncTaskLoader<Cursor> implements LoaderCompatShim<Cursor> {

    private static final SyncListener sNullListener = new SyncListener() {

        @Override
        public void onSyncDone(MediaSet mediaSet, int resultCode) {
        }
    };

    private final MediaSet mMediaSet;

    private final DataManager mDataManager;

    private Future<Integer> mSyncTask = null;

    private ContentListener mObserver = new ContentListener() {

        @Override
        public void onContentDirty() {
            onContentChanged();
        }
    };

    private SparseArray<MediaItem> mMediaItems;

    public MediaItemsLoader(Context context) {
        super(context);
        mDataManager = DataManager.from(context);
        String path = mDataManager.getTopSetPath(DataManager.INCLUDE_ALL);
        mMediaSet = mDataManager.getMediaSet(path);
    }

    public MediaItemsLoader(Context context, String parentPath) {
        super(context);
        mDataManager = DataManager.from(getContext());
        mMediaSet = mDataManager.getMediaSet(parentPath);
    }

    @Override
    protected void onStartLoading() {
        super.onStartLoading();
        mMediaSet.addContentListener(mObserver);
        mSyncTask = mMediaSet.requestSync(sNullListener);
        forceLoad();
    }

    @Override
    protected boolean onCancelLoad() {
        if (mSyncTask != null) {
            mSyncTask.cancel();
            mSyncTask = null;
        }
        return super.onCancelLoad();
    }

    @Override
    protected void onStopLoading() {
        super.onStopLoading();
        cancelLoad();
        mMediaSet.removeContentListener(mObserver);
    }

    @Override
    protected void onReset() {
        super.onReset();
        onStopLoading();
    }

    @Override
    public Cursor loadInBackground() {
        // TODO: This probably doesn't work
        mMediaSet.reload();
        final MatrixCursor cursor = new MatrixCursor(PhotoSetLoader.PROJECTION);
        final Object[] row = new Object[PhotoSetLoader.PROJECTION.length];
        final SparseArray<MediaItem> mediaItems = new SparseArray<MediaItem>();
        mMediaSet.enumerateTotalMediaItems(new ItemConsumer() {

            @Override
            public void consume(int index, MediaItem item) {
                row[PhotoSetLoader.INDEX_ID] = index;
                row[PhotoSetLoader.INDEX_DATA] = item.getContentUri().toString();
                row[PhotoSetLoader.INDEX_DATE_ADDED] = item.getDateInMs();
                row[PhotoSetLoader.INDEX_HEIGHT] = item.getHeight();
                row[PhotoSetLoader.INDEX_WIDTH] = item.getWidth();
                row[PhotoSetLoader.INDEX_WIDTH] = item.getWidth();
                int rawMediaType = item.getMediaType();
                int mappedMediaType = FileColumns.MEDIA_TYPE_NONE;
                if (rawMediaType == MediaItem.MEDIA_TYPE_IMAGE) {
                    mappedMediaType = FileColumns.MEDIA_TYPE_IMAGE;
                } else if (rawMediaType == MediaItem.MEDIA_TYPE_VIDEO) {
                    mappedMediaType = FileColumns.MEDIA_TYPE_VIDEO;
                }
                row[PhotoSetLoader.INDEX_MEDIA_TYPE] = mappedMediaType;
                row[PhotoSetLoader.INDEX_SUPPORTED_OPERATIONS] = item.getSupportedOperations();
                cursor.addRow(row);
                mediaItems.append(index, item);
            }
        });
        synchronized (mMediaSet) {
            mMediaItems = mediaItems;
        }
        return cursor;
    }

    @Override
    public Drawable drawableForItem(Cursor item, Drawable recycle) {
        BitmapJobDrawable drawable = null;
        if (recycle == null || !(recycle instanceof BitmapJobDrawable)) {
            drawable = new BitmapJobDrawable();
        } else {
            drawable = (BitmapJobDrawable) recycle;
        }
        int index = item.getInt(PhotoSetLoader.INDEX_ID);
        drawable.setMediaItem(mMediaItems.get(index));
        return drawable;
    }

    public static int getThumbnailSize() {
        return MediaItem.getTargetSize(MediaItem.TYPE_MICROTHUMBNAIL);
    }

    @Override
    public Uri uriForItem(Cursor item) {
        int index = item.getInt(PhotoSetLoader.INDEX_ID);
        MediaItem mi = mMediaItems.get(index);
        return mi == null ? null : mi.getContentUri();
    }

    @Override
    public ArrayList<Uri> urisForSubItems(Cursor item) {
        return null;
    }

    @Override
    public void deleteItemWithPath(Object path) {
        MediaObject o = mDataManager.getMediaObject((Path) path);
        if (o != null) {
            o.delete();
        }
    }

    @Override
    public Object getPathForItem(Cursor item) {
        int index = item.getInt(PhotoSetLoader.INDEX_ID);
        MediaItem mi = mMediaItems.get(index);
        if (mi != null) {
            return mi.getPath();
        }
        return null;
    }
}

See More Examples