/* Copyright (C) 2014,2015 Hendryk Köppel, Florian Kempf, Hauke Heinrichs * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> */ package de.hu_berlin.informatik.spws2014.mapever; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.GridView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.Toast; import org.opencv.android.OpenCVLoader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import java.util.regex.Matcher; import de.hu_berlin.informatik.spws2014.ImagePositionLocator.TrackDB; import de.hu_berlin.informatik.spws2014.ImagePositionLocator.TrackDBEntry; import de.hu_berlin.informatik.spws2014.mapever.camera.CornerDetectionCamera; import de.hu_berlin.informatik.spws2014.mapever.entzerrung.Entzerren; import de.hu_berlin.informatik.spws2014.mapever.navigation.Navigation; public class Start extends BaseActivity { private FrameLayout layout; // Neue Karte Popup private AlertDialog newMapPopup; // Requestcodes für Neue Karte-Aktionen private static final int CHOOSE_FILE_REQUESTCODE = 1337; private static final int TAKE_PICTURE_REQUESTCODE = 42; // Requestcode für Aufruf der Navigation (Rückgabewert bei Fehler) private static final int NAVIGATION_REQUESTCODE = 413; private static final String IMAGE_TARGET_FILENAME = MapEverApp.TEMP_IMAGE_FILENAME; // image path public static final String INTENT_IMAGEPATH = "de.hu_berlin.informatik.spws2014.mapever.Start.NewImagePath"; public static final String INTENT_EXIT = "de.hu_berlin.informatik.spws2014.mapever.Start.Exit"; // OpenCV initialisieren static { if (!OpenCVLoader.initDebug()) { Log.e("OpenCV", "Could not load OpenCV!"); } } // keeps track of the maps and their respective positions in the grid private Map<Integer, TrackDBEntry> positionIdList = new HashMap<Integer, TrackDBEntry>(); private List<Bitmap> bitmapList = new ArrayList<Bitmap>(); // track the state of some GUI-elements for orientation changes private boolean isPopupOpen = false; private boolean isHelpShown = false; private boolean isContextMenuOpen = false; private int noMaps = 0; private double[] intentPos = null; private static int tileSize = 0; @Override protected void onCreate(Bundle savedInstanceState) { Log.d("Start", "onCreate..." + (savedInstanceState != null ? " with savedInstanceState" : "")); super.onCreate(savedInstanceState); if (savedInstanceState == null) { Intent intent = getIntent(); if (intent != null && intent.getBooleanExtra(INTENT_EXIT, false)) { finish(); return; } if (intent != null && intent.getData() != null && intent.getData().getScheme() != null && intent.getData().getScheme().equals("geo")) { String pos = intent.getData().getSchemeSpecificPart(); Pattern p = Pattern.compile("([+-]?\\d+(?:\\.\\d+)?),([+-]?\\d+(?:\\.\\d+)?).*"); Matcher m = p.matcher(pos); if (m.find()) { intentPos = new double[2]; intentPos[0] = Double.valueOf(m.group(1)); intentPos[1] = Double.valueOf(m.group(2)); } } } PreferenceManager.setDefaultValues(this, R.xml.pref_general, false); layout = new FrameLayout(getBaseContext()); setContentView(layout); getLayoutInflater().inflate(R.layout.activity_start, layout); // number of columns for the gridview int column = 3; Resources resources = getResources(); // get a list of all maps from the databse if (!TrackDB.loadDB(new File(MapEverApp.getAbsoluteFilePath("")))) { Log.e("Start", "Could not start DB!"); System.exit(-1); } ArrayList<TrackDBEntry> mapList = new ArrayList<TrackDBEntry>(TrackDB.main.getAllMaps()); Collections.sort(mapList, new Comparator<TrackDBEntry>() { public int compare(TrackDBEntry t1, TrackDBEntry t2) { if (t1.getIdentifier() > t2.getIdentifier()) return -1; if (t1.getIdentifier() < t2.getIdentifier()) return 1; return 0; } }); // Debug System.out.println("getAllEntries: " + mapList); System.out.println("isContextMenuOpen: " + isContextMenuOpen); final GridView gridview = (GridView) findViewById(R.id.start); gridview.setNumColumns(column); gridview.setAdapter(new ImageAdapter(this)); if (mapList.isEmpty()) { noMaps = 1; } // uses null tiles to enforce the respective orientation layouts if (noMaps == 1) { // no maps present, landscape orientation if (getResources().getConfiguration().orientation == 2) { bitmapList.add(null); bitmapList.add(BitmapFactory.decodeResource(resources, R.drawable.neue_karte)); bitmapList.add(null); } // no maps present, portrait orientation else { bitmapList.add(null); bitmapList.add(null); bitmapList.add(null); bitmapList.add(null); bitmapList.add(BitmapFactory.decodeResource(resources, R.drawable.neue_karte)); bitmapList.add(null); } } // if maps are present, get them from the list and assign them to the positions in the grid else { bitmapList.add(BitmapFactory.decodeResource(resources, R.drawable.neue_karte)); int position = 0; for (TrackDBEntry d : mapList) { position++; positionIdList.put(position, d); // get the ID of the map String id_string = Long.toString(positionIdList.get(position).getIdentifier()); File thumbFile = new File(MapEverApp.getAbsoluteFilePath(id_string + "_thumb")); Bitmap thumbBitmap = null; // try to load bitmap of thumbnail if it exists if (thumbFile.exists()) { thumbBitmap = BitmapFactory.decodeFile(thumbFile.getAbsolutePath()); } // add the thumbnail of the map to the bitmapList if it exists, a dummy picture otherwise if (thumbBitmap != null) { bitmapList.add(thumbBitmap); } else { bitmapList.add(BitmapFactory.decodeResource(resources, R.drawable.map_dummy)); } // (((Debug System.out.println("mapID: " + d.getIdentifier()); System.out.println("ID String:" + MapEverApp.getAbsoluteFilePath(id_string)); System.out.println("ID map (position , ID)"); for (Map.Entry<Integer, TrackDBEntry> entry : positionIdList.entrySet()) { System.out.println("ID map: " + "(" + entry.getKey() + " , " + entry.getValue() + ")"); } // )))Debug } } // ////////// hier wird das popup fenster erstellt /////////////// newMapPopup = new AlertDialog.Builder(Start.this).create(); // /////////sobald man irgendwo ausserhalb den bildschirm beruehrt // /////////wird das popup geschlossen newMapPopup.setCanceledOnTouchOutside(true); newMapPopup.setOnCancelListener( new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { isPopupOpen = false; } } ); gridview.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // clicks auf die Karten ignorieren, wenn das Hilfe-Overlay angezeigt wird if (isHelpShown) { return; } // Erster Button: Neue Karte // Wenn keine Karten vorhanden sind, ist die Position des Buttons egal if (noMaps == 1 || position == 0) { // //////sobald neue karte button geklickt erscheint schon das popup/////// showNewMapPopup(); } else { // Toast.makeText(Start.this, "" + position, Toast.LENGTH_SHORT).show(); Intent intent = new Intent(getApplicationContext(), Navigation.class); intent.putExtra(Navigation.INTENT_LOADMAPID, positionIdList.get(position).getIdentifier()); intent.putExtra(Navigation.INTENT_POS, intentPos); startActivityForResult(intent, NAVIGATION_REQUESTCODE); } } }); registerForContextMenu(gridview); } public class ImageAdapter extends BaseAdapter { private Context mContext; public ImageAdapter(Context c) { mContext = c; } public int getCount() { return bitmapList.size(); } public Object getItem(int position) { return null; } public long getItemId(int position) { return 0; } public int getPx(int dimensionDp) { float density = getResources().getDisplayMetrics().density; return (int) (dimensionDp * density + 0.5f); } // handles, if tiles can be clicked @Override public boolean isEnabled(int position) { if (noMaps == 0) { return true; } else { if (getResources().getConfiguration().orientation == 1 && position == 4) { return true; } else if (getResources().getConfiguration().orientation == 2 && position != 1) { return false; } else if (getResources().getConfiguration().orientation == 2 && position == 1) { return true; } else { return false; } } } DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = new ImageView(mContext); if (convertView == null) { // About 3/4 inch seems like a good size tileSize = (int)(120 * displayMetrics.density); imageView.setLayoutParams(new GridView.LayoutParams(tileSize, tileSize)); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(getPx(8), getPx(8), getPx(8), getPx(8)); } else { imageView = (ImageView) convertView; } // adds bitmaps of the map-thumbnails to the grid Bitmap[] bitmapArray = new Bitmap[bitmapList.size()]; bitmapList.toArray(bitmapArray); if (position == 0) { imageView.setFocusable(false); } if (bitmapArray[position] != null) { imageView.setImageBitmap(bitmapArray[position]); } return imageView; } } @Override protected void onStart() { super.onStart(); Log.d("Start", "onStart..."); } @Override protected void onStop() { super.onStop(); Log.d("Start", "onStop..."); } @Override protected void onResume() { super.onResume(); Log.d("Start", "onResume..."); if (isPopupOpen) { showNewMapPopup(); } } public void onPause() { super.onPause(); Log.d("Start", "onPause..."); if (newMapPopup != null) { newMapPopup.dismiss(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.start, menu); // If in debug mode, activate debug options if (MapEverApp.isDebugModeEnabled(this)) { menu.findItem(R.id.action_load_testmap).setVisible(true); } return super.onCreateOptionsMenu(menu); } // application-state handling @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putBoolean("isPopupOpen", isPopupOpen); savedInstanceState.putBoolean("isHelpShown", isHelpShown); } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); isPopupOpen = savedInstanceState.getBoolean("isPopupOpen"); isHelpShown = savedInstanceState.getBoolean("isHelpShown"); if (isHelpShown) { isHelpShown = false; toggleQuickHelp(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_quick_help) { toggleQuickHelp(); return true; } if (id == R.id.action_load_testmap) { // load test map (ID 0) Intent intent = new Intent(getApplicationContext(), Navigation.class); intent.putExtra(Navigation.INTENT_LOADMAPID, 0L); startActivityForResult(intent, NAVIGATION_REQUESTCODE); return true; } return super.onOptionsItemSelected(item); } private void toggleQuickHelp() { if (isHelpShown) { hideHelp(); } else { getLayoutInflater().inflate(R.layout.start_help, layout); findViewById(R.id.start_help_layout).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { hideHelp(); } }); isHelpShown = true; } } private boolean hideHelp() { if (!isHelpShown) { return false; } layout.removeViewAt(layout.getChildCount() - 1); isHelpShown = false; return true; } public static int getStatusBarHeight(Context context) { int result = 0; int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; } @Override public void onBackPressed() { if (isHelpShown) { hideHelp(); return; } // beendet offiziell die App finish(); } // ////// for getting the images protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CHOOSE_FILE_REQUESTCODE && resultCode == RESULT_OK) { Intent EntzerrenActivity = new Intent(getApplicationContext(), Entzerren.class); // Quell-Uri lesen Uri srcUri = data.getData(); try { // InputStream für Quelldatei erzeugen Log.d("Neue_Karte/onActivityResult", "Copying file '" + srcUri.toString() + "'"); InputStream inStream = this.getContentResolver().openInputStream(srcUri); // Zieldatei erstellen String destFilename = IMAGE_TARGET_FILENAME; File destFile = new File(MapEverApp.getAbsoluteFilePath(destFilename)); // Kopiere Daten von InputStream zu OutputStream FileUtils.copyStreamToFile(inStream, destFile); // Stream auf Quelldatei schließen inStream.close(); EntzerrenActivity.putExtra(INTENT_IMAGEPATH, destFilename); } catch (IOException e) { showErrorAlert(R.string.new_map_copy_error); e.printStackTrace(); } startActivity(EntzerrenActivity); } else if (requestCode == TAKE_PICTURE_REQUESTCODE && resultCode == RESULT_OK) { Intent EntzerrenActivity = new Intent(getApplicationContext(), Entzerren.class); EntzerrenActivity.putExtra(INTENT_IMAGEPATH, IMAGE_TARGET_FILENAME); startActivity(EntzerrenActivity); } else if (requestCode == NAVIGATION_REQUESTCODE && resultCode != RESULT_OK) { // Die Navigation hat einen Fehler zurückgegeben. // Öffne einen AlertDialog showErrorAlert(resultCode == 0 ? R.string.navigation_map_not_found : resultCode); } } private void showNewMapPopup() { newMapPopup.show(); isPopupOpen = true; Window win = newMapPopup.getWindow(); win.setContentView(R.layout.newmap); // camera ImageButton camera = (ImageButton) win.findViewById(R.id.camera); camera.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent photoIntent; if (Settings.getPreference_cdCamera(Start.this)) { // Intent erzeugen, der die CornerDetectionCamera startet photoIntent = new Intent(getApplicationContext(), CornerDetectionCamera.class); // (In MediaStore.EXTRA_OUTPUT wird hier ein String statt einer Uri übergeben.) photoIntent.putExtra(MediaStore.EXTRA_OUTPUT, MapEverApp.getAbsoluteFilePath(IMAGE_TARGET_FILENAME)); photoIntent.putExtra(CornerDetectionCamera.NO_CONFIRM, true); } else { // Intent erzeugen, der Standard-Android-Kamera startet photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File destFile = new File(MapEverApp.getAbsoluteFilePath(IMAGE_TARGET_FILENAME)); photoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(destFile)); } // Activity starten und auf Ergebnis (Bild) warten startActivityForResult(photoIntent, TAKE_PICTURE_REQUESTCODE); } }); // filechooser ImageButton filechooser = (ImageButton) win.findViewById(R.id.filechooser); filechooser.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); Intent i = Intent.createChooser(intent, "File"); startActivityForResult(i, CHOOSE_FILE_REQUESTCODE); } }); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; int position = info.position; String header = ""; if (position != 0 && noMaps == 0) { header = positionIdList.get(position).getMapname(); if (header.isEmpty()) { header = getResources().getString(R.string.navigation_const_name_of_unnamed_maps); } } if (position != 0 && noMaps == 0) { String rename = getString(R.string.start_context_rename); String delete = getString(R.string.start_context_delete); menu.add(0, v.getId(), 0, rename); menu.add(0, v.getId(), 0, delete); menu.setHeaderTitle(header); } } public void deleteMap(TrackDBEntry map) { TrackDB.main.delete(map); String basefile = MapEverApp.getAbsoluteFilePath(Long.toString(map.getIdentifier())); new File(basefile).delete(); new File(basefile + MapEverApp.THUMB_EXT).delete(); } public void renameMap(TrackDBEntry map, String newName) { map.setMapname(newName); } public boolean onContextItemSelected(MenuItem item) { final AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); int position = info.position; String rename = getString(R.string.start_context_rename); String delete = getString(R.string.start_context_delete); String mapName = positionIdList.get(position).getMapname(); if (mapName.isEmpty()) { mapName = getResources().getString(R.string.navigation_const_name_of_unnamed_maps); } if (item.getTitle() == rename) { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle(R.string.navigation_rename_map); final EditText input = new EditText(this); input.setText(mapName); alert.setView(input); alert.setPositiveButton(R.string.navigation_rename_map_rename, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String newName = input.getEditableText().toString(); renameMap(positionIdList.get(info.position), newName); showToast(getResources().getString(R.string.start_context_rename_success)); } }); alert.setNegativeButton(R.string.navigation_rename_map_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.cancel(); } }); AlertDialog alertDialog = alert.create(); alertDialog.show(); } else if (item.getTitle() == delete) { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setIcon(android.R.drawable.ic_dialog_alert); alert.setTitle(R.string.start_context_delete); alert.setMessage(R.string.start_context_delete_confirmation_msg); alert.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { deleteMap(positionIdList.get(info.position)); Intent intent = getIntent(); finish(); startActivity(intent); } }); alert.setNegativeButton(android.R.string.no, null); alert.show(); } else { return false; } return true; } private void showToast(String message) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); } private void showErrorAlert(int stringResId) { // Erstelle entsprechenden AlertDialog AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.general_error_title); builder.setMessage(stringResId); AlertDialog dialog = builder.create(); // Dialog anzeigen dialog.show(); // Wenn der Dialog geschlossen wird // dialog.setOnCancelListener(new OnCancelListener() { // public void onCancel(DialogInterface dialog) { // } // }); } // returns the size of the grid's tiles in px public static int getThumbnailSize() { return tileSize; } }