/** @contributor(s): Erlend Stav (SINTEF) Copyright 2012 SINTEF, http://www.sintef.no This software was developed in the UbiCompForAll project. See the NOTICE file distributed with this work for additional information regarding copyright ownership and the project. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package org.ubicompforall.ubicomposer.android; import java.util.List; import org.ubicompforall.descriptor.BuildingBlockDesc; import org.ubicompforall.descriptor.TriggerDesc; import org.ubicompforall.simplelanguage.SimpleLanguageFactory; import org.ubicompforall.simplelanguage.Step; import org.ubicompforall.simplelanguage.Task; import org.ubicompforall.simplelanguage.Trigger; import org.ubicompforall.simplelanguage.UserService; import org.ubicompforall.ubicomposer.util.DescriptorLibraryUtils; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; /** * This activity is used to edit the details of a Task, including * changing its trigger and adding, deleting and reordering its * step sequence. * The activity will load the UserService specified in the data part * of the intent, and expects intent extras with key "task" that * specifies the task sequence number within the user service. * The activity will load the user service from file on creation and * on resume, and will save to file on pause. * * @author erlend * */ public class TaskActivity extends AbstractUbiComposerActivity { Uri userServiceUri; BuildingBlockListAdapter<Step> taskListAdapter; ListView stepListView; int taskIndex; Task task; View triggerView; EditText taskNameText; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); UserService userService = null; taskIndex = 0; // default if (this.getIntent().getExtras().containsKey("task")) { taskIndex = getIntent().getExtras().getInt("task"); Uri fileUri = this.getIntent().getData(); if (fileUri != null) { userServiceUri = fileUri; userService = openFile(fileUri); } } if (userService == null) { ModelUtils.copyAssetFiles(this); userService = ModelUtils.createModel(this, "DebugService"); } task = userService.getTasks().get(taskIndex); setContentView(R.layout.ubicomposer_task); taskNameText = (EditText)this.findViewById(R.id.ubicomposer_taskNameText); stepListView = (ListView)this.findViewById(R.id.ubicomposer_stepListView); stepListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { editStep(arg2); } }); // stepListView.setOnLongClickListener(new) this.registerForContextMenu(stepListView); ImageButton addStepButton = (ImageButton)this.findViewById(R.id.ubicomposer_addStepButton); addStepButton.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View arg0) { showDialog(SELECT_STEP_DIALOG); } }); // Trigger FrameLayout triggerContainerView = (FrameLayout)this.findViewById(R.id.ubicomposer_triggerFrameLayout); LayoutInflater inflater = LayoutInflater.from(this); triggerView = inflater.inflate(R.layout.ubicomposer_step_layout, null); triggerView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (task.getTrigger() == null) showDialog(SELECT_TRIGGER_DIALOG); else editTrigger(); }}); this.registerForContextMenu(triggerView); triggerContainerView.addView(triggerView); } private void updateTriggerView() { ImageView triggerIcon = (ImageView)triggerView.findViewById(R.id.ubicomposer_stepIconView); TextView triggerMainText = (TextView)triggerView.findViewById(R.id.ubicomposer_mainStepText); TextView triggerMinorText = (TextView)triggerView.findViewById(R.id.ubicomposer_minorStepText); Trigger trigger = task.getTrigger(); if (trigger != null) { String iconFileName = ""; try { iconFileName = this.getFileStreamPath(trigger.getDescriptor().getIconUrl()).getAbsolutePath(); } catch (Exception e) { e.printStackTrace(); } triggerIcon.setImageURI(Uri.parse(iconFileName)); triggerMainText.setText(trigger.getDescriptor().getUserFriendlyName()); triggerMinorText.setText(trigger.getName()); } else { triggerIcon.setImageURI(null); triggerMainText.setText("<< press to add trigger >>"); triggerMinorText.setText(""); } } private void editStep(int stepIndex) { if ((stepIndex < 0) || (getUserService().getTasks().get(taskIndex).getStepSequence().size() <= stepIndex)) { Toast.makeText(this, "Task selection out of range", Toast.LENGTH_SHORT).show(); return; } Intent stepEditIntent = new Intent(this, EditStepActivity.class); stepEditIntent.setData(userServiceUri); stepEditIntent.putExtra("task", taskIndex); stepEditIntent.putExtra("step", stepIndex); this.startActivity(stepEditIntent); } private void removeStep(int stepIndex) { Step step = taskListAdapter.getItem(stepIndex); if (step != null) taskListAdapter.remove(step); } private void moveStep(int stepIndex, boolean up) { Step step = taskListAdapter.getItem(stepIndex); if (step != null) { if (up && (stepIndex > 0)) { taskListAdapter.remove(step); taskListAdapter.insert(step, stepIndex-1); } if (!up && (stepIndex < taskListAdapter.getCount()-1)) { taskListAdapter.remove(step); taskListAdapter.insert(step, stepIndex+1); } } } private void editTrigger() { if (task.getTrigger() != null) { Intent tiggerEditIntent = new Intent(this, EditTriggerActivity.class); tiggerEditIntent.setData(userServiceUri); tiggerEditIntent.putExtra("task", taskIndex); this.startActivity(tiggerEditIntent); } } int stepSelectedInContextMenu = -1; @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); if (v.getId() == R.id.ubicomposer_stepListView) { getMenuInflater().inflate(R.menu.ubicomposer_step_list_context_menu, menu); menu.setHeaderTitle("Step control:"); stepSelectedInContextMenu = ((AdapterView.AdapterContextMenuInfo)menuInfo).position; } else if (v == triggerView) { getMenuInflater().inflate(R.menu.ubicomposer_trigger_context_menu, menu); menu.setHeaderTitle("Trigger control:"); } } @Override public boolean onContextItemSelected(MenuItem item) { super.onContextItemSelected(item); int itemId = item.getItemId(); if (itemId == R.id.ubicomposer_edit_step) { if (stepSelectedInContextMenu != -1) editStep(stepSelectedInContextMenu); } else if (itemId == R.id.ubicomposer_remove_step) { if (stepSelectedInContextMenu != -1) removeStep(stepSelectedInContextMenu); } else if (itemId == R.id.ubicomposer_move_step_down) { if (stepSelectedInContextMenu != -1) moveStep(stepSelectedInContextMenu, false); } else if (itemId == R.id.ubicomposer_move_step_up) { if (stepSelectedInContextMenu != -1) moveStep(stepSelectedInContextMenu, true); } else if (itemId == R.id.ubicomposer_edit_trigger) { editTrigger(); } else if (itemId == R.id.ubicomposer_change_trigger) { showDialog(SELECT_TRIGGER_DIALOG); } stepSelectedInContextMenu = -1; return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add("Add step") .setIcon(android.R.drawable.ic_menu_add) .setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem arg0) { showDialog(SELECT_STEP_DIALOG); return true; }}); menu.add("Change trigger") .setIcon(android.R.drawable.ic_menu_edit) .setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem arg0) { showDialog(SELECT_TRIGGER_DIALOG); return true; }}); return true; } static final int SELECT_STEP_DIALOG = 1; static final int SELECT_TRIGGER_DIALOG = 2; @Override protected Dialog onCreateDialog(int id) { switch(id) { case SELECT_STEP_DIALOG: return createSelectStepDialog(); case SELECT_TRIGGER_DIALOG: return createSelectTriggerDialog(); } return super.onCreateDialog(id); } // TODO: Handle refresh of dialogs private Dialog createSelectStepDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Select step to add"); ListAdapter adapter = new BuildingBlockDescListAdapter(this, R.layout.ubicomposer_buildingblockdesc_layout, R.id.ubicomposer_buildingBlockNameText, getBuildingBlockDescs()); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { addStepToTask(arg1); }} ); return builder.create(); } List<BuildingBlockDesc> triggerDescList; private Dialog createSelectTriggerDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Select trigger for the task:"); triggerDescList = DescriptorLibraryUtils.getTriggerDescs(getUserService()); ListAdapter adapter = new BuildingBlockDescListAdapter(this, R.layout.ubicomposer_buildingblockdesc_layout, R.id.ubicomposer_buildingBlockNameText, triggerDescList); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { addTriggerToTask((TriggerDesc)triggerDescList.get(arg1)); }} ); return builder.create(); } private List<BuildingBlockDesc> getBuildingBlockDescs() { return DescriptorLibraryUtils.getStepDescs(getUserService()); } private void addTriggerToTask(TriggerDesc triggerDesc) { Trigger trigger = SimpleLanguageFactory.eINSTANCE.createTrigger(); trigger.setName(triggerDesc.getUserFriendlyName()); trigger.setDescriptor(triggerDesc); task.setTrigger(trigger); updateTriggerView(); } private void addStepToTask(int buildingBlockId) { try { List<BuildingBlockDesc> bbs = getBuildingBlockDescs(); BuildingBlockDesc desc = (BuildingBlockDesc)bbs.get(buildingBlockId); Step myStep = SimpleLanguageFactory.eINSTANCE.createStep(); myStep.setName("New " + desc.getUserFriendlyName()); myStep.setDescriptor(desc); taskListAdapter.add(myStep); // Now, trigger editing of the new step editStep(taskListAdapter.getCount()-1); } catch (Exception e) { e.printStackTrace(); } } @Override protected void updateViewsFromModel() { task = getUserService().getTasks().get(taskIndex); taskNameText = (EditText)this.findViewById(R.id.ubicomposer_taskNameText); taskNameText.setText(task.getName()); taskListAdapter = new BuildingBlockListAdapter<Step>(this, R.layout.ubicomposer_step_layout, R.id.ubicomposer_mainStepText, task.getStepSequence()); stepListView.setAdapter(taskListAdapter); this.updateTriggerView(); } @Override protected void updateModelFromViews() { task.setName(taskNameText.getText().toString()); } }