/* * 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.ui; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.AlertDialog; import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.facebook.AccessToken; import com.facebook.CallbackManager; import com.facebook.FacebookCallback; import com.facebook.FacebookException; import com.facebook.FacebookSdk; import com.facebook.login.LoginManager; import com.facebook.login.LoginResult; import org.catrobat.catroid.ProjectManager; import org.catrobat.catroid.R; import org.catrobat.catroid.common.Constants; import org.catrobat.catroid.content.Project; import org.catrobat.catroid.content.Scene; import org.catrobat.catroid.content.bricks.Brick; import org.catrobat.catroid.drone.DroneServiceWrapper; import org.catrobat.catroid.drone.DroneStageActivity; import org.catrobat.catroid.facedetection.FaceDetectionHandler; import org.catrobat.catroid.formulaeditor.SensorHandler; import org.catrobat.catroid.stage.PreStageActivity; import org.catrobat.catroid.stage.StageActivity; import org.catrobat.catroid.transfers.GetFacebookUserInfoTask; import org.catrobat.catroid.ui.controller.BackPackListManager; import org.catrobat.catroid.ui.dialogs.LegoEV3SensorConfigInfoDialog; import org.catrobat.catroid.ui.dialogs.LegoNXTSensorConfigInfoDialog; import org.catrobat.catroid.ui.dialogs.MergeSceneDialog; import org.catrobat.catroid.ui.dialogs.NewSceneDialog; import org.catrobat.catroid.ui.dialogs.NewSpriteDialog; import org.catrobat.catroid.ui.dialogs.PlaySceneDialog; import org.catrobat.catroid.ui.dialogs.SignInDialog; import org.catrobat.catroid.ui.fragment.ListItemActionsInterface; import org.catrobat.catroid.ui.fragment.SceneListFragment; import org.catrobat.catroid.ui.fragment.SpritesListFragment; import org.catrobat.catroid.utils.ToastUtil; import org.catrobat.catroid.utils.Utils; import java.util.concurrent.locks.Lock; public class ProjectActivity extends BaseActivity { private static final String TAG = ProjectActivity.class.getSimpleName(); public static final int FRAGMENT_SPRITES = 0; public static final int FRAGMENT_SCENES = 1; public static final String EXTRA_FRAGMENT_POSITION = "org.catrobat.catroid.ui.fragmentPosition"; private ListItemActionsInterface actionListener; private Fragment currentFragment; private SpritesListFragment spritesListFragment; private SceneListFragment sceneListFragment; private static int currentFragmentPosition; private FragmentManager fragmentManager = getFragmentManager(); private String currentFragmentTag; private Lock viewSwitchLock = new ViewSwitchLock(); private CallbackManager callbackManager; private SignInDialog signInDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initializeFacebookSdk(); setContentView(R.layout.activity_project); currentFragmentPosition = FRAGMENT_SCENES; if (getIntent() != null && getIntent().hasExtra(Constants.PROJECT_OPENED_FROM_PROJECTS_LIST)) { setReturnToProjectsList(true); } if (savedInstanceState == null) { Bundle bundle = this.getIntent().getExtras(); if (bundle != null) { currentFragmentPosition = bundle.getInt(EXTRA_FRAGMENT_POSITION, FRAGMENT_SCENES); } } if (ProjectManager.getInstance().getCurrentProject().getSceneList().size() == 1) { currentFragmentPosition = FRAGMENT_SPRITES; } FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); updateCurrentFragment(currentFragmentPosition, fragmentTransaction); fragmentTransaction.commit(); showLegoInfoFragmentIfNeeded(this.getFragmentManager()); } @Override protected void onStart() { super.onStart(); SettingsActivity.setLegoMindstormsNXTSensorChooserEnabled(this, true); SettingsActivity.setLegoMindstormsEV3SensorChooserEnabled(this, true); SettingsActivity.setDroneChooserEnabled(this, true); } @Override protected void onResume() { super.onResume(); setActionBarTitle(); } private void setActionBarTitle() { String programName = getString(R.string.app_name); Bundle bundle = getIntent().getExtras(); if (bundle != null) { programName = bundle.getString(Constants.PROJECTNAME_TO_LOAD); } else { Project project = ProjectManager.getInstance().getCurrentProject(); if (project != null) { programName = project.getName(); } } final ActionBar actionBar = getActionBar(); if (actionBar != null) { actionBar.setHomeButtonEnabled(true); actionBar.setTitle(programName); actionBar.setDisplayHomeAsUpEnabled(true); } } @Override public void onPause() { super.onPause(); Bundle bundle = getIntent().getExtras(); if (bundle != null) { bundle.remove(Constants.PROJECTNAME_TO_LOAD); } } private void updateCurrentFragment(int fragmentPosition, FragmentTransaction fragmentTransaction) { boolean fragmentExists = true; currentFragmentPosition = fragmentPosition; switch (currentFragmentPosition) { case FRAGMENT_SCENES: if (sceneListFragment == null) { sceneListFragment = new SceneListFragment(); fragmentExists = false; } currentFragmentTag = SceneListFragment.TAG; currentFragment = sceneListFragment; actionListener = sceneListFragment; break; case FRAGMENT_SPRITES: if (spritesListFragment == null) { spritesListFragment = new SpritesListFragment(); fragmentExists = false; } currentFragmentTag = SpritesListFragment.TAG; currentFragment = spritesListFragment; actionListener = spritesListFragment; break; } if (fragmentExists) { fragmentTransaction.show(currentFragment); } else { fragmentTransaction.add(R.id.fragment_container, currentFragment, currentFragmentTag); } } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (currentFragmentPosition == FRAGMENT_SPRITES && spritesListFragment != null) { handleShowDetails(spritesListFragment.getShowDetails(), menu.findItem(R.id.show_details)); } else { menu.findItem(R.id.groups_create).setVisible(false); } return super.onPrepareOptionsMenu(menu); } @Override public boolean onCreateOptionsMenu(Menu menu) { if (currentFragment != null) { getMenuInflater().inflate(R.menu.menu_current_project, menu); if (currentFragmentPosition == FRAGMENT_SCENES) { menu.findItem(R.id.show_details).setVisible(false); menu.findItem(R.id.backpack).setVisible(true); menu.findItem(R.id.merge_scene).setVisible(true); } else { menu.findItem(R.id.backpack).setVisible(true); } } return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); return true; case R.id.show_details: handleShowDetails(!spritesListFragment.getShowDetails(), item); break; case R.id.backpack: showBackPackChooser(); break; case R.id.copy: actionListener.startCopyActionMode(); break; case R.id.cut: break; case R.id.insert_below: break; case R.id.move: break; case R.id.rename: actionListener.startRenameActionMode(); break; case R.id.delete: actionListener.startDeleteActionMode(); break; case R.id.upload: ProjectManager.getInstance().uploadProject(Utils.getCurrentProjectName(this), this); break; case R.id.groups_create: spritesListFragment.showNewObjectGroupDialog(); break; case R.id.new_scene: FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); Fragment previousFragment = getFragmentManager().findFragmentByTag(NewSceneDialog.DIALOG_FRAGMENT_TAG); if (previousFragment != null) { fragmentTransaction.remove(previousFragment); } boolean fromSpriteOverview = currentFragmentPosition == FRAGMENT_SPRITES; fromSpriteOverview &= ProjectManager.getInstance().getCurrentProject().getSceneList().size() > 1; NewSceneDialog newSceneFragment = new NewSceneDialog(false, fromSpriteOverview); newSceneFragment.show(fragmentTransaction, NewSceneDialog.DIALOG_FRAGMENT_TAG); break; case R.id.merge_scene: fragmentTransaction = getFragmentManager().beginTransaction(); previousFragment = getFragmentManager().findFragmentByTag(MergeSceneDialog.DIALOG_FRAGMENT_TAG); if (previousFragment != null) { fragmentTransaction.remove(previousFragment); } MergeSceneDialog mergeSceneDialog = new MergeSceneDialog(); mergeSceneDialog.show(fragmentTransaction, MergeSceneDialog.DIALOG_FRAGMENT_TAG); break; } return super.onOptionsItemSelected(item); } private void showBackPackChooser() { updateFragmentPosition(); AlertDialog.Builder builder = new AlertDialog.Builder(this); CharSequence[] items; int numberOfItemsInBackpack = 0; switch (currentFragmentPosition) { case FRAGMENT_SPRITES: numberOfItemsInBackpack = BackPackListManager.getInstance().getBackPackedSprites().size(); break; case FRAGMENT_SCENES: numberOfItemsInBackpack = BackPackListManager.getInstance().getBackPackedScenes().size(); break; } if (numberOfItemsInBackpack == 0) { actionListener.startBackPackActionMode(); } else { items = new CharSequence[] { getString(R.string.packing), getString(R.string.unpack) }; builder.setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == 0) { actionListener.startBackPackActionMode(); } else if (which == 1) { openBackPack(); } dialog.dismiss(); } }); builder.setTitle(R.string.backpack_title); builder.setCancelable(true); builder.show(); } } private void openBackPack() { updateFragmentPosition(); Intent intent = new Intent(this, BackPackActivity.class); int fragmentPos = 0; switch (currentFragmentPosition) { case FRAGMENT_SCENES: fragmentPos = BackPackActivity.FRAGMENT_BACKPACK_SCENES; break; case FRAGMENT_SPRITES: fragmentPos = BackPackActivity.FRAGMENT_BACKPACK_SPRITES; break; } intent.putExtra(BackPackActivity.EXTRA_FRAGMENT_POSITION, fragmentPos); startActivity(intent); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); callbackManager.onActivityResult(requestCode, resultCode, data); if (requestCode == PreStageActivity.REQUEST_RESOURCES_INIT && resultCode == RESULT_OK) { Intent intent; if (data != null) { if (DroneServiceWrapper.checkARDroneAvailability()) { intent = new Intent(ProjectActivity.this, DroneStageActivity.class); } else { intent = new Intent(ProjectActivity.this, StageActivity.class); } startActivity(intent); } } if (requestCode == StageActivity.STAGE_ACTIVITY_FINISH) { SensorHandler.stopSensorListeners(); FaceDetectionHandler.stopFaceDetection(); } } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { sendBroadcast(new Intent(ScriptActivity.ACTION_SPRITES_LIST_INIT)); } } public void handleAddButton(View view) { if (!viewSwitchLock.tryLock()) { return; } FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); Fragment previousFragment; previousFragment = getFragmentManager().findFragmentByTag(NewSpriteDialog.DIALOG_FRAGMENT_TAG); if (previousFragment != null) { fragmentTransaction.remove(previousFragment); } updateFragmentPosition(); switch (currentFragmentPosition) { case FRAGMENT_SCENES: NewSceneDialog newSceneFragment = new NewSceneDialog(false, false); newSceneFragment.show(fragmentTransaction, NewSpriteDialog.DIALOG_FRAGMENT_TAG); break; case FRAGMENT_SPRITES: NewSpriteDialog newSpriteFragment = new NewSpriteDialog(); newSpriteFragment.show(fragmentTransaction, NewSpriteDialog.DIALOG_FRAGMENT_TAG); break; } } public void handlePlayButton(View view) { if (!viewSwitchLock.tryLock()) { return; } Project currentProject = ProjectManager.getInstance().getCurrentProject(); Scene currentScene = ProjectManager.getInstance().getCurrentScene(); updateFragmentPosition(); switch (currentFragmentPosition) { case FRAGMENT_SCENES: ProjectManager.getInstance().setSceneToPlay(currentProject.getDefaultScene()); ProjectManager.getInstance().setStartScene(currentProject.getDefaultScene()); startPreStageActivity(); break; case FRAGMENT_SPRITES: if (currentScene.getName().equals(currentProject.getDefaultScene().getName())) { ProjectManager.getInstance().setSceneToPlay(currentScene); ProjectManager.getInstance().setStartScene(currentScene); startPreStageActivity(); return; } FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); Fragment previousFragment = getFragmentManager().findFragmentByTag(NewSceneDialog.DIALOG_FRAGMENT_TAG); if (previousFragment != null) { fragmentTransaction.remove(previousFragment); } PlaySceneDialog playSceneDialog = new PlaySceneDialog(); playSceneDialog.show(fragmentTransaction, PlaySceneDialog.DIALOG_FRAGMENT_TAG); break; } } public void startPreStageActivity() { Intent intent = new Intent(this, PreStageActivity.class); startActivityForResult(intent, PreStageActivity.REQUEST_RESOURCES_INIT); } @Override public boolean dispatchKeyEvent(KeyEvent event) { // Dismiss ActionMode without effecting sounds if (actionListener.getActionModeActive() && event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { updateFragmentPosition(); switch (currentFragmentPosition) { case FRAGMENT_SCENES: sceneListFragment.clearCheckedItems(); break; case FRAGMENT_SPRITES: spritesListFragment.getSpriteAdapter().clearCheckedItems(); break; } } return super.dispatchKeyEvent(event); } public void handleShowDetails(boolean showDetails, MenuItem item) { spritesListFragment.setShowDetails(showDetails); item.setTitle(showDetails ? R.string.hide_details : R.string.show_details); } public void showEmptyActionModeDialog(String actionMode) { @SuppressLint("InflateParams") View dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_action_mode_empty, null); TextView actionModeEmptyText = (TextView) dialogView.findViewById(R.id.dialog_action_mode_emtpy_text); if (actionMode.equals(getString(R.string.backpack))) { actionModeEmptyText.setText(getString(R.string.nothing_to_backpack_and_unpack)); } else if (actionMode.equals(getString(R.string.unpack))) { actionModeEmptyText.setText(getString(R.string.nothing_to_unpack)); } else if (actionMode.equals(getString(R.string.delete))) { actionModeEmptyText.setText(getString(R.string.nothing_to_delete)); } else if (actionMode.equals(getString(R.string.copy))) { actionModeEmptyText.setText(getString(R.string.nothing_to_copy)); } else if (actionMode.equals(getString(R.string.rename))) { actionModeEmptyText.setText(getString(R.string.nothing_to_rename)); } AlertDialog actionModeEmptyDialog = new AlertDialog.Builder(this).setView(dialogView) .setTitle(actionMode) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }).create(); actionModeEmptyDialog.setCanceledOnTouchOutside(true); actionModeEmptyDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); actionModeEmptyDialog.show(); } public SpritesListFragment getSpritesListFragment() { return spritesListFragment; } public SceneListFragment getSceneListFragment() { return sceneListFragment; } public void initializeFacebookSdk() { FacebookSdk.sdkInitialize(getApplicationContext()); callbackManager = CallbackManager.Factory.create(); LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { Log.d(TAG, loginResult.toString()); AccessToken accessToken = loginResult.getAccessToken(); GetFacebookUserInfoTask getFacebookUserInfoTask = new GetFacebookUserInfoTask(ProjectActivity.this, accessToken.getToken(), accessToken.getUserId()); getFacebookUserInfoTask.setOnGetFacebookUserInfoTaskCompleteListener(signInDialog); getFacebookUserInfoTask.execute(); } @Override public void onCancel() { Log.d(TAG, "cancel"); } @Override public void onError(FacebookException exception) { ToastUtil.showError(ProjectActivity.this, exception.getMessage()); Log.d(TAG, exception.getMessage()); } }); } public void setSignInDialog(SignInDialog signInDialog) { this.signInDialog = signInDialog; } private void updateFragmentPosition() { //TODO: Just a quickfix, we need to investigate why the position is sometimes not correct if (currentFragment instanceof SceneListFragment) { currentFragmentPosition = FRAGMENT_SCENES; } else if (currentFragment instanceof SpritesListFragment) { currentFragmentPosition = FRAGMENT_SPRITES; } } private boolean needToShowLegoEV3InfoDialog() { boolean isLegoEV3InfoDialogDisabled = SettingsActivity .getShowLegoEV3MindstormsSensorInfoDialog(getApplicationContext()); boolean legoEV3ResourcesRequired = (ProjectManager.getInstance().getCurrentProject().getRequiredResources() & Brick.BLUETOOTH_LEGO_EV3) != 0; boolean dialogAlreadyShown = !ProjectManager.getInstance().getShowLegoSensorInfoDialog(); return !isLegoEV3InfoDialogDisabled && legoEV3ResourcesRequired && !dialogAlreadyShown; } private boolean needToShowLegoNXTInfoDialog() { boolean isLegoNXTInfoDialogDisabled = SettingsActivity .getShowLegoNXTMindstormsSensorInfoDialog(getApplicationContext()); boolean legoNXTResourcesRequired = (ProjectManager.getInstance().getCurrentProject().getRequiredResources() & Brick.BLUETOOTH_LEGO_NXT) != 0; boolean dialogAlreadyShown = !ProjectManager.getInstance().getShowLegoSensorInfoDialog(); return !isLegoNXTInfoDialogDisabled && legoNXTResourcesRequired && !dialogAlreadyShown; } private void showLegoInfoFragmentIfNeeded(FragmentManager fragmentManager) { if (needToShowLegoNXTInfoDialog()) { DialogFragment dialog = new LegoNXTSensorConfigInfoDialog(); dialog.show(fragmentManager, LegoNXTSensorConfigInfoDialog.DIALOG_FRAGMENT_TAG); } if (needToShowLegoEV3InfoDialog()) { DialogFragment dialog = new LegoEV3SensorConfigInfoDialog(); dialog.show(fragmentManager, LegoEV3SensorConfigInfoDialog.DIALOG_FRAGMENT_TAG); } ProjectManager.getInstance().setShowLegoSensorInfoDialog(false); } }