initial area tracking

This commit is contained in:
Felix Diemar 2020-09-09 01:30:47 +02:00
parent 4d931b5ab0
commit 4153dbce6b
22 changed files with 2389 additions and 138 deletions

View File

@ -3,6 +3,7 @@
package="com.example.meinwald">
<application
android:name="com.example.meinwald.MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@ -22,7 +23,17 @@
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<service
android:name=".ui.area.LocationTrack"
android:exported="false">
</service>
</application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<OwnArea> areaList;
LayoutInflater inflater;
Context context;
public AreaAdapter(Context applicationContext, List<OwnArea> 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;
}
}

View File

@ -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<OwnArea> allAreas;
private ListView areaList;
private static final String KEY_AREA_REFERENCES = "areaReferences";
private List<AreaReference> 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<LatLng> 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<String>() {
//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 onChanged(@Nullable String s) {
textView.setText(s);
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);
}
});
FloatingActionButton fab = root.findViewById(R.id.fab_areas);
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<OwnArea> loadAreasFromPreferences()
{
List<OwnArea> 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<AreaReference> readAreaReferencesFromPreferences() {
List<AreaReference> 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<jsonObjects.length();i++) {
areaReferences.add(new AreaReference(jsonObjects.getJSONObject(i)));
}
}
} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(TAG, "Error while parsing epicolors as jsonObjects from preferences");
e.printStackTrace();
}
}
return areas;
}
/**
* Saves epicolors to preferences
*/
private void emptyPreferencesAndSaveEpiColorsToPreferences()
{
if (!areaReferences.isEmpty()) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "areaReferences not empty");
}
PreferenceManager.getDefaultSharedPreferences(getContext()).edit().remove(KEY_AREA_REFERENCES).commit();
JSONArray writeObjects = new JSONArray();
for (AreaReference reference: areaReferences) {
JSONObject object = reference.toJSONObject();
writeObjects.put(object);
if (BuildConfig.DEBUG) {
Log.d("Color is ", object.toString());
}
}
PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putString(KEY_AREA_REFERENCES, writeObjects.toString()).commit();
}
}
/**
* DOCU ME!
* TOOD: What are grant results etc for?
* @param requestCode
* @param permissions
* @param grantResults
*/
@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: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 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);
}
}
}

View File

@ -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 + '\'' +
'}';
}
}

View File

@ -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<String> mText;
public DashboardViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is dashboard fragment");
}
public LiveData<String> getText() {
return mText;
}
}

View File

@ -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<LatLng> 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<LatLng> 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;
}
}

View File

@ -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<LatLng> 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<LatLng> 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<LatLng> 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 + '\'' +
'}';
}
}

View File

@ -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<OwnTask> 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<OwnTask> readTasksFromPreferences() {
List<OwnTask> 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<jsonObjects.length();i++) {
tasks.add(new OwnTask(jsonObjects.getJSONObject(i)));
if (BuildConfig.DEBUG) {
Log.d(TAG, "Task loaded from shared preferences: " + tasks.get(i).toString());
}
Bitmap image = BitmapFactory.decodeFile(tasks.get(i).getPathImage() + File.separator + tasks.get(i).getId() + ".jpeg");
if (BuildConfig.DEBUG) {
Log.d(TAG, "Image loaded from shared preferences: " + image.getByteCount());
}
tasks.get(i).setImage(image);
}
}
} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(TAG, "Error while parsing tasks as jsonObjects from preferences");
e.printStackTrace();
}
}
return tasks;
}
@Override

View File

