diff --git a/Code Android/meinWald/app/src/main/AndroidManifest.xml b/Code Android/meinWald/app/src/main/AndroidManifest.xml index 38ae097..0fdc19c 100644 --- a/Code Android/meinWald/app/src/main/AndroidManifest.xml +++ b/Code Android/meinWald/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.example.meinwald"> + + + + + + + + \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/MainActivity.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/MainActivity.java index cd02c23..50aea1a 100644 --- a/Code Android/meinWald/app/src/main/java/com/example/meinwald/MainActivity.java +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/MainActivity.java @@ -1,5 +1,6 @@ package com.example.meinwald; +import android.content.Context; import android.os.Bundle; import com.google.android.material.bottomnavigation.BottomNavigationView; @@ -12,9 +13,14 @@ import androidx.navigation.ui.NavigationUI; public class MainActivity extends AppCompatActivity { + private static Context context; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + context = getApplicationContext(); + setContentView(R.layout.activity_main); BottomNavigationView navView = findViewById(R.id.nav_view); // Passing each menu ID as a set of Ids because each @@ -27,4 +33,8 @@ public class MainActivity extends AppCompatActivity { NavigationUI.setupWithNavController(navView, navController); } + public static Context getAppContext() { + return context; + } + } \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/MyApplication.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/MyApplication.java new file mode 100644 index 0000000..ee89c96 --- /dev/null +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/MyApplication.java @@ -0,0 +1,18 @@ +package com.example.meinwald; + +import android.app.Application; +import android.content.Context; + +public class MyApplication extends Application { + + private static Context context; + + public void onCreate() { + super.onCreate(); + MyApplication.context = getApplicationContext(); + } + + public static Context getAppContext() { + return MyApplication.context; + } +} \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaAdapter.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaAdapter.java new file mode 100644 index 0000000..c68c8c3 --- /dev/null +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaAdapter.java @@ -0,0 +1,143 @@ +package com.example.meinwald.ui.area; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Rect; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.meinwald.BuildConfig; +import com.example.meinwald.R; +import com.example.meinwald.ui.task.OwnTask; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import java.util.ArrayList; +import java.util.List; + +import androidx.appcompat.widget.AlertDialogLayout; +import androidx.appcompat.widget.LinearLayoutCompat; +import androidx.constraintlayout.widget.ConstraintLayout; + +import static java.security.AccessController.getContext; + +public class AreaAdapter extends BaseAdapter +{ + List areaList; + LayoutInflater inflater; + Context context; + + public AreaAdapter(Context applicationContext, List areaList) + { + this.areaList = new ArrayList<>(); + this.areaList = areaList; + this.context = applicationContext; + + inflater = LayoutInflater.from(applicationContext); + + if (BuildConfig.DEBUG) + { + Log.d("AreaAdapter","size: " + areaList.size()); + } + } + + @Override + public View getView(final int i, View view, final ViewGroup viewGroup) { + + view = inflater.inflate(R.layout.area_element, null); + final ConstraintLayout elementView = view.findViewById(R.id.areaInfoView); + final ConstraintLayout infovView = view.findViewById(R.id.areaInfoView); + final TextView title = (TextView) view.findViewById(R.id.areaInfoTitle); + final TextView notice = (TextView) view.findViewById(R.id.areaInfoNotice); + final ImageView icon = (ImageView) view.findViewById(R.id.areaIcon); + context = view.getContext(); + + + + if (BuildConfig.DEBUG) + { + Log.d("AreaAdapter",areaList.get(i).toString()); + Log.d("AreaAdapter",areaList.get(i).getTitle()); + Log.d("AreaAdapter",areaList.get(i).getNotice()); + } + + title.setText(areaList.get(i).getTitle()); + notice.setText(areaList.get(i).getNotice()); + icon.setImageBitmap(areaList.get(i).getImage()); + + title.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) + { + + + } + }); + + notice.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) + { + + + } + }); + + icon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) + { + + final AlertDialog.Builder builder = new AlertDialog.Builder(v.getRootView().getContext()); + final View viewInflated = LayoutInflater.from(v.getRootView().getContext()).inflate(R.layout.image_large, viewGroup, false); + + builder.setView(viewInflated); + + final ConstraintLayout imageViewLayout = viewInflated.findViewById(R.id.taskLargeImageLayout); + final ImageView imageView = viewInflated.findViewById(R.id.taskLargeImage); + + imageView.setImageBitmap(areaList.get(i).getImage()); + + builder.setNegativeButton("Zurück", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + } + }); + + view.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + // TODO Auto-generated method stub + return true; + } + }); + + return view; + } + + @Override + public int getCount() { + return areaList.size(); + } + + @Override + public Object getItem(int i) { + return areaList.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } +} + diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaFragment.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaFragment.java index e97e8ae..52967ae 100644 --- a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaFragment.java +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaFragment.java @@ -1,39 +1,570 @@ package com.example.meinwald.ui.area; +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.content.ComponentName; +import android.content.DialogInterface; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.location.Location; import android.os.Bundle; +import android.os.IBinder; +import android.os.PowerManager; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.ListView; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; -import androidx.lifecycle.ViewModelProviders; +import com.example.meinwald.BuildConfig; import com.example.meinwald.R; +import com.example.meinwald.ui.task.TaskAdapter; +import com.example.meinwald.ui.task.TasksFragment; +import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import static android.content.Context.POWER_SERVICE; + public class AreaFragment extends Fragment { - private DashboardViewModel dashboardViewModel; + private static final String TAG = TasksFragment.class.getSimpleName(); + + /** + * ______________________________________________________________________________________________ + * AREA + */ + private OwnArea newArea = new OwnArea(); + private List allAreas; + private ListView areaList; + private static final String KEY_AREA_REFERENCES = "areaReferences"; + private List areaReferences; + + /** + * ______________________________________________________________________________________________ + * LOCATION + */ + private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1; + /** + * The entry point to the Fused Location Provider. + */ + private FusedLocationProviderClient mFusedLocationProviderClient; + private boolean mLocationPermissionGranted; + /** + * The geographical locations which were received from location tracking. + */ + private List newPositions; + + /** + * ______________________________________________________________________________________________ + * CAMERA + */ + private static final int MY_CAMERA_PERMISSION_CODE = 100; + private boolean mCameraPermissionGranted; + private static final int CAMERA_REQUEST = 1888; + + /** + * ______________________________________________________________________________________________ + * STORAGE + */ + private static final int READ_EXTERNAL_STORAGE_CODE = 200; + private static final int WRITE_EXTERNAL_STORAGE_CODE = 201; + private boolean mReadStorageGranted; + private boolean mWriteStorageGranted; + + PowerManager.WakeLock wakeLock; + LocationService gps; + + + @SuppressLint("InvalidWakeLockTag") + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - public View onCreateView(@NonNull LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { - dashboardViewModel = - ViewModelProviders.of(this).get(DashboardViewModel.class); View root = inflater.inflate(R.layout.fragment_areas, container, false); - final TextView textView = root.findViewById(R.id.text_areas); - dashboardViewModel.getText().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(@Nullable String s) { - textView.setText(s); - } - }); - FloatingActionButton fab = root.findViewById(R.id.fab_areas); + //construct a FusedLocationProviderClient. + mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity()); + + //get permissions + getLocationPermission(); + getReadStoragePermission(); + + //instantiate area lists + areaList = (ListView) root.findViewById(R.id.areaListView); + allAreas = new ArrayList<>(); + areaReferences = new ArrayList<>(); + + PowerManager powerManager = (PowerManager) getContext().getSystemService(POWER_SERVICE); + wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag"); + gps = new LocationService(getContext()); + + //instantiate add button + final FloatingActionButton fab = root.findViewById(R.id.fab_areas); + + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + //permissions + getLocationPermission(); + getWriteStoragePPermission(); + + //get saved areas + areaReferences = readAreaReferencesFromPreferences(); + allAreas = loadAreasFromPreferences(); + instantiateAreasList(); + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + + newArea = new OwnArea(); + + final View viewInflated = LayoutInflater.from(getContext()).inflate(R.layout.area_input, (ViewGroup) getView(), false); + builder.setView(viewInflated); + + final Button startTracking = viewInflated.findViewById(R.id.areaStartTracking); + final Button stopTracking = viewInflated.findViewById(R.id.areaStopTracking); + + + startTracking.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + //start tracking + startLocationTracking(); + + startTracking.setVisibility(View.INVISIBLE); + stopTracking.setVisibility(View.VISIBLE); + } + }); + + stopTracking.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + //stop tracking + newPositions = gps.getPositions(); + + if (BuildConfig.DEBUG) + { + Log.d(TAG, "Received locations: " + newPositions.size()); + } + + newArea.setLocations(newPositions); + wakeLock.release(); + + startTracking.setVisibility(View.VISIBLE); + stopTracking.setVisibility(View.INVISIBLE); + } + }); + + builder.setPositiveButton("Bestätigen", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + final TextView titleView = viewInflated.findViewById(R.id.areaTitleUserInput); + final TextView noticeView = viewInflated.findViewById(R.id.areaNoticeUserInput); + + if (BuildConfig.DEBUG) { + Log.d(TAG, "new title: " + titleView.getText()); + } + + if (titleView.getText().length()>0) + { + //save user input + newArea.setTitle(String.valueOf(titleView.getText())); + newArea.setNotice(String.valueOf(noticeView.getText())); + + boolean result = allAreas.add(newArea); + + if (BuildConfig.DEBUG) + { + Log.d(TAG, "new Task: " + newArea.toString()); + Log.d(TAG, "add new task result: " + result); + } + + //stop tracking + //wakeLock.release(); + + //save new area + allAreas.add(newArea); + writeAreaToExternalStorage(newArea); + + //actuate list + instantiateAreasList(); + + dialog.dismiss(); + + //confirm added task + Toast toast = Toast.makeText(getActivity(), "Grundstück hinzugefügt!", Toast.LENGTH_SHORT); + TextView v = (TextView) toast.getView().findViewById(android.R.id.message); + if( v != null) + { + //text align center + v.setGravity(Gravity.CENTER); + } + toast.show(); + } + else + { + //title needed + Toast toast = Toast.makeText(getActivity(), "Grundstückstitel fehlt!", Toast.LENGTH_SHORT); + TextView v = (TextView) toast.getView().findViewById(android.R.id.message); + if( v != null) + { + //text align center + v.setGravity(Gravity.CENTER); + } + toast.show(); + } + } + }); + + builder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + }}); return root; } + + /** + * Get all stored areas and save them temporary. + */ + public void instantiateAreasList() + { + final AreaAdapter adapter = new AreaAdapter(getActivity().getApplicationContext(), allAreas); + areaList.setAdapter(adapter); + + //initialise onClickListeners + areaList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + + //for (int j = 0; j < adapterView.getChildCount(); j++) + //adapterView.getChildAt(j).setBackgroundColor(Color.TRANSPARENT); + + // change the background color of the selected element + //view.setBackgroundColor(Color.LTGRAY); + //adapterView.setSelection(i); + }}); + } + + + @Override + public void onPause() { + + //save area references to shared preferences + emptyPreferencesAndSaveEpiColorsToPreferences(); + + super.onPause(); + } + + /** + * Get OwnAreas from a JSONString. + * @return + */ + private List loadAreasFromPreferences() + { + List areas = new ArrayList<>(); + + for (AreaReference reference: areaReferences) + { + String jsonString = readAreaFromExternalStorage(reference.getPath()); + + areas.add(new OwnArea(jsonString)); + } + + return areas; + } + + /** + * Save OwnArea object in textfile on external storage. + * + * @param newArea OwnArea object to write to file. + * @return + */ + private String writeAreaToExternalStorage(OwnArea newArea){ + + // Find the root of the external storage. + File root = android.os.Environment.getExternalStorageDirectory(); + + //create file if it does not exist + File path = new File (root.getAbsolutePath() + "meinWald" + File.pathSeparator + "areas"); + if(!path.exists()){ + path.mkdirs(); + } + File file = new File(path, newArea.getId() + ".txt"); + + //open file and write to it + try { + FileOutputStream f = new FileOutputStream(file); + PrintWriter pw = new PrintWriter(f); + pw.print(areaToString(newArea)); + pw.close(); + f.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return file.getPath(); + } + + /** + * Read OwnArea from file in external storage and return as a string. + * + * @param path File path where the OwnArea is saved. + * @return + */ + private String readAreaFromExternalStorage(String path) + { + //Get the text file + File file = new File(path); + + //Read text from file + StringBuilder text = new StringBuilder(); + + try { + BufferedReader br = new BufferedReader(new FileReader(file)); + String line; + + while ((line = br.readLine()) != null) { + text.append(line); + } + br.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + + return text.toString(); +} + + /** + * Converts an OwnArea object into a JSONString object. + * + * @param area Area to convert into JSONString + * @return + */ + + public String areaToString(OwnArea area) + { + JSONObject areaObject = newArea.toJSONObject(); + + return areaObject.toString(); + } + + /** + * Reads areaReferences saved in preferences as jsonStrings + * + * @return list of epiColorDtos + */ + private List readAreaReferencesFromPreferences() { + List areas = new ArrayList<>(); + + try { + String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_AREA_REFERENCES, "error"); + if(!"error".equalsIgnoreCase(jsonString)) { + JSONArray jsonObjects = new JSONArray(jsonString); + for (int i = 0; i 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) + { + mLocationPermissionGranted = true; + } + } + case MY_CAMERA_PERMISSION_CODE: { + + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + mCameraPermissionGranted = true; + } + } + case READ_EXTERNAL_STORAGE_CODE: { + + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + mReadStorageGranted = true; + } + } + case WRITE_EXTERNAL_STORAGE_CODE: { + + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + mWriteStorageGranted = true; + } + } + } + } + + public void getLocation(){ + + wakeLock.acquire(); + + gps = new LocationService(getContext()); + + } + + public void startLocationTracking(){ + + final Runnable runnable= new Runnable() { + public void run() { + // do stuff here + getLocation(); + } + }; + runnable.run(); + } + + /** + * Request location permission, so that we can get the location of the device. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getLocationPermission() { + if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), + android.Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + mLocationPermissionGranted = true; + } else { + ActivityCompat.requestPermissions(getActivity(), + new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, + PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION); + } + } + + /** + * Request read external storage permission, so that we can get saved images from external storage. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getReadStoragePermission() { + if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), + Manifest.permission.READ_EXTERNAL_STORAGE) + == PackageManager.PERMISSION_GRANTED) { + mReadStorageGranted = true; + } else { + ActivityCompat.requestPermissions(getActivity(), + new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, + READ_EXTERNAL_STORAGE_CODE); + } + } + + /** + * Request read external storage permission, so that we can get saved images from external storage. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getWriteStoragePPermission() { + if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), + Manifest.permission.WRITE_EXTERNAL_STORAGE) + == PackageManager.PERMISSION_GRANTED) { + mWriteStorageGranted = true; + } else { + ActivityCompat.requestPermissions(getActivity(), + new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, + WRITE_EXTERNAL_STORAGE_CODE); + } + } } \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaReference.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaReference.java new file mode 100644 index 0000000..0f3fdbd --- /dev/null +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/AreaReference.java @@ -0,0 +1,73 @@ +package com.example.meinwald.ui.area; + +import android.util.Log; + +import com.example.meinwald.BuildConfig; + +import org.json.JSONException; +import org.json.JSONObject; + +public class AreaReference +{ + private String id; + private String path; + + public AreaReference(String id, String path) + { + this.id = id; + this.path = path; + } + + public String getId() { + return id; + } + + public String getPath() { + return path; + } + + /** + * Creates EpiColorDto from JSON-Representation + * + * @param jsonRepresentation epiColorDto values as jsonObject + */ + public AreaReference(JSONObject jsonRepresentation) { + try { + this.id = jsonRepresentation.getString("id"); + this.path = jsonRepresentation.getString("path"); + } catch (JSONException e) { + if (BuildConfig.DEBUG) { + Log.e(this.getClass().getSimpleName(), + String.format("Error while parsing epiColorDto to JSONObject. Values of epiColorDto: %s", this.toString())); + } + } + } + + /** + * Returns AreaReference as JSONObject. + * + * @return the mapped object or null, if parsing fails + */ + public JSONObject toJSONObject() { + JSONObject object = new JSONObject(); + try { + object.put("id",this.id); + object.put("path",this.path); + return object; + } catch (JSONException e) { + if (BuildConfig.DEBUG) { + Log.e(this.getClass().getSimpleName(), + String.format("Error while parsing epiColorDto to JSONObject. Values of epiColorDto: %s", this.toString())); + } + return null; + } + } + + @Override + public String toString() { + return "AreaReference{" + + "id='" + id + '\'' + + ", path='" + path + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/DashboardViewModel.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/DashboardViewModel.java deleted file mode 100644 index 53536ba..0000000 --- a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/DashboardViewModel.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.example.meinwald.ui.area; - -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; - -public class DashboardViewModel extends ViewModel { - - private MutableLiveData mText; - - public DashboardViewModel() { - mText = new MutableLiveData<>(); - mText.setValue("This is dashboard fragment"); - } - - public LiveData getText() { - return mText; - } -} \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/LocationService.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/LocationService.java new file mode 100644 index 0000000..483151b --- /dev/null +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/LocationService.java @@ -0,0 +1,290 @@ +package com.example.meinwald.ui.area; + + +import android.Manifest; +import android.app.AlertDialog; +import android.app.Service; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.IBinder; +import android.provider.Settings; +import android.util.Log; + +import com.example.meinwald.BuildConfig; +import com.google.android.gms.maps.model.LatLng; + +import java.util.ArrayList; +import java.util.List; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +//import static com.name.name.MapsActivity.NOTIFICATION_ID; + +public class LocationService extends Service implements LocationListener { + + private static final String TAG = "LocationService"; + + private final Context mContext; + + // flag for GPS status + boolean isGPSEnabled = false; + + // flag for network status + boolean isNetworkEnabled = false; + + // flag for GPS status + boolean canGetLocation = false; + private boolean mLocationPermissionGranted; + + Location location; // location + double latitude; // latitude + double longitude; // longitude + + private List positions; + + // The minimum distance to change Updates in meters + private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1; // 5 meters + + // The minimum time between updates in milliseconds + private static final long MIN_TIME_BW_UPDATES = 1000 * 5 * 1; // 5 seconds + + // Declaring a Location Manager + protected LocationManager mLocationManager; + + public LocationService(Context context) { + + if (BuildConfig.DEBUG) { + Log.d(TAG, "LocationService(Context context)"); + } + + this.mContext = context; + this.positions = new ArrayList<>(); + this.mLocationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE); + + getLocationPermission(); + + try { + // getting GPS status + isGPSEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + + if (!isGPSEnabled && !isNetworkEnabled) { + // no network provider is enabled + + Log.d(TAG,"No permission to get location from any provider!"); + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + + + } + + } + else + { + Log.d(TAG,"Permission to get location from any provider!"); + + this.canGetLocation = true; + // First get location from Network Provider + if (isNetworkEnabled) { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + + Log.d(TAG,"No permission to get location from network provider!"); + } + + if (BuildConfig.DEBUG) + { + Log.d(TAG, "getLocation() requestLocationUpdates() from GPS"); + } + + mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); + + if (mLocationManager != null) { + location = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + + if (location != null) { + positions.add(new LatLng(location.getLatitude(), location.getLongitude())); + if (BuildConfig.DEBUG) + { + Log.d(TAG, "getLocation() new location added"); + } + } + } + } + + // if GPS Enabled get lat/long using GPS Services + if (isGPSEnabled && mLocationPermissionGranted) { + if (location == null) { + if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + + Log.d(TAG,"No permission to get location from gps provider!"); + } + + if (BuildConfig.DEBUG) + { + Log.d(TAG, "getLocation() requestLocationUpdates() from GPS"); + } + + mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this); + + if (mLocationManager != null) { + location = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (location != null) { + positions.add(new LatLng(location.getLatitude(), location.getLongitude())); + if (BuildConfig.DEBUG) + { + Log.d(TAG, "getLocation() new location added"); + } + } + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public void getLocation() { + + if (BuildConfig.DEBUG) { + Log.d(TAG, "getLocation()"); + } + + } + + /** + * Stop using GPS listener + * Calling this function will stop using GPS in your app + * */ + public void stopUsingGPS(){ + if(mLocationManager != null){ + mLocationManager.removeUpdates(LocationService.this); + } + } + + /** + * Function to get latitude + * */ + public double getLatitude(){ + if(location != null){ + latitude = location.getLatitude(); + } + + // return latitude + return latitude; + } + + public List getPositions() + { + if (BuildConfig.DEBUG) + { + Log.d(TAG, "getPositions() count: " + this.positions.size()); + } + + return this.positions; + } + + /** + * Function to get longitude + * */ + public double getLongitude(){ + if(location != null){ + longitude = location.getLongitude(); + } + + // return longitude + return longitude; + } + + /** + * Function to check GPS/wifi enabled + * @return boolean + * */ + public boolean canGetLocation() { + return this.canGetLocation; + } + + /** + * Function to show settings alert dialog + * On pressing Settings button will lauch Settings Options + * */ + public void showSettingsAlert(){ + AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext); + + // Setting Dialog Title + alertDialog.setTitle("GPS is settings"); + + // Setting Dialog Message + alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?"); + + // On pressing Settings button + alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog,int which) { + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + mContext.startActivity(intent); + } + }); + + // on pressing cancel button + alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + // Showing Alert Message + alertDialog.show(); + } + + /** + * Request location permission, so that we can get the location of the device. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getLocationPermission() { + if (ContextCompat.checkSelfPermission(mContext, + android.Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + mLocationPermissionGranted = true; + } + else + { + mLocationPermissionGranted = false; + } + } + + @Override + public void onLocationChanged(Location location) { + if (BuildConfig.DEBUG) + { + Log.d(TAG, "onLocationChanged(), new location: " + location.toString()); + } + + positions.add(new LatLng(location.getLatitude(), getLongitude())); + } + + @Override + public void onProviderDisabled(String provider) { + } + + @Override + public void onProviderEnabled(String provider) { + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + } + + @Override + public IBinder onBind(Intent arg0) { + return null; + } +} \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/OwnArea.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/OwnArea.java new file mode 100644 index 0000000..f40bd2a --- /dev/null +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/area/OwnArea.java @@ -0,0 +1,170 @@ +package com.example.meinwald.ui.area; + +import android.graphics.Bitmap; +import android.location.Location; +import android.util.Log; + +import com.example.meinwald.BuildConfig; +import com.google.android.gms.maps.model.LatLng; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.sql.Time; +import java.util.Date; +import java.util.List; + +public class OwnArea { + + private String title; + private String notice; + private List locations; + private Bitmap image; + private String pathImage; + private String pathLocations; + private String id; + private Date time; + + public void setImage(Bitmap image) { + this.image = image; + } + + public void setTitle(String title) { + this.title = title; + this.id = generateAreaID(title); + } + + public void setNotice(String notice) { + this.notice = notice; + } + + public void setLocations(List locations) { + this.locations = locations; + } + + public void setPathImage(String pathImage) { + this.pathImage = pathImage; + } + + public void setPathLocations(String pathLocations) { + this.pathLocations = pathLocations; + } + + public String getNotice() { + return notice; + } + + public String getTitle() { + return title; + } + + public Bitmap getImage() { + return image; + } + + public List getLocations() { + return locations; + } + + public String getId() { + return id; + } + + public String getPathImage() { + return pathImage; + } + + public String getPathLocations() { + return pathLocations; + } + + public OwnArea() + { + + } + + public OwnArea(String jsonString){ + try { + JSONObject areaObject = new JSONObject(jsonString); + this.title = areaObject.getString("title"); + this.notice = areaObject.getString("description"); + this.id = areaObject.getString("id"); + this.time = new Date(areaObject.getString("time")); + + } catch (JSONException e) { + if (BuildConfig.DEBUG) { + Log.e(this.getClass().getSimpleName(), "earthquakeJSON " + jsonString); + e.printStackTrace(); + } + } + } + + private String generateAreaID(String title) + { + String id = title.replaceAll(" ", "_") + "_" + new Date().getTime(); + + if (BuildConfig.DEBUG) + { + Log.d(getClass().getSimpleName(), "new ID: " + id); + } + return id; + } + + + /** + * Returns OwnArea as JSONObject. + * + * @return the mapped object or null, if parsing fails + */ + public JSONObject toJSONObject() { + JSONObject object = new JSONObject(); + try { + object.put("title",this.title); + object.put("description",this.notice); + object.put("id",this.id); + + if (this.time != null) + { + object.put("time", this.time); + } + else + { + object.put("time", new Date().getTime()); + } + + + JSONObject locations = new JSONObject(); + Long count = Long.valueOf(0); + + //convert all locations + for (LatLng location: this.locations) + { + JSONObject locationObject = new JSONObject(); + locationObject.put("Lat", location.latitude); + locationObject.put("Lng", location.longitude); + locations.put("location"+count, locationObject.toString()); + } + object.put("locations", locations.toString()); + + return object; + + } catch (JSONException e) { + if (BuildConfig.DEBUG) { + Log.e(this.getClass().getSimpleName(), + String.format("Error while parsing epiColorDto to JSONObject. Values of epiColorDto: %s", this.toString())); + } + return null; + } + } + + @Override + public String toString() { + return "OwnArea{" + + "title='" + title + '\'' + + ", notice='" + notice + '\'' + + ", pathImage='" + pathImage + '\'' + + ", pathLocations='" + pathLocations + '\'' + + ", id='" + id + '\'' + + '}'; + } +} diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/map/MapsFragment.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/map/MapsFragment.java index 7547331..6fb5c6c 100644 --- a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/map/MapsFragment.java +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/map/MapsFragment.java @@ -1,27 +1,43 @@ package com.example.meinwald.ui.main.map; +import android.Manifest; import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.location.Location; import android.os.Bundle; +import android.os.IBinder; import android.preference.PreferenceManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ListView; import com.example.meinwald.BuildConfig; import com.example.meinwald.R; +import com.example.meinwald.ui.task.OwnTask; +import com.google.android.gms.dynamic.IObjectWrapper; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationServices; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; +import com.google.android.gms.maps.model.BitmapDescriptor; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; +import org.json.JSONArray; +import org.json.JSONException; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -62,6 +78,22 @@ public class MapsFragment extends Fragment implements OnMapReadyCallback { */ private Location mLastKnownLocation; + /** + * ______________________________________________________________________________________________ + * TASKS + */ + private List allTasks; + private static final String KEY_ALL_TASKS = "allTasks"; + + /** + * ______________________________________________________________________________________________ + * STORAGEE + */ + private static final int READ_EXTERNAL_STORAGE_CODE = 200; + private static final int WRITE_EXTERNAL_STORAGE_CODE = 201; + private boolean mReadStorageGranted; + private boolean mWriteStorageGranted; + /** * Is called when the MapsFragment view is created. Initializes all service connections, the location client and map itself. * @param inflater Calling LayoutInflater @@ -74,6 +106,12 @@ public class MapsFragment extends Fragment implements OnMapReadyCallback { //get view to inflate View root = inflater.inflate(fragment_map, container, false); + //get storage permission + getReadStoragePermission(); + + //get tasks + allTasks = readTasksFromPreferences(); + //display map fragment SupportMapFragment mapFragment = new SupportMapFragment(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); @@ -187,6 +225,13 @@ public class MapsFragment extends Fragment implements OnMapReadyCallback { mLocationPermissionGranted = true; } } + case READ_EXTERNAL_STORAGE_CODE: { + + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + mReadStorageGranted = true; + } + } } } @@ -274,6 +319,72 @@ public class MapsFragment extends Fragment implements OnMapReadyCallback { e.printStackTrace(); } } + + for (OwnTask task: allTasks) + { + MarkerOptions marker = new MarkerOptions(); + + //set options + marker.position(new LatLng(task.getLocation().getLatitude(), task.getLocation().getLongitude())); + marker.title(task.getTitle()); + + mMap.addMarker(marker); + } + } + + /** + * Request read external storage permission, so that we can get saved images from external storage. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getReadStoragePermission() { + if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), + Manifest.permission.READ_EXTERNAL_STORAGE) + == PackageManager.PERMISSION_GRANTED) { + mReadStorageGranted = true; + } else { + ActivityCompat.requestPermissions(getActivity(), + new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, + READ_EXTERNAL_STORAGE_CODE); + } + } + + /** + * Reads tasks saved in preferences as jsonStrings + * + * @return list of OwnTask + */ + private List readTasksFromPreferences() { + List tasks = new ArrayList<>(); + + try { + String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_ALL_TASKS, "error"); + if(!"error".equalsIgnoreCase(jsonString)) { + JSONArray jsonObjects = new JSONArray(jsonString); + + for (int i = 0; i taskList; + LayoutInflater inflater; + Context context; + + public TaskAdapter(Context applicationContext, List taskList) + { + this.taskList = new ArrayList<>(); + this.taskList = taskList; + this.context = applicationContext; + + inflater = LayoutInflater.from(applicationContext); + + if (BuildConfig.DEBUG) + { + //Log.d("TaskAdapter",taskList.get(0).toString()); + Log.d("TaskAdapter","size: " + taskList.size()); + } + } + + @Override + public View getView(final int i, View view, final ViewGroup viewGroup) { + + view = inflater.inflate(R.layout.task_element, null); + final ConstraintLayout elementView = view.findViewById(R.id.taskInfoView); + final ConstraintLayout infovView = view.findViewById(R.id.taskInfoView); + final TextView title = (TextView) view.findViewById(R.id.taskInfoTitle); + final TextView notice = (TextView) view.findViewById(R.id.taskInfoNotice); + final ImageView icon = (ImageView) view.findViewById(R.id.taskIcon); + context = view.getContext(); + + + + if (BuildConfig.DEBUG) + { + Log.d("TaskAdapter",taskList.get(i).toString()); + Log.d("TaskAdapter",taskList.get(i).getTitle()); + Log.d("TaskAdapter",taskList.get(i).getNotice()); + } + + title.setText(taskList.get(i).getTitle()); + notice.setText(taskList.get(i).getNotice()); + icon.setImageBitmap(taskList.get(i).getImage()); + + title.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) + { + + + } + }); + + notice.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) + { + + + } + }); + + icon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) + { + + final AlertDialog.Builder builder = new AlertDialog.Builder(v.getRootView().getContext()); + final View viewInflated = LayoutInflater.from(v.getRootView().getContext()).inflate(R.layout.image_large, viewGroup, false); + + //viewInflated.setLayoutParams(new AlertDialogLayout.LayoutParams(taskList.get(i).getImage().getWidth(),5 * taskList.get(i).getImage().getHeight())); + + builder.setView(viewInflated); + + final ConstraintLayout imageViewLayout = viewInflated.findViewById(R.id.taskLargeImageLayout); + final ImageView imageView = viewInflated.findViewById(R.id.taskLargeImage); + + //ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(taskList.get(i).getImage().getWidth(),5 * taskList.get(i).getImage().getHeight()); + //imageViewLayout.setLayoutParams(layoutParams); + imageView.setImageBitmap(taskList.get(i).getImage()); + + builder.setNegativeButton("Zurück", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + } + }); + + view.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + // TODO Auto-generated method stub + return true; + } + }); + + return view; + } + + @Override + public int getCount() { + return taskList.size(); + } + + @Override + public Object getItem(int i) { + return taskList.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } +} diff --git a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TasksFragment.java b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TasksFragment.java index ee63c60..18f52ff 100644 --- a/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TasksFragment.java +++ b/Code Android/meinWald/app/src/main/java/com/example/meinwald/ui/task/TasksFragment.java @@ -1,23 +1,35 @@ package com.example.meinwald.ui.task; +import android.Manifest; +import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; import android.location.Location; import android.media.Image; +import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.preference.PreferenceManager; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.Button; +import android.widget.ImageView; +import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; @@ -34,19 +46,32 @@ import com.google.android.gms.tasks.Task; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + public class TasksFragment extends Fragment { private static final String TAG = TasksFragment.class.getSimpleName(); + private View root; + private LayoutInflater layoutInflater; + private ImageView imageToAdd; /** * ______________________________________________________________________________________________ * LOCATION */ private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1; - private static final String KEY_LOCATION = "location"; /** * The entry point to the Fused Location Provider. */ @@ -58,85 +83,51 @@ public class TasksFragment extends Fragment { */ private Location mLastKnownLocation; - private NotificationsViewModel notificationsViewModel; + /** + * ______________________________________________________________________________________________ + * TASKS + */ + private OwnTask newTask = new OwnTask(); + private List allTasks; + private ListView taskList; + private static final String KEY_ALL_TASKS = "allTasks"; - public class OwnTask - { - private String title; - private String notice; - private Location location; - private Image image; + /** + * ______________________________________________________________________________________________ + * CAMERA + */ + private static final int MY_CAMERA_PERMISSION_CODE = 100; + private boolean mCameraPermissionGranted; + private static final int CAMERA_REQUEST = 1888; - public OwnTask() - { - this.title = null; - this.notice = null; - this.location = null; - this.image = null; - } - - public OwnTask(String title, String notice, Location location, Image image) - { - this.title = title; - this.notice = notice; - this.location = location; - this.image = image; - } - - public String getTitle() { - return title; - } - - public String getNotice() { - return notice; - } - - public Location getLocation() { - return location; - } - - public Image getImage() { - return image; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setNotice(String notice) { - this.notice = notice; - } - - public void setLocation(Location location) { - this.location = location; - } - - public void setImage(Image image) { - this.image = image; - } - - @Override - public String toString() { - return "OwnTask{" + - "title='" + title + '\'' + - ", notice='" + notice + '\'' + - ", location=" + location + - '}'; - } - } - - OwnTask newTask = new OwnTask(); + /** + * ______________________________________________________________________________________________ + * STORAGE + */ + private static final int READ_EXTERNAL_STORAGE_CODE = 200; + private static final int WRITE_EXTERNAL_STORAGE_CODE = 201; + private boolean mReadStorageGranted; + private boolean mWriteStorageGranted; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.fragment_tasks, container, false); + layoutInflater = inflater; + root = inflater.inflate(R.layout.fragment_tasks, container, false); - //instance add button + taskList = (ListView) root.findViewById(R.id.taskListView); + + //instantiate add button FloatingActionButton fab = root.findViewById(R.id.fab_tasks); + allTasks = readTasksFromPreferences(); + instantiateTaskList(); + //construct a FusedLocationProviderClient. mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity()); + //get read storage permission + getReadStoragePermission(); + //get location permission getLocationPermission(); @@ -145,11 +136,18 @@ public class TasksFragment extends Fragment { public void onClick(View view) { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + newTask = new OwnTask(); + + //check permissions getDeviceLocation(); + getCameraPPermission(); + getWriteStoragePPermission(); final View viewInflated = LayoutInflater.from(getContext()).inflate(R.layout.task_input, (ViewGroup) getView(), false); builder.setView(viewInflated); + imageToAdd = viewInflated.findViewById(R.id.taskImage); + //set location final Button buttonSetLocation = viewInflated.findViewById(R.id.taskSetLocation); final TextView locationText = viewInflated.findViewById(R.id.taskLocation); @@ -157,6 +155,11 @@ public class TasksFragment extends Fragment { buttonSetLocation.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { + if (BuildConfig.DEBUG) + { + Log.d(TAG, "add Location!"); + } + getLocationPermission(); getDeviceLocation(); @@ -181,7 +184,29 @@ public class TasksFragment extends Fragment { buttonAddPicture.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - // Code here executes on main thread after user presses button + + if (BuildConfig.DEBUG) + { + Log.d(TAG, "add Picture!"); + } + + if (!mCameraPermissionGranted) + { + if (BuildConfig.DEBUG) + { + Log.d(TAG, "Camera permission not granted!"); + } + getCameraPPermission(); + } + else + { + if (BuildConfig.DEBUG) + { + Log.d(TAG, "Camera permission granted!"); + } + Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); + startActivityForResult(cameraIntent, CAMERA_REQUEST); + } } }); @@ -192,17 +217,35 @@ public class TasksFragment extends Fragment { final TextView titleView = viewInflated.findViewById(R.id.taskTitleUserInput); final TextView noticeView = viewInflated.findViewById(R.id.taskNoticeUserInput); - if (titleView.getText()!=null) + if (BuildConfig.DEBUG) { + Log.d(TAG, "new title: " + titleView.getText()); + } + + if (titleView.getText().length()>0) { //save user input newTask.setTitle(String.valueOf(titleView.getText())); newTask.setNotice(String.valueOf(noticeView.getText())); + + boolean result = allTasks.add(newTask); + if (BuildConfig.DEBUG) { Log.d(TAG, "new Task: " + newTask.toString()); + Log.d(TAG, "add new task result: " + result); + + /** + for (OwnTask task: allTasks) + { + if (BuildConfig.DEBUG) { + Log.d(TAG, task.toString()); + } + } + **/ } + instantiateTaskList(); dialog.dismiss(); //confirm added task @@ -244,6 +287,160 @@ public class TasksFragment extends Fragment { return root; } + @Override + public void onPause() + { + super.onPause(); + + emptyPreferencesAndSaveTasksToPreferences(); + } + + /** + * Saves tasks to preferences + */ + private void emptyPreferencesAndSaveTasksToPreferences() { + if (!allTasks.isEmpty()) { + if (BuildConfig.DEBUG) { + Log.d(TAG, "allTasks not empty!"); + for (OwnTask task: allTasks) + { + Log.d(TAG, task.toString()); + } + } + + PreferenceManager.getDefaultSharedPreferences(getContext()).edit().remove(KEY_ALL_TASKS).commit(); + + JSONArray writeObjects = new JSONArray(); + + for (OwnTask task: allTasks) + { + if (BuildConfig.DEBUG) { + Log.d(TAG, task.toString()); + } + } + + + for (OwnTask task: allTasks) + { + if (BuildConfig.DEBUG) { + Log.d(TAG, "save task: " + task.toString()); + } + + if (task.getImage() != null) + { + + //save image to external storage and save path + String path = saveReceivedImage(task.getImage(), task.getId()); + task.setPathImage(path); + + if (BuildConfig.DEBUG) { + Log.d(TAG, "saved image with path: " + task.getPathImage()); + } + } + + + JSONObject object = task.toJSONObject(); + writeObjects.put(object); + + if (BuildConfig.DEBUG) { + Log.d(TAG, object.toString()); + } + } + + PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putString(KEY_ALL_TASKS, writeObjects.toString()).commit(); + } + } + + private String saveReceivedImage(Bitmap bitmap, String imageName){ + + File path = null; + + try { + path = new File(getContext().getFilesDir(), "meinWald" + File.separator + "Images"); + if(!path.exists()){ + path.mkdirs(); + } + + if (BuildConfig.DEBUG) { + Log.d(TAG, "Image file path: " + path); + } + + File outFile = new File(path, imageName + ".jpeg"); + if (!outFile.exists()) + { + FileOutputStream outputStream = new FileOutputStream(outFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); + outputStream.close(); + } + + } catch (FileNotFoundException e) { + Log.e(TAG, "Saving received message failed with", e); + } catch (IOException e) { + Log.e(TAG, "Saving received message failed with", e); + } + + return path.toString(); + } + + /** + * Reads tasks saved in preferences as jsonStrings + * + * @return list of OwnTask + */ + private List readTasksFromPreferences() { + List tasks = new ArrayList<>(); + + try { + String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_ALL_TASKS, "error"); + if(!"error".equalsIgnoreCase(jsonString)) { + JSONArray jsonObjects = new JSONArray(jsonString); + + for (int i = 0; i adapterView, View view, int i, long l) { + + //for (int j = 0; j < adapterView.getChildCount(); j++) + //adapterView.getChildAt(j).setBackgroundColor(Color.TRANSPARENT); + + // change the background color of the selected element + //view.setBackgroundColor(Color.LTGRAY); + //adapterView.setSelection(i); + }}); + } + /** * Request location permission, so that we can get the location of the device. * The result of the permission request is handled by a callback, @@ -262,6 +459,60 @@ public class TasksFragment extends Fragment { } } + /** + * Request camera permission, so that we can get an image from the camera. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getCameraPPermission() { + if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), + Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED) { + mCameraPermissionGranted = true; + } else { + ActivityCompat.requestPermissions(getActivity(), + new String[]{android.Manifest.permission.CAMERA}, + MY_CAMERA_PERMISSION_CODE); + } + } + + /** + * Request read external storage permission, so that we can get saved images from external storage. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getReadStoragePermission() { + if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), + Manifest.permission.READ_EXTERNAL_STORAGE) + == PackageManager.PERMISSION_GRANTED) { + mReadStorageGranted = true; + } else { + ActivityCompat.requestPermissions(getActivity(), + new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, + READ_EXTERNAL_STORAGE_CODE); + } + } + + /** + * Request read external storage permission, so that we can get saved images from external storage. + * The result of the permission request is handled by a callback, + * onRequestPermissionsResult. + * + */ + private void getWriteStoragePPermission() { + if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), + Manifest.permission.WRITE_EXTERNAL_STORAGE) + == PackageManager.PERMISSION_GRANTED) { + mWriteStorageGranted = true; + } else { + ActivityCompat.requestPermissions(getActivity(), + new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, + WRITE_EXTERNAL_STORAGE_CODE); + } + } + /** * DOCU ME! * TOOD: What are grant results etc for? @@ -272,6 +523,9 @@ public class TasksFragment extends Fragment { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (BuildConfig.DEBUG) { + Log.d(TAG, "onRequestPermissionResult Code: " + requestCode); + } mLocationPermissionGranted = false; switch (requestCode) { case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: { @@ -282,6 +536,44 @@ public class TasksFragment extends Fragment { mLocationPermissionGranted = true; } } + case MY_CAMERA_PERMISSION_CODE: { + + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + mCameraPermissionGranted = true; + } + } + case READ_EXTERNAL_STORAGE_CODE: { + + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + mReadStorageGranted = true; + } + } + case WRITE_EXTERNAL_STORAGE_CODE: { + + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + mWriteStorageGranted = true; + } + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) + { + if (requestCode == CAMERA_REQUEST && resultCode == Activity.RESULT_OK) + { + Bitmap photo = (Bitmap) data.getExtras().get("data"); + newTask.setImage(photo); + newTask.setPathImage(saveReceivedImage(photo,newTask.getId())); + + if (imageToAdd != null && photo != null) + { + imageToAdd.setImageBitmap(photo); + } } } diff --git a/Code Android/meinWald/app/src/main/res/layout/area_element.xml b/Code Android/meinWald/app/src/main/res/layout/area_element.xml new file mode 100644 index 0000000..28a9423 --- /dev/null +++ b/Code Android/meinWald/app/src/main/res/layout/area_element.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Code Android/meinWald/app/src/main/res/layout/area_input.xml b/Code Android/meinWald/app/src/main/res/layout/area_input.xml new file mode 100644 index 0000000..e0a10eb --- /dev/null +++ b/Code Android/meinWald/app/src/main/res/layout/area_input.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + +