11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | ==========
3 |
4 | Release 1.2 *(2019-09-21)*
5 | ----------------------------
6 | * Stop service correctly to fix memory leak & reduce code
7 | * Option to randomize location every x minutes added
8 | * App widget implemented
9 | * RU (@0ndrey), ES (@sguinetti), IT (@Lion-box), pt-rBR (@iramaro) translations added
10 | * pt-Rbr (@Andre-Gloria) typos corrected
11 | * Intro activity added
12 | * OpenStreetMap data attribution added
13 | * Notification priority changed to low for Nougat and lower
14 | * Minor code improvements & clean up
15 | * Logo update to prevent whitespace around edges
16 | * Gradle & library updates
17 |
18 | Release 1.1 *(2019-06-25)*
19 | ----------------------------
20 | * Minor design updates
21 | * Start service on boot option added
22 | * Fastlane metadata for F-droid added
23 |
24 | Release 1.0 *(2019-06-01)*
25 | ----------------------------
26 | * Initial release
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Private Location
2 |
3 | [](LICENSE)
4 |
5 | [](https://f-droid.org/packages/com.wesaphzt.privatelocation/)
6 |
7 | A simple app to set your location to anywhere in the world, and improve general phone location privacy.
8 |
9 | This app will fake/spoof both your GPS and network location on your phone.
10 |
11 | Many apps on your phone won't work without location permissions, and can make repeated and unnecessary location requests in the background throughout the day.
12 | Setting your location somewhere else will help to mitigate that and protect your privacy.
13 |
14 | The open-source Leaflet map library along with Wikimedia to provide map tiles (OpenStreetMap) are used in place of Google Maps.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ## Features
25 | - Set phone location
26 | - Favorite locations
27 | - Go to location from coordinates
28 | - Option to change to random location every x minutes
29 | - Notification when location is set
30 | - Find current location
31 |
32 | *Note: this app, or similar apps, are unlikely to fool apps or services that have a legitimate need to determine whether users are actually where they claim to be (gaming, check-in apps etc.), and will likely deploy various anti-spoofing techniques and methods to determine if you are there or not.*
33 |
34 | ## Requirements
35 | The app will guide you through the steps needed.
36 |
37 | 1. Developer settings will need to be enabled.
38 |
39 | 2. App will need to be set as the mock location app (or 'mock locations enabled' in older Android versions)
40 |
41 | For better privacy, or if you're having issues with your real location being exposed, it's best to turn off any options that allow use of WiFi and network to help determine your location.
42 |
43 | ## Issues
44 | To contribute, or to report issues please use the [Issue Tracker](https://github.com/wesaphzt/privatelocation/issues/).
45 |
46 | ## Privacy
47 | Free from ads and tracking.
48 |
49 | Map tiles are provided by Wikimedia [(Maps Terms of Service)](https://foundation.wikimedia.org/wiki/Maps_Terms_of_Use/), which uses [(OpenStreetMap)](https://www.openstreetmap.org/copyright/) data.
50 |
51 | ## License
52 | [GPL v3.0](LICENSE)
53 |
54 | ## Tips
55 | If you find these apps useful, consider supporting me in some way in my mission to create simple, useful, privacy-oriented, open-source apps.
56 |
57 | BTC: 1GCkvAg9oG79niQTbh6EH9rPALQDXKyHKK
58 |
59 | LTC: LV687s3wVdhmLZyJMFxomJHdHFXeFAKT5R
60 |
61 | ETH: 0x785a8804c85b88683a5cce5e53f60878831e5d03
62 |
63 | XMR: 43Vijzdt3y42mmT954rSYPjXYabDsjYEV2KyhxfC46JibR2ny9VmRS1fjdJTHxxPVPFE8ajgArwjWfyaRgjh9vcNAwmkfJj
64 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | defaultConfig {
6 | applicationId "com.wesaphzt.privatelocation"
7 | minSdkVersion 17
8 | targetSdkVersion 29
9 | versionCode 4
10 | versionName "1.2"
11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
12 | dataBinding.enabled = true
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | //custom dependencies
24 | implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
25 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
26 | implementation 'androidx.preference:preference:1.1.0'
27 |
28 | implementation 'com.github.GrenderG:Toasty:1.4.2'
29 | implementation 'com.github.AppIntro:AppIntro:5.1.0'
30 |
31 | //db
32 | implementation 'com.intuit.sdp:sdp-android:1.0.3'
33 |
34 | implementation fileTree(dir: 'libs', include: ['*.jar'])
35 | implementation 'androidx.appcompat:appcompat:1.1.0'
36 | implementation 'com.google.android.material:material:1.1.0-alpha10'
37 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
38 | testImplementation 'junit:junit:4.13-beta-3'
39 | androidTestImplementation 'androidx.test:runner:1.3.0-alpha02'
40 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha02'
41 | }
42 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/wesaphzt/privatelocation/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation;
2 |
3 | import android.content.Context;
4 | import androidx.test.InstrumentationRegistry;
5 | import androidx.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.wesaphzt.privatelocation", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
56 |
57 |
58 |
59 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/assets/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet-locate/L.Control.Locate.min.css:
--------------------------------------------------------------------------------
1 | .leaflet-control-locate a {
2 | font-size:1.4em;
3 | color:#444;
4 | cursor:pointer
5 | }
6 |
7 | .leaflet-control-locate.active a {
8 | color:#2074b6
9 | }
10 |
11 | .leaflet-control-locate.active.following a {
12 | color:#fc8428
13 | }
14 |
15 | .leaflet-control-locate-location circle {
16 | animation:leaflet-control-locate-throb 4s ease infinite
17 | }
18 | @keyframes leaflet-control-locate-throb {
19 | 0% {
20 | r:9;stroke-width:1
21 | }
22 | 50% {
23 | r:7;stroke-width:3
24 | }
25 | 100% {
26 | r:9;stroke-width:1
27 | }
28 | }
29 | /*# sourceMappingURL=L.Control.Locate.min.css.map*/
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet-locate/L.Control.Locate.min.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sourceRoot":"","sources":["../src/L.Control.Locate.scss"],"names":[],"mappings":"AAAA;AAEE;EACE;EACA;EACA;;AAGA;EACE;;AAEF;EACE;;;AAKN;EACE;;;AAGF;EACI;IAAK;IAAM;;EACZ;IAAM;IAAM;;EACb;IAAO;IAAM","file":"L.Control.Locate.css"}
2 |
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Map
5 |
6 |
7 |
8 |
9 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
43 |
44 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/leaflet/images/layers-2x.png
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/leaflet/images/layers.png
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/leaflet/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/leaflet/images/marker-icon.png
--------------------------------------------------------------------------------
/app/src/main/assets/leaflet/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/assets/leaflet/images/marker-shadow.png
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/IntroActivity.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation;
2 |
3 | import android.os.Bundle;
4 | import android.view.WindowManager;
5 |
6 | import androidx.annotation.Nullable;
7 | import androidx.fragment.app.Fragment;
8 |
9 | import com.github.paolorotolo.appintro.AppIntro;
10 | import com.github.paolorotolo.appintro.AppIntroFragment;
11 | import com.github.paolorotolo.appintro.model.SliderPage;
12 |
13 | public class IntroActivity extends AppIntro {
14 |
15 | @Override
16 | protected void onCreate(@Nullable Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 |
19 | //fullscreen
20 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
21 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
22 |
23 | //slider pages
24 | SliderPage sliderPageOne = new SliderPage();
25 | sliderPageOne.setTitle(getResources().getString(R.string.slider_page_one_title));
26 | sliderPageOne.setDescription(getString(R.string.slider_page_one_desc));
27 | sliderPageOne.setImageDrawable(R.drawable.ic_intro_location);
28 | sliderPageOne.setBgColor(getResources().getColor(R.color.colorPrimary));
29 | addSlide(AppIntroFragment.newInstance(sliderPageOne));
30 |
31 | SliderPage sliderPageTwo = new SliderPage();
32 | sliderPageTwo.setTitle(getResources().getString(R.string.slider_page_two_title));
33 | sliderPageTwo.setDescription(getResources().getString(R.string.slider_page_two_desc));
34 | sliderPageTwo.setImageDrawable(R.drawable.ic_intro_cloud);
35 | sliderPageTwo.setBgColor(getResources().getColor(R.color.colorIntroGrey));
36 | addSlide(AppIntroFragment.newInstance(sliderPageTwo));
37 |
38 | SliderPage sliderPageThree = new SliderPage();
39 | sliderPageThree.setTitle(getResources().getString(R.string.slider_page_three_title));
40 | sliderPageThree.setDescription(getResources().getString(R.string.slider_page_three_desc));
41 | sliderPageThree.setImageDrawable(R.drawable.ic_intro_settings);
42 | sliderPageThree.setBgColor(getResources().getColor(R.color.colorIntroGreen));
43 | addSlide(AppIntroFragment.newInstance(sliderPageThree));
44 |
45 | //options
46 | setFadeAnimation();
47 | showSkipButton(false);
48 | setProgressButtonEnabled(true);
49 |
50 | //setBarColor(getResources().getColor(R.color.colorPrimary));
51 | //setSeparatorColor(getResources().getColor(R.color.white));
52 | }
53 |
54 | @Override
55 | public void onSkipPressed(Fragment currentFragment) {
56 | super.onSkipPressed(currentFragment);
57 | }
58 |
59 | @Override
60 | public void onDonePressed(Fragment currentFragment) {
61 | super.onDonePressed(currentFragment);
62 | finish();
63 | }
64 |
65 | @Override
66 | public void onSlideChanged(@Nullable Fragment oldFragment, @Nullable Fragment newFragment) {
67 | super.onSlideChanged(oldFragment, newFragment);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/db/Favorite.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.db;
2 |
3 | public class Favorite {
4 |
5 | private int id;
6 | private String name;
7 | private Double lat;
8 | private Double lng;
9 |
10 | public Favorite(String name, Double lat, Double lng) {
11 | this.name = name;
12 | this.lat = lat;
13 | this.lng = lng;
14 | }
15 |
16 | public Favorite(int id, String name, Double lat, Double lng) {
17 | this.id = id;
18 | this.name = name;
19 | this.lat = lat;
20 | this.lng = lng;
21 | }
22 |
23 | public int getId() {
24 | return id;
25 | }
26 |
27 | public void setId(int id) {
28 | this.id = id;
29 | }
30 |
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public void setName(String name) {
36 | this.name = name;
37 | }
38 |
39 | public Double getLat() {
40 | return lat;
41 | }
42 |
43 | Double getLong() {
44 | return lng;
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/db/FavoriteAdapter.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.db;
2 |
3 | import android.content.Context;
4 | import android.content.DialogInterface;
5 |
6 | import android.text.TextUtils;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.EditText;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import androidx.appcompat.app.AlertDialog;
15 | import androidx.recyclerview.widget.RecyclerView;
16 |
17 | import com.wesaphzt.privatelocation.fragments.DialogFragmentFavorite;
18 | import com.wesaphzt.privatelocation.MainActivity;
19 | import com.wesaphzt.privatelocation.R;
20 |
21 | import java.util.List;
22 |
23 | public class FavoriteAdapter extends RecyclerView.Adapter {
24 |
25 | private Context context;
26 |
27 | private List listFavorites;
28 | private SQLiteDB mDatabase;
29 | private int position;
30 |
31 | private View view;
32 | private MainActivity mainActivity;
33 | private DialogFragmentFavorite dfFavorite;
34 |
35 | public FavoriteAdapter(Context context, List listFavorites, MainActivity mActivity, DialogFragmentFavorite dfFavorite) {
36 | this.context = context;
37 | this.listFavorites = listFavorites;
38 | mDatabase = new SQLiteDB(context);
39 | this.mainActivity = mActivity;
40 | this.dfFavorite = dfFavorite;
41 | }
42 |
43 | @Override
44 | public FavoriteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
45 | view = LayoutInflater.from(parent.getContext()).inflate(R.layout.dialog_favorites_list_item, parent, false);
46 | return new FavoriteViewHolder(view);
47 | }
48 |
49 | @Override
50 | public void onBindViewHolder(final FavoriteViewHolder holder, final int mPosition) {
51 | final Favorite singleFavorite = listFavorites.get(mPosition);
52 |
53 | view.setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 | if(mainActivity != null){
57 | //get position again in case delete operations have been done prior
58 | Favorite favorite = listFavorites.get(mPosition);
59 | mainActivity.setLocation(favorite.getLat(), favorite.getLong());
60 | }
61 |
62 | dfFavorite.dismiss();
63 | }
64 | });
65 |
66 | holder.name.setText(singleFavorite.getName());
67 |
68 | holder.editFavorite.setOnClickListener(new View.OnClickListener() {
69 | @Override
70 | public void onClick(View view) {
71 | position = mPosition;
72 |
73 | editTaskDialog(singleFavorite);
74 | }
75 | });
76 |
77 | holder.deleteFavorite.setOnClickListener(new View.OnClickListener() {
78 | @Override
79 | public void onClick(View view) {
80 | position = mPosition;
81 |
82 | //delete row from database
83 | mDatabase.deleteProduct(singleFavorite.getId());
84 |
85 | //remove and notify change
86 | listFavorites.remove(position);
87 | //notify of position changes
88 | notifyDataSetChanged();
89 | }
90 | });
91 | }
92 |
93 | @Override
94 | public int getItemCount() {
95 | return listFavorites.size();
96 | }
97 |
98 | private void editTaskDialog(final Favorite favorite){
99 | LayoutInflater inflater = LayoutInflater.from(context);
100 | View subView = inflater.inflate(R.layout.dialog_favorites_add, null);
101 |
102 | final EditText nameField = (EditText)subView.findViewById(R.id.enter_name);
103 | final TextView latLngField = (TextView) subView.findViewById(R.id.display_lat_long);
104 |
105 | if(favorite != null){
106 | nameField.setText(favorite.getName());
107 | latLngField.setText("Latitude: " + String.valueOf(favorite.getLat() + "\nLongitude: " + String.valueOf(favorite.getLong())));
108 | }
109 |
110 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
111 | builder.setTitle("Edit Favorite");
112 | builder.setView(subView);
113 | builder.create();
114 |
115 | builder.setPositiveButton("EDIT", new DialogInterface.OnClickListener() {
116 | @Override
117 | public void onClick(DialogInterface dialog, int which) {
118 |
119 | final String name = nameField.getText().toString();
120 |
121 | if(TextUtils.isEmpty(name) /*|| lat_long <= 0*/){
122 | Toast.makeText(context, "Can't be empty", Toast.LENGTH_LONG).show();
123 | } else {
124 | mDatabase.updateFavorite(new Favorite(favorite.getId(), name, favorite.getLat(), favorite.getLong()));
125 |
126 | listFavorites.set(position, new Favorite(favorite.getId(), name, favorite.getLat(), favorite.getLong()));
127 | notifyItemChanged(position);
128 | }
129 | }
130 | });
131 |
132 | builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
133 | @Override
134 | public void onClick(DialogInterface dialog, int which) {
135 |
136 | }
137 | });
138 |
139 | builder.show();
140 | }
141 |
142 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/db/FavoriteViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.db;
2 |
3 | import android.view.View;
4 | import android.widget.ImageView;
5 | import android.widget.TextView;
6 |
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | import com.wesaphzt.privatelocation.R;
10 |
11 | public class FavoriteViewHolder extends RecyclerView.ViewHolder {
12 |
13 | public TextView name;
14 | ImageView deleteFavorite;
15 | ImageView editFavorite;
16 |
17 | FavoriteViewHolder(View itemView) {
18 | super(itemView);
19 |
20 | name = (TextView)itemView.findViewById(R.id.favorite_name);
21 | deleteFavorite = (ImageView)itemView.findViewById(R.id.delete_favorite);
22 | editFavorite = (ImageView)itemView.findViewById(R.id.edit_favorite);
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/db/SQLiteDB.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.db;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteOpenHelper;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | public class SQLiteDB extends SQLiteOpenHelper {
12 | private static final int DATABASE_VERSION = 5;
13 | private static final String DATABASE_NAME = "favorites";
14 | private static final String TABLE_FAVORITES = "favorites";
15 | private static final String COLUMN_ID = "_id";
16 | private static final String COLUMN_FAVORITENAME = "favoritename";
17 | private static final String COLUMN_LAT = "lat";
18 | private static final String COLUMN_LNG = "lng";
19 |
20 | public SQLiteDB(Context context) {
21 | super(context, DATABASE_NAME, null, DATABASE_VERSION);
22 | }
23 |
24 | @Override
25 | public void onCreate(android.database.sqlite.SQLiteDatabase db) {
26 | String CREATE_FAVORITES_TABLE = "CREATE TABLE " + TABLE_FAVORITES + "(" + COLUMN_ID + " INTEGER PRIMARY KEY," + COLUMN_FAVORITENAME + " TEXT," + COLUMN_LAT + " DOUBLE," + COLUMN_LNG + " DOUBLE" + ")";
27 | db.execSQL(CREATE_FAVORITES_TABLE);
28 | }
29 |
30 | @Override
31 | public void onUpgrade(android.database.sqlite.SQLiteDatabase db, int oldVersion, int newVersion) {
32 | db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
33 | onCreate(db);
34 | }
35 |
36 | public List listFavorites(){
37 | String sql = "select * from " + TABLE_FAVORITES;
38 | android.database.sqlite.SQLiteDatabase db = this.getReadableDatabase();
39 | List storeFavorites = new ArrayList<>();
40 | Cursor cursor = db.rawQuery(sql, null);
41 | if(cursor.moveToFirst()){
42 | do{
43 | int id = Integer.parseInt(cursor.getString(0));
44 | String name = cursor.getString(1);
45 | Double lat = cursor.getDouble(2);
46 | Double lng = cursor.getDouble(3);
47 | storeFavorites.add(new Favorite(id, name, lat, lng));
48 | } while (cursor.moveToNext());
49 | }
50 | cursor.close();
51 | return storeFavorites;
52 | }
53 |
54 | public void addProduct(Favorite favorite){
55 | ContentValues values = new ContentValues();
56 | values.put(COLUMN_FAVORITENAME, favorite.getName());
57 | values.put(COLUMN_LAT, favorite.getLat());
58 | values.put(COLUMN_LNG, favorite.getLong());
59 | android.database.sqlite.SQLiteDatabase db = this.getWritableDatabase();
60 | db.insert(TABLE_FAVORITES, null, values);
61 | }
62 |
63 | void updateFavorite(Favorite favorite){
64 | ContentValues values = new ContentValues();
65 | values.put(COLUMN_FAVORITENAME, favorite.getName());
66 | values.put(COLUMN_LAT, favorite.getLat());
67 | values.put(COLUMN_LNG, favorite.getLong());
68 | android.database.sqlite.SQLiteDatabase db = this.getWritableDatabase();
69 | db.update(TABLE_FAVORITES, values, COLUMN_ID + " = ?", new String[] { String.valueOf(favorite.getId())});
70 | }
71 |
72 | public Favorite findFavorite(String name){
73 | String query = "Select * FROM " + TABLE_FAVORITES + " WHERE " + COLUMN_FAVORITENAME + " = " + "name";
74 | android.database.sqlite.SQLiteDatabase db = this.getWritableDatabase();
75 | Favorite mFavorite = null;
76 | Cursor cursor = db.rawQuery(query, null);
77 | if (cursor.moveToFirst()){
78 | int id = Integer.parseInt(cursor.getString(0));
79 | String favoriteName = cursor.getString(1);
80 | Double favoriteLat = cursor.getDouble(2);
81 | Double favoriteLng = cursor.getDouble(3);
82 |
83 | mFavorite = new Favorite(id, favoriteName, favoriteLat, favoriteLng);
84 | }
85 | cursor.close();
86 | return mFavorite;
87 | }
88 |
89 | void deleteProduct(int id){
90 | android.database.sqlite.SQLiteDatabase db = this.getWritableDatabase();
91 | db.delete(TABLE_FAVORITES, COLUMN_ID + " = ?", new String[] { String.valueOf(id)});
92 | }
93 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/fragments/DialogFragmentAddFavorite.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.fragments;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Dialog;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.os.Bundle;
8 | import android.text.Editable;
9 | import android.text.TextUtils;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.widget.EditText;
13 | import android.widget.TextView;
14 | import android.widget.Toast;
15 |
16 | import androidx.annotation.NonNull;
17 | import androidx.appcompat.app.AlertDialog;
18 | import androidx.fragment.app.DialogFragment;
19 |
20 | import com.wesaphzt.privatelocation.R;
21 | import com.wesaphzt.privatelocation.db.Favorite;
22 | import com.wesaphzt.privatelocation.db.SQLiteDB;
23 |
24 | import es.dmoral.toasty.Toasty;
25 |
26 | public class DialogFragmentAddFavorite extends DialogFragment {
27 |
28 | private Context context;
29 |
30 | private SQLiteDB mDatabase;
31 |
32 | @NonNull
33 | @SuppressLint("InflateParams")
34 | @Override
35 | public Dialog onCreateDialog(Bundle savedInstanceState) {
36 |
37 | //init
38 | context = getContext();
39 |
40 | mDatabase = new SQLiteDB(context);
41 |
42 | assert getArguments() != null;
43 | final double mLat = getArguments().getDouble("lat");
44 | final double mLng = getArguments().getDouble("lng");
45 |
46 | LayoutInflater inflater = LayoutInflater.from(context);
47 | View subView = inflater.inflate(R.layout.dialog_favorites_add, null);
48 |
49 | final EditText etName = (EditText) subView.findViewById(R.id.enter_name);
50 | final TextView tvLatLong = (TextView) subView.findViewById(R.id.display_lat_long);
51 |
52 | tvLatLong.setText(getString(R.string.dialog_favorites_add_lat_long, mLat, mLng));
53 |
54 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
55 | builder.setTitle("Add Favorite");
56 | builder.setView(subView);
57 | builder.create();
58 |
59 | builder.setPositiveButton("ADD", new DialogInterface.OnClickListener() {
60 | @Override
61 | public void onClick(DialogInterface dialog, int which) {
62 | if (isEmpty(etName.getText())) {
63 | //is empty
64 | Toasty.info(context, "Can't be empty", Toast.LENGTH_SHORT, true).show();
65 | } else {
66 | //isn't empty
67 | Favorite newFavorite = new Favorite(etName.getText().toString(), mLat, mLng);
68 | mDatabase.addProduct(newFavorite);
69 |
70 | Toasty.success(context, "Favorite added", Toast.LENGTH_SHORT, true).show();
71 | }
72 | }
73 | });
74 |
75 | builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
76 | @Override
77 | public void onClick(DialogInterface dialog, int which) {
78 | dismiss();
79 | }
80 | });
81 |
82 | return builder.create();
83 | }
84 |
85 | private boolean isEmpty(Editable value) {
86 | return TextUtils.isEmpty(value);
87 | }
88 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/fragments/DialogFragmentFavorite.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.fragments;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Dialog;
5 | import android.content.Context;
6 | import android.os.Bundle;
7 | import androidx.annotation.NonNull;
8 | import androidx.fragment.app.DialogFragment;
9 | import androidx.appcompat.app.AlertDialog;
10 | import androidx.recyclerview.widget.LinearLayoutManager;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.widget.TextView;
16 |
17 | import com.wesaphzt.privatelocation.MainActivity;
18 | import com.wesaphzt.privatelocation.R;
19 | import com.wesaphzt.privatelocation.db.Favorite;
20 | import com.wesaphzt.privatelocation.db.FavoriteAdapter;
21 | import com.wesaphzt.privatelocation.db.SQLiteDB;
22 |
23 | import java.util.List;
24 |
25 | public class DialogFragmentFavorite extends DialogFragment {
26 |
27 | private SQLiteDB mDatabase;
28 |
29 | private MainActivity mainActivity;
30 |
31 | public DialogFragmentFavorite(Context context, MainActivity mActivity) {
32 | mainActivity = mActivity;
33 | }
34 |
35 | //default constructor
36 | public DialogFragmentFavorite() { }
37 |
38 | @NonNull
39 | @SuppressLint("InflateParams")
40 | @Override
41 | public Dialog onCreateDialog(Bundle savedInstanceState) {
42 |
43 | Context context = getContext();
44 |
45 | //setup alert builder
46 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
47 | builder.setTitle(getString(R.string.dialog_favorites_title));
48 |
49 | //set listview as view
50 | LayoutInflater inflater = getActivity().getLayoutInflater();
51 | final View view = inflater.inflate(R.layout.dialog_favorites, null);
52 | builder.setView(view);
53 |
54 | RecyclerView favoriteView = (RecyclerView) view.findViewById(R.id.favorite_list);
55 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
56 |
57 | //empty view
58 | TextView tvEmpty = view.findViewById(R.id.tvEmpty);
59 |
60 | favoriteView.setLayoutManager(linearLayoutManager);
61 | favoriteView.setHasFixedSize(true);
62 |
63 | //db
64 | mDatabase = new SQLiteDB(context);
65 | List allFavorites = mDatabase.listFavorites();
66 |
67 | //if db empty
68 | if(allFavorites.isEmpty()) {
69 | favoriteView.setVisibility(View.GONE);
70 | tvEmpty.setVisibility(View.VISIBLE);
71 |
72 | } else {
73 | favoriteView.setVisibility(View.VISIBLE);
74 | tvEmpty.setVisibility(View.GONE);
75 | //pass mainActivity so we can callback in FavoriteAdapter
76 | FavoriteAdapter mAdapter = new FavoriteAdapter(context, allFavorites, mainActivity, DialogFragmentFavorite.this);
77 | favoriteView.setAdapter(mAdapter);
78 | }
79 |
80 | return builder.create();
81 | }
82 |
83 | @Override
84 | public void onDestroy() {
85 | super.onDestroy();
86 |
87 | if(mDatabase != null){
88 | mDatabase.close();
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/fragments/DialogFragmentGoTo.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.fragments;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Dialog;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.os.Bundle;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.fragment.app.DialogFragment;
11 | import androidx.appcompat.app.AlertDialog;
12 | import android.text.Editable;
13 | import android.text.TextUtils;
14 | import android.util.Log;
15 | import android.view.LayoutInflater;
16 | import android.view.View;
17 | import android.widget.EditText;
18 | import android.widget.Toast;
19 |
20 | import com.wesaphzt.privatelocation.R;
21 | import com.wesaphzt.privatelocation.interfaces.ILatLong;
22 |
23 | import es.dmoral.toasty.Toasty;
24 |
25 | public class DialogFragmentGoTo extends DialogFragment {
26 |
27 | private Context context;
28 |
29 | private Double dLat;
30 | private final Double latMin = -90.0;
31 | private final Double latMax = 90.0;
32 |
33 | private Double dLng;
34 | private final Double lngMin = -180.0;
35 | private final Double lngMax = 180.0;
36 |
37 | private ILatLong mCallback;
38 |
39 | @NonNull
40 | @SuppressLint("InflateParams")
41 | @Override
42 | public Dialog onCreateDialog(Bundle savedInstanceState) {
43 |
44 | //init
45 | context = getContext();
46 |
47 | LayoutInflater inflater = LayoutInflater.from(context);
48 | View subView = inflater.inflate(R.layout.dialog_go_to, null);
49 |
50 | final EditText etLatitude = (EditText) subView.findViewById(R.id.enter_latitude);
51 | final EditText etLongitude = (EditText) subView.findViewById(R.id.enter_longitude);
52 |
53 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
54 | builder.setTitle(R.string.dialog_go_to_title);
55 | builder.setView(subView);
56 | builder.create();
57 |
58 | builder.setPositiveButton("GO", new DialogInterface.OnClickListener() {
59 | @Override
60 | public void onClick(DialogInterface dialog, int which) {
61 | if(!isEmpty(etLatitude.getText()) || !isEmpty(etLongitude.getText())) {
62 | //isn't empty
63 | try {
64 | //is double
65 | dLat = Double.parseDouble(etLatitude.getText().toString());
66 | dLng = Double.parseDouble(etLongitude.getText().toString());
67 |
68 | if (!isMinMax(dLat, latMin, latMax) || !isMinMax(dLng, latMin, latMax)) {
69 | //isn't valid lat/long range
70 | Toasty.info(context, getString(R.string.dialog_go_to_invalid_range), Toast.LENGTH_SHORT, true).show();
71 | } else {
72 | //is valid lat/long range
73 | mCallback.setLocation(dLat, dLng);
74 | }
75 | } catch (Exception e1) {
76 | //isn't double
77 | Toasty.info(context, R.string.dialog_go_to_invalid_number, Toast.LENGTH_SHORT, true).show();
78 | }
79 | } else {
80 | //is empty
81 | Toasty.info(context, R.string.dialog_go_to_invalid_empty, Toast.LENGTH_SHORT, true).show();
82 | }
83 | }
84 | });
85 |
86 | builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
87 | @Override
88 | public void onClick(DialogInterface dialog, int which) {
89 | dismiss();
90 | }
91 | });
92 |
93 | return builder.create();
94 | }
95 |
96 | private boolean isMinMax(Double num, Double min, Double max) {
97 | return (num > min && num < max);
98 | }
99 |
100 | private boolean isEmpty(Editable value){
101 | return TextUtils.isEmpty(value);
102 | }
103 |
104 | @Override
105 | public void onAttach(Context context) {
106 | super.onAttach(context);
107 |
108 | try {
109 | mCallback = (ILatLong) context;
110 | }
111 | catch (ClassCastException e) {
112 | Log.d("DialogFragmentGoTo", "ILatLong not implemented");
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/fragments/FragmentAbout.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.fragments;
2 |
3 | import android.content.Intent;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.net.Uri;
7 | import android.os.Bundle;
8 | import androidx.annotation.Nullable;
9 | import androidx.fragment.app.Fragment;
10 |
11 | import android.util.Log;
12 | import android.view.LayoutInflater;
13 | import android.view.Menu;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.LinearLayout;
17 | import android.widget.TextView;
18 |
19 | import com.wesaphzt.privatelocation.R;
20 |
21 | public class FragmentAbout extends Fragment {
22 |
23 | private static String GITHUB_URI;
24 | private static String LICENSE_URI;
25 | private static String BUG_REPORT_URI;
26 | private static String AUTHOR_GITHUB;
27 |
28 | @Nullable
29 | @Override
30 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
31 | View v = inflater.inflate(R.layout.fragment_about, container, false);
32 |
33 | GITHUB_URI = getString(R.string.app_github);
34 | LICENSE_URI = GITHUB_URI + "/blob/master/LICENSE";
35 | BUG_REPORT_URI = GITHUB_URI + "/issues";
36 | AUTHOR_GITHUB = getString(R.string.app_github_dev);
37 |
38 | String versionName = "";
39 | try {
40 | PackageInfo packageInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0);
41 | versionName = packageInfo.versionName;
42 | } catch (PackageManager.NameNotFoundException e) {
43 | e.printStackTrace();
44 | }
45 |
46 | TextView version = v.findViewById(R.id.about_text_version);
47 | version.setText(versionName);
48 |
49 | LinearLayout license = v.findViewById(R.id.about_layout_license);
50 | LinearLayout source = v.findViewById(R.id.about_layout_source);
51 |
52 | license.setOnClickListener(new View.OnClickListener() {
53 | @Override
54 | public void onClick(View view) {
55 | openURI(LICENSE_URI);
56 | }
57 | });
58 | source.setOnClickListener(new View.OnClickListener() {
59 | @Override
60 | public void onClick(View view) {
61 | openURI(GITHUB_URI);
62 | }
63 | });
64 |
65 | LinearLayout authorLayout = v.findViewById(R.id.aboutLayoutAuthor);
66 | authorLayout.setOnClickListener(new View.OnClickListener() {
67 | @Override
68 | public void onClick(View view) {
69 | openURI(AUTHOR_GITHUB);
70 | }
71 | });
72 |
73 | LinearLayout bugReport = v.findViewById(R.id.about_layout_bugs);
74 | bugReport.setOnClickListener(new View.OnClickListener() {
75 | @Override
76 | public void onClick(View view) {
77 | openURI(BUG_REPORT_URI);
78 | }
79 | });
80 |
81 | return v;
82 | }
83 |
84 | @Override
85 | public void onCreate(Bundle savedInstanceState) {
86 | setHasOptionsMenu(true);
87 |
88 | super.onCreate(savedInstanceState);
89 | }
90 |
91 | private void openURI(String uri) {
92 | try {
93 | Intent openURI = new Intent(Intent.ACTION_VIEW);
94 | openURI.setData(Uri.parse(uri));
95 | startActivity(openURI);
96 | } catch (Exception e) {
97 | Log.d("app-error", "error opening uri");
98 | }
99 | }
100 |
101 | @Override
102 | public void onPrepareOptionsMenu(Menu menu) {
103 | //hide action bar menu
104 | menu.setGroupVisible(R.id.menu_top, false);
105 | menu.setGroupVisible(R.id.menu_bottom, false);
106 |
107 | super.onPrepareOptionsMenu(menu);
108 | }
109 |
110 | @Override
111 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
112 | super.onViewCreated(view, savedInstanceState);
113 | //set title
114 | getActivity().setTitle(getString(R.string.fragment_about_title));
115 | }
116 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/fragments/FragmentDonate.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.fragments;
2 |
3 | import android.content.ClipData;
4 | import android.content.ClipboardManager;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 |
10 | import androidx.annotation.Nullable;
11 | import androidx.fragment.app.Fragment;
12 | import android.view.LayoutInflater;
13 | import android.view.Menu;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.TextView;
17 | import android.widget.Toast;
18 |
19 | import com.wesaphzt.privatelocation.R;
20 |
21 | import es.dmoral.toasty.Toasty;
22 |
23 | public class FragmentDonate extends Fragment {
24 |
25 | private Context context;
26 |
27 | private static final String BITCOIN_PREFIX = "bitcoin:";
28 | private static final String LITECOIN_PREFIX = "litecoin:";
29 | private static final String ETHEREUM_PREFIX = "ethereum:";
30 | private static final String MONERO_PREFIX = "monero:";
31 |
32 | private static String BITCOIN_ADDRESS;
33 | private static String BITCOIN_FULL;
34 |
35 | private static String LITECOIN_ADDRESS;
36 | private static String LITECOIN_FULL;
37 |
38 | private static String ETHEREUM_ADDRESS;
39 | private static String ETHEREUM_FULL;
40 |
41 | private static String MONERO_ADDRESS;
42 | private static String MONERO_FULL;
43 |
44 | @Override
45 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
46 | View view = inflater.inflate(R.layout.fragment_donate, container, false);
47 |
48 | setHasOptionsMenu(true);
49 |
50 | context = getContext();
51 |
52 | final TextView tvAddressBtc = view.findViewById(R.id.donate_bitcoin_address);
53 | final TextView tvAddressLtc = view.findViewById(R.id.donate_litecoin_address);
54 | final TextView tvAddressEth = view.findViewById(R.id.donate_ethereum_address);
55 | final TextView tvAddressXmr = view.findViewById(R.id.donate_monero_address);
56 |
57 | BITCOIN_ADDRESS = getString(R.string.donate_bitcoin_address);
58 | BITCOIN_FULL = BITCOIN_PREFIX + BITCOIN_ADDRESS;
59 | tvAddressBtc.setText(BITCOIN_ADDRESS);
60 |
61 | LITECOIN_ADDRESS = getString(R.string.donate_litecoin_address);
62 | LITECOIN_FULL = LITECOIN_PREFIX + LITECOIN_ADDRESS;
63 | tvAddressLtc.setText(LITECOIN_ADDRESS);
64 |
65 | ETHEREUM_ADDRESS = getString(R.string.donate_ethereum_address);
66 | ETHEREUM_FULL = ETHEREUM_PREFIX + ETHEREUM_ADDRESS;
67 | tvAddressEth.setText(ETHEREUM_ADDRESS);
68 |
69 | MONERO_ADDRESS = getString(R.string.donate_monero_address);
70 | MONERO_FULL = MONERO_PREFIX + MONERO_ADDRESS;
71 | tvAddressXmr.setText(MONERO_ADDRESS);
72 |
73 | tvAddressBtc.setOnClickListener(new View.OnClickListener() {
74 | @Override
75 | public void onClick(View view) {
76 | //attempt to open bitcoin app, else copy to clipboard
77 | try {
78 | openURI(BITCOIN_FULL);
79 | } catch(Exception ignored) {
80 | copyToClipboard(BITCOIN_ADDRESS);
81 | }
82 | }
83 | });
84 | tvAddressBtc.setOnLongClickListener(new View.OnLongClickListener() {
85 | @Override
86 | public boolean onLongClick(View v) {
87 | copyToClipboard(BITCOIN_ADDRESS);
88 | return true;
89 | }
90 | });
91 |
92 | //litecoin
93 | tvAddressLtc.setOnClickListener(new View.OnClickListener() {
94 | @Override
95 | public void onClick(View view) {
96 | //attempt to open litecoin app, else copy to clipboard
97 | try {
98 | openURI(LITECOIN_FULL);
99 | } catch(Exception ignored) {
100 | copyToClipboard(LITECOIN_ADDRESS);
101 | }
102 | }
103 | });
104 | tvAddressLtc.setOnLongClickListener(new View.OnLongClickListener() {
105 | @Override
106 | public boolean onLongClick(View v) {
107 | copyToClipboard(LITECOIN_ADDRESS);
108 | return true;
109 | }
110 | });
111 |
112 | //ethereum
113 | tvAddressEth.setOnClickListener(new View.OnClickListener() {
114 | @Override
115 | public void onClick(View view) {
116 | //attempt to open ethereum app, else copy to clipboard
117 | try {
118 | openURI(ETHEREUM_FULL);
119 | } catch(Exception ignored) {
120 | copyToClipboard(ETHEREUM_ADDRESS);
121 | }
122 | }
123 | });
124 | tvAddressEth.setOnLongClickListener(new View.OnLongClickListener() {
125 | @Override
126 | public boolean onLongClick(View v) {
127 | copyToClipboard(ETHEREUM_ADDRESS);
128 | return true;
129 | }
130 | });
131 |
132 | //monero
133 | tvAddressXmr.setOnClickListener(new View.OnClickListener() {
134 | @Override
135 | public void onClick(View view) {
136 | //attempt to open ethereum app, else copy to clipboard
137 | try {
138 | openURI(MONERO_FULL);
139 | } catch(Exception ignored) {
140 | copyToClipboard(MONERO_ADDRESS);
141 | }
142 | }
143 | });
144 | tvAddressXmr.setOnLongClickListener(new View.OnLongClickListener() {
145 | @Override
146 | public boolean onLongClick(View v) {
147 | copyToClipboard(MONERO_ADDRESS);
148 | return true;
149 | }
150 | });
151 |
152 | return view;
153 | }
154 |
155 | private void copyToClipboard(String AUTHOR_EXTRA) {
156 | ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
157 | ClipData clip = ClipData.newPlainText(getString(R.string.fragment_donate_clipboard_label), AUTHOR_EXTRA);
158 | clipboard.setPrimaryClip(clip);
159 |
160 | Toasty.success(context, R.string.fragment_donate_clipboard_message, Toast.LENGTH_SHORT, true).show();
161 | }
162 |
163 | private void openURI(String uri) {
164 | Intent openURI = new Intent(Intent.ACTION_VIEW);
165 | openURI.setData(Uri.parse(uri));
166 | startActivity(openURI);
167 | }
168 |
169 | @Override
170 | public void onPrepareOptionsMenu(Menu menu) {
171 | //hide action bar menu
172 | menu.setGroupVisible(R.id.menu_top, false);
173 | menu.setGroupVisible(R.id.menu_bottom, false);
174 |
175 | super.onPrepareOptionsMenu(menu);
176 | }
177 |
178 | @Override
179 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
180 | super.onViewCreated(view, savedInstanceState);
181 | //set title
182 | getActivity().setTitle(getString(R.string.fragment_donate_title));
183 | }
184 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/fragments/FragmentSettings.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.fragments;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.os.Bundle;
6 | import androidx.annotation.Nullable;
7 |
8 | import android.view.Menu;
9 | import android.view.View;
10 | import android.widget.Toast;
11 |
12 | import androidx.preference.CheckBoxPreference;
13 | import androidx.preference.PreferenceFragmentCompat;
14 | import androidx.preference.PreferenceManager;
15 |
16 | import com.wesaphzt.privatelocation.R;
17 |
18 | public class FragmentSettings extends PreferenceFragmentCompat {
19 |
20 | private Context context;
21 |
22 | private CheckBoxPreference cbRandomize;
23 |
24 | private SharedPreferences sharedPreferences;
25 | private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener;
26 |
27 | @Override
28 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
29 | addPreferencesFromResource(R.xml.preferences);
30 |
31 | setHasOptionsMenu(true);
32 | context = getContext();
33 |
34 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
35 |
36 | //this static call will reset default values only on the first ever read
37 | PreferenceManager.setDefaultValues(context, R.xml.preferences, false);
38 |
39 | cbRandomize = findPreference("RANDOMIZE_LOCATION");
40 | }
41 |
42 | @Override
43 | public void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | }
46 |
47 | @Override
48 | public void onResume() {
49 | super.onResume();
50 | sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
51 | }
52 |
53 | @Override
54 | public void onDestroy() {
55 | super.onDestroy();
56 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
57 | }
58 |
59 | @Override
60 | public void onPause() {
61 | super.onPause();
62 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
63 | }
64 |
65 | @Override
66 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
67 | super.onViewCreated(view, savedInstanceState);
68 | //set title
69 | getActivity().setTitle("Settings");
70 |
71 | //background color
72 | view.setBackgroundColor(getResources().getColor(R.color.white));
73 |
74 | sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
75 | @Override
76 | public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
77 | if(key.equals("RANDOMIZE_LOCATION") && cbRandomize.isChecked()) {
78 | Toast.makeText(context, getString(R.string.settings_randomize_toast), Toast.LENGTH_LONG).show();
79 | }
80 | }
81 | };
82 | sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
83 | }
84 |
85 | @Override
86 | public void onPrepareOptionsMenu(Menu menu) {
87 | //hide action bar menu
88 | menu.setGroupVisible(R.id.menu_top, false);
89 | menu.setGroupVisible(R.id.menu_bottom, false);
90 |
91 | super.onPrepareOptionsMenu(menu);
92 | }
93 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/interfaces/ILatLong.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.interfaces;
2 |
3 | public interface ILatLong {
4 | void setLocation(Double lat, Double lng);
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/interfaces/JSInterface.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.interfaces;
2 |
3 | import android.content.Context;
4 | import android.webkit.JavascriptInterface;
5 |
6 | import com.wesaphzt.privatelocation.MainActivity;
7 |
8 | public class JSInterface {
9 |
10 | private Context context;
11 |
12 | private MainActivity mainActivity;
13 | public JSInterface(Context context, MainActivity mActivity) {
14 | mainActivity = mActivity;
15 | }
16 |
17 | public Context getContext() {
18 | return context;
19 | }
20 |
21 | //store user location in shared prefs on leaflet move end, unreliable elsewhere
22 | @JavascriptInterface
23 | public void setLatLongZoom(final String latlng, int zoom) {
24 | //separate lat & long
25 | String lat = latlng.substring(latlng.indexOf('(') + 1, latlng.indexOf(','));
26 | String lng = latlng.substring(latlng.indexOf(',') + 2, latlng.indexOf(')'));
27 |
28 | mainActivity.setSharedPreferencesLatLng(lat, lng, zoom);
29 | }
30 |
31 | @JavascriptInterface
32 | public void setMockLocation(final String location) {
33 | //separate lat & long
34 | String lat = location.substring(location.indexOf('(') + 1, location.indexOf(','));
35 | String lng = location.substring(location.indexOf(',') + 2, location.indexOf(')'));
36 |
37 | //call method to add to shared prefs
38 | mainActivity.setMockLatLong(lat, lng);
39 | }
40 |
41 | @JavascriptInterface
42 | public void addFavoriteLocation(final String favorite) {
43 | //separate lat & long
44 | String lat = favorite.substring(favorite.indexOf('(') + 1, favorite.indexOf(','));
45 | String lng = favorite.substring(favorite.indexOf(',') + 2, favorite.indexOf(')'));
46 |
47 | mainActivity.addFavoriteLocation(lat, lng);
48 | }
49 |
50 | @JavascriptInterface
51 | public void onLocationError() {
52 | mainActivity.getLocationGps();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/receivers/ActionReceiver.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.receivers;
2 |
3 | import android.app.NotificationManager;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.location.LocationManager;
8 | import android.os.Build;
9 |
10 | import com.wesaphzt.privatelocation.R;
11 | import com.wesaphzt.privatelocation.service.LocationProvider;
12 | import com.wesaphzt.privatelocation.service.LocationService;
13 | import com.wesaphzt.privatelocation.widget.LocationWidgetProvider;
14 |
15 | import static com.wesaphzt.privatelocation.service.LocationService.isRunning;
16 | import static com.wesaphzt.privatelocation.service.LocationService.mCountDown;
17 |
18 | public class ActionReceiver extends BroadcastReceiver {
19 |
20 | private static final int NOTIFICATION = 100;
21 |
22 | @Override
23 | public void onReceive(Context context, Intent intent) {
24 | String action = intent.getStringExtra("location_service");
25 |
26 | if(action.equals("service_notification")){
27 | Intent stopIntent = new Intent(context, LocationService.class);
28 | stopIntent.setAction(LocationService.ACTION_STOP_FOREGROUND_SERVICE);
29 |
30 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
31 | context.startForegroundService(stopIntent);
32 | } else {
33 | context.startService(stopIntent);
34 | }
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/receivers/BootReceiver.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.receivers;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.os.Build;
8 | import android.preference.PreferenceManager;
9 |
10 | import com.wesaphzt.privatelocation.service.LocationService;
11 |
12 | import static com.wesaphzt.privatelocation.MainActivity.USER_LAT_NAME;
13 | import static com.wesaphzt.privatelocation.MainActivity.USER_LNG_NAME;
14 |
15 | public class BootReceiver extends BroadcastReceiver {
16 |
17 | @Override
18 | public void onReceive(Context context, Intent intent) {
19 |
20 | if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
21 | //shared prefs
22 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
23 |
24 | if(sharedPreferences.getBoolean("START_ON_BOOT", false)) {
25 | Intent startIntent = new Intent(context, LocationService.class);
26 | startIntent.setAction(LocationService.ACTION_START_FOREGROUND_SERVICE);
27 |
28 | //init
29 | double lat = 0;
30 | double lng = 0;
31 |
32 | try {
33 | lat = Double.parseDouble(sharedPreferences.getString(USER_LAT_NAME, "null"));
34 | lng = Double.parseDouble(sharedPreferences.getString(USER_LNG_NAME, "null"));
35 | } catch (Exception e) {
36 | e.printStackTrace();
37 | }
38 |
39 | //add location data to the intent
40 | startIntent.putExtra("lat", lat);
41 | startIntent.putExtra("lng", lng);
42 |
43 | //check android api
44 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
45 | context.startForegroundService(startIntent);
46 | } else {
47 | context.startService(startIntent);
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/service/LocationProvider.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.service;
2 |
3 | import android.content.Context;
4 | import android.location.Criteria;
5 | import android.location.Location;
6 | import android.location.LocationManager;
7 | import android.os.Build;
8 | import android.os.SystemClock;
9 |
10 | public class LocationProvider {
11 |
12 | private String providerName;
13 | public Context context;
14 |
15 | public LocationProvider(String name, Context context) {
16 | this.providerName = name;
17 | this.context = context;
18 |
19 | LocationManager locationManager = (LocationManager) context.getSystemService(
20 | Context.LOCATION_SERVICE);
21 | try
22 | {
23 | locationManager.addTestProvider(providerName, false, false, false, false, false,
24 | true, true, Criteria.POWER_LOW, Criteria.ACCURACY_FINE);
25 | locationManager.setTestProviderEnabled(providerName, true);
26 | } catch (SecurityException e) {
27 | throw new SecurityException("Error applying mock location");
28 | }
29 | }
30 |
31 | void pushLocation(double lat, double lon) {
32 | LocationManager locationManager = (LocationManager) context.getSystemService(
33 | Context.LOCATION_SERVICE);
34 |
35 | Location mockLocation = new Location(providerName);
36 | mockLocation.setLatitude(lat);
37 | mockLocation.setLongitude(lon);
38 | mockLocation.setAltitude(3F);
39 | mockLocation.setTime(System.currentTimeMillis());
40 | mockLocation.setSpeed(0.01F);
41 | mockLocation.setBearing(1F);
42 | mockLocation.setAccuracy(3F);
43 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
44 | mockLocation.setBearingAccuracyDegrees(0.1F);
45 | }
46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
47 | mockLocation.setVerticalAccuracyMeters(0.1F);
48 | }
49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
50 | mockLocation.setSpeedAccuracyMetersPerSecond(0.01F);
51 | }
52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
53 | mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
54 | }
55 | locationManager.setTestProviderLocation(providerName, mockLocation);
56 | }
57 |
58 | public void shutdown() {
59 | LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
60 | locationManager.removeTestProvider(providerName);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/service/LocationService.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.service;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.app.Service;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.SharedPreferences;
11 | import android.location.LocationManager;
12 | import android.os.Build;
13 | import android.os.CountDownTimer;
14 | import android.os.IBinder;
15 | import android.widget.Toast;
16 |
17 | import androidx.preference.PreferenceManager;
18 | import androidx.core.app.NotificationCompat;
19 |
20 | import com.wesaphzt.privatelocation.MainActivity;
21 | import com.wesaphzt.privatelocation.R;
22 | import com.wesaphzt.privatelocation.receivers.ActionReceiver;
23 | import com.wesaphzt.privatelocation.widget.LocationWidgetProvider;
24 |
25 | import java.util.Random;
26 |
27 | import static androidx.core.app.NotificationCompat.PRIORITY_LOW;
28 | import static androidx.core.app.NotificationCompat.PRIORITY_MIN;
29 |
30 | public class LocationService extends Service {
31 |
32 | LocationProvider mockNetwork;
33 | LocationProvider mockGps;
34 |
35 | //notifications
36 | public static PendingIntent pendingIntent;
37 | public static PendingIntent pendingCloseIntent;
38 |
39 | public static final int NOTIFICATION_ID = 100;
40 |
41 | Notification notification;
42 | NotificationManager notificationManager;
43 |
44 | public static final String CHANNEL_ID = "location_notification_channel_id";
45 | public static final String CHANNEL_NAME = "Location Notification Service";
46 |
47 | Context context;
48 | SharedPreferences sharedPreferences;
49 |
50 | public static boolean disabled = true;
51 |
52 | //randomize
53 | public static CountDownTimer mCountDown;
54 | public static boolean isRunning = false;
55 | private static int RANDOMIZE_LOCATION_INTERVAL;
56 |
57 | public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";
58 | public static final String ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE";
59 |
60 | @Override
61 | public int onStartCommand(Intent intent, int flags, int startId) {
62 | context = getApplicationContext();
63 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
64 | notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
65 |
66 | if (intent != null) {
67 | String action = intent.getAction();
68 |
69 | LocationWidgetProvider locationWidgetProvider = new LocationWidgetProvider();
70 |
71 | switch (action) {
72 | case ACTION_START_FOREGROUND_SERVICE:
73 | setNotification();
74 |
75 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
76 | //create foreground service
77 | startForeground(NOTIFICATION_ID, notification);
78 | pushLocation(intent);
79 | disabled = false;
80 | locationWidgetProvider.setWidgetStart(context);
81 | } else {
82 | notificationManager.notify(NOTIFICATION_ID, notification);
83 | pushLocation(intent);
84 | disabled = false;
85 | locationWidgetProvider.setWidgetStart(context);
86 | }
87 |
88 | break;
89 |
90 | case ACTION_STOP_FOREGROUND_SERVICE:
91 | shutdown();
92 | stopService(intent);
93 | disabled = true;
94 | locationWidgetProvider.setWidgetStop(context);
95 |
96 | break;
97 | }
98 | } else {
99 | return LocationService.START_REDELIVER_INTENT;
100 | }
101 |
102 | return LocationService.START_REDELIVER_INTENT;
103 | }
104 |
105 | @Override
106 | public void onDestroy() {
107 | super.onDestroy();
108 | }
109 |
110 | @Override
111 | public IBinder onBind(Intent intent) {
112 | return null;
113 | }
114 |
115 | private void setNotification() {
116 | //open main activity when clicked
117 | pendingIntent = PendingIntent.getActivity(context, 0,
118 | new Intent(context, MainActivity.class)
119 | .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP),
120 | 0);
121 |
122 | //action when notification button clicked
123 | Intent intentAction = new Intent(context, ActionReceiver.class);
124 | intentAction.putExtra("location_service","service_notification");
125 | pendingCloseIntent = PendingIntent.getBroadcast(context,0, intentAction, PendingIntent.FLAG_UPDATE_CURRENT);
126 |
127 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
128 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
129 | notification = notificationBuilder
130 | .setSmallIcon(R.drawable.ic_notification_pin_drop_white_24dp)
131 | .setContentTitle(getString(R.string.app_name) + " is running")
132 | .setCategory(NotificationCompat.CATEGORY_SERVICE)
133 | .setContentIntent(pendingIntent)
134 | .setWhen(System.currentTimeMillis())
135 | .setTicker(getString(R.string.app_name) + " is running")
136 | .addAction(android.R.drawable.ic_menu_close_clear_cancel, "STOP", pendingCloseIntent)
137 | .setOngoing(true)
138 | .setPriority(PRIORITY_LOW)
139 | .build();
140 |
141 | } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N | Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
142 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
143 | notification = notificationBuilder
144 | .setSmallIcon(R.drawable.ic_notification_pin_drop_white_24dp)
145 | .setContentTitle(getString(R.string.app_name) + " is running")
146 | .setCategory(NotificationCompat.CATEGORY_SERVICE)
147 | .setColor(getColor(R.color.colorPrimary))
148 | .setContentIntent(pendingIntent)
149 | .setWhen(System.currentTimeMillis())
150 | .setTicker(getString(R.string.app_name) + " is running")
151 | .addAction(android.R.drawable.ic_menu_close_clear_cancel, "STOP", pendingCloseIntent)
152 | .setOngoing(true)
153 | .setPriority(PRIORITY_LOW)
154 | .build();
155 | }
156 |
157 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
158 | NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
159 | channel.setImportance(NotificationManager.IMPORTANCE_LOW);
160 | channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
161 | notificationManager.createNotificationChannel(channel);
162 |
163 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
164 | notification = notificationBuilder
165 | .setSmallIcon(R.drawable.ic_notification_pin_drop_white_24dp)
166 | .setContentTitle(getString(R.string.app_name) + " is running")
167 | .setPriority(PRIORITY_MIN)
168 | .setVisibility(NotificationCompat.VISIBILITY_SECRET)
169 | .setCategory(NotificationCompat.CATEGORY_SERVICE)
170 | .setColor(getColor(R.color.colorPrimary))
171 | .setContentIntent(pendingIntent)
172 | .setWhen(System.currentTimeMillis())
173 | .setTicker(getString(R.string.app_name) + " is running")
174 | .addAction(android.R.drawable.ic_menu_close_clear_cancel, "STOP", pendingCloseIntent)
175 | .setOngoing(true)
176 | .build();
177 | }
178 | }
179 |
180 | private void pushLocation(Intent intent) {
181 | try {
182 | if (intent.hasExtra("lat") && intent.hasExtra("lng") ) {
183 | double lat = intent.getDoubleExtra("lat", 45);
184 | double lng = intent.getDoubleExtra("lng", 45);
185 |
186 | mockNetwork = new LocationProvider(LocationManager.NETWORK_PROVIDER, context);
187 | mockGps = new LocationProvider(LocationManager.GPS_PROVIDER, context);
188 |
189 | mockNetwork.pushLocation(lat, lng);
190 | mockGps.pushLocation(lat, lng);
191 |
192 | if(sharedPreferences.getBoolean("RANDOMIZE_LOCATION", false)) {
193 | randomize();
194 | }
195 | }
196 | } catch (Exception e) {
197 | e.printStackTrace();
198 | }
199 | }
200 |
201 | public void shutdown() {
202 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
203 | NotificationManager notificationManager =
204 | (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
205 | String id = "location_notification_channel_id";
206 | notificationManager.deleteNotificationChannel(id);
207 | } else {
208 | NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
209 | notificationManager.cancel(NOTIFICATION_ID);
210 | }
211 |
212 | try {
213 | disabled = true;
214 | isRunning = false;
215 |
216 | if (mockNetwork != null)
217 | mockNetwork.shutdown();
218 | if (mockGps != null)
219 | mockGps.shutdown();
220 | if (isRunning)
221 | mCountDown.cancel();
222 | } catch (Exception e) {
223 | e.printStackTrace();
224 | }
225 | }
226 |
227 | //---------------------------------------------------------------------
228 | private void randomize() {
229 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
230 | try {
231 | RANDOMIZE_LOCATION_INTERVAL = Integer.parseInt(prefs.getString("RANDOMIZE_LOCATION_INTERVAL", "60"));
232 |
233 | float randomLat = randomLat();
234 | float randomLng = randomLng();
235 |
236 | mockNetwork = new LocationProvider(LocationManager.NETWORK_PROVIDER, context);
237 | mockGps = new LocationProvider(LocationManager.GPS_PROVIDER, context);
238 |
239 | mockNetwork.pushLocation(randomLat, randomLng);
240 | mockGps.pushLocation(randomLat, randomLng);
241 |
242 | randomizeTimer();
243 | } catch (Exception e) {
244 | e.printStackTrace();
245 | }
246 | }
247 |
248 | private void randomizeTimer() {
249 | mCountDown = new CountDownTimer(RANDOMIZE_LOCATION_INTERVAL * 1000 * 60, 1000) {
250 | public void onTick(long millisUntilFinished) {
251 | isRunning = true;
252 | }
253 | public void onFinish() {
254 | isRunning = false;
255 | randomize();
256 | }
257 | }.start();
258 | }
259 |
260 | private float randomLat() {
261 | Random r = new Random();
262 | return r.nextFloat() * (180) - 90;
263 | }
264 |
265 | private float randomLng() {
266 | Random r = new Random();
267 | return r.nextFloat() * (360) - 180;
268 | }
269 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/wesaphzt/privatelocation/widget/LocationWidgetProvider.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation.widget;
2 |
3 | import android.app.PendingIntent;
4 | import android.appwidget.AppWidgetManager;
5 | import android.appwidget.AppWidgetProvider;
6 | import android.content.ComponentName;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.SharedPreferences;
10 | import android.os.Build;
11 | import android.preference.PreferenceManager;
12 | import android.widget.RemoteViews;
13 |
14 | import com.wesaphzt.privatelocation.R;
15 | import com.wesaphzt.privatelocation.service.LocationService;
16 |
17 | import static com.wesaphzt.privatelocation.MainActivity.DEFAULT_LAT;
18 | import static com.wesaphzt.privatelocation.MainActivity.DEFAULT_LNG;
19 | import static com.wesaphzt.privatelocation.MainActivity.USER_LAT_NAME;
20 | import static com.wesaphzt.privatelocation.MainActivity.USER_LNG_NAME;
21 |
22 | public class LocationWidgetProvider extends AppWidgetProvider {
23 |
24 | private static final String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
25 | public boolean SERVICE_STATUS;
26 |
27 | public void onUpdate(Context context, AppWidgetManager appWidgetManager,
28 | int[] appWidgetIds) {
29 |
30 | for (int appWidgetId : appWidgetIds) {
31 | RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
32 | R.layout.app_widget);
33 |
34 | //default status
35 | remoteViews.setTextViewText(R.id.tvWidgetToggle, context.getResources().getString(R.string.widget_start_text));
36 |
37 | Intent intent = new Intent(context, LocationWidgetProvider.class);
38 | intent.setAction(ACTION_WIDGET_RECEIVER);
39 | PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
40 |
41 | remoteViews.setOnClickPendingIntent(R.id.llWidget, pendingIntent);
42 |
43 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
44 | boolean value = prefs.getBoolean(context.getString(R.string.widget_prefs_service_id), false);
45 |
46 | if (value) {
47 | SharedPreferences.Editor editor = prefs.edit();
48 | editor.putBoolean(context.getString(R.string.widget_prefs_service_id), false);
49 | editor.apply();
50 | }
51 |
52 | appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
53 | }
54 | }
55 |
56 | @Override
57 | public void onReceive(Context context, Intent intent) {
58 | if (intent.getAction().equals(ACTION_WIDGET_RECEIVER)) {
59 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
60 | boolean value = prefs.getBoolean(context.getString(R.string.widget_prefs_service_id), false);
61 | SharedPreferences.Editor editor = prefs.edit();
62 |
63 | SERVICE_STATUS = value;
64 |
65 | //if service is running
66 | if (SERVICE_STATUS) {
67 | editor.putBoolean(context.getString(R.string.widget_prefs_service_id), false);
68 | editor.apply();
69 |
70 | Intent stopIntent = new Intent(context, LocationService.class);
71 | stopIntent.setAction(LocationService.ACTION_STOP_FOREGROUND_SERVICE);
72 |
73 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
74 | context.startForegroundService(stopIntent);
75 |
76 | } else {
77 | context.startService(stopIntent);
78 | }
79 |
80 | //if service is not running
81 | } else {
82 | editor.putBoolean(context.getString(R.string.widget_prefs_service_id), true);
83 | editor.commit();
84 |
85 | double mLat;
86 | double mLng;
87 |
88 | //grab last lat/lng or use defaults if app hasn't run yet
89 | try {
90 | mLat = Double.parseDouble(prefs.getString(USER_LAT_NAME, "null"));
91 | mLng = Double.parseDouble(prefs.getString(USER_LNG_NAME, "null"));
92 | } catch (Exception e) {
93 | e.printStackTrace();
94 |
95 | mLat = DEFAULT_LAT;
96 | mLng = DEFAULT_LNG;
97 | }
98 |
99 | Intent startIntent = new Intent(context, LocationService.class);
100 | startIntent.setAction(LocationService.ACTION_START_FOREGROUND_SERVICE);
101 | startIntent.putExtra("lat", mLat);
102 | startIntent.putExtra("lng", mLng);
103 |
104 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
105 | context.startForegroundService(startIntent);
106 | } else {
107 | context.startService(startIntent);
108 | }
109 | }
110 | }
111 | super.onReceive(context, intent);
112 | }
113 |
114 | @Override
115 | public void onDeleted(Context context, int[] appWidgetIds) {
116 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
117 | boolean value = prefs.getBoolean(context.getString(R.string.widget_prefs_service_id), false);
118 |
119 | if (value) {
120 | SharedPreferences.Editor editor = prefs.edit();
121 | editor.putBoolean(context.getString(R.string.widget_prefs_service_id), false);
122 | editor.apply();
123 | }
124 |
125 | super.onDeleted(context, appWidgetIds);
126 | }
127 |
128 | //update widget methods
129 | public void setWidgetStart(Context context) {
130 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
131 | prefs.edit().putBoolean(context.getString(R.string.widget_prefs_service_id), true).apply();
132 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
133 | ComponentName thisWidget = new ComponentName(context, LocationWidgetProvider.class);
134 | RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.app_widget);
135 |
136 | remoteViews.setTextViewText(R.id.tvWidgetToggle, context.getResources().getString(R.string.widget_stop_text));
137 | remoteViews.setImageViewResource(R.id.ivWidgetLocation, R.drawable.ic_widget_location_on_white_24dp);
138 | remoteViews.setInt(R.id.llWidget, "setBackgroundResource", R.color.colorWidgetStart);
139 |
140 | appWidgetManager.updateAppWidget(thisWidget, remoteViews);
141 | }
142 |
143 | public void setWidgetStop(Context context) {
144 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
145 | prefs.edit().putBoolean(context.getString(R.string.widget_prefs_service_id), false).apply();
146 |
147 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
148 | ComponentName thisWidget = new ComponentName(context, LocationWidgetProvider.class);
149 | RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.app_widget);
150 |
151 | remoteViews.setTextViewText(R.id.tvWidgetToggle, context.getResources().getString(R.string.widget_start_text));
152 | remoteViews.setImageViewResource(R.id.ivWidgetLocation, R.drawable.ic_widget_location_off_white_24dp);
153 | remoteViews.setInt(R.id.llWidget, "setBackgroundResource", R.color.colorWidgetStop);
154 |
155 | appWidgetManager.updateAppWidget(thisWidget, remoteViews);
156 | }
157 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/enter_from_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/enter_from_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/exit_to_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/exit_to_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_light.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about_bug_report_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about_code_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about_copyright_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about_info_outline_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about_person_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_favorite_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_pin_drop_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_settings_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_donate_bitcoin_logo.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_donate_ethereum_logo.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
11 |
15 |
19 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_donate_litecoin_logo.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_donate_monero_logo.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_donate_note_text_emoji.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
7 |
9 |
11 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_empty_view.xml:
--------------------------------------------------------------------------------
1 |
3 |
5 |
7 |
9 |
11 |
13 |
15 |
17 |
19 |
21 |
23 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorites_delete_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorites_edit_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_intro_cloud.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
8 |
11 |
14 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_intro_location.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
8 |
11 |
15 |
20 |
23 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notification_pin_drop_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_widget_location_off_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_widget_location_on_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_widget.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
16 |
17 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_favorites.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
18 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_favorites_add.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_favorites_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
25 |
26 |
34 |
35 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_go_to.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_donate.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
19 |
24 |
25 |
33 |
34 |
43 |
44 |
45 |
46 |
47 |
48 |
53 |
54 |
59 |
60 |
68 |
69 |
79 |
80 |
85 |
86 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
104 |
105 |
110 |
111 |
119 |
120 |
130 |
131 |
136 |
137 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
155 |
156 |
161 |
162 |
170 |
171 |
181 |
182 |
187 |
188 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
206 |
207 |
212 |
213 |
221 |
222 |
232 |
233 |
238 |
239 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Private Location
3 | Open-Source Location Privacy
4 |
5 | https://github.com/wesaphzt
6 | https://github.com/wesaphzt/PrivateLocation
7 |
8 |
9 | Favorito
10 | Ir a
11 | Ajustes
12 | Donar
13 | Mostrar introducción
14 | Acerca de
15 |
16 |
17 | Dona
18 | Dirección copiada
19 | Dirección copiada al portapapeles
20 | Acerca de
21 |
22 |
23 | Lugares favoritos
24 | Nada aquí…
25 | Nombre
26 | Latitud: %1$f \nLongitud: %2$f
27 | Nombre
28 | Editar
29 | Borrar
30 |
31 | Coordinadas del lugar
32 | Latitud
33 | Longitud
34 | No es un rango válido
35 | No es un número válido
36 | No puede estar vacía
37 |
38 |
39 | Ajustes de localización
40 | Si experimenta problemas con la exposición de su ubicación real, especialmente con las aplicaciones y servicios basados en Google Maps,
41 | se recomienda deshabilitar cualquier modificación en los ajustes de ubicación que utilizan puntos de Wi-Fi y más para ayudar a determinar su ubicación de forma más rápida y precisa.
42 |
43 | Ubicación simulada deshabilitada
44 | Seleccione esta aplicación en los ajustes de ubicación simulada.
45 | Active las ubicaciones simuladas en los ajustes.
46 |
47 | Ajustes de desarrollador desactivados
48 | Habilite las opciones de desarrollador haciendo clic en el número de compilación de su teléfono 7 (siete) veces.
49 |
50 | Ajustes de desarrollador
51 | Asegúrese de que los ajustes de desarrollador estén activados antes de intentar establecer la ubicación para evitar problemas en Nougat.
52 | \n\n Puede hacerlo haciendo clic en el número de compilación de su teléfono 7 (siete) veces.
53 |
54 |
55 | Sobre el logo general de la aplicación
56 |
57 | Contribuye
58 | Encuentre errores
59 | Encuentre errores o sugiere características
60 |
61 | Imagen del autor
62 | wesaphzt
63 | Desarrollador
64 | Desarrollador
65 |
66 | Versión
67 | Imagen de la versión
68 |
69 | Licencia
70 | Licencia GPL v3.0
71 | Imagen de la licencia
72 |
73 | Código fuente
74 | Imagen del código fuente
75 |
76 | Imagen de reporte de errores
77 |
78 |
79 | Si el servicio se está ejecutando actualmente, reinicie para aplicar la configuración.
80 | \n\nPuede interferir con la temperatura de la pantalla y la localización.
81 |
82 |
83 | Comienzo
84 | Detener
85 |
86 | SERVICE_STATUS
87 | Imagen de ubicación del widget
88 |
89 |
90 | @string/app_name
91 | El compañero perfecto para ayudar a proteger la privacidad y seguridad de la ubicación de su teléfono al suplantar su ubicación a cualquier parte del mundo.
92 | Limite sus datos
93 | Muchas aplicaciones pueden realizar solicitudes de ubicación repetidas e innecesarias en segundo plano, a menudo enviando estos datos a la nube.
94 | \n\nLos datos de ubicación son personales y potencialmente muy sensibles, esta aplicación puede ayudar a proteger su privacidad y datos.
95 | Verifica tu configuración
96 | Para navegar sin problemas, asegúrese de que la configuración de su ubicación no utilice WiFi, red u otros métodos para determinar su ubicación que pueda filtrar su ubicación real,
97 | y que la optimización de la batería está desactivada para esta aplicación.
98 |
99 |
100 | Imagen de Bitcoin
101 | Imagen de Litecoin
102 | Imagen de Ethereum
103 | Imagen de Monero
104 |
105 | 1GCkvAg9oG79niQTbh6EH9rPALQDXKyHKK
106 | LV687s3wVdhmLZyJMFxomJHdHFXeFAKT5R
107 | 0x785a8804c85b88683a5cce5e53f60878831e5d03
108 | 43Vijzdt3y42mmT954rSYPjXYabDsjYEV2KyhxfC46JibR2ny9VmRS1fjdJTHxxPVPFE8ajgArwjWfyaRgjh9vcNAwmkfJj
109 |
110 | Si estas aplicaciones resultan útiles, considera ayudarme de alguna manera en mi misión para crear aplicaciones simples, útiles, orientadas a la privacidad y de código abierto.
111 | Text emoji image
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Private Location
3 | Open-Source Location Privacy
4 |
5 | https://github.com/wesaphzt
6 | https://github.com/wesaphzt/PrivateLocation
7 |
8 |
9 | Preferiti
10 | Vai a
11 | Impostazioni
12 | Dona
13 | Mostra Introduzione
14 | Informazioni
15 |
16 |
17 | Dona
18 | Indirizzo copiato
19 | Indirizzo copiato negli appunti
20 | Informazioni
21 |
22 |
23 | Luoghi Preferiti
24 | Nulla…
25 | Nome
26 | Latitudine: %1$f \nLongitudine: %2$f
27 | Nome
28 | Modifica
29 | Elimina
30 |
31 | Coordinate del luogo
32 | Latitudine
33 | Longitudine
34 | Range non valido
35 | Non è un numero valido
36 | Non può essere vuoto
37 |
38 |
39 | Impostazioni di Geolocalizzazione
40 | Se si verificano problemi di esposizione della propria posizione reale, in particolare con le applicazioni e i servizi basati su Google Maps,
41 | si consiglia di disabilitare nelle impostazioni di geolocalizzazione tutte le funzioni che utilizzano bluetooth e reti Wi-Fi per aiutare a determinare la posizione in modo più rapido.
42 |
43 | Posizione Fittizia Disabilitata
44 | Selezionare questa applicazione nell\'impostazione dell\'app di posizione fittizia.
45 | Attivare le posizioni simulate nelle impostazioni.
46 |
47 | Modalità Sviluppatore Disattivata
48 | Abilita le opzioni sviluppatore cliccando 7 (sette) volte sul numero build del tuo telefono.
49 |
50 | Opzioni Sviluppatore
51 | Assicurati che le impostazioni sviluppatore siano abilitate prima di cercare di impostare la posizione per evitare problemi su Nougat.
52 | \n\nLo puoi verificare cliccando 7 (sette) volte sul numero build del tuo telefono.
53 |
54 |
55 | Informazioni sul logo dell\'applicazione
56 |
57 | Contribuisci
58 | Segnala un Bug
59 | Segnala bugs o richiedi nuove funzioni
60 |
61 | Immagine dell\'autore
62 | wesaphzt
63 | Developer
64 | Developer
65 |
66 | Versione
67 | Version image
68 |
69 | Licenza
70 | GPL v3.0 License
71 | License image
72 |
73 | Codice sorgente
74 | Source code image
75 |
76 | Bug report image
77 |
78 |
79 | Se il servizio è in esecuzione, riavviare per applicare l\'impostazione.
80 | \n\nPuò interferire con la temperatura dello schermo e la localizzazione.
81 |
82 |
83 | Avvia
84 | Stop
85 |
86 | SERVICE_STATUS
87 | Widget location image
88 |
89 |
90 | @string/app_name
91 | Il compagno perfetto per proteggere la privacy della posizione del tuo telefono spostando la tua posizione in qualsiasi parte del mondo.
92 | Limita il consumo di dati
93 | Molte applicazioni possono fare richieste di posizione ripetute e inutili in background, spesso inviando questi dati al cloud.
94 | \n\nI dati di localizzazione sono personali e potenzialmente molto sensibili, questa applicazione può aiutare a proteggere la tua privacy e i tuoi dati.
95 | Controlla le tue Impostazioni
96 | Per un funzionamento ottimale, assicurati che le impostazioni di Geolocalizzazione non utilizzino WiFi, la rete cellulare o altri metodi per determinare la tua posizione che possano far trapelare la tua posizione reale,
97 | e che l\'ottimizzazione della batteria sia disattivata per questa applicazione.
98 |
99 |
100 | Bitcoin image
101 | Litecoin image
102 | Ethereum image
103 | Monero image
104 |
105 | 1GCkvAg9oG79niQTbh6EH9rPALQDXKyHKK
106 | LV687s3wVdhmLZyJMFxomJHdHFXeFAKT5R
107 | 0x785a8804c85b88683a5cce5e53f60878831e5d03
108 | 43Vijzdt3y42mmT954rSYPjXYabDsjYEV2KyhxfC46JibR2ny9VmRS1fjdJTHxxPVPFE8ajgArwjWfyaRgjh9vcNAwmkfJj
109 |
110 | Se trovi utili queste applicazioni, considera la possibilità di supportarmi in qualche modo nella mia missione di creare applicazioni semplici, utili, orientate alla privacy e open-source.
111 | Text emoji image
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Private Location
3 | Open-Source Location Privacy
4 |
5 | https://github.com/wesaphzt
6 | https://github.com/wesaphzt/PrivateLocation
7 |
8 |
9 | Favoritos
10 | Ir para
11 | Configurações
12 | Doar
13 | Mostrar introdução
14 | Sobre
15 |
16 |
17 | Doar
18 | Endereço copiado
19 | Endereço copiado para a área de transferência
20 | Sobre
21 |
22 |
23 | Localizações Favoritas
24 | Nada aqui…
25 | Nome
26 | Latitude: %1$f \nLongitude: %2$f
27 | Nome
28 | Editar
29 | Apagar
30 |
31 | Coordenadas de localização
32 | Latitude
33 | Longitude
34 | Intervalo inválido
35 | Não é um número válido
36 | Não pode ser vazio.
37 |
38 |
39 | Configurações de localização
40 | Se voce tiver problemas com a sua localização real sendo exposta, em particular com os serviços e aplicativos baseados no Google Maps, é recomendável desabilitar qualquer configuração na opção de Localização que utilize pontos de Wi-Fi e outras opções que ajudam a determinar sua localização com mais rapidez e precisa.
41 |
42 |
43 | Localização falsa desabilitada
44 | Selecione esse aplicativo nas configurações de localização falsa.
45 | Habilitar a localização falsa nas configurações.
46 |
47 | Modo desenvolvedor desabilitado
48 | Habilitar opções de desenvolvedor ao clicar na opção de versão do seu aparelho 7 (sete) vezes.
49 |
50 | Configurações de desenvolvedor
51 | Certifique-se de que as configurações do desenvolvedor estejam ativadas antes de tentar definir o local para evitar problemas no Nougat.
52 | \n\nVocê pode fazer isso clicando na opção de versão do seu aparelho 7 (sete) vezes .
53 |
54 |
55 | Sobre o logótipo do aplicativo de visão geral
56 |
57 | Contribuir
58 | Reportar erros
59 | Reportar erros ou requisitar novas funções
60 |
61 | Imagem do autor
62 | wesaphzt
63 | Desenvolvedor
64 | Desenvolvedor
65 |
66 | Versão
67 | Imagem da versão
68 |
69 | Licença
70 | Licença GPL v3.0
71 | Imagem da licença
72 |
73 | Código fornte
74 | Imagem do código fonte
75 |
76 | Imagem do reportar erro
77 |
78 |
79 | Se o serviço estiver sendo executado, reinicie para aplicar a configuração.
80 | \n\nPode interferir na temperatura e localização da tela.
81 |
82 |
83 | Começar
84 | Pare
85 |
86 | SERVICE_STATUS
87 | Imagem de localização do widget
88 |
89 |
90 | @string/app_name
91 | O companheiro perfeito para ajudar a proteger a privacidade e a segurança da localização do telefone, falsificando sua localização para qualquer lugar do mundo.
92 | Limite seus dados
93 | Muitos aplicativos podem fazer solicitações de localização repetidas e desnecessárias em segundo plano, geralmente enviando esses dados de volta para a nuvem.
94 | \n\nOs dados de localização são pessoais e potencialmente muito sensíveis, este aplicativo pode ajudar a proteger sua privacidade e dados.
95 | Verifique suas configurações
96 | Para uma navegação tranquila, verifique se as configurações de localização não estão usando Wi-Fi, rede ou outros métodos para determinar sua localização que pode vazar sua localização real,
97 | e a otimização da bateria está desativada para este aplicativo.
98 |
99 |
100 | Logo Bitcoin
101 | Logo Litecoin
102 | Logo Ethereum
103 | Logo Monero
104 |
105 | 1GCkvAg9oG79niQTbh6EH9rPALQDXKyHKK
106 | LV687s3wVdhmLZyJMFxomJHdHFXeFAKT5R
107 | 0x785a8804c85b88683a5cce5e53f60878831e5d03
108 | 43Vijzdt3y42mmT954rSYPjXYabDsjYEV2KyhxfC46JibR2ny9VmRS1fjdJTHxxPVPFE8ajgArwjWfyaRgjh9vcNAwmkfJj
109 |
110 | Se você acha esses aplicativos úteis, considere apoiar-me de alguma forma em minha missão de criar aplicativos simples, úteis, orientados à privacidade e de código aberto.
111 | Imagem do texto do emoji
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Private Location
3 | Приватность местоположения с открытым исходным кодом
4 |
5 | https://github.com/wesaphzt
6 | https://github.com/wesaphzt/PrivateLocation
7 |
8 |
9 | Избранные
10 | Перейти к
11 | Настройки
12 | Поддержать
13 | Показать введение
14 | О приложении
15 |
16 |
17 | Поддержать
18 | Скопированный адрес
19 | Адрес скопирован в буфер обмена
20 | О приложении
21 |
22 |
23 | Избранные местоположения
24 | Ничего нет…
25 | Название
26 | Широта: %1$f \nLongitude: %2$f
27 | Название
28 | Изменить
29 | Удалить
30 |
31 | Координаты местоположения
32 | Широта
33 | Долгота
34 | Недопустимый диапазон
35 | Недопустимое значение
36 | Не может быть пустым
37 |
38 |
39 | Настройки местоположения
40 | Если у вас возникают проблемы с отображением вашего реального местоположения, особенно в приложениях и сервисах на основе Карт Google, рекомендуется отключить
41 | в настройках местоположения любые параметры, использующие точки Wi-Fi и другие, чтобы быстрее и точнее определить ваше местоположение.
42 |
43 | Фиктивное местоположение отключено
44 | Выберите это приложение в настройках фиктивного местоположения.
45 | Включите фиктивные местоположения в настройках.
46 |
47 | Режим разработчика отключен
48 | Включите параметры разработчика, кликнув на номер сборки своего телефона 7 (семь) раз.
49 |
50 | Настройки разработчика
51 | Пожалуйста, убедитесь, что настройки разработчика включены, прежде чем пытаться установить местоположение, чтобы предотвратить проблемы на Nougat.
52 | \n\nВы можете сделать это, кликнув на номере сборки вашего телефона 7 (семь) раз.
53 |
54 |
55 | Сведения о логотипе приложения
56 |
57 | Внести свой вклад
58 | Сообщить об ошибках
59 | Сообщить об ошибках или запросить новые возможности
60 |
61 | Изображение автора
62 | wesaphzt
63 | Разработчик
64 | Разработчик
65 |
66 | Версия
67 | Изображение версии
68 |
69 | Лицензия
70 | Лицензия GPL v3.0
71 | Изображение лицензии
72 |
73 | Исходный код
74 | Изображение исходного кода
75 |
76 | Изображение отчета об ошибке
77 |
78 |
79 | Если служба в данный момент запущена, перезапустите для применения настроек.
80 | \n\nМожет влиять на температуру экрана и локализацию.
81 |
82 |
83 | Старт
84 | Стоп
85 |
86 | SERVICE_STATUS
87 | Изображение виджета местоположения
88 |
89 |
90 | @string/app_name
91 | Идеальный помощник, помогающий защитить конфиденциальность и безопасность местоположения вашего телефона путем подмены местоположения в любом уголке мира.
92 | Ограничьте доступ к вашим данным
93 | Многие приложения могут посылать многократные и неоправданные запросы местоположения в фоновом режиме, зачастую отправляя эти данные на свой сервер.
94 | \n\nДанные о местоположении являются конфиденциальными и могут быть весьма деликатными. Данное приложение может помочь защитить вашу конфиденциальность и данные.
95 | Проверьте свои настройки
96 | Для бесперебойной работы убедитесь, что в настройках вашего местоположения не используется Wi-Fi, сотовая сеть или другие методы определения местоположения, которые могут привести к утечке информации о вашем реальном местоположении,
97 | а также в том, что для этого приложения отключена оптимизация заряда батареи.
98 |
99 |
100 | Изображение Bitcoin
101 | Изображение Litecoin
102 | Изображение Ethereum
103 | Изображение Monero
104 |
105 | 1GCkvAg9oG79niQTbh6EH9rPALQDXKyHKK
106 | LV687s3wVdhmLZyJMFxomJHdHFXeFAKT5R
107 | 0x785a8804c85b88683a5cce5e53f60878831e5d03
108 | 43Vijzdt3y42mmT954rSYPjXYabDsjYEV2KyhxfC46JibR2ny9VmRS1fjdJTHxxPVPFE8ajgArwjWfyaRgjh9vcNAwmkfJj
109 |
110 | Если вы находите эти приложения полезными, подумайте о том, чтобы поддержать меня в моей миссии по созданию простых, полезных, ориентированных на конфиденциальность приложений с открытым исходным кодом.
111 | Изображение текстового эмодзи
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 5 minutes
6 | 10 minutes
7 | 15 minutes
8 | 30 minutes
9 | 1 hour
10 | 3 hours
11 | 6 hours
12 | 12 hours
13 | 24 hours
14 |
15 |
16 |
17 | 5
18 | 10
19 | 15
20 | 30
21 | 60
22 | 180
23 | 360
24 | 720
25 | 1440
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #0081dc
4 | #0065ac
5 | #D81B60
6 |
7 | #FFFFFF
8 |
9 |
10 | @color/colorPrimary
11 | #222222
12 | #ff9600
13 |
14 | #7e7e7e
15 | #4caf50
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 8dp
6 | 176dp
7 | 16dp
8 |
9 |
10 | 4dp
11 | 8dp
12 | 16dp
13 | 24dp
14 | 32dp
15 | 40dp
16 |
17 | 14dp
18 | 46dp
19 |
20 | 64dp
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #F3F3F3
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Private Location
3 | Open-Source Location Privacy
4 |
5 | https://github.com/wesaphzt
6 | https://github.com/wesaphzt/PrivateLocation
7 |
8 |
9 | Favorites
10 | Go To
11 | Settings
12 | Donate
13 | Show Intro
14 | About
15 |
16 |
17 | Donate
18 | Copied address
19 | Address copied to clipboard
20 | About
21 |
22 |
23 | Favorite Locations
24 | Nothing here…
25 | Name
26 | Latitude: %1$f \nLongitude: %2$f
27 | Name
28 | Edit
29 | Delete
30 |
31 | Location Coordinates
32 | Latitude
33 | Longitude
34 | Not a valid range
35 | Not a valid number
36 | Can\'t be empty
37 |
38 |
39 | Location Settings
40 | If you experience issues with your real location being exposed, particularly with Google Maps based apps and services,
41 | it\'s recommended you disable any settings in your Location settings that use Wi-Fi points and more to help determine your location faster and more accurately.
42 |
43 | Mock Location Disabled
44 | Select this app in the mock location app setting.
45 | Enable mock locations in settings.
46 |
47 | Developer Mode Disabled
48 | Enable developer options by clicking on your phone build number 7 (seven) times.
49 |
50 | Developer Settings
51 | Please make sure developer settings are enabled before trying to set location to prevent issues on Nougat.
52 | \n\nYou can do this by clicking on your phone build number 7 (seven) times.
53 |
54 |
55 | About overview app logo
56 |
57 | Contribute
58 | Report Bugs
59 | Report bugs or request new features
60 |
61 | Author image
62 | wesaphzt
63 | Developer
64 | Developer
65 |
66 | Version
67 | Version image
68 |
69 | License
70 | GPL v3.0 License
71 | License image
72 |
73 | Source code
74 | Source code image
75 |
76 | Bug report image
77 |
78 |
79 | If service is currently running, restart to apply setting.
80 | \n\nMay interfere with screen temperature and localization.
81 |
82 |
83 | Start
84 | Stop
85 |
86 | SERVICE_STATUS
87 | Widget location image
88 |
89 |
90 | @string/app_name
91 | The perfect companion to help protect your phone location privacy and security by spoofing your location to anywhere in the world.
92 | Limit Your Data
93 | Many apps can make repeated and unnecessary location requests in the background, often sending this data back to the cloud.
94 | \n\nLocation data is personal and potentially very sensitive, this app can help protect your privacy and data.
95 | Check Your Settings
96 | For smooth sailing, make sure your location settings aren\'t using WiFi, network or other methods to determine your location that can leak your real location,
97 | and that battery optimization is turned off for this app.
98 |
99 |
100 | Bitcoin image
101 | Litecoin image
102 | Ethereum image
103 | Monero image
104 |
105 | 1GCkvAg9oG79niQTbh6EH9rPALQDXKyHKK
106 | LV687s3wVdhmLZyJMFxomJHdHFXeFAKT5R
107 | 0x785a8804c85b88683a5cce5e53f60878831e5d03
108 | 43Vijzdt3y42mmT954rSYPjXYabDsjYEV2KyhxfC46JibR2ny9VmRS1fjdJTHxxPVPFE8ajgArwjWfyaRgjh9vcNAwmkfJj
109 |
110 | If you find these apps useful, consider supporting me in some way in my mission to create simple, useful, privacy-oriented, open-source apps.
111 | Text emoji image
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/app_widget_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
13 |
17 |
18 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/test/java/com/wesaphzt/privatelocation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.wesaphzt.privatelocation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.5.0'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | maven { url "https://jitpack.io" }
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/1.txt:
--------------------------------------------------------------------------------
1 | * Initial release.
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/2.txt:
--------------------------------------------------------------------------------
1 | * Minor design updates
2 | * Start service on boot option added
3 | * Fastlane metadata for F-droid added
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/4.txt:
--------------------------------------------------------------------------------
1 | * Stop service correctly to fix memory leak & reduce code
2 | * Option to randomize location every x minutes added
3 | * App widget implemented
4 | * RU (@0ndrey), ES (@sguinetti), IT (@Lion-box), pt-rBR (@iramaro) translations added
5 | * pt-Rbr (@Andre-Gloria) typos corrected
6 | * Intro activity added
7 | * OpenStreetMap data attribution added
8 | * Notification priority changed to low for Nougat and lower
9 | * Minor code improvements & clean up
10 | * Logo update to prevent whitespace around edges
11 | * Gradle & library updates
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | A simple app to set your location to anywhere in the world, and improve general phone location privacy.
2 | This app will fake/spoof both your GPS and network location on your phone.
3 |
4 | Many apps on your phone won't work without location permissions, and can make repeated and unnecessary location requests in the background throughout the day.
5 | Setting your location somewhere else will help to mitigate that and protect your privacy.
6 |
7 | The open-source Leaflet map library along with Wikimedia to provide map tiles are used in place of Google Maps.
8 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/featureGraphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/fastlane/metadata/android/en-US/images/featureGraphic.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/01-main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/fastlane/metadata/android/en-US/images/phoneScreenshots/01-main.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/02-favorites.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/fastlane/metadata/android/en-US/images/phoneScreenshots/02-favorites.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/03-goto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/fastlane/metadata/android/en-US/images/phoneScreenshots/03-goto.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Set your phone location
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Private Location
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | android.enableJetifier=true
10 | android.useAndroidX=true
11 | org.gradle.jvmargs=-Xmx1536m
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 | distributionBase=GRADLE_USER_HOME
17 | distributionPath=wrapper/dists
18 | zipStoreBase=GRADLE_USER_HOME
19 | zipStorePath=wrapper/dists
20 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
21 | distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc64d8b400e1fb2c3b
22 |
23 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesaphzt/privatelocation/d37b12f59d3f8de2b8506f44b09d2436b719fe50/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Aug 21 22:36:34 BST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------