I am trying to do something along the lines of signal strength triangulation using cell towers, on android. I'm using android studio and java. I've found useful csv with cell tower latitude and longitude, and written some fairly trivial code to parse it, all I need now is the cell towers' mcc, mnc, lac and cell id, so I can search the csv and find the lat and long. I'm using the telephonyManager class and .getAllCellInfo(), like so:
tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
InputStream inputStream = getResources().openRawResource(R.raw.cells);
CsvFile csvFile = new CsvFile(inputStream);
List<String[]> res = csvFile.read();
List<CellInfo> cellsTemp = tel.getAllCellInfo();
for (CellInfo ci : cellsTemp) {
if (ci instanceof CellInfoLte) {
Log.d("Cells: ", ((CellInfoLte) ci).getCellIdentity().toString());
this.cellsLte.add((CellInfoLte) ci);
this.towers.add(new cellTower((CellInfoLte) ci, res));
}
}
However, when I log the cellIdentity of those cells, I get this:
CellIdentityLte:{ mCi=2147483647 mPci=313 mTac=2147483647 mEarfcn=1300 mBandwidth=2147483647 mMcc=null mMnc=null mAlphaLong= mAlphaShort=}
As you can see, the mcc and mnc are null, and the the cell id and location code are 2147483647, or Integer.MAX_VALUE, which as I understand it, is used when they are for whatever reason unavailable.
I have the ACCESS_FINE_LOCATION and READ_PHONE_STATE runtime permissions, and I've added them to the manifest file as well. I've also tried just logging the objects directly from tel.getAllCellInfo(), same exact result.
This is the declaration for tel and towers:
public class MainActivity extends AppCompatActivity {
protected RequestQueue requestQueue;
protected TelephonyManager tel;
protected List<CellInfoLte> cellsLte = new ArrayList<CellInfoLte>();
protected List<cellTower> towers = new ArrayList<cellTower>();
And cellTower is just a sort of wrapper class that contains some information I'm going to need to calculate distance later. It also contains the cellInfo of the tower.
I am also aware that there are apis that can do this whole thing automatically, but I need to do this myself, as a sort of a proof of concept.
I'm running this on a LGE LG-H870, but I've also tried it on a Xiaomi Redmi 8, and had the same issue.
I am an (almost)complete beginner with android studio, but I think I have a perfectly decent understanding of java. Is there any way at all to get around this? Any help would be greatly appreciated.
Related
I have searched for an answer to this question with my time in my Computer Science lab. We are using Android Studio for this app.
What I want to do is to use randomization to make a set of screens be randomized when you click a button. My duo is working on a dice rolling app, and we had the idea to make six different screens for each of the sides of the die. Basically, when we click the button to "roll the dice", it think for a second, then brings you to a random page with a picture of the number on the die which you got.
This is incredibly weird, and I have searched for at least 3 hours straight for a solution to this problem but to no avail. If anybody needs more information on the problem (because I do not know how to properly phrase it), then just ask me.
Just use Random.nextInt() to get a random number up to 6, and use that to choose one image of the 6 for each die side. You do not need to create 6 different screens, you just need 6 different images where the number indicates which image to use. For example:
// A list of drawables you've defined in /res/drawable folder for each die side
final int[] images = new int[6] {
R.drawable.die_side_1,
R.drawable.die_side_2,
R.drawable.die_side_3,
R.drawable.die_side_4,
R.drawable.die_side_5,
R.drawable.die_side_6
};
int random = Random.nextInt(6); // Get random value, 0-5
int dieSideDrawable = images[random]; // Pick image to show based on random value
mDieImageView.setImageResource(dieSideDrawable); // Show image on an image view
Hope that helps!
The easiest way to do exactly what you want would be to put the Activities in an Array, and select by using the Random class' nextInt method to choose the appropriate activity from the Array.
That being said, most likely you want to create a single activity with two images, and instead of selecting an activity or Fragment to show, you'd select the images you'd load into the Activity.
I would recommend using Fragments to achieve this.
create a list of fragments
ArrayList<Fragment> fragmentList = new ArrayList<>();
Now use the java Random class to generate the random number.
Random rand = new Random();
int n = rand.nextInt(fragmentList.size());
then just show that fragment.
getSupportFragmentManager()
.beginTransaction()
.replace(containerViewId, fragmentList.get(n))
.addToBackStack(null)
.commit();
Using multiple activities seems unnecessary here (and will significantly slow down your app). If you want to show a different image based on the result of a random number that's been generated, then just .setImageResource() for your Image View based on the result of that random number.
In the example below I separated the random number generation (the generateRandomInt() method which stores a random integer in the thisRoll variable) and only called it when the changeImageView() method runs onClick.
public void changeImageView(View view){
generateRandomInt();
if (thisRoll == 1) {
mainImage.setImageResource(R.drawable.s1);
} else if (thisRoll == 2) {
mainImage.setImageResource(R.drawable.s2);
} else if (thisRoll == 3) {
mainImage.setImageResource(R.drawable.s3);
} else if (thisRoll == 4) {
mainImage.setImageResource(R.drawable.s4);
} else if (thisRoll == 5) {
mainImage.setImageResource(R.drawable.s5);
} else {
mainImage.setImageResource(R.drawable.s6);
}
Toast.makeText(DiceRollActivity.this, thisRoll + " ...But The House Always Wins!", Toast.LENGTH_SHORT).show();
}
i've made an app that implements augmented reality based on POI's and have all the functionality working for one POI but i would now like to be able to put in multiple points. Can any give me advice on how to do this ? Can i create an array of POI's ?? posted my relevant code below but don't really know where to go from here.
private void setAugmentedRealityPoint() {
homePoi = new AugmentedPOI(
"Home",
"Latitude, longitude",
28.306802, -81.601358
);
This is how its currently set and i then go on to use it in other area's as shown belown:
public double calculateAngle() {
double dX = homePoi.getPoiLatitude() - myLatitude;
double dY = homePoi.getPoiLongitude() - myLongitude;
}
and here:
private boolean isWithinDistance(double myLatitude, double myLongitude){
Location my1 = new Location("One");
my1.setLatitude(myLatitude);
my1.setLongitude(myLongitude);
Location target =new Location("Two");
target.setLatitude(homePoi.getPoiLatitude());
target.setLongitude(homePoi.getPoiLongitude());
double range =my1.distanceTo(target);
double zone = 20;
if (range < zone ) {
return true;
}
else {
return false;
}
}
Any help would be appreciated.
Using a List would be a smart idea. You could add all entries into it in code, or you could pull them in from a JSON file. When you're rendering them, you could check if they are in range.
If you have a lot of these POIs, you should divide them into smaller and smaller regions, and only load what you need. For example, structure them like this:
- CountryA
+ County 1
* POI
* POI
- CountryB
+ County 1
* POI
* POI
+ County 2
* POI
Get the country and county of the user, and only load what you really need. I assume this is a multiplayer game, so I'll share some of my code.
On the server side, I have 3 objects: Country, County and POI.
First I discover all countries on the disk, and make an object for it. Inside my country object I have a list for all counties, and inside my County object I have a list of POIs. When a player joins, they send a packet with their Country and County, and I can select the appropriate POIs for them. Storing them in smaller regions is essential, or your server will have a hard time if you go through all of the POIs for every player.
Here is my method for discovering data: Server.java#L311-L385
Code for selecting POIs for a player: Server.java#L139-L181
And how you can render it: PlayScreen.java#L209-L268
You need to port it to your own app, and I'm probably horrible at explaining, but I hope you got something out of it.
I work with camera2API and i need to get focal lenght property.
I found one way to get it from camera characteristic
float[] f = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
for (float d : f) {
Logger.logGeneral("LENS_INFO_AVAILABLE_FOCAL_LENGTHS : " + d);
}
but this approach retern back value like 3.8 or smth close to it. It depend of the device. But this value have to be approximately close to 30-35...
Then i found another solution. When i take a photo i opened photo properties and saw exextly what i get and what i need
I tryed to get this property directly from image
private JSONObject getJsonProperties() {
JSONObject properties = new JSONObject();
final ExifInterface exif = getExifInterface();
final String [] tagProperties = {TAG_DATETIME, TAG_DATETIME_DIGITIZED, TAG_EXPOSURE_TIME,
TAG_FLASH, TAG_FOCAL_LENGTH, TAG_GPS_ALTITUDE, TAG_GPS_ALTITUDE_REF, TAG_GPS_DATESTAMP,
TAG_GPS_LATITUDE, TAG_GPS_LATITUDE_REF, TAG_GPS_LONGITUDE, TAG_GPS_LONGITUDE_REF,
TAG_GPS_PROCESSING_METHOD, TAG_GPS_TIMESTAMP, TAG_IMAGE_LENGTH, TAG_IMAGE_WIDTH, TAG_ISO, TAG_MAKE,
TAG_MODEL, TAG_ORIENTATION, TAG_SUBSEC_TIME, TAG_SUBSEC_TIME_DIG, TAG_SUBSEC_TIME_ORIG, TAG_WHITE_BALANCE};
for (String tag : tagProperties){
try {
properties.put(tag, exif.getAttribute(tag));
} catch (JSONException e) {
e.printStackTrace();
}
}
return properties;
}
private ExifInterface getExifInterface() {
ExifInterface exif = null;
try {
exif = new ExifInterface(ImageSaver.getImageFilePath());
} catch (IOException e) {
e.printStackTrace();
}
return exif;
}
I combine set of entire properties and of course include one that i very need TAG_FOCAL_LENGTH. But again i get wrong valeu like this 473/100... i don't know what does it mean... Valeu have to be approximatly 30-35...
What am i doing wrong?
Eventyally i found the answer.
According #Aleks G
The 35mm equivalent would be your obtained focal length multiplied by a certain number, known as crop factor. This factor is very much different for different manufacturers and even models. For example, for many Nikon DSLR cameras it's 1.5; for many Canon DSLRs it's 1.6; for Apple iPhone 5 it's 6.99, for Samsung Galaxy S3 it's 7.6, and so on.
To the best of my knowledge, Android does not provide an API to determine the crop factor of the device's camera.
There's one trick you can try using though. Once you take a photo with the device's camera, some devices will populate FocalLengthIn35mmFilm exif tag - so you can try using this technique. Not all phones do this though, for example, my Huawei doesn't.
Some other devices will populate two fields for Focal Length - the first being the actual focal length used, the second being the 35mm equivalent. Again, not all do. The same Huawei phone doesn't, but my iPhone 5 does.
To make the long story short, there's no guaranteed way of figuring out the 35mm equivalent from the focal length you obtain on the device.
And eventually i just add to my list of properties such tag
TAG_FOCAL_LENGTH_IN_35MM_FILM
And now if it is available i can get it
I'm using Mapbox Android SDK
compile ('com.mapbox.mapboxsdk:mapbox-android-sdk:3.0.0#aar').
I asked the similar question before at here, but still have some problem. I don't know how to implement when I get currentRoute. my code is as below:
private Waypoint lastCorrectWayPoint;
private boolean checkOffRoute(Waypoint target) {
boolean isOffRoute = false;
if(currentRoute != null){
if (currentRoute.isOffRoute(target)) {
showMessage("You are off-route, recalculating...");
isOffRoute = true;
lastCorrectWayPoint = null;
//would recalculating route.
} else {
lastCorrectWayPoint = target;
String direction = "Turn right"; //The message what should I prompt to user
double distance = 0.0;//The distance which from target to next step.
int duration = 0;//The time which from target to next step.
String desc = "Turn right to xx street.";
//Implement logic to get them here.
showMessage("direction:" + direction + ", distance:" + distance + ", duration:" + duration + ", desc:" + desc);
}
}
checkOffRoute() would be called within onLocationChanged(). I think MapBox SDK should provide these data to developer instead of developer implement it by himself. or if I miss something important information in SDK? Any suggestion?
hope your app is coming along well. I see your trying to get direction, distance, and duration to next step. I'll try and answer this as best I can while keeping it short.
Direction
First when you request the route you need to include a couple lines:
MapboxDirections client = new MapboxDirections.Builder()
.setAccessToken(getString(R.string.accessToken))
.setOrigin(origin)
.setDestination(destination)
.setProfile(DirectionsCriteria.PROFILE_DRIVING)
.setAlternatives(true) // Gives you more then one route if alternative routes available
.setSteps(true) // Gives you the steps for each direction
.setInstructions(true) // Gives human readable instructions
.build();
Once you receive the response you can do something along the lines of
response.body().getRoutes().get(0).getSteps().get(0).getDirection()
which will give you the approximate cardinal direction of travel following the maneuver. Typically one of the following: 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', or 'NW'. This specific line gives you the first route in the list (also typically the shortest and best choice route) and the first step. To change through the steps you simply change the integer value of the second .get(int) to whatever step you need.
Duration and Distance
Same as above but instead of .getDirection() you use:
response.body().getRoutes().get(0).getSteps().get(0).getDuration()
and
response.body().getRoutes().get(0).getSteps().get(0).getDistance()
respectively. I hope this at least helps to guide you in the right direction while creating your app.
I am doing a GPS app, with latitude, longitude, speed, altitude...but I don't get any data for this one. I always get 1.0 as a value. (With the speed it happens the same).
I tried with the simulator of GPX in Eclipse (DDMS) and on the terminal (KML simulator, not on the street)...but it always shows 0.0 or 1.0.
My code is the following:
private Location currentLoc;
private Location previousLoc;
The criteria for the GPS...
// Criteria object is optional. Will return value representing "GPS"
Criteria oGPSSettings = new Criteria();
oGPSSettings.setAccuracy(Criteria.ACCURACY_FINE);
oGPSSettings.setSpeedRequired(true);
oGPSSettings.setAltitudeRequired(true);
oGPSSettings.setBearingRequired(false);
oGPSSettings.setCostAllowed(false);
oGPSSettings.setPowerRequirement(Criteria.POWER_MEDIUM);
When a new location is recieved...
#Override
public void onLocationChanged(Location location) {
currentLoc = location;
String sText = "Altitude: " + currentLoc.getAltitude();
txtOutput.setText(sText);
}
// sets this location as last location.
previousLoc = currentLoc;
}
I removed from the code things like displaying latitude, longitude...right now I'll show only altitude.
The question is: Why do you think is it happening this? The latitude and longitude works fine, but not the altitude. Maybe is it a hardware issue? Because the code seems correct, I think. Only with the getAltitude function should works.
Thank you in advance!
Did you ask for "android.permission.ACCESS_FINE_LOCATION" in your manifest?
also try changing ACCURACY_FINE to ACCURACY_HIGH