I have to programmatically retrieve permissions from the manifest.xml of an android application and I don't know how to do it.
I read the post here but I am not entirely satisfied by the answers.
I guess there should be a class in the android API which would allow to retrieve information from the manifest.
Thank you.
You can get an application's requested permissions (they may not be granted) using PackageManager:
PackageInfo info = getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
String[] permissions = info.requestedPermissions;//This array contains the requested permissions.
I have used this in a utility method to check if the expected permission is declared:
//for example, permission can be "android.permission.WRITE_EXTERNAL_STORAGE"
public boolean hasPermission(String permission)
{
try {
PackageInfo info = getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.equals(permission)) {
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Here's a useful utility method that does just that (in both Java & Kotlin).
Java
public static String[] retrievePermissions(Context context) {
final var pkgName = context.getPackageName();
try {
return context
.getPackageManager()
.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS)
.requestedPermissions;
} catch (PackageManager.NameNotFoundException e) {
return new String[0];
// Better to throw a custom exception since this should never happen unless the API has changed somehow.
}
}
Kotlin
fun retrievePermissions(context: Context): Array<String> {
val pkgName = context.getPackageName()
try {
return context
.packageManager
.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS)
.requestedPermissions
} catch (e: PackageManager.NameNotFoundException) {
return emptyArray<String>()
// Better to throw a custom exception since this should never happen unless the API has changed somehow.
}
}
You can get a working class from this gist.
Use this:
public static String getListOfPermissions(final Context context)
{
String _permissions = "";
try
{
final AssetManager _am = context.createPackageContext(context.getPackageName(), 0).getAssets();
final XmlResourceParser _xmlParser = _am.openXmlResourceParser(0, "AndroidManifest.xml");
int _eventType = _xmlParser.getEventType();
while (_eventType != XmlPullParser.END_DOCUMENT)
{
if ((_eventType == XmlPullParser.START_TAG) && "uses-permission".equals(_xmlParser.getName()))
{
for (byte i = 0; i < _xmlParser.getAttributeCount(); i ++)
{
if (_xmlParser.getAttributeName(i).equals("name"))
{
_permissions += _xmlParser.getAttributeValue(i) + "\n";
}
}
}
_eventType = _xmlParser.nextToken();
}
_xmlParser.close(); // Pervents memory leak.
}
catch (final XmlPullParserException exception)
{
exception.printStackTrace();
}
catch (final PackageManager.NameNotFoundException exception)
{
exception.printStackTrace();
}
catch (final IOException exception)
{
exception.printStackTrace();
}
return _permissions;
}
// Test: Log.wtf("test", getListOfPermissions(getApplicationContext()));
If anyone is looking for a short Kotlin Version
fun Manifest.getDeclaredPermissions(context: Context): Array<String> {
return context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS).requestedPermissions
}
I have a simple C# code, "using System.Xml"
private void ShowPermissions()
{
XmlDocument doc = new XmlDocument();
doc.Load("c:\\manifest.xml");
XmlNodeList nodeList = doc.GetElementsByTagName("uses-permission");
foreach(XmlNode node in nodeList)
{
XmlAttributeCollection Attr = node.Attributes;
string Permission=Attr["android:permission"].Value;
MessageBox.Show(Permission);
}
}
Related
I made a DRM media player app in Xamarin which drops course.licns and pass.licns files in internal memory in app directory for reading correct key.
It's working fine in Android 10 but it's not working in above versions like Android 11 and 12 when I put course name and key then app added both files but can't read it again when I want to play a video. The same thing is working fine on lower versions.
My code:
using System;
using System.Text;
using System.IO;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Android.OS;
namespace MediaElement
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Add : ContentPage
{
public Add()
{
InitializeComponent();
}
async void Appears(object sender, EventArgs e)
{
try
{
this.FindByName<Entry>("ID").Text =Helper. GetIMEI();
}
catch (Exception e2)
{
await DisplayAlert("Error!", e2.Message, "Ok");
}
}
public static string Pass()
{
return Path.Combine((string)System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "pass.licns");
//return Path.Combine((string)System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "pass.licns");
}
public static string Course()
{
//return Path.Combine((string)System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "course.licns");
return Path.Combine((string)System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "course.licns");
}
void Register(object sender, EventArgs e)
{
try
{
string key = this.FindByName<Entry>("Key").Text.Trim();
string Name = this.FindByName<Entry>("Name").Text.Trim();
if (key== string.Empty || Name == string.Empty) { throw new Exception("Key or Name is empty"); }
if (!IsBase(key)) { throw new Exception("Invalid key!"); }
if (!IsValidID(key)) { throw new Exception("This key is not designed for your ID."); }
if (File.Exists(Pass()) && File.Exists(Course()))
{
if (File.ReadAllText(Pass()).Contains(key) || File.ReadAllText(Course()).Contains(Name)){ throw new Exception("Key or Course Already exists."); }
}
File.AppendAllText(Pass(), key+",");
File.AppendAllText(Course(), Name + ",");
DisplayAlert("Success", "License added successfully.", "Ok");
}
catch (Exception e2)
{
DisplayAlert("Error", e2.Message, "Ok");
}
}
bool IsBase(string base64)
{
try
{
if (base64 == Convert.ToBase64String(Convert.FromBase64String(base64))) { return true; }
}
catch (Exception)
{
}
return false;
}
public static bool IsValidID(string key)
{
return Encoding.ASCII.GetString(MainPage.Decrypt(Convert.FromBase64String(key),Helper. IDkey)).Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)[0].ToString() == Helper. GetIMEI();
}
}
}
Note:
I don't want to use All file access permissions due to so many restrictions in Google Play Store and my App is only accessing a particular file. Is there a proper way for upper versions?
I'm trying to initialize a MethodHandle for a non-public method in an upstream library.
private static Method OF_METHOD;
static Method ofMethod() {
if (OF_METHOD == null) {
try {
OF_METHOD = RequestObject.class.getDeclaredMethod(
"of", Class.class, String.class, String.class,
Object.class, Object.class);
if (!OF_METHOD.isAccessible()) {
OF_METHOD.setAccessible(true);
}
} catch (final NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
}
return OF_METHOD;
}
private static MethodHandle OF_HANDLE;
static MethodHandle ofHandle() {
if (OF_HANDLE == null) {
try {
OF_HANDLE = MethodHandles.lookup().unreflect(ofMethod());
} catch (final ReflectiveOperationException roe) {
throw new RuntimeException(roe);
}
}
return OF_HANDLE;
}
And my SpotBugs Bug Detecter Report says the ofMethod() has a LI_LAZY_INIT_UPDATE_STATIC problem.
I understand what it's saying. I see those two steps(assigning and setting accessible) are problematic in multi-threaded environment.
How can I solve the problem? Should I apply Double-checked locking?
Or should I put ofMethod() logic into ofHandle()?
I'm answering for my own question.
The idea of holding a lazy object reference is a bad idea.
Even with the Double-checked locking,
private static volatile Method OF_METHOD;
static Method ofMethod() {
Method ofMethod = OF_METHOD;
if (ofMethod == null) {
synchronized (JacksonRequest.class) {
ofMethod = OF_METHOD;
if (ofMethod == null) {
try {
ofMethod = ...;
} catch (final NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
if (!ofMethod.isAccessible()) {
ofMethod.setAccessible(true);
}
OF_METHOD = ofMethod;
}
}
}
return ofMethod;
}
Anyone can change the accessible state.
I ended up with following code which doesn't depend on any external variables.
static Method ofMethod() {
try {
final Method ofMethod = ...;
if (!ofMethod.isAccessible()) {
ofMethod.setAccessible(true);
}
return ofMethod;
} catch (final NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
}
I am trying to convert Java method which checks the SignalStrength level for Android API's which is like this:
public static int getSignalLevel(final SignalStrength signal) {
try {
final Method m = SignalStrength.class.getDeclaredMethod("getLevel", (Class[]) null);
m.setAccessible(true);
return (Integer) m.invoke(signal, (Object[]) null);
} catch (Exception e) {
Log.debug(TAG, "Google hates developers", e);
return 0;
}
}
When converted to Kotlin I am getting this (I aim to make Kotlin Extension):
fun SignalStrength.getSignalLevel(): Int {
return try {
val m = SignalStrength::class.java.getDeclaredMethod("getLevel", *null as Array<Class<*>>?)
m.isAccessible = true
m.invoke(this, *null as Array<Any>?) as Int
} catch (e: Exception) {
0
}
}
The issue is for:
*null as Array<Class<*>>?
The spread operator (*foo) may not be applied to an argument of nullable type
public class Midlet extends MIDlet implements CommandListener{
Player p;
public void startApp() {
Display.getDisplay(this).setCurrent(new SongsList(this));
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
notifyDestroyed();
}
public void commandAction(Command cmnd, Displayable dsplbl) {
if (cmnd.getLabel().equals("Exit"))
{
destroyApp(true);
}
else
{
try {
//InputStream is = getClass().getResourceAsStream("/res/getlucky.mpeg");
//p = Manager.createPlayer(is, "audio/mpeg");
p = Manager.createPlayer("http://puu.sh/6n9jC.mp3");
p.realize();
p.start();
} catch (IOException ex) {
ex.printStackTrace();
} catch (MediaException ex) {
ex.printStackTrace();
}
}
}
}
this is the songslist class :
public class SongsList extends List{
public SongsList(Midlet midlet)
{
super("Songs", List.IMPLICIT);
append("get lucky", null);
addCommand(new Command("Exit", Command.EXIT, 0));
addCommand(new Command("Select", Command.OK, 0));
setCommandListener(midlet);
}
}
tried use via file stored in project (its under src/res):
inputStream = getClass().getResourceAsStream("res/getlucky.mpg");
audioPlayer = Manager.createPlayer(inputStream, "audio/mpg");
as well as from HTTP:
//audioPlayer = Manager.createPlayer("http://puu.sh/6n9jC.mp3");
Nothing works, what am I doing wrong?
EDIT:
I've tried to delete my application and just copy paste it to a new project and it worked for some reason.. now I encounter new problems:
1) I try to play a song - this is the link http://puu.sh/6n9jC.mp3
its not playing so I guess there's a limited file size for what can be played can someone tell me what is this limit ?
2) Im trying to record the audio with RecordPlayer but its always null
public AudioAnalyzer()
{
try {
thread = new Thread(this);
recordFinished = false;
//inputStream = getClass().getResourceAsStream("res/getlucky.mpg");
//audioPlayer = Manager.createPlayer(inputStream, "audio/mpg");
audioPlayer = Manager.createPlayer("http://puu.sh/35YTG.mp3");
//audioPlayer = Manager.createPlayer("http://puu.sh/6n9jC.mp3");
audioPlayer.realize();
System.out.println(System.getProperty("supports.audio.capture"));
recordControl = (RecordControl)audioPlayer.getControl("RecordControl");
recordOutput = new ByteArrayOutputStream();
recordControl.setRecordStream(recordOutput);
recordControl.startRecord();
audioPlayer.start();
//thread.start();
} catch (MediaException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
I even tried to print if the system is supporting audio capture and the result were true but I get NullPointException at this line :
recordOutput = new ByteArrayOutputStream();
although I tried to get the recordcontrol from the player it is still null :
recordControl = (RecordControl)audioPlayer.getControl("RecordControl");
I think I read that it'll always give NullPointerException unless you run it on a real device and not an emulator is that true ? can someone verify it ? and if so what can I do if I don't own a device currently any other way to use recordcontrol feature in emulator (assuming recordcontrol isn't working on emulators).
File size is 8MB (maybe play on your phone), try to this code
public void initMedia(final String aFileUrl) {
if (m_player == null) {
try {
m_player = Manager.createPlayer(aFileUrl);
m_player.addPlayerListener(this);
m_player.realize();
m_player.prefetch();
m_volumeControl = (VolumeControl) m_player.getControl("VolumeControl");
} catch (IOException ex) {
} catch (Exception ex) {
} catch (OutOfMemoryError e) {
}
}
}
In your code, i guess you miss "m_player.prefetch()", try this. And print your Exception message...
This code in general for file, resourcce, http...
public void initMedia(final String aProtocol, final String aMediaSource) {
if (m_player == null) {
try {
if (aMediaSource.indexOf("file://") == 0) {
InputStream iRecordStream = Connector.openInputStream(aMediaSource);
m_player = Manager.createPlayer(iRecordStream, "audio/amr");
} else {
m_player = Manager.createPlayer(aProtocol);
}
m_player.addPlayerListener(this);
m_player.realize();
boolean isPrefetch = true;
try {
m_player.prefetch();
} catch (Exception ex) {
isPrefetch = false;
}
// trick to pass prefetch error
if (!isPrefetch) {
if (m_player != null) {
m_player.close();
m_player = null;
}
if (aMediaSource.indexOf("file://") == 0) {
InputStream iRecordStream = Connector.openInputStream(aMediaSource);
m_player = Manager.createPlayer(iRecordStream, "audio/amr");
} else {
m_player = Manager.createPlayer(aProtocol);
}
m_player.addPlayerListener(this);
m_player.realize();
m_player.prefetch();
}
m_volumeControl = (VolumeControl) m_player.getControl("VolumeControl");
} catch (IOException ex) {
} catch (Exception ex) {
} catch (OutOfMemoryError e) {
}
}
}
In general when it comes to J2ME development, you should always test your app on multiple real devices.
Emulators can't be trusted.
Also, J2ME is very fragmented, and various devices have various bugs and behaves differently with the same code. This will affect any app on many areas. One area being audio playback.
For example, some devices requires that you use the realize() and prefetch() methods, while other devices will crash if you use prefetch(). The only possible solution (if you wish to support as many devices as possible) is to use multiple try/catch blocks.
See this link for a detailed explanation and other tips'n'tricks on audio playback with MIDP2.0
http://indiegamemusic.com/help.php?id=1
This question already has answers here:
Modifying if-else to strategy pattern
(2 answers)
Closed 9 years ago.
I want to know how we better way refctoring this part of code with else-if operators. When is performed eguals check with different extentions?
Code:
private void findFiles(String path) {
try {
File root = new File(path);
File[] list = root.listFiles();
for (File currentFile : list) {
if (currentFile.isDirectory()) {
findFiles(currentFile.getAbsolutePath());
} else {
if (currentFile.getName().toLowerCase().endsWith((".txt"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".pdf"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".doc"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".docx"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".html"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".htm"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".xml"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".djvu"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".djv"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".rar"))) {
queue.put(currentFile);
} else if (currentFile.getName().toLowerCase()
.endsWith((".rtf"))) {
queue.put(currentFile);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Questions:
How better way to refactoring code? Make it simpler for
understanding.
Can we use some another way to check extentions
variants?
Thanks,
Nazar.
You can replace your whole list of checking extensions with this:
// outside the loop (or even method):
Set<String> extensions = new HashSet<>(Arrays.asList(".txt", ".pdf", ".doc",
".docx", ".html", ".htm", ".xml", ".djvu", ".rar", ".rtf"));
// in the loop:
String fileName = currentFile.getName().toLowerCase();
if (extensions.contains(fileName.substring(fileName.lastIndexOf(".")))) {
queue.put(currentFile);
}
You could use a regex:
String s = currentFile.getName().toLowerCase();
if (s.matches("^.+?\\.(txt|pdf|doc|docx|html|htm|xml|djvu|rar|rtf)$")) {
queue.put(currentFile);
}
That assumes that the action to be taken is the same for all extensions.
In details:
^ beginning of string
.+ one or more characters
? non greedy -> don't consume characters that match the rest of the regex
\\. a period
(pdf|doc) match pdf or doc
$ the end of the string
The best solution would be to refactor this to the STRATEGY Pattern, as seen here:
I would create a getExtension() method, which returns the extension of the file, and a final set of accepted extensions:
private static final Set<String> ACCEPTED_EXTENSIONS =
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(".txt", ".doc", ...));
private String getExtension(File f) {
// TODO return the extension of the file
}
The code would then be redueced to:
private void findFiles(String path) {
try {
File root = new File(path);
File[] list = root.listFiles();
for (File currentFile : list) {
if (currentFile.isDirectory()) {
findFiles(currentFile.getAbsolutePath());
}
else if (ACCEPTED_EXTENSIONS.contains(getExtension(currentFile))) {
queue.put(currentFile);
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
Or even better, I would create a FileFilter which only accepts directories and files with one of the accepted extensions (using the same set and getExtension() method), and would use root.listFiles(fileFilter).
Create a method
public boolean isPermissibleFileType(String fileName){
String[] fileTypes = {".pdf",".doc",".docx",".html",".htm",".xml",".djvu",".djv",".rar",".rtf"};
return Arrays.asList(fileTypes).contains(fileName.substring(fileName.lastIndexOf('.')).toLowerCase());
}
Use Method in Loop
private void findFiles(String path) {
try {
File root = new File(path);
File[] list = root.listFiles();
for (File currentFile : list) {
if (currentFile.isDirectory()) {
findFiles(currentFile.getAbsolutePath());
} else {
if(isPermissibleFileType(currentFile.getName()){
queue.put(currentFile);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
You can extract the extension checks into some helper method using class FileNameFilter. And then for recursion you can use your original finder method.