Feature detection - java

I'm not sure if there is an Android way to do this or if this is just a general Java question. What is the best design for a feature detection mechanism? I want to be able to ask if the runtime environment supports feature foo (this may be determined at compile time as well, so not just runtime stuff).
UPDATE
I'm thinking of using the following (naive?) approach:
public enum Feautures {
GPS, DockToKeyboard;
public boolean isSupported() {
//switch statement
}
}

PackageManager pm = getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(new Intent(
RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
if (activities.size()>0); // then you have SPEECH RECOGNIZER.
or
final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER)); // then you have GPS.

http://developer.android.com/reference/android/content/pm/PackageManager.html#hasSystemFeature(java.lang.String)
http://developer.android.com/reference/android/content/pm/PackageManager.html#FEATURE_AUDIO_LOW_LATENCY

Related

Android App Recognising lack of permissions but not allowing the ability to grant them

I am trying to develop a basic app usage monitor for Android. There's not much online help I could find bar one video here without just copying someone else's GitHub repo. I selected development with Android 10 (Q) as my SDK.
Essentially, since to my understanding in Lollipop and above you have to perform an Intent to get permissions, it should be as simple doing an intent to get Settings.ACTION_USAGE_ACCESS_SETTINGS which is what I would need to get an app's total time in foreground.
However, the app recognises it lacks permissions and takes the user to the system permissions page in the settings, but there is no option to actually give the app any settings. The app will complain about having no required permissions but I, as the user, have no ability to grant it any of those permissions on the emulated device.
The following is an extract of the start of my MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sharedPreferences = getSharedPreferences("Focus", MODE_PRIVATE);
if(!checkUsageStatsAllowedOrNot()) {
Intent usageAccessIntent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
usageAccessIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(usageAccessIntent);
if (checkUsageStatsAllowedOrNot()) {
startService(new Intent(MainActivity.this, BackgroundService.class));
}
else {
Toast.makeText(getApplicationContext(), "please give me access", Toast.LENGTH_SHORT).show();
}
This is the checkUsageStatsAllowedOrNot function:
public boolean checkUsageStatsAllowedOrNot() {
try {
PackageManager packageManager = getPackageManager();
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) getSystemService(APP_OPS_SERVICE);
int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
return (mode==AppOpsManager.MODE_ALLOWED);
}
catch (Exception e) {
Toast.makeText(getApplicationContext(), "error cannot find any usage stats", Toast.LENGTH_SHORT).show();
return false;
}
}
As you can see from this image (ignore the crossed out one, that's not relevant), the only apps there are generic pre-installed ones when it opens the Usage permissions screen:
usage permissions opens but relevant developer app not there
Do you have any idea why this may be the case? I'm not sure if it's just because the video I followed is a bit old or most likely the fact that I only started using Android Studio 2 weeks and have barely a clue how this all works, but from my research this seems fine??
Any ideas will go a long way, thanks for reading.

List the all apps in Android

I'm trying to list all apps in android device with queryIntentActivities method but the list doesn't return all the apps , It returns only three of them. Here is my code:
PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> allApps = packageManager.queryIntentActivities(intent, 0);
for (ResolveInfo ri : allApps) {
Log.d("Labels", String.valueOf(ri.loadLabel(packageManager)));
}
is there anyone now why it returns only 3 applications ?
You are most likely trying to do this on Android 11. Make sure you add the <uses-permission android:name"android.permission.QUERY_ALL_PACKAGES"> permission to the AndroidManifest.xml file.
While I haven't tested this aspect of R DP2 yet, it appears that your
app now can't find out what other apps are installed, on a general
basis. The cited example is queryIntentActivities(), but to make this
really work you would need to seriously lobotomize PackageManager. You
can whitelist certain packages and certain structures
to try to get by this for certain use cases. And, this is where the
mysterious QUERY_ALL_PACKAGES permission seen in DP1 comes into play —
this permission removes these new restrictions. Given the "look for
Google Play to provide guidelines for apps that need this permission"
caveat, it is safest to assume that if you try using it, eventually
you will be banned from the Play Store by a bot.

Android LocationManager, rough data and battery consumption

I need just rough data about a location on Android, so when getting it the main consideration is to keep the battery power. I consider this code:
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 60 * 1000, 1000, this);
Is it right strategy? Or is it better to check, something like every 10 minutes for new location and disable listener, which seems closer to code proposed on Google's site, though less logical to me?
Instead of mentioning provider name use criteria to get get provider. And, use criteria to set your requirement.
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
final String bestProvider = manager.getBestProvider(criteria, true);
And then finally,
locationManager.requestLocationUpdates(bestProvider, 0,1000, this);
Alternatively you can request for single location update or disable listener as soon as you done with task

Android HTC Hero not reporting back correct FeatureInfo

I'm having a strange problem with my HTC Hero 2.1
model=HERO200
manufacturer=HTC
APILevel=7
It is not reporting back that it has a hardware microphone. Here is my code to check for Features.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Context context = this;
PackageManager pm = context.getPackageManager();
FeatureInfo[] foo = pm.getSystemAvailableFeatures();
for (FeatureInfo bar : foo) {
if (bar.name != null) {
System.out.println(bar.toString());
if (bar.name.equalsIgnoreCase("android.hardware.microphone"))
System.out.println("Booyah!");
}
}
}
It does report back these features:
android.hardware.camera
android.hardware.wifi
android.hardware.location.network
android.hardware.bluetooth
android.hardware.sensor.light
android.hardware.location
android.hardware.location.gps
android.hardware.camera.autofocus
android.hardware.touchscreen.multitouch
android.hardware.touchscreen
android.hardware.sensor.accelerometer
android.hardware.sensor.compass
Some are API Level 8 like compass and gps, and others are level 7. Is there another way I can search for features? Something else I can use besides getSystemAvailableFeatures()? Maybe a lower level system call? Why is my phone not reporting back that it has a hardware microphone? Help please :) Thanks!
I guess if this phone is set for Android API Level 7... then I just can't set a requirement that was designed for API Level 8 (Like microphone).
This is the proper way to request features of the phone from Android.
So... this sucks... oh well. But still weird that this phone does report back some features from API Level 8, but you shouldn't rely upon that.

Possible to skip track from an Android application?

I'm planning on doing a application for Android 2.1 that changes song every minute (through what I hope exists in Android, "next") for the application using the audio device atm.
So if I have Spotify running in background already, playing music, can I through my program change to the next track?
Let me know if I was unclear about anything.
Thanks in advance!
I know this is a bit old question, but it took me some time searching something other then what is mentioned here.
There is a workaround - broadcasting media button action. There is one catch - receiver can recognize if the broadcast was from system or from another app, so they can ignore the non-system broadcasts.
Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
synchronized (this) {
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
sendOrderedBroadcast(i, null);
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
sendOrderedBroadcast(i, null);
}
There's no universal audio transport API for music applications, so you'd need to see if the music applications you're targeting publicly expose service bindings or intents. If not, you won't be able to do this.
Just posted a relevant answer here
Using the AudioManager's dispatchMediaKeyEvent() method with a defined KeyEvent worked for me using the latest SDK.
The system music homescreen widget sends this intent for the built-in music player:
final ComponentName serviceName = new ComponentName(context,
MediaPlaybackService.class);
intent = new Intent(MediaPlaybackService.NEXT_ACTION);
intent.setComponent(serviceName);
pendingIntent = PendingIntent.getService(context,
0 /* no requestCode */, intent, 0 /* no flags */);
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
But it looks like this might take some hackery to implement outside packages in the music app itself because the MediaPlaybackService only accepts explicit Intents and isn't accessible from the outside. This thread seems to indicate it's possible with a bit of hackery, though.
But even then, as Roman said, not every music player will respect that Intent. You'll have to check with Spotify/Pandora/Last.fm themselves and see if they have any available intents to bind like that.
Looks that it's possible to use AudioManager to inject media keys.
Here is a snippet from another question
this.mAudioManager = (AudioManager) this.context.getSystemService(Context.AUDIO_SERVICE);
long eventtime = SystemClock.uptimeMillis();
KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0);
mAudioManager.dispatchMediaKeyEvent(downEvent);
KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0);
mAudioManager.dispatchMediaKeyEvent(upEvent);
The same way you can inject PlayPause button and some others.
I've tested it within a background service controlling Youtube and it worked for Android 6

Categories