I have developed an Android application which prints a photo using either PrintHelper or Hp mobile print SDK. However, when before the printing process, Android print Dialog comes up on the screen.
How can I skip the android print dialog, when the application prints the photo ?
I have already come across below questions. Briefly, the answers are "there is no way to do this."
Print without print dialog Android
Print from android without system dialog
Is it possible to directly print content to a wifi-connnected printer without user interaction in android programming?
https://code.google.com/p/android/issues/detail?id=160908
However, I have tried to use HP ePrint android application to print any photo. In this application, there is no any Android Print Dialog, It can print any document directly, without displaying Android Print Dialog on the screen.
So that means, there is a way to print a doc directly.
It is possible for printint to PDF by calling print adapter lifecycle methods. However as callbacks are non public abstract classes and system throws segfault if null is supplied, you need to use DexMaker to implement them. I have implemented for webView adapter like this:
#Override
protected void onPreExecute() {
super.onPreExecute();
printAdapter = webView.createPrintDocumentAdapter();
}
#Override
protected Void doInBackground(Void... voids) {
File file = new File(pdfPath);
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
// get file descriptor
descriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
// create print attributes
PrintAttributes attributes = new PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
.setResolution(new PrintAttributes.Resolution("id", PRINT_SERVICE, 300, 300))
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0))
.build();
ranges = new PageRange[]{new PageRange(1, numberPages)};
// dexmaker cache folder
cacheFolder = new File(context.getFilesDir() +"/etemp/");
printAdapter.onStart();
printAdapter.onLayout(attributes, attributes, new CancellationSignal(), getLayoutResultCallback(new InvocationHandler() {
#Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onLayoutFinished")) {
onLayoutSuccess();
} else {
Log.e(TAG, "Layout failed");
pdfCallback.onPdfFailed();
}
return null;
}
}, cacheFolder), new Bundle());
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, e != null ? e.getMessage() : "PrintPdfTask unknown error");
}
return null;
}
private void onLayoutSuccess() throws IOException {
PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback(new InvocationHandler() {
#Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if (method.getName().equals("onWriteFinished")) {
pdfCallback.onPdfCreated();
} else {
Log.e(TAG, "Layout failed");
pdfCallback.onPdfFailed();
}
return null;
}
}, cacheFolder);
printAdapter.onWrite(ranges, descriptor, new CancellationSignal(), callback);
}
/**
* Implementation of non public abstract class LayoutResultCallback obtained via DexMaker
* #param invocationHandler
* #param dexCacheDir
* #return LayoutResultCallback
* #throws IOException
*/
public static PrintDocumentAdapter.LayoutResultCallback getLayoutResultCallback(InvocationHandler invocationHandler,
File dexCacheDir) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
/**
* Implementation of non public abstract class WriteResultCallback obtained via DexMaker
* #param invocationHandler
* #param dexCacheDir
* #return LayoutResultCallback
* #throws IOException
*/
public static PrintDocumentAdapter.WriteResultCallback getWriteResultCallback(InvocationHandler invocationHandler,
File dexCacheDir) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.WriteResultCallback.class)
.dexCache(dexCacheDir)
.handler(invocationHandler)
.build();
}
Related
I am trying to find a way to have a tablet basically auto-accept/give permission to accept an incoming Bluetooth Share file transferred from a laptop to my Nexus Android device. Since the Android bluetooth system itself does not support this feature, I was wondering if this could be done programmatically using an Android application that listened for the notification and accepted it for me.
MUCH EASIER WAY
If you have a rooted device and use XPosed Framework, your goal can be achieved much easier.
You Need not implement your own bluetooth server nor kill the original BT service, which are very bothering!!!
xposed tutorial link.
Try this code.
import android.util.*;
import de.robv.android.xposed.*;
import de.robv.android.xposed.callbacks.XC_LoadPackage.*;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
public class Tutorial implements IXposedHookLoadPackage
{
private String TAG="TUTORIAL";
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.bluetooth"))
{
Log.i(TAG,"Not: "+lpparam.packageName);
return;
}
Log.i(TAG,"Yes "+lpparam.packageName);
findAndHookMethod("com.android.bluetooth.opp.BluetoothOppManager", lpparam.classLoader, "isWhitelisted", String.class,new XC_MethodHook() {
#Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.v(TAG,"HOOK DONE");
param.setResult(true); /* you can compare the sender address(String) with your computer and determine if you return true or just allow the original method to be called after this returns.*/
}
});
}
}
I tested and it works fine:)
Links
Dropbox link of the auto accepting app
Dropbox link of the project files (zip)
Xposed apk site
Towelroot site to root your phone
Background(Original answer)
As I commented above, you bay be able to, and I tried and succeeded in blocking (though not receiving) with this code.
import android.util.*;
import de.robv.android.xposed.*;
import de.robv.android.xposed.callbacks.XC_LoadPackage.*;
import java.io.*;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
public class Tutorial implements IXposedHookLoadPackage
{
private String TAG="TUTORIAL";
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.bluetooth"))
{
Log.i(TAG,"Not: "+lpparam.packageName);
return;
}
Log.i(TAG,"Yes "+lpparam.packageName);
findAndHookMethod("com.android.bluetooth.opp.BluetoothOppService", lpparam.classLoader, "startSocketListener", new XC_MethodHook() {
#Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.v(TAG,"HOOK DONE");
param.setResult(null);
}
});
}
}
The code above hooks the method startListenerSocket() of com.android.bluetooth.BluetoothOppService and prevents the original method from being called by the line param.setResult(null);
Refer to here to see the full code of com.android.bluetooth.BluetoothOppService.java and you will understand the operation.
And the code you can start from is shown below.
import android.util.*;
import de.robv.android.xposed.*;
import de.robv.android.xposed.callbacks.XC_LoadPackage.*;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
public class Tutorial implements IXposedHookLoadPackage
{
private String TAG="TUTORIAL";
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.bluetooth"))
{
Log.i(TAG,"Not: "+lpparam.packageName);
return;
}
Log.i(TAG,"Yes "+lpparam.packageName);
findAndHookMethod("com.android.bluetooth.opp.BluetoothOppObexServerSession", lpparam.classLoader, "onPut", new XC_MethodHook() {
#Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.v(TAG,"HOOK DONE");
Class c=param.thisObject.getClass();
}
});
}
}
This code hooks the onPut method of com.android.bluetooth. BluetoothOppObexServerSession linked here. I either am newbie to xposed framework but I hope my answer helped.
I had the same issues you asked and partially solved the problem by implementing my custom OBEX server and manually / programmatically(with ps|grep and su kill pid) killing the native BluetoothOppService. But I will either try the idea of hooking and directly executing my code.
And to help you customize OBEX server session I post my implementation below.
#Override
public int onPut(Operation op)
{
if (D)
{
Log.d(TAG, "onPut " + op.toString());
}
HeaderSet request;
String name, mimeType;
Long length;
String extension=null;// type;
int obexResponse = ResponseCodes.OBEX_HTTP_OK;
String destination;
if (mTransport instanceof BluetoothObexTransport)
{
destination = ((BluetoothObexTransport) mTransport).getRemoteAddress();
}
else
{
destination = "FF:FF:FF:00:00:00";
}
boolean isWhitelisted =IsWhitelisted(destination);
try
{
boolean preReject = false;
request = op.getReceivedHeader();
if (V)
{
// Constants.logHeader(request);
}
name = (String) request.getHeader(HeaderSet.NAME);
length = (Long) request.getHeader(HeaderSet.LENGTH);
mimeType = (String) request.getHeader(HeaderSet.TYPE);
if (length == 0)
{
if (D)
{
Log.w(TAG, "length is 0, reject the transfer");
}
preReject = true;
obexResponse = ResponseCodes.OBEX_HTTP_LENGTH_REQUIRED;
}
if (name == null || name.isEmpty())
{
if (D)
{
Log.w(TAG, "name is null or empty, reject the transfer");
}
preReject = true;
obexResponse = ResponseCodes.OBEX_HTTP_BAD_REQUEST;
}
int dotIndex = name.lastIndexOf(".");
if (dotIndex > 0)
{
extension = name.substring(dotIndex + 1).toLowerCase();
}
// Reject policy: anything outside the "white list" plus unspecified
// MIME Types. Also reject everything in the "black list".
// if (!preReject && (mimeType == null || (!isWhitelisted && !Constants.mimeTypeMatches(
// mimeType, Constants.ACCEPTABLE_SHARE_INBOUND_TYPES))
// || Constants.mimeTypeMatches(mimeType,
// Constants.UNACCEPTABLE_SHARE_INBOUND_TYPES))) {
// if (D) {
// Log.w(TAG, "mimeType is null or in unacceptable list, reject the transfer");
// }
// preReject = true;
// obexResponse = ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE;
// }
if (preReject && obexResponse != ResponseCodes.OBEX_HTTP_OK)
{
// some bad implemented client won't send disconnect
return obexResponse;
}
}
catch (IOException e)
{
Log.e(TAG, "get getReceivedHeaders error " + e);
return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
}
int status = receiveFile(destination, name, extension, length, op);
/*
* TODO map status to obex response code
*/
if (status != BluetoothShare.STATUS_SUCCESS)
{
obexResponse = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
}
Log.d(TAG, "MIME TYPE)" + mimeType);
return obexResponse;
}
I just removed some rejecting codes from the original one.
Also to look at my full code please refer to my git repository.
I also thank the contributors to the android project!
Android Studio 2.1.2
I am trying to test getJsonFromResource which calls loadNewsFeed.
I want to be able to test 2 cases 1 where loadNewsFeed will return an empty string and the other where it will return some json string.
So I am trying to mock the loadNewsFeed function to return an empty string. However, when the concrete getJsonFromResource is called it will call the real loadNewsFeed and cause a null pointer exception.
This is what I have tried in my test comments explaining what I am doing:
#Test
public void shouldFailIfJSONStringIsEmpty() throws Exception {
/* Mock Context class */
Context context = mock(Context.class);
/* initialize the concrete parseNewsFeed passing in the fake context */
ParseNewsFeed parseNewsFeed = new ParseNewsFeed(context);
/* Create a mock of the parseNewsFeed so a fake call to loadNewsFeed will return an empty string */
ParseNewsFeed mockParseNewsFeed = mock(ParseNewsFeed.class);
/* Mock the events that will be verified */
ParseNewsFeedContract.Events<Status> mockEvents = mock(ParseNewsFeedContract.Events.class);
/* Return an empty string when loadNewsFeed is called */
when(mockParseNewsFeed.loadNewsFeed()).thenReturn("");
/* Called the concrete getJsonFromResource */
parseNewsFeed.getJsonFromResource(mockEvents);
/* verify that onNewsFailure was called once and onNewsSuccess was never called */
verify(mockEvents, times(1)).onNewsFailure(anyString());
verify(mockEvents, never()).onNewsSuccess(any(Status.class));
}
This is the class I am trying to test.
public class ParseNewsFeed implements ParseNewsFeedContract {
private Context mContext;
public ParseNewsFeed(Context context) {
if(context != null) {
Timber.d("mContext != null");
mContext = context;
}
}
/**
* Get the json from the local resource file and add to the cache to save loading each time
* #return the json in string representation
*/
#Override
public void getJsonFromResource(Events<Status> events) {
/* Get the json in string format */
final String jsonString = loadNewsFeed();
/* Check that is contains something */
if(!jsonString.isEmpty()) {
try {
final Status status = new Gson().fromJson(jsonString, Status.class);
if(status != null) {
Timber.d("url: %s", status.getResults().get(0).getMultimedia().get(0).getUrl());
events.onNewsSuccess(status);
}
else {
Timber.e("status == null");
events.onNewsFailure("Failed to get results from json");
}
}
catch (JsonSyntaxException e) {
Timber.e("Invalid JSON: %s", e.getMessage());
events.onNewsFailure(e.getMessage());
}
}
}
/**
* Opens and reads from the news_list and writes to a buffer
* #return return the json representation as a string or a empty string for failure
*/
public String loadNewsFeed() {
InputStream inputStream = mContext.getResources().openRawResource(R.raw.news_list);
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
InputStreamReader inputReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferReader = new BufferedReader(inputReader);
int n;
while ((n = bufferReader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
inputStream.close();
}
catch (IOException ioException) {
return "";
}
return writer.toString();
}
}
First of all, the reason why your original code doesn't work is because there's no relationship between your two objects parseNewsFeed and mockParseNewsFeed, hence the stubbing that you do for the mockParseNewsFeed doesn't have any effect when you invoke parseNewsFeed.getJsonFromResource(mockEvents). Using spy as David Wallace suggested would work, but if I were you, I would rewrite the code a bit differently to make it even easier to test.
One observation is that the code in loadNewsFeed() method doesn't seem to have a strong relationship with the ParseNewsFeed class, so I'd extract this code into an object (e.g. NewsFeedLoader), and then have this object as a dependency of ParseNewsFeed class. Then you can mock this Loader easily (return "" or any string that you want when passing a Context and possibly the R.raw.news_list id as well). With this Loader class, you can even unit test it separately from the ParseNewsFeed, and being able to improve the Loader however you want to (e.g. a better way to read a raw resource) without affecting the ParseNewsFeed class.
Use when() and then() methods of your mocked context. It is actually described in example of official tutorial here.
#Mock
Context mMockContext;
#Test
public void readStringFromContext_LocalizedString() {
// Given a mocked Context injected into the object under test...
when(mMockContext.getString(R.string.hello_word))
.thenReturn(FAKE_STRING);
ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);
// ...when the string is returned from the object under test...
String result = myObjectUnderTest.getHelloWorldString();
// ...then the result should be the expected one.
assertThat(result, is(FAKE_STRING));
It looks like you want to have a ParseNewsFeed object where the loadNewsFeed method has been stubbed, but other methods work correctly. The simplest way to get that would probably be to create a spy, something like
ParseNewsFeed spyParseNewsFeed = Mockito.spy(new ParseNewsFeed(context));
Mockito.doReturn("").when(spyParseNewsFeed).loadNewsFeed();
I want to use android in industry,
I can connect to Profilic and Ftdi USB to Serial chips with slickdevlabs.com library without any problem.
The application has a service and it starts on boot,connect to the usb serial port and do the other things.
my problem is that the host device does not have any interaction with user,
so when the android asks
Allow the app "MyAPP" to access the USB device ?
[checkmark]Use by default for this USB device
Cancel OK
there is no person to click on ok.
even when I check the use by default... checkbox,If I reinsert the USB ,or reboot the host device, it asks again on next boot.
and the answer is mentioned in this link :
bypass android usb host permission confirmation dialog
but the codes are for :
"Note that interfaces of these classes may change depending on the version of Android. In my case the version is 4.0.3. So if you have another version of Android and this code doesn't work you will have to check the source code for your particular version of OS."
so i need the same codes for android 5.1 please
It's been a while since you asked this... but in case it can help someone here is my answer.
The accepted answer in the initial question states:
So if you have another version of Android and this code doesn't work you will have to check the source code for your particular version of OS.
So you should get the files you need directly from the android source code. You can download the source code relative to your version or browse directly from the repo.
The IUsbManager interface you are searching for is normally under:
/frameworks/base/android-branch-name/core/java/android/hardware/usb. As for the Service Manager it can be found under:
/frameworks/base/android-branch-name/core/java/android/os/
I didn't post the code since I suppose you're not searching for it anymore after 2 years+ :)
=== EDIT ===
As asked, here is the code. I made it work for version 6.0.0, but I think functions calls are the same as 5.1. To be verified.
First, here is the android project structure you will get:
Create the interface IUsbManager.java in android.harware.usb:
package android.hardware.usb;
public interface IUsbManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.hardware.usb.IUsbManager
{
/** Construct the stub at attach it to the interface. */
public Stub()
{
throw new RuntimeException( "Stub!" );
}
/**
* Cast an IBinder object into an android.hardware.usb.IUsbManager interface,
* generating a proxy if needed.
*/
public static android.hardware.usb.IUsbManager asInterface( android.os.IBinder obj )
{
throw new RuntimeException( "Stub!" );
}
public android.os.IBinder asBinder()
{
throw new RuntimeException( "Stub!" );
}
public boolean onTransact( int code, android.os.Parcel data, android.os.Parcel reply, int flags ) throws android.os.RemoteException
{
throw new RuntimeException( "Stub!" );
}
static final int TRANSACTION_getDeviceList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_openDevice = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_getCurrentAccessory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_openAccessory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_setDevicePackage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_setAccessoryPackage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
static final int TRANSACTION_hasDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
static final int TRANSACTION_hasAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
static final int TRANSACTION_requestDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
static final int TRANSACTION_requestAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9);
static final int TRANSACTION_grantDevicePermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 10);
static final int TRANSACTION_grantAccessoryPermission = (android.os.IBinder.FIRST_CALL_TRANSACTION + 11);
static final int TRANSACTION_hasDefaults = (android.os.IBinder.FIRST_CALL_TRANSACTION + 12);
static final int TRANSACTION_clearDefaults = (android.os.IBinder.FIRST_CALL_TRANSACTION + 13);
static final int TRANSACTION_setCurrentFunction = (android.os.IBinder.FIRST_CALL_TRANSACTION + 14);
static final int TRANSACTION_setMassStorageBackingFile = (android.os.IBinder.FIRST_CALL_TRANSACTION + 15);
}
/* Returns a list of all currently attached USB devices */
public void getDeviceList( android.os.Bundle devices ) throws android.os.RemoteException;
/* Returns a file descriptor for communicating with the USB device.
* The native fd can be passed to usb_device_new() in libusbhost.
*/
public android.os.ParcelFileDescriptor openDevice( java.lang.String deviceName ) throws android.os.RemoteException;
/* Returns the currently attached USB accessory */
public android.hardware.usb.UsbAccessory getCurrentAccessory() throws android.os.RemoteException;
/* Returns a file descriptor for communicating with the USB accessory.
* This file descriptor can be used with standard Java file operations.
*/
public android.os.ParcelFileDescriptor openAccessory( android.hardware.usb.UsbAccessory accessory ) throws android.os.RemoteException;
/* Sets the default package for a USB device
* (or clears it if the package name is null)
*/
public void setDevicePackage(android.hardware.usb.UsbDevice device, java.lang.String packageName, int userId) throws android.os.RemoteException;
/* Sets the default package for a USB accessory
* (or clears it if the package name is null)
*/
public void setAccessoryPackage( android.hardware.usb.UsbAccessory accessory, java.lang.String packageName ) throws android.os.RemoteException;
/* Returns true if the caller has permission to access the device. */
public boolean hasDevicePermission(android.hardware.usb.UsbDevice device) throws android.os.RemoteException;
/* Returns true if the caller has permission to access the accessory. */
public boolean hasAccessoryPermission( android.hardware.usb.UsbAccessory accessory ) throws android.os.RemoteException;
/* Requests permission for the given package to access the device.
* Will display a system dialog to query the user if permission
* had not already been given.
*/
public void requestDevicePermission( android.hardware.usb.UsbDevice device, java.lang.String packageName, android.app.PendingIntent pi ) throws android.os.RemoteException;
/* Requests permission for the given package to access the accessory.
* Will display a system dialog to query the user if permission
* had not already been given. Result is returned via pi.
*/
public void requestAccessoryPermission( android.hardware.usb.UsbAccessory accessory, java.lang.String packageName, android.app.PendingIntent pi ) throws android.os.RemoteException;
/* Grants permission for the given UID to access the device */
public void grantDevicePermission( android.hardware.usb.UsbDevice device, int uid ) throws android.os.RemoteException;
/* Grants permission for the given UID to access the accessory */
public void grantAccessoryPermission( android.hardware.usb.UsbAccessory accessory, int uid ) throws android.os.RemoteException;
/* Returns true if the USB manager has default preferences or permissions for the package */
public boolean hasDefaults( java.lang.String packageName ) throws android.os.RemoteException;
/* Clears default preferences and permissions for the package */
public void clearDefaults( java.lang.String packageName ) throws android.os.RemoteException;
/* Sets the current USB function. */
public void setCurrentFunction( java.lang.String function, boolean makeDefault ) throws android.os.RemoteException;
/* Sets the file path for USB mass storage backing file. */
public void setMassStorageBackingFile( java.lang.String path ) throws android.os.RemoteException;
}
Then create the java class ServiceManager.java in android.os:
package android.os;
import java.util.Map;
public final class ServiceManager
{
public static IBinder getService( String name )
{
throw new RuntimeException( "Stub!" );
}
/**
* Place a new #a service called #a name into the service
* manager.
*
* #param name the name of the new service
* #param service the service object
*/
public static void addService( String name, IBinder service )
{
throw new RuntimeException( "Stub!" );
}
/**
* Retrieve an existing service called #a name from the
* service manager. Non-blocking.
*/
public static IBinder checkService( String name )
{
throw new RuntimeException( "Stub!" );
}
public static String[] listServices() throws RemoteException
{
throw new RuntimeException( "Stub!" );
}
/**
* This is only intended to be called when the process is first being brought
* up and bound by the activity manager. There is only one thread in the process
* at that time, so no locking is done.
*
* #param cache the cache of service references
* #hide
*/
public static void initServiceCache( Map<String, IBinder> cache )
{
throw new RuntimeException( "Stub!" );
}
}
Once this is done, don't forget to add the android.permission.MANAGE_USB in you AndroidManifest.
Then you can use those function calls:
/**
* Verify if the application is a system app and has MANAGE_USB permission
* before granting the USB permission for you specific USB devices
*/
private void manageUSBPermissions() {
if ((this.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Log.i(TAG,"This is a system application");
if (getApplicationContext().checkCallingOrSelfPermission("android.permission.MANAGE_USB") == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG,"I have android.permission.MANAGE_USB");
grantUsbPermissions();
} else {
Log.i(TAG,"I do not have android.permission.MANAGE_USB");
}
} else {
Log.i(TAG,"This is not a system application");
}
}
/**
* This is to avoid the android usb host permission confirmation dialog
* The application need to be a system app and have MANAGE_USB permission for it to work
*/
private void grantUsbPermissions() {
try {
PackageManager pm = getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo( "com.your.package", 0 );
if( ai != null ) {
UsbManager manager = (UsbManager) getSystemService( Context.USB_SERVICE );
IBinder b = ServiceManager.getService( Context.USB_SERVICE );
IUsbManager service = IUsbManager.Stub.asInterface( b );
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while( deviceIterator.hasNext() ) {
UsbDevice device = deviceIterator.next();
if ( device.getVendorId() == 0x1234 ) {
service.grantDevicePermission( device, ai.uid );
service.setDevicePackage( device, "com.your.package", ai.uid );
}
}
}
}
catch ( Exception e ) {
Log.e(TAG, "Error granting USB permissions: " + e);
}
}
There's a check on whether your application is a system application and if it has the correct permission, otherwise it would not work.
Also be aware that your vendor id is not in hexadecimal but in decimal.
Have you tried using an intent-filter in the Manifest as described here: https://developer.android.com/guide/topics/connectivity/usb/host.html#using-intents
I had a similar issue - it seems like if you programmatically request a USB permission, it will ignore the ticked checkbox and ask you every time again.
Edit:
If you are having issues because of the service, you might want to read this too: https://stackoverflow.com/a/15151075/3540885
I have a doubt about the possibility of repeating an AsyncTask in an application for Android. I would like to repeat some operations, the download of a file from a server for example, n times if it is impossible for some reasons download the file. There is a quick way to do this?
You cannot repeat an AsyncTask but you could repeat the operations it executes.
I've made this little helper class that you might want to extend in place of AsyncTask, the only big difference is that you will use repeatInBackground instead of doInBackground and that onPostExecute will have a new parameter, the eventual Exception thrown.
Anything inside repeatInBackground will be repeated automatically until result is different from null / exception is not thrown and there are been less than maxTries.
The last exception thrown inside the loop will be returned in the onPostExecute(Result, Exception).
You can set max tries using the RepeatableAsyncTask(int retries) constructor.
public abstract class RepeatableAsyncTask<A, B, C> extends AsyncTask<A, B, C> {
private static final String TAG = "RepeatableAsyncTask";
public static final int DEFAULT_MAX_RETRY = 5;
private int mMaxRetries = DEFAULT_MAX_RETRY;
private Exception mException = null;
/**
* Default constructor
*/
public RepeatableAsyncTask() {
super();
}
/**
* Constructs an AsyncTask that will repeate itself for max Retries
* #param retries Max Retries.
*/
public RepeatableAsyncTask(int retries) {
super();
mMaxRetries = retries;
}
/**
* Will be repeated for max retries while the result is null or an exception is thrown.
* #param inputs Same as AsyncTask's
* #return Same as AsyncTask's
*/
protected abstract C repeatInBackground(A...inputs);
#Override
protected final C doInBackground(A...inputs) {
int tries = 0;
C result = null;
/* This is the main loop, repeatInBackground will be repeated until result will not be null */
while(tries++ < mMaxRetries && result == null) {
try {
result = repeatInBackground(inputs);
} catch (Exception exception) {
/* You might want to log the exception everytime, do it here. */
mException = exception;
}
}
return result;
}
/**
* Like onPostExecute but will return an eventual Exception
* #param c Result same as AsyncTask
* #param exception Exception thrown in the loop, even if the result is not null.
*/
protected abstract void onPostExecute(C c, Exception exception);
#Override
protected final void onPostExecute(C c) {
super.onPostExecute(c);
onPostExecute(c, mException);
}
}
You cannot reuse the same AsyncTask object as, according to the AsyncTask Docs
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
But you can create however many new objects of that class you need inside of a loop. However a better way you be to do the download operation n number of times inside your doInBackground().
If this doesn't answer your question then please be more specific as to your problem
I did it that way. It can try and try until (tries == MAX_RETRY) or the result is not null. A slightly modified code from accepted answer, better for me.
private class RssReaderTask extends AsyncTask<String, Void, ArrayList<RssItem>> {
// max number of tries when something is wrong
private static final int MAX_RETRY = 3;
#Override
protected ArrayList<RssItem> doInBackground(String... params) {
ArrayList<RssItem> result = null;
int tries = 0;
while(tries++ < MAX_RETRY && result == null) {
try {
Log.i("RssReaderTask", "********** doInBackground: Processing... Trial: " + tries);
URL url = new URL(params[0]);
RssFeed feed = RssReader.read(url);
result = feed.getRssItems();
} catch (Exception ex) {
Log.i("RssReaderTask", "********** doInBackground: Feed error!");
}
}
return result;
}
#Override
protected void onPostExecute(ArrayList<RssItem> result) {
// deal with result
}
}
I was working on capturing the order of elements contained in tag. Here is all the code:
League.java:
#Root
#Convert(value = LeagueConverter.class)
public class League
{
#Attribute
private String name;
#Element(name="headlines", required = false)
private Headlines headlines;
#Element(name="scores", required = false)
private Scores scores;
#Element(name="standings", required = false)
private Standing standings;
#Element(name="statistics", required = false)
private LeagueStatistics statistics;
public List<String> order = new ArrayList<String>();
// get methods for all variables
}
LeagueConverter.java:
public class LeagueConverter implements Converter<League>
{
#Override
public League read(InputNode node) throws Exception
{
League league = new League();
InputNode next = node.getNext();
while( next != null )
{
String tag = next.getName();
if(tag.equalsIgnoreCase("headlines"))
{
league.order.add("headlines");
}
else if(tag.equalsIgnoreCase("scores"))
{
league.order.add("scores");
}
else if(tag.equalsIgnoreCase("statistics"))
{
league.order.add("statistics");
}
else if(tag.equalsIgnoreCase("standings"))
{
league.order.add("standings");
}
next = node.getNext();
}
return league;
}
#Override
public void write(OutputNode arg0, League arg1) throws Exception
{
throw new UnsupportedOperationException("Not supported yet.");
}
}
Exampe of XML:
<android>
<leagues>
<league name ="A">
<Headlines></Headlines>
<Scores></Scores>
...
</league>
<league name ="B">...</league>
</leagues>
</android>
How I'm calling it and expecting it to behave: (Snippet)
Android android = null;
Serializer serial = new Persister(new AnnotationStrategy());
android = serial.read(Android.class, source);
Log.i("Number of leagues found ",tsnAndroid.getLeagueCount() + ""); // prints fine
League nhl = tsnAndroid.getLeagues().get(0); // works fine
// DOES NOT WORK throws NullPointerEx
League nhl2 = tsnAndroid.getLeagueByName("A");
// DOES NOT WORK throws NullPointerEx
for(String s : nhl.getOrder())
{
Log.i("ORDER>>>>>", s);
}
The problem:
android.getLeagueByName() (Works with #Attribute name) suddenly stops working when I have the converter set, so its like the following from League.java, never gets set.
#Attribute
private String name; // not being set
However, when I comment out the converter declaration in League.java - Every league has an attribute called name and android.getLeagueByName() starts working fine...
Does #Convert for League somehow interfere with #Attribute in League?
Even though this question is outrageously old (as is the SimpleXML library), I will give my two cents.
#Convert annotation works only with #Element, but it does not have any effect on #Attribute. I'm not sure if that's a bug or a feature, but there is another way of handling custom serialized objects - called Transform with Matcher, and it works both with Attributes and with Elements. Instead of using the Converters, you define a Transform class that handles serialization and deserialization:
import java.util.UUID;
import org.simpleframework.xml.transform.Transform;
public class UUIDTransform implements Transform<UUID> {
#Override
public UUID read(String value) throws Exception {
return value != null ? UUID.fromString(value) : null;
}
#Override
public String write(UUID value) throws Exception {
return value != null ? value.toString() : null;
}
}
As you can see, it is more straight-forward than implementing the Convert interface!
Create a similar class for all your objects that require custom de/serialization.
Now instantiate a RegistryMatcher object and register there your custom classes with their corresponding Transform classes. This is a thread-safe object that internally uses a cache, so it might be a good idea to keep it as a singleton.
private static final RegistryMatcher REGISTRY_MATCHER = new RegistryMatcher();
static {
try {
REGISTRY_MATCHER.bind(UUID.class, UUIDTransform.class);
// register all your Transform classes here...
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Finally, you can create a Persister class each time before a conversion and pass it the AnnotationStrategy together with your RegistryMatcher instance. In this factory method below, we will also use an indenting formatter:
private static Persister createPersister(int indent) {
return new Persister(new AnnotationStrategy(), REGISTRY_MATCHER, new Format(indent));
}
Now you can make your serialization/deserialization methods:
public static String objectToXml(Object object, int indent) throws MyObjectConversionException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Persister p = createPersister(indent);
try {
p.write(object, out, "UTF-8");
return out.toString("UTF-8");
} catch (Exception e) {
throw new MyObjectConversionException("Cannot serialize object " + object + " to XML: " + e.getMessage(), e);
}
}
public static <T> T xmlToObject(String xml, final Class<T> clazz) throws MyObjectConversionException {
Persister p = createPersister(0);
try {
return (T) p.read(clazz, xml);
} catch (Exception e) {
throw new MyObjectConversionException(
"Cannot deserialize XML to object of type " + clazz + ": " + e.getMessage(), e);
}
}
The only issue with this approach is when you want to have different formatting for the same object - e.g. once you want the java.util.Date to have just the date component, while later on you also want to have the time component. Then just extend the Date class, calling it DateWithTime, and make a different Transform for it.
#ElementListUnion will capture the order of elements
The #Convert annotation works only on #Element fields. I am struggling against converting #Attribute fields too but with no success for now...