KeyFrames.java

/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.constraintlayout.motion.widget;

import android.content.Context;
import android.content.res.XmlResourceParser;
import androidx.constraintlayout.widget.ConstraintAttribute;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.util.Log;
import android.util.Xml;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

/**
 * The parses the KeyFrame structure in a MotionScene xml
 * @suppress
 */

public class KeyFrames {
    public static final int UNSET = ConstraintLayout.LayoutParams.UNSET;
    private static final String CUSTOM_METHOD = "CustomMethod";
    private static final String CUSTOM_ATTRIBUTE = "CustomAttribute";
    private HashMap<Integer, ArrayList<Key>> mFramesMap = new HashMap<Integer, ArrayList<Key>>();
    static HashMap<String, Constructor<? extends Key>> sKeyMakers = new HashMap<>();
    private static final String TAG = "KeyFrames";

    static {
        try {
            sKeyMakers.put(KeyAttributes.NAME, KeyAttributes.class.getConstructor());
            sKeyMakers.put(KeyPosition.NAME, KeyPosition.class.getConstructor());
            sKeyMakers.put(KeyCycle.NAME, KeyCycle.class.getConstructor());
            sKeyMakers.put(KeyTimeCycle.NAME, KeyTimeCycle.class.getConstructor());
            sKeyMakers.put(KeyTrigger.NAME, KeyTrigger.class.getConstructor());

        } catch (NoSuchMethodException e) {
            Log.e(TAG, "unable to load", e);
        }
    }

    public void addKey(Key key) {
        if (!mFramesMap.containsKey(key.mTargetId)) {
            mFramesMap.put(key.mTargetId, new ArrayList<>());
        }
        ArrayList<Key> frames = mFramesMap.get(key.mTargetId);
        if (frames != null) {
            frames.add(key);
        }
    }
    public KeyFrames() {

    }
    public KeyFrames(Context context, XmlPullParser parser) {
        String tagName = null;
        try {
            Key key = null;
            for (int eventType = parser.getEventType();
                 eventType != XmlResourceParser.END_DOCUMENT;
                 eventType = parser.next()) {
                switch (eventType) {
                    case XmlResourceParser.START_DOCUMENT:
                        break;
                    case XmlResourceParser.START_TAG:
                        tagName = parser.getName();

                        if (sKeyMakers.containsKey(tagName)) {
                            try {
                                Constructor<? extends Key> keyMaker = sKeyMakers.get(tagName);
                                if (keyMaker != null) {
                                    key = keyMaker.newInstance();
                                    key.load(context, Xml.asAttributeSet(parser));
                                    addKey(key);
                                } else {
                                    throw new NullPointerException("Keymaker for " + tagName + " not found");
                                }
                            } catch (Exception e) {
                                Log.e(TAG, "unable to create ", e);
                            }
                        } else if (tagName.equalsIgnoreCase(CUSTOM_ATTRIBUTE)) {
                            if (key != null && key.mCustomConstraints != null) {
                                ConstraintAttribute.parse(context, parser, key.mCustomConstraints);
                            }
                        } else if (tagName.equalsIgnoreCase(CUSTOM_METHOD)) {
                            if (key != null && key.mCustomConstraints != null) {
                                ConstraintAttribute.parse(context, parser, key.mCustomConstraints);
                            }
                        }
                        break;
                    case XmlResourceParser.END_TAG:
                        if ("KeyFrameSet".equals(parser.getName())) {
                            return;
                        }
                        break;
                    case XmlResourceParser.TEXT:
                        break;
                }
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Do not filter the set by matches
     * @param motionController
     */
    public void addAllFrames(MotionController motionController) {
        ArrayList<Key> list = mFramesMap.get(UNSET);
        if (list != null) {
            motionController.addKeys(list);
        }
    }

    public void addFrames(MotionController motionController) {
        ArrayList<Key> list = mFramesMap.get(motionController.mId);
        if (list != null) {
            motionController.addKeys(list);
        }
        list = mFramesMap.get(UNSET);

        if (list != null) {
            for (Key key : list) {
                String tag = ((ConstraintLayout.LayoutParams) (motionController.mView.getLayoutParams())).constraintTag;
                if (key.matches(tag)) {
                    motionController.addKey(key);
                }
            }

        }

    }

    static String name(int viewId, Context context) {
        return context.getResources().getResourceEntryName(viewId);
    }

    public Set<Integer> getKeys() {
        return mFramesMap.keySet();
    }

    public ArrayList<Key> getKeyFramesForView(int id) {
        return mFramesMap.get(id);
    }
}