package wb.android.flex; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.EditText; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import wb.android.storage.InternalStorageManager; import wb.android.storage.StorageManager; public class Flex { private static final String TAG = "FLEX"; static final boolean D = true; private static final String FLEX_PREFERENCES = "Flex_Preferences"; private static final String STRING_FLEX_FILE = "FlexFile"; private static final String DEFAULT_FILENAME = "Flex.xml"; private FlexViews mFlexViews; private FlexStrings mFlexStrings; public Flex(Context context, Flexable flexable) { int rawID = flexable.getFleXML(); //Try to find an old flex file SharedPreferences prefs = context.getSharedPreferences(FLEX_PREFERENCES, 0); if (prefs != null) { // This check is really just to avoid RoboElectric failures String flexFilePath = prefs.getString(STRING_FLEX_FILE, ""); if (D) Log.d(TAG, flexFilePath); if (this.isFleXMLDefined(rawID)) { InputStream is = context.getResources().openRawResource(rawID); this.parseFleXML(is); //Since this InputStream gets closed here is = context.getResources().openRawResource(rawID); if (flexFilePath.length() > 0) { //A Flex file exists. Let's test if any updates have been applied String rawHash = StorageManager.getMD5Checksum(is); String flexHash = StorageManager.getMD5Checksum(new File(flexFilePath)); if (D) Log.d(TAG, "Raw Hash: " + rawHash); if (D) Log.d(TAG, "Flex Hash: " + flexHash); if (rawHash != null && flexHash != null) { if (!rawHash.equalsIgnoreCase(flexHash)) { //It really should check that the file on Disk has a lesser version number, instead of just auto overwriting writeFlexFileToSD(is, prefs, context); } } else { //Something went wrong. Try writing the file again writeFlexFileToSD(is, prefs, context); } } else { //Write the new Flex File writeFlexFileToSD(is, prefs, context); } try { if (is != null) is.close(); } catch (IOException e) { Log.e(TAG, e.toString()); } } else { if (flexFilePath.length() > 0) { //If a flex file exists. If not, all defaults will be used FileInputStream fis = null; try { fis = new FileInputStream(flexFilePath); this.parseFleXML(fis); fis.close(); } catch (FileNotFoundException e) { Log.e(TAG, "The defined flex file does not exists: " + flexFilePath); } catch (IOException e) { Log.e(TAG, toString()); } finally { try { if (fis != null) fis.close(); } catch (IOException e) { Log.e(TAG, toString()); } } } } } } private final void writeFlexFileToSD(InputStream is, SharedPreferences prefs, Context context) { InternalStorageManager internal = StorageManager.getInternalInstance(context); byte[] data = internal.read(is); internal.write(DEFAULT_FILENAME, data); File flexFile = internal.getFile(DEFAULT_FILENAME); if (flexFile != null && flexFile.exists()) { Editor editor = prefs.edit(); editor.putString(STRING_FLEX_FILE, flexFile.getAbsolutePath()); editor.apply(); if (D) Log.d(TAG, "Wrote the Flex file to: " + flexFile.getAbsolutePath()); } } private final boolean isFleXMLDefined(int rawID) { if (rawID == Flexable.UNDEFINED) { if (D) Log.d(TAG, "No FleXML file was defined. All default data will be used."); return false; } else return true; } public void onResume() { } public void onPause() { } public static final Flex getInstance(Context context, Flexable flexable) { //throws FlexFailedException { return new Flex(context, flexable); } private final void parseFleXML(InputStream is) { try { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); FlexHandler dataHandler = new FlexHandler(this); xr.setContentHandler(dataHandler); xr.parse(new InputSource(is)); } catch(Exception e) { Log.e(TAG, e.toString()); } } public String getString(Context context, int resId) { String string = context.getString(resId); if (mFlexStrings == null) return string; else { String name = context.getResources().getResourceEntryName(resId); return mFlexStrings.update(string, name); } } public String[] getStringArray(Context context, int resID) { return context.getResources().getStringArray(resID); } public View getView(Context context, int layoutID) { return LayoutInflater.from(context).inflate(layoutID, null); } public View getSubView(Context context, View parent, int resId) { View view = parent.findViewById(resId); if (mFlexViews == null) return view; String id = "@+id/" + context.getResources().getResourceEntryName(resId); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; try { mFlexViews.addFlexViewsToParent(context, group, id); } catch (FlexFailedException e) { Log.e(TAG, e.toString()); } } try { if (view instanceof EditText) mFlexViews.updateView((EditText)view, id); else if (view instanceof CheckBox) mFlexViews.updateView((CheckBox)view, id); else mFlexViews.updateView(view, id); } catch (FlexFailedException e) { Log.e(TAG, e.toString()); } return view; } /* public <T extends View> T getSubView(View parent, int resId, Class<T> viewClass) { View view = parent.findViewById(resId); T t = viewClass.cast(view); if (mFlexViews == null) return viewClass.cast(view); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; try { mFlexViews.addFlexViewsToParent(activity, group); } catch (FlexFailedException e) { Log.e(TAG, e.toString()); } } try { if (view instanceof EditText) mFlexViews.updateView((EditText)t); } catch (FlexFailedException e) { e.printStackTrace(); } return t; }*/ void setFlexViews(FlexViews flexViews) { this.mFlexViews = flexViews; } void setFlexStrings(FlexStrings flexStrings) { this.mFlexStrings = flexStrings; } enum Element { FLEX ("Flex"), FLEX_VIEWS ("FlexViews"), FLEX_STRINGS ("FlexStrings"); private String name; private Element(String name) {this.name = name;} boolean isTag(String localName) {return this.name.equalsIgnoreCase(localName); } String tagName() { return this.name; } } /*Attribs * xmlns:android="http://schemas.android.com/apk/res/android" version="1" apkDistURL="www.test.com/app.apk" flexURL="www.test.com/flex.xml" customerID="JC1"> */ }