1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.constraintlayout.motion.widget; 18 19 import android.content.Context; 20 import android.content.res.XmlResourceParser; 21 import android.util.Log; 22 import android.util.Xml; 23 24 import androidx.constraintlayout.widget.ConstraintAttribute; 25 import androidx.constraintlayout.widget.ConstraintLayout; 26 27 import org.xmlpull.v1.XmlPullParser; 28 import org.xmlpull.v1.XmlPullParserException; 29 30 import java.io.IOException; 31 import java.lang.reflect.Constructor; 32 import java.util.ArrayList; 33 import java.util.HashMap; 34 import java.util.Set; 35 36 /** 37 * The parses the KeyFrame structure in a MotionScene xml 38 * 39 */ 40 41 public class KeyFrames { 42 public static final int UNSET = ConstraintLayout.LayoutParams.UNSET; 43 private static final String CUSTOM_METHOD = "CustomMethod"; 44 private static final String CUSTOM_ATTRIBUTE = "CustomAttribute"; 45 private HashMap<Integer, ArrayList<Key>> mFramesMap = new HashMap<Integer, ArrayList<Key>>(); 46 static HashMap<String, Constructor<? extends Key>> sKeyMakers = new HashMap<>(); 47 private static final String TAG = "KeyFrames"; 48 49 static { 50 try { sKeyMakers.put(KeyAttributes.NAME, KeyAttributes.class.getConstructor())51 sKeyMakers.put(KeyAttributes.NAME, KeyAttributes.class.getConstructor()); sKeyMakers.put(KeyPosition.NAME, KeyPosition.class.getConstructor())52 sKeyMakers.put(KeyPosition.NAME, KeyPosition.class.getConstructor()); sKeyMakers.put(KeyCycle.NAME, KeyCycle.class.getConstructor())53 sKeyMakers.put(KeyCycle.NAME, KeyCycle.class.getConstructor()); sKeyMakers.put(KeyTimeCycle.NAME, KeyTimeCycle.class.getConstructor())54 sKeyMakers.put(KeyTimeCycle.NAME, KeyTimeCycle.class.getConstructor()); sKeyMakers.put(KeyTrigger.NAME, KeyTrigger.class.getConstructor())55 sKeyMakers.put(KeyTrigger.NAME, KeyTrigger.class.getConstructor()); 56 57 } catch (NoSuchMethodException e) { 58 Log.e(TAG, "unable to load", e); 59 } 60 } 61 62 /** 63 * Add a key to this set of keyframes 64 * @param key 65 */ addKey(Key key)66 public void addKey(Key key) { 67 if (!mFramesMap.containsKey(key.mTargetId)) { 68 mFramesMap.put(key.mTargetId, new ArrayList<>()); 69 } 70 ArrayList<Key> frames = mFramesMap.get(key.mTargetId); 71 if (frames != null) { 72 frames.add(key); 73 } 74 } 75 KeyFrames()76 public KeyFrames() { 77 78 } 79 KeyFrames(Context context, XmlPullParser parser)80 public KeyFrames(Context context, XmlPullParser parser) { 81 String tagName = null; 82 try { 83 Key key = null; 84 for (int eventType = parser.getEventType(); 85 eventType != XmlResourceParser.END_DOCUMENT; 86 eventType = parser.next()) { 87 switch (eventType) { 88 case XmlResourceParser.START_DOCUMENT: 89 break; 90 case XmlResourceParser.START_TAG: 91 tagName = parser.getName(); 92 93 if (sKeyMakers.containsKey(tagName)) { 94 95 switch (tagName) { 96 case KeyAttributes.NAME: 97 key = new KeyAttributes(); 98 break; 99 case KeyPosition.NAME: 100 key = new KeyPosition(); 101 break; 102 case KeyCycle.NAME: 103 key = new KeyCycle(); 104 break; 105 case KeyTimeCycle.NAME: 106 key = new KeyTimeCycle(); 107 break; 108 case KeyTrigger.NAME: 109 key = new KeyTrigger(); 110 break; 111 default: 112 throw new NullPointerException( 113 "Key " + tagName + " not found"); 114 } 115 key.load(context, Xml.asAttributeSet(parser)); 116 addKey(key); 117 118 } else if (tagName.equalsIgnoreCase(CUSTOM_ATTRIBUTE)) { 119 if (key != null && key.mCustomConstraints != null) { 120 ConstraintAttribute.parse(context, parser, key.mCustomConstraints); 121 } 122 } else if (tagName.equalsIgnoreCase(CUSTOM_METHOD)) { 123 if (key != null && key.mCustomConstraints != null) { 124 ConstraintAttribute.parse(context, parser, key.mCustomConstraints); 125 } 126 } 127 break; 128 case XmlResourceParser.END_TAG: 129 if ("KeyFrameSet".equals(parser.getName())) { 130 return; 131 } 132 break; 133 case XmlResourceParser.TEXT: 134 break; 135 } 136 } 137 } catch (XmlPullParserException e) { 138 Log.e(TAG, "Error parsing XML resource", e); 139 } catch (IOException e) { 140 Log.e(TAG, "Error parsing XML resource", e); 141 } 142 } 143 144 /** 145 * Do not filter the set by matches 146 * @param motionController 147 */ addAllFrames(MotionController motionController)148 public void addAllFrames(MotionController motionController) { 149 ArrayList<Key> list = mFramesMap.get(UNSET); 150 if (list != null) { 151 motionController.addKeys(list); 152 } 153 } 154 155 /** 156 * add the key frames to the motion controller 157 * @param motionController 158 */ addFrames(MotionController motionController)159 public void addFrames(MotionController motionController) { 160 ArrayList<Key> list = mFramesMap.get(motionController.mId); 161 if (list != null) { 162 motionController.addKeys(list); 163 } 164 list = mFramesMap.get(UNSET); 165 166 if (list != null) { 167 for (Key key : list) { 168 String tag = 169 ((ConstraintLayout.LayoutParams) 170 motionController.mView.getLayoutParams()).constraintTag; 171 if (key.matches(tag)) { 172 motionController.addKey(key); 173 } 174 } 175 176 } 177 178 } 179 name(int viewId, Context context)180 static String name(int viewId, Context context) { 181 return context.getResources().getResourceEntryName(viewId); 182 } 183 getKeys()184 public Set<Integer> getKeys() { 185 return mFramesMap.keySet(); 186 } 187 188 /** 189 * Get the list of keyframes given and ID 190 * @param id 191 * @return 192 */ getKeyFramesForView(int id)193 public ArrayList<Key> getKeyFramesForView(int id) { 194 return mFramesMap.get(id); 195 } 196 } 197