@ -0,0 +1,187 @@
package com.example.meinwald.ui.task;
import android.graphics.Bitmap;
import android.location.Location;
import android.media.Image;
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.util.Date;
public class OwnTask
{
private String title;
private String notice;
private Location location;
private Bitmap image;
private String pathImage;
private String id;
public OwnTask(String JSONString){
try {
JSONObject taskJSON = new JSONObject(JSONString);
this.title = taskJSON.getString("title");
this.notice = taskJSON.getString("notice");
this.location = new Location("");
this.location.setLatitude(taskJSON.getDouble("lat"));
this.location.setLongitude(taskJSON.getDouble("lng"));
this.pathImage = taskJSON.getString("pathImage");
this.id = taskJSON.getString("taskID");
} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(this.getClass().getSimpleName(), "taskJSON: " + JSONString);
e.printStackTrace();
}
}
}
public OwnTask(JSONObject taskJSON){
try {
if (BuildConfig.DEBUG) {
Log.d(this.getClass().getSimpleName(), "JSONObject: " + taskJSON.toString());
}
this.title = taskJSON.getString("title");
this.notice = taskJSON.getString("notice");
this.location = new Location("");
this.location.setLatitude(taskJSON.getDouble("lat"));
this.location.setLongitude(taskJSON.getDouble("lng"));
this.id = taskJSON.getString("taskID");
this.pathImage = taskJSON.getString("taskPATHIMAGE");
} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(this.getClass().getSimpleName(), "taskJSON: " + taskJSON.toString());
Log.e(this.getClass().getSimpleName(), "taskJSON Error: " + e.toString());
e.printStackTrace();
}
}
}
public OwnTask()
{
this.title = null;
this.notice = null;
this.location = null;
this.image = null;
this.pathImage = null;
this.id = null;
}
public OwnTask(String title, String notice, Location location, Bitmap image, String pathImage)
{
this.title = title;
this.notice = notice;
this.location = location;
this.image = image;
this.pathImage = pathImage;
this.id = generateTaskID(title);
}
public String getTitle() {
return title;
}
public String getNotice() {
return notice;
}
public Location getLocation() {
return location;
}
public Bitmap getImage() {
return image;
}
public String getPathImage() { return pathImage; }
public String getId() { return id; }
public void setTitle(String title)
{
this.id = generateTaskID(title);
this.title = title;
}
public void setNotice(String notice) {
this.notice = notice;
}
public void setLocation(Location location) {
this.location = location;
}
public void setImage(Bitmap image) {
this.image = image;
}
public void setPathImage(String pathImage) { this.pathImage = pathImage; }
@Override
public String toString() {
return "OwnTask{" +
"title='" + title + '\'' +
", notice='" + notice + '\'' +
", location=" + location + '\'' +
", pathImage=" + pathImage + '\'' +
", id=" + id +
'}';
}
private String generateTaskID(String title)
{
String id = title.replaceAll(" ", "_") + "_" + new Date().getTime();
if (BuildConfig.DEBUG)
{
Log.d(getClass().getSimpleName(), "new ID: " + id);
}
return id;
}
/**
* Returns task 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("notice",this.notice);
object.put("taskPATHIMAGE",this.pathImage);
object.put("taskID",this.id);
if (this.location != null)
{
object.put("lat",this.location.getLatitude());
object.put("lng",this.location.getLongitude());
}
if (BuildConfig.DEBUG) {
Log.d(this.getClass().getSimpleName(), "JSONObject: " + object.toString());
Log.d(this.getClass().getSimpleName(), "Task: " + this.toString());
Log.d(this.getClass().getSimpleName(), "path: " + this.getPathImage());
Log.d(this.getClass().getSimpleName(), "id: " + this.getId());
}
return object;
} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(this.getClass().getSimpleName(), String.format("Error while parsing OwnTask to JSONObject. Values of OwnTask: %s", this.toString()));
}
return null;
}
}
}

View File

@ -0,0 +1,147 @@
package com.example.meinwald.ui.task;
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.area.OwnArea;
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 TaskAdapter extends BaseAdapter
{
List<OwnTask> taskList;
LayoutInflater inflater;
Context context;
public TaskAdapter(Context applicationContext, List<OwnTask> 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;
}
}

View File

@ -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<OwnTask> 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<OwnTask> readTasksFromPreferences() {
List<OwnTask> 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<jsonObjects.length();i++) {
tasks.add(new OwnTask(jsonObjects.getJSONObject(i)));
if (BuildConfig.DEBUG) {
Log.d(TAG, "Task loaded from shared preferences: " + tasks.get(i).toString());
}
Bitmap image = BitmapFactory.decodeFile(tasks.get(i).getPathImage() + File.separator + tasks.get(i).getId() + ".jpeg");
if (BuildConfig.DEBUG) {
Log.d(TAG, "Image loaded from shared preferences: " + image.getByteCount());
}
tasks.get(i).setImage(image);
}
}
} catch (JSONException e) {
if (BuildConfig.DEBUG) {
Log.e(TAG, "Error while parsing tasks as jsonObjects from preferences");
e.printStackTrace();
}
}
return tasks;
}
/**
* Get all stored tasks and save them temporary.
*/
public void instantiateTaskList()
{
final TaskAdapter adapter = new TaskAdapter(getActivity().getApplicationContext(),allTasks);
taskList.setAdapter(adapter);
//initialise onClickListeners
taskList.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);
}});
}
/**
* 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);
}
}
}

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/areaElement"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:longClickable="true"
android:orientation="horizontal">
<TextView
android:id="@+id/areaInfoTitle"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="left"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:clickable="false"
android:focusable="false"
android:textColor="@android:color/primary_text_light"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/areaInfoView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:orientation="horizontal"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/areaInfoTitle"
tools:visibility="visible">
<ImageView
android:id="@+id/areaIcon"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginBottom="5dp"
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:src="@android:drawable/ic_menu_camera"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:drawable/ic_menu_camera" />
<TextView
android:id="@+id/areaInfoNotice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:textColor="@android:color/primary_text_light"
android:textSize="12sp"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="@+id/taskIcon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/layout_area_root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="10dp" >
<TextView
android:id="@+id/areaTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Grundstück"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/areaTitleUserInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Titel eingeben!">
<requestFocus />
</EditText>
<TextView
android:id="@+id/areaNotice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Beschreibung"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/areaNoticeUserInput"
android:layout_width="match_parent"
android:layout_height="149dp"
android:hint="Beschreibung eingeben!"
android:isScrollContainer="true">
<requestFocus />
</EditText>
<Button
android:id="@+id/areaStartTracking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Grundstücksaufnahme Starten!" />
<Button
android:id="@+id/areaStopTracking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Grundstücksaufnahme Beenden!"
android:visibility="invisible"/>
</LinearLayout>

View File

@ -6,20 +6,20 @@
android:layout_height="match_parent"
tools:context=".ui.area.AreaFragment">
<TextView
android:id="@+id/text_areas"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
<ListView
android:id="@+id/areaListView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginLeft="1dp"
android:layout_marginEnd="1dp"
android:layout_marginRight="1dp"
android:choiceMode="singleChoice"
android:listSelector="@color/selectionBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center_horizontal" />
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_areas"

View File

@ -6,21 +6,6 @@
android:layout_height="match_parent"
tools:context=".ui.task.TasksFragment">
<TextView
android:id="@+id/text_tasks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_tasks"
android:layout_width="wrap_content"
@ -35,4 +20,19 @@
app:layout_constraintEnd_toEndOf="parent"
app:rippleColor="#00000000"
app:srcCompat="@android:drawable/ic_menu_add" />
<ListView
android:id="@+id/taskListView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginLeft="1dp"
android:layout_marginEnd="1dp"
android:layout_marginRight="1dp"
android:choiceMode="singleChoice"
android:listSelector="@color/selectionBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/taskLargeImageLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toEndOf="parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:orientation="vertical">
<ImageView
android:id="@+id/taskLargeImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/taskElement"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:longClickable="true"
android:orientation="horizontal">
<TextView
android:id="@+id/taskInfoTitle"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="left"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:clickable="false"
android:focusable="false"
android:textColor="@android:color/primary_text_light"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/taskInfoView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:orientation="horizontal"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/taskInfoTitle"
tools:visibility="visible">
<ImageView
android:id="@+id/taskIcon"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginBottom="5dp"
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:src="@android:drawable/ic_menu_camera"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:drawable/ic_menu_camera" />
<TextView
android:id="@+id/taskInfoNotice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:textColor="@android:color/primary_text_light"
android:textSize="12sp"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="@+id/taskIcon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -61,13 +61,38 @@
android:layout_height="wrap_content"
android:text="Bild hinzufügen!" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="309dp"
android:layout_marginStart="5dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:isScrollContainer="true"
android:orientation="horizontal"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/taskInfoTitle">
<ImageView
android:id="@+id/taskImage"
android:layout_width="243dp"
android:layout_height="149dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:baselineAlignBottom="true"
android:foregroundGravity="center_vertical|center_horizontal"
android:scaleType="fitXY"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:drawable/ic_menu_camera" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@ -3,4 +3,5 @@
<color name="colorPrimary">#1B5E20</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="selectionBackground">#c0edc3</color>
</resources>

View File

@ -7,4 +7,17 @@
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="ImageTheme" parent="android:Theme.Dialog">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_marginTop">20dp</item>
<item name="android:layout_marginBottom">20dp</item>
<item name="android:layout_marginLeft">10dp</item>
<item name="android:layout_marginRight">10dp</item>
<!-- No backgrounds, titles or window float -->
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
</style>
</resources>