@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
@@ -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); | |||
} | |||
}); | |||
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()); | |||
} | |||
FloatingActionButton fab = root.findViewById(R.id.fab_areas); | |||
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); | |||
} | |||
} | |||
} |
@@ -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 + '\'' + | |||
'}'; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 + '\'' + | |||
'}'; | |||
} | |||
} |
@@ -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 |
@@ -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; | |||
} | |||
} | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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; | |||
public class OwnTask | |||
{ | |||
private String title; | |||
private String notice; | |||
private Location location; | |||
private Image image; | |||
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; | |||
} | |||
/** | |||
* ______________________________________________________________________________________________ | |||
* TASKS | |||
*/ | |||
private OwnTask newTask = new OwnTask(); | |||
private List<OwnTask> allTasks; | |||
private ListView taskList; | |||
private static final String KEY_ALL_TASKS = "allTasks"; | |||
@Override | |||
public String toString() { | |||
return "OwnTask{" + | |||
"title='" + title + '\'' + | |||
", notice='" + notice + '\'' + | |||
", location=" + location + | |||
'}'; | |||
} | |||
} | |||
/** | |||
* ______________________________________________________________________________________________ | |||
* CAMERA | |||
*/ | |||
private static final int MY_CAMERA_PERMISSION_CODE = 100; | |||
private boolean mCameraPermissionGranted; | |||
private static final int CAMERA_REQUEST = 1888; | |||
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); | |||
taskList = (ListView) root.findViewById(R.id.taskListView); | |||
//instance add button | |||
//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); | |||
} | |||
} | |||
} | |||
@@ -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> |
@@ -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> |
@@ -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" |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -61,13 +61,38 @@ | |||
android:layout_height="wrap_content" | |||
android:text="Bild hinzufügen!" /> | |||
<ImageView | |||
android:id="@+id/taskImage" | |||
android:layout_width="243dp" | |||
android:layout_height="149dp" | |||
android:layout_gravity="center" | |||
android:baselineAlignBottom="true" | |||
android:foregroundGravity="center_vertical|center_horizontal" | |||
app:srcCompat="@android:drawable/ic_menu_camera" /> | |||
<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="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> |
@@ -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> |
@@ -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> |