package org.commcare.android.resource.installers; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import org.commcare.AppUtils; import org.commcare.CommCareApp; import org.commcare.logging.AndroidLogger; import org.commcare.android.database.global.models.ApplicationRecord; import org.commcare.resources.model.Resource; import org.commcare.resources.model.ResourceLocation; import org.commcare.resources.model.ResourceTable; import org.commcare.resources.model.UnresolvedResourceException; import org.commcare.suite.model.Profile; import org.commcare.suite.model.PropertySetter; import org.commcare.utils.AndroidCommCarePlatform; import org.commcare.utils.DummyResourceTable; import org.commcare.xml.CommCareElementParser; import org.commcare.xml.ProfileParser; import org.javarosa.core.reference.InvalidReferenceException; import org.javarosa.core.reference.Reference; import org.javarosa.core.reference.ReferenceManager; import org.javarosa.core.services.Logger; import org.javarosa.xml.util.InvalidStructureException; import org.javarosa.xml.util.UnfullfilledRequirementsException; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; /** * @author ctsims */ public class ProfileAndroidInstaller extends FileSystemInstaller { @SuppressWarnings("unused") public ProfileAndroidInstaller() { // For externalization } public ProfileAndroidInstaller(String localDestination, String upgradeDestination) { super(localDestination, upgradeDestination); } @Override public boolean initialize(AndroidCommCarePlatform instance, boolean isUpgrade) { try { Reference local = ReferenceManager.instance().DeriveReference(localLocation); ProfileParser parser = new ProfileParser(local.getStream(), instance, instance.getGlobalResourceTable(), null, Resource.RESOURCE_STATUS_INSTALLED, false); Profile p = parser.parse(); instance.setProfile(p); return true; } catch (UnfullfilledRequirementsException | XmlPullParserException | InvalidStructureException | IOException | InvalidReferenceException e) { e.printStackTrace(); } return false; } @Override public boolean install(Resource r, ResourceLocation location, Reference ref, ResourceTable table, AndroidCommCarePlatform instance, boolean upgrade) throws UnresolvedResourceException, UnfullfilledRequirementsException { //First, make sure all the file stuff is managed. super.install(r, location, ref, table, instance, upgrade); try { Reference local = ReferenceManager.instance().DeriveReference(localLocation); ProfileParser parser = new ProfileParser(local.getStream(), instance, table, r.getRecordGuid(), Resource.RESOURCE_STATUS_UNINITIALIZED, false); Profile p = parser.parse(); if (!upgrade) { initProperties(p); checkDuplicate(p); } table.commitCompoundResource(r, upgrade ? Resource.RESOURCE_STATUS_UPGRADE : Resource.RESOURCE_STATUS_INSTALLED, p.getVersion()); return true; } catch (XmlPullParserException | InvalidReferenceException | IOException e) { e.printStackTrace(); } catch (InvalidStructureException e) { throw new UnresolvedResourceException(r, "Invalid content in the Profile Definition: " + e.getMessage(), true); } return false; } // Check that this app is not already installed on the phone private void checkDuplicate(Profile p) throws UnfullfilledRequirementsException { String newAppId = p.getUniqueId(); ArrayList<ApplicationRecord> installedApps = AppUtils. getInstalledAppRecords(); for (ApplicationRecord record : installedApps) { if (record.getUniqueId().equals(newAppId)) { throw new UnfullfilledRequirementsException( "The app you are trying to install already exists on this device", CommCareElementParser.SEVERITY_PROMPT, true); } } } private void initProperties(Profile profile) { // TODO Baaaaaad. Encapsulate this better!!! SharedPreferences prefs = CommCareApp.currentSandbox.getAppPreferences(); Editor editor = prefs.edit(); for (PropertySetter p : profile.getPropertySetters()) { editor.putString(p.getKey(), p.isForce() ? p.getValue() : prefs.getString(p.getKey(), p.getValue())); } editor.commit(); } @Override public boolean upgrade(Resource r) { if (!super.upgrade(r)) { return false; } try { Reference local = ReferenceManager.instance().DeriveReference(localLocation); //Create a parser with no side effects ProfileParser parser = new ProfileParser(local.getStream(), null, new DummyResourceTable(), null, Resource.RESOURCE_STATUS_INSTALLED, false); //Parse just the file (for the properties) Profile p = parser.parse(); initProperties(p); } catch (InvalidReferenceException e) { e.printStackTrace(); Logger.log(AndroidLogger.TYPE_RESOURCES, "Profile not available after upgrade: " + e.getMessage()); return false; } catch (IOException e) { Logger.log(AndroidLogger.TYPE_RESOURCES, "Profile not available after upgrade: " + e.getMessage()); return false; } catch (InvalidStructureException e) { Logger.log(AndroidLogger.TYPE_RESOURCES, "Profile not available after upgrade: " + e.getMessage()); return false; } catch (UnfullfilledRequirementsException e) { Logger.log(AndroidLogger.TYPE_RESOURCES, "Profile not available after upgrade: " + e.getMessage()); return false; } catch (XmlPullParserException e) { Logger.log(AndroidLogger.TYPE_RESOURCES, "Profile not available after upgrade: " + e.getMessage()); return false; } return true; } @Override protected int customInstall(Resource r, Reference local, boolean upgrade) throws IOException, UnresolvedResourceException { return Resource.RESOURCE_STATUS_LOCAL; } @Override public boolean requiresRuntimeInitialization() { return true; } }