/* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2016 The Catrobat Team * (<http://developer.catrobat.org/credits>) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * An additional term exception under section 7 of the GNU Affero * General Public License, version 3, is available at * http://developer.catrobat.org/license_additional_term * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.catrobat.catroid; import android.app.Activity; import android.app.FragmentManager; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.util.Log; import com.facebook.AccessToken; import org.catrobat.catroid.common.Constants; import org.catrobat.catroid.common.DefaultProjectHandler; import org.catrobat.catroid.common.FileChecksumContainer; import org.catrobat.catroid.common.MessageContainer; import org.catrobat.catroid.common.ScreenModes; import org.catrobat.catroid.content.Project; import org.catrobat.catroid.content.Scene; import org.catrobat.catroid.content.Script; import org.catrobat.catroid.content.Sprite; import org.catrobat.catroid.content.bricks.Brick; import org.catrobat.catroid.content.bricks.IfLogicBeginBrick; import org.catrobat.catroid.content.bricks.IfLogicElseBrick; import org.catrobat.catroid.content.bricks.IfLogicEndBrick; import org.catrobat.catroid.content.bricks.IfThenLogicBeginBrick; import org.catrobat.catroid.content.bricks.IfThenLogicEndBrick; import org.catrobat.catroid.content.bricks.LoopBeginBrick; import org.catrobat.catroid.content.bricks.LoopEndBrick; import org.catrobat.catroid.content.bricks.UserBrick; import org.catrobat.catroid.exceptions.CompatibilityProjectException; import org.catrobat.catroid.exceptions.LoadingProjectException; import org.catrobat.catroid.exceptions.OutdatedVersionProjectException; import org.catrobat.catroid.io.LoadProjectTask; import org.catrobat.catroid.io.LoadProjectTask.OnLoadProjectCompleteListener; import org.catrobat.catroid.io.StorageHandler; import org.catrobat.catroid.transfers.CheckFacebookServerTokenValidityTask; import org.catrobat.catroid.transfers.CheckTokenTask; import org.catrobat.catroid.transfers.CheckTokenTask.OnCheckTokenCompleteListener; import org.catrobat.catroid.transfers.FacebookExchangeTokenTask; import org.catrobat.catroid.ui.SettingsActivity; import org.catrobat.catroid.ui.controller.BackPackListManager; import org.catrobat.catroid.ui.dialogs.SignInDialog; import org.catrobat.catroid.ui.dialogs.UploadProjectDialog; import org.catrobat.catroid.utils.Utils; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public final class ProjectManager implements OnLoadProjectCompleteListener, OnCheckTokenCompleteListener, CheckFacebookServerTokenValidityTask.OnCheckFacebookServerTokenValidityCompleteListener, FacebookExchangeTokenTask.OnFacebookExchangeTokenCompleteListener { private static final ProjectManager INSTANCE = new ProjectManager(); private static final String TAG = ProjectManager.class.getSimpleName(); private Project project; private Scene currentScene; private Scene sceneToPlay; private Scene startScene; private Script currentScript; private Sprite currentSprite; private Sprite previousSprite; private UserBrick currentUserBrick; private boolean asynchronousTask = true; private boolean comingFromScriptFragmentToSoundFragment; private boolean comingFromScriptFragmentToLooksFragment; private boolean handleNewSceneFromScriptActivity; private boolean showUploadDialog = false; private boolean showLegoSensorInfoDialog = true; private FileChecksumContainer fileChecksumContainer = new FileChecksumContainer(); private ProjectManager() { this.comingFromScriptFragmentToSoundFragment = false; this.comingFromScriptFragmentToLooksFragment = false; this.handleNewSceneFromScriptActivity = false; } public static ProjectManager getInstance() { return INSTANCE; } public boolean getComingFromScriptFragmentToSoundFragment() { return this.comingFromScriptFragmentToSoundFragment; } public void setComingFromScriptFragmentToSoundFragment(boolean value) { this.comingFromScriptFragmentToSoundFragment = value; } public boolean getComingFromScriptFragmentToLooksFragment() { return this.comingFromScriptFragmentToLooksFragment; } public void setComingFromScriptFragmentToLooksFragment(boolean value) { this.comingFromScriptFragmentToLooksFragment = value; } public void setHandleNewSceneFromScriptActivity() { handleNewSceneFromScriptActivity = true; } public boolean getHandleNewSceneFromScriptActivity() { if (handleNewSceneFromScriptActivity) { handleNewSceneFromScriptActivity = false; return true; } return false; } public void uploadProject(String projectName, Activity activity) { if (getCurrentProject() == null || !getCurrentProject().getName().equals(projectName)) { LoadProjectTask loadProjectTask = new LoadProjectTask(activity, projectName, true, false); loadProjectTask.setOnLoadProjectCompleteListener(this); loadProjectTask.execute(); } SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); String token = preferences.getString(Constants.TOKEN, Constants.NO_TOKEN); String username = preferences.getString(Constants.USERNAME, Constants.NO_USERNAME); if (!Utils.isUserLoggedIn(activity)) { showSignInDialog(activity, true); } else { CheckTokenTask checkTokenTask = new CheckTokenTask(activity, token, username); checkTokenTask.setOnCheckTokenCompleteListener(this); checkTokenTask.execute(); } } public void loadProject(String projectName, Context context) throws LoadingProjectException, OutdatedVersionProjectException, CompatibilityProjectException { fileChecksumContainer = new FileChecksumContainer(); Project oldProject = project; MessageContainer.createBackup(); project = StorageHandler.getInstance().loadProject(projectName, context); StorageHandler.getInstance().fillChecksumContainer(); if (project == null) { if (oldProject != null) { project = oldProject; currentScene = project.getDefaultScene(); sceneToPlay = currentScene; MessageContainer.restoreBackup(); } else { project = Utils.findValidProject(context); if (project == null) { try { project = DefaultProjectHandler.createAndSaveDefaultProject(context); MessageContainer.clearBackup(); } catch (IOException ioException) { Log.e(TAG, "Cannot load project.", ioException); throw new LoadingProjectException(context.getString(R.string.error_load_project)); } } } throw new LoadingProjectException(context.getString(R.string.error_load_project)); } else if (project.getCatrobatLanguageVersion() > Constants.CURRENT_CATROBAT_LANGUAGE_VERSION) { if (project.getCatrobatLanguageVersion() == 0.93f) { // this was done because of insufficient error message in older program versions project.setCatrobatLanguageVersion(0.92f); } else { project = oldProject; currentScene = oldProject.getDefaultScene(); sceneToPlay = currentScene; throw new OutdatedVersionProjectException(context.getString(R.string.error_outdated_pocketcode_version)); } } else { if (project.getCatrobatLanguageVersion() == 0.8f) { //TODO insert in every "When project starts" script list a "show" brick project.setCatrobatLanguageVersion(0.9f); } if (project.getCatrobatLanguageVersion() == 0.9f) { project.setCatrobatLanguageVersion(0.91f); //no convertion needed - only change to white background } if (project.getCatrobatLanguageVersion() == 0.91f) { project.setCatrobatLanguageVersion(0.92f); project.setScreenMode(ScreenModes.STRETCH); checkNestingBrickReferences(false, false); } if (project.getCatrobatLanguageVersion() == 0.92f || project.getCatrobatLanguageVersion() == 0.93f) { //0.93 should be left out because it available unintentional for a day //raise language version here to 0.94 project.setCatrobatLanguageVersion(0.94f); } if (project.getCatrobatLanguageVersion() == 0.94f) { project.setCatrobatLanguageVersion(0.95f); } if (project.getCatrobatLanguageVersion() == 0.95f) { project.setCatrobatLanguageVersion(0.96f); } if (project.getCatrobatLanguageVersion() == 0.96f) { project.setCatrobatLanguageVersion(0.97f); } if (project.getCatrobatLanguageVersion() == 0.97f) { project.setCatrobatLanguageVersion(0.98f); } if (project.getCatrobatLanguageVersion() == 0.98f) { project.setCatrobatLanguageVersion(0.99f); } if (project.getCatrobatLanguageVersion() == 0.99f) { project.setCatrobatLanguageVersion(0.991f); } if (project.getCatrobatLanguageVersion() == 0.991f) { //With the introduction of grouping there are several Sprite-classes //This is simply done in XStreamSpriteConverter project.setCatrobatLanguageVersion(0.992f); } if (project.getCatrobatLanguageVersion() == 0.992f) { project.updateCollisionFormulasToVersion(0.993f); project.setCatrobatLanguageVersion(0.993f); } if (project.getCatrobatLanguageVersion() == 0.993f) { project.setCatrobatLanguageVersion(Constants.CURRENT_CATROBAT_LANGUAGE_VERSION); } // insert further conversions here checkNestingBrickReferences(true, false); if (project.getCatrobatLanguageVersion() == Constants.CURRENT_CATROBAT_LANGUAGE_VERSION) { //project seems to be converted now and can be loaded localizeBackgroundSprite(context); } else { //project cannot be converted project = oldProject; if (oldProject != null) { currentScene = oldProject.getDefaultScene(); sceneToPlay = currentScene; } throw new CompatibilityProjectException(context.getString(R.string.error_project_compatability)); } } if (project != null) { project.loadLegoNXTSettingsFromProject(context); project.loadLegoEV3SettingsFromProject(context); showLegoSensorInfoDialog = true; int resources = project.getRequiredResources(); if ((resources & Brick.BLUETOOTH_PHIRO) > 0) { SettingsActivity.setPhiroSharedPreferenceEnabled(context, true); } if ((resources & Brick.BLUETOOTH_SENSORS_ARDUINO) > 0) { SettingsActivity.setArduinoSharedPreferenceEnabled(context, true); } currentScene = project.getDefaultScene(); sceneToPlay = currentScene; } } private void localizeBackgroundSprite(Context context) { // Set generic localized name on background sprite and move it to the back. if (currentScene == null) { return; } if (currentScene.getSpriteList().size() > 0) { currentScene.getSpriteList().get(0).setName(context.getString(R.string.background)); currentScene.getSpriteList().get(0).look.setZIndex(0); } MessageContainer.clearBackup(); currentSprite = null; currentScript = null; Utils.saveToPreferences(context, Constants.PREF_PROJECTNAME_KEY, project.getName()); } public boolean cancelLoadProject() { return StorageHandler.getInstance().cancelLoadProject(); } public void saveProject(Context context) { if (project == null) { return; } project.saveLegoNXTSettingsToProject(context); project.saveLegoEV3SettingsToProject(context); if (asynchronousTask) { SaveProjectAsynchronousTask saveTask = new SaveProjectAsynchronousTask(); saveTask.execute(); } else { StorageHandler.getInstance().saveProject(project); } } public boolean initializeDefaultProject(Context context) { try { fileChecksumContainer = new FileChecksumContainer(); project = DefaultProjectHandler.createAndSaveDefaultProject(context); currentSprite = null; currentScript = null; currentScene = project.getDefaultScene(); sceneToPlay = currentScene; return true; } catch (IOException ioException) { Log.e(TAG, "Cannot initialize default project.", ioException); Utils.showErrorDialog(context, R.string.error_load_project); return false; } } public void initializeNewProject(String projectName, Context context, boolean empty, boolean drone, boolean landscapeMode) throws IllegalArgumentException, IOException { fileChecksumContainer = new FileChecksumContainer(); if (empty) { project = DefaultProjectHandler.createAndSaveEmptyProject(projectName, context, landscapeMode); } else { if (drone) { DefaultProjectHandler.getInstance().setDefaultProjectCreator(DefaultProjectHandler.ProjectCreatorType .PROJECT_CREATOR_DRONE); } else { DefaultProjectHandler.getInstance().setDefaultProjectCreator(DefaultProjectHandler.ProjectCreatorType .PROJECT_CREATOR_DEFAULT); } project = DefaultProjectHandler.createAndSaveDefaultProject(projectName, context, landscapeMode); } currentSprite = null; currentScript = null; currentScene = project.getDefaultScene(); sceneToPlay = currentScene; } public Project getCurrentProject() { return project; } public Scene getSceneToPlay() { if (sceneToPlay == null) { sceneToPlay = getCurrentScene(); } return sceneToPlay; } public void setSceneToPlay(Scene scene) { sceneToPlay = scene; } public Scene getStartScene() { if (startScene == null) { startScene = getCurrentScene(); } return startScene; } public void setStartScene(Scene scene) { startScene = scene; } public Scene getCurrentScene() { if (currentScene == null) { currentScene = project.getDefaultScene(); } return currentScene; } public boolean isCurrentProjectLandscapeMode() { int virtualScreenWidth = getCurrentProject().getXmlHeader().virtualScreenWidth; int virtualScreenHeight = getCurrentProject().getXmlHeader().virtualScreenHeight; return virtualScreenWidth > virtualScreenHeight; } public void setProject(Project project) { currentScript = null; currentSprite = null; this.project = project; if (project != null) { currentScene = project.getDefaultScene(); sceneToPlay = currentScene; } } public void setCurrentProject(Project project) { this.project = project; } //@Deprecated public void deleteCurrentProject(Context context) throws IllegalArgumentException, IOException { deleteProject(project.getName(), context); } public void deleteProject(String projectName, Context context) throws IllegalArgumentException, IOException { Log.d(TAG, "deleteProject " + projectName); if (StorageHandler.getInstance().projectExists(projectName)) { StorageHandler.getInstance().deleteProject(projectName); } if (project != null && project.getName().equals(projectName)) { Log.d(TAG, "deleteProject(): project instance set to null"); project = null; if (context != null) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); String currentProjectName = sharedPreferences.getString(Constants.PREF_PROJECTNAME_KEY, "notFound"); if (!currentProjectName.equals("notFound")) { Utils.removeFromPreferences(context, Constants.PREF_PROJECTNAME_KEY); } } } } public void deleteScene(String projectName, String sceneName) throws IOException { Log.d(TAG, "deleteScene " + sceneName); StorageHandler.getInstance().deleteScene(projectName, sceneName); } public boolean renameProject(String newProjectName, Context context) { if (StorageHandler.getInstance().projectExists(newProjectName)) { Utils.showErrorDialog(context, R.string.error_project_exists); return false; } String oldProjectPath = Utils.buildProjectPath(project.getName()); File oldProjectDirectory = new File(oldProjectPath); String newProjectPath = Utils.buildProjectPath(newProjectName); File newProjectDirectory = new File(newProjectPath); boolean directoryRenamed; if (oldProjectPath.equalsIgnoreCase(newProjectPath)) { String tmpProjectPath = Utils.buildProjectPath(createTemporaryDirectoryName(newProjectName)); File tmpProjectDirectory = new File(tmpProjectPath); directoryRenamed = oldProjectDirectory.renameTo(tmpProjectDirectory); if (directoryRenamed) { directoryRenamed = tmpProjectDirectory.renameTo(newProjectDirectory); } } else { directoryRenamed = oldProjectDirectory.renameTo(newProjectDirectory); } if (directoryRenamed) { project.setName(newProjectName); saveProject(context); } if (!directoryRenamed) { Utils.showErrorDialog(context, R.string.error_rename_project); } return directoryRenamed; } public Sprite getCurrentSprite() { return currentSprite; } public void setCurrentSprite(Sprite sprite) { previousSprite = currentSprite; currentSprite = sprite; } public Sprite getPreviousSprite() { return previousSprite; } public Script getCurrentScript() { return currentScript; } public void setCurrentScene(Scene scene) { this.currentScene = scene; sceneToPlay = scene; } public void addScene(Scene scene) { project.addScene(scene); } public void setCurrentScript(Script script) { if (script == null) { currentScript = null; } else if (currentSprite.getScriptIndex(script) != -1) { currentScript = script; } } public UserBrick getCurrentUserBrick() { return currentUserBrick; } public void setCurrentUserBrick(UserBrick brick) { currentUserBrick = brick; } public void addSprite(Sprite sprite) { getCurrentScene().addSprite(sprite); } public void addScript(Script script) { currentSprite.addScript(script); } public boolean spriteExists(String spriteName) { for (Sprite sprite : getCurrentScene().getSpriteList()) { if (sprite.getName().equalsIgnoreCase(spriteName)) { return true; } } return false; } public boolean sceneExists(String sceneName) { for (Scene scene : project.getSceneList()) { if (scene.getName().equalsIgnoreCase(sceneName)) { return true; } } return false; } public int getCurrentSpritePosition() { return getCurrentScene().getSpriteList().indexOf(currentSprite); } public int getCurrentScriptPosition() { int currentSpritePosition = this.getCurrentSpritePosition(); if (currentSpritePosition == -1) { return -1; } return getCurrentScene().getSpriteList().get(currentSpritePosition).getScriptIndex(currentScript); } private String createTemporaryDirectoryName(String projectDirectoryName) { String temporaryDirectorySuffix = "_tmp"; String temporaryDirectoryName = projectDirectoryName + temporaryDirectorySuffix; int suffixCounter = 0; while (Utils.checkIfProjectExistsOrIsDownloadingIgnoreCase(temporaryDirectoryName)) { temporaryDirectoryName = projectDirectoryName + temporaryDirectorySuffix + suffixCounter; suffixCounter++; } return temporaryDirectoryName; } public FileChecksumContainer getFileChecksumContainer() { return this.fileChecksumContainer; } public void setFileChecksumContainer(FileChecksumContainer fileChecksumContainer) { this.fileChecksumContainer = fileChecksumContainer; } @Override public void onTokenNotValid(Activity activity) { showSignInDialog(activity, true); } @Override public void onCheckTokenSuccess(Activity activity) { if (AccessToken.getCurrentAccessToken() != null) { CheckFacebookServerTokenValidityTask checkFacebookServerTokenValidityTask = new CheckFacebookServerTokenValidityTask(activity, AccessToken.getCurrentAccessToken().getUserId()); checkFacebookServerTokenValidityTask.setOnCheckFacebookServerTokenValidityCompleteListener(this); checkFacebookServerTokenValidityTask.execute(); } else { ProjectManager.getInstance().showUploadProjectDialog(activity.getFragmentManager(), null); } } @Override public void onCheckFacebookServerTokenValidityComplete(Boolean requestNewToken, Activity activity) { if (requestNewToken) { triggerFacebookTokenRefreshOnServer(activity); } else { ProjectManager.getInstance().showUploadProjectDialog(activity.getFragmentManager(), null); } } private void triggerFacebookTokenRefreshOnServer(Activity activity) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity); sharedPreferences.edit().putBoolean(Constants.FACEBOOK_TOKEN_REFRESH_NEEDED, true); FacebookExchangeTokenTask facebookExchangeTokenTask = new FacebookExchangeTokenTask(activity, AccessToken.getCurrentAccessToken().getToken(), sharedPreferences.getString(Constants.FACEBOOK_EMAIL, Constants.NO_FACEBOOK_EMAIL), sharedPreferences.getString(Constants.FACEBOOK_USERNAME, Constants.NO_FACEBOOK_USERNAME), sharedPreferences.getString(Constants.FACEBOOK_ID, Constants.NO_FACEBOOK_ID), sharedPreferences.getString(Constants.FACEBOOK_LOCALE, Constants.NO_FACEBOOK_LOCALE) ); facebookExchangeTokenTask.setOnFacebookExchangeTokenCompleteListener(this); facebookExchangeTokenTask.execute(); } public void showSignInDialog(Activity activity, Boolean showUploadDialogWhenDone) { if (!Utils.isNetworkAvailable(activity, true)) { return; } showUploadDialog = showUploadDialogWhenDone; SignInDialog signInDialog = new SignInDialog(); signInDialog.show(activity.getFragmentManager(), SignInDialog.DIALOG_FRAGMENT_TAG); } public void showUploadProjectDialog(FragmentManager fragmentManager, Bundle bundle) { UploadProjectDialog uploadProjectDialog = new UploadProjectDialog(); if (bundle != null) { uploadProjectDialog.setArguments(bundle); } uploadProjectDialog.show(fragmentManager, UploadProjectDialog.DIALOG_FRAGMENT_TAG); } public void signInFinished(FragmentManager fragmentManager, Bundle bundle) { if (showUploadDialog) { showUploadProjectDialog(fragmentManager, bundle); } else { showUploadDialog = true; } } @Override public void onLoadProjectSuccess(boolean startProjectActivity) { } @Override public void onLoadProjectFailure() { } public boolean checkNestingBrickReferences(boolean assumeWrong, boolean inBackPack) { return checkNestingBrickReferences(assumeWrong, inBackPack, false); } public boolean checkNestingBrickReferences(boolean assumeWrong, boolean inBackPack, boolean sceneBackpack) { List<Sprite> spritesToCheck = new ArrayList<>(); boolean projectCorrect = true; if (inBackPack) { if (sceneBackpack) { for (Scene scene : BackPackListManager.getInstance().getAllBackpackedScenes()) { spritesToCheck.addAll(scene.getSpriteList()); } } else { spritesToCheck = BackPackListManager.getInstance().getAllBackPackedSprites(); } HashMap<String, List<Script>> backPackedScripts = BackPackListManager.getInstance().getAllBackPackedScripts(); for (String scriptGroup : backPackedScripts.keySet()) { List<Script> scriptListToCheck = backPackedScripts.get(scriptGroup); for (Script scriptToCheck : scriptListToCheck) { checkCurrentScript(scriptToCheck, assumeWrong); } } for (Sprite currentSprite : spritesToCheck) { if (!checkCurrentSprite(currentSprite, assumeWrong)) { projectCorrect = false; } } } else { for (Scene scene : project.getSceneList()) { Project currentProject = ProjectManager.getInstance().getCurrentProject(); if (currentProject == null) { return false; } spritesToCheck = scene.getSpriteList(); for (Sprite currentSprite : spritesToCheck) { if (!checkCurrentSprite(currentSprite, assumeWrong)) { projectCorrect = false; } } } } return projectCorrect; } public boolean checkCurrentSprite(Sprite currentSprite, boolean assumeWrong) { boolean spriteCorrect = true; int numberOfScripts = currentSprite.getNumberOfScripts(); for (int pos = 0; pos < numberOfScripts; pos++) { Script script = currentSprite.getScript(pos); if (!checkCurrentScript(script, assumeWrong)) { spriteCorrect = false; } } return spriteCorrect; } public boolean checkCurrentScript(Script script, boolean assumeWrong) { boolean scriptCorrect = true; if (assumeWrong) { scriptCorrect = false; } for (Brick currentBrick : script.getBrickList()) { if (!scriptCorrect) { break; } scriptCorrect = checkReferencesOfCurrentBrick(currentBrick); } if (!scriptCorrect) { correctAllNestedReferences(script); } return scriptCorrect; } private boolean checkReferencesOfCurrentBrick(Brick currentBrick) { if (currentBrick instanceof IfThenLogicBeginBrick) { IfThenLogicEndBrick endBrick = ((IfThenLogicBeginBrick) currentBrick).getIfThenEndBrick(); if (endBrick == null || endBrick.getIfBeginBrick() == null || !endBrick.getIfBeginBrick().equals(currentBrick)) { Log.d(TAG, "Brick has wrong reference:" + currentSprite + " " + currentBrick); return false; } } else if (currentBrick instanceof IfLogicBeginBrick) { IfLogicElseBrick elseBrick = ((IfLogicBeginBrick) currentBrick).getIfElseBrick(); IfLogicEndBrick endBrick = ((IfLogicBeginBrick) currentBrick).getIfEndBrick(); if (elseBrick == null || endBrick == null || elseBrick.getIfBeginBrick() == null || elseBrick.getIfEndBrick() == null || endBrick.getIfBeginBrick() == null || endBrick.getIfElseBrick() == null || !elseBrick.getIfBeginBrick().equals(currentBrick) || !elseBrick.getIfEndBrick().equals(endBrick) || !endBrick.getIfBeginBrick().equals(currentBrick) || !endBrick.getIfElseBrick().equals(elseBrick)) { Log.d(TAG, "Brick has wrong reference:" + currentSprite + " " + currentBrick); return false; } } else if (currentBrick instanceof LoopBeginBrick) { LoopEndBrick endBrick = ((LoopBeginBrick) currentBrick).getLoopEndBrick(); if (endBrick == null || endBrick.getLoopBeginBrick() == null || !endBrick.getLoopBeginBrick().equals(currentBrick)) { Log.d(TAG, "Brick has wrong reference:" + currentSprite + " " + currentBrick); return false; } } return true; } private void correctAllNestedReferences(Script script) { ArrayList<IfLogicBeginBrick> ifBeginList = new ArrayList<>(); ArrayList<IfThenLogicBeginBrick> ifThenBeginList = new ArrayList<>(); ArrayList<Brick> loopBeginList = new ArrayList<>(); ArrayList<Brick> bricksWithInvalidReferences = new ArrayList<>(); for (Brick currentBrick : script.getBrickList()) { if (currentBrick instanceof IfThenLogicBeginBrick) { ifThenBeginList.add((IfThenLogicBeginBrick) currentBrick); } else if (currentBrick instanceof IfLogicBeginBrick) { ifBeginList.add((IfLogicBeginBrick) currentBrick); } else if (currentBrick instanceof LoopBeginBrick) { loopBeginList.add(currentBrick); } else if (currentBrick instanceof LoopEndBrick) { if (loopBeginList.isEmpty()) { Log.e(TAG, "Removing LoopEndBrick without reference to a LoopBeginBrick"); bricksWithInvalidReferences.add(currentBrick); continue; } LoopBeginBrick loopBeginBrick = (LoopBeginBrick) loopBeginList.get(loopBeginList.size() - 1); loopBeginBrick.setLoopEndBrick((LoopEndBrick) currentBrick); ((LoopEndBrick) currentBrick).setLoopBeginBrick(loopBeginBrick); loopBeginList.remove(loopBeginBrick); } else if (currentBrick instanceof IfLogicElseBrick) { if (ifBeginList.isEmpty()) { Log.e(TAG, "Removing IfLogicElseBrick without reference to an IfBeginBrick"); bricksWithInvalidReferences.add(currentBrick); continue; } IfLogicBeginBrick ifBeginBrick = ifBeginList.get(ifBeginList.size() - 1); ifBeginBrick.setIfElseBrick((IfLogicElseBrick) currentBrick); ((IfLogicElseBrick) currentBrick).setIfBeginBrick(ifBeginBrick); } else if (currentBrick instanceof IfThenLogicEndBrick) { if (ifThenBeginList.isEmpty()) { Log.e(TAG, "Removing IfThenLogicEndBrick without reference to an IfBeginBrick"); bricksWithInvalidReferences.add(currentBrick); continue; } IfThenLogicBeginBrick ifBeginBrick = ifThenBeginList.get(ifThenBeginList.size() - 1); ifBeginBrick.setIfThenEndBrick((IfThenLogicEndBrick) currentBrick); ((IfThenLogicEndBrick) currentBrick).setIfThenBeginBrick(ifBeginBrick); ifThenBeginList.remove(ifBeginBrick); } else if (currentBrick instanceof IfLogicEndBrick) { if (ifBeginList.isEmpty()) { Log.e(TAG, "Removing IfLogicEndBrick without reference to an IfBeginBrick"); bricksWithInvalidReferences.add(currentBrick); continue; } IfLogicBeginBrick ifBeginBrick = ifBeginList.get(ifBeginList.size() - 1); IfLogicElseBrick elseBrick = ifBeginBrick.getIfElseBrick(); ifBeginBrick.setIfEndBrick((IfLogicEndBrick) currentBrick); elseBrick.setIfEndBrick((IfLogicEndBrick) currentBrick); ((IfLogicEndBrick) currentBrick).setIfBeginBrick(ifBeginBrick); ((IfLogicEndBrick) currentBrick).setIfElseBrick(elseBrick); ifBeginList.remove(ifBeginBrick); } } for (Brick brick : ifBeginList) { bricksWithInvalidReferences.add(brick); } for (Brick brick : ifThenBeginList) { bricksWithInvalidReferences.add(brick); } for (Brick brick : loopBeginList) { bricksWithInvalidReferences.add(brick); } script.removeBricks(bricksWithInvalidReferences); } public boolean getShowLegoSensorInfoDialog() { return showLegoSensorInfoDialog; } public void setShowLegoSensorInfoDialog(boolean showLegoSensorInfoDialogFlag) { showLegoSensorInfoDialog = showLegoSensorInfoDialogFlag; } @Override public void onFacebookExchangeTokenComplete(Activity fragmentActivity) { Log.d(TAG, "Facebook token refreshed on server"); ProjectManager.getInstance().showUploadProjectDialog(fragmentActivity.getFragmentManager(), null); } private class SaveProjectAsynchronousTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { StorageHandler.getInstance().saveProject(project); return null; } } }