I try to implement my own printer (means print server) based on the Android PrintServer API. This print server provides a static single printer which tasks is to upload the print job to a web page via http upload.
I am using Marshmallow on a Sony Z2. And for testing I use the email application and "printing" from the submenu.
In principle I managed all the business logic already and it works, so at least I used the right approach. But when I press the "print" button (with the printer logo) in the Android print dialog to fast, the whole print server crashes. If I wait until the dialog rendered all the preview and then press the button, everything is fine.
I dont know if the problem is clear therefore I made a small movie (1,8MB), which you can find here:
https://c.geniusbytes.com/index.php/s/leJrSGRlxBSSCux
To reduce the problem I removed all the transfer code and arrived at the most minimal version which still causes the crash, see below.
Can somebody see what is the problem? On my mobile there is also the PDF-writer PrintServer (Sony!?). This does not crash with the same procedure. Instead the "print" behavior, which is the selection of the destination to store the PDF, waits until the preview is rendered and then pops up.
It is important to mention that one need a larger document to print. Otherwise the preview is rendered to fast for causing the crash by pressing the print button.
Here is the code for the PrintServer implementation:
public class UploadPrintService extends PrintService {
private static final String LOG_TAG = "UploadPrintService";
////////////////////////////////////////////////
//
// service methods
//
/////////////////////////////////////////////////
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
protected void onConnected() {
Log.i(LOG_TAG, "#onConnected()");
}
#Override
protected void onDisconnected() {
Log.i(LOG_TAG, "#onDisconnected()");
}
#Override
protected PrinterDiscoverySession onCreatePrinterDiscoverySession() {
Log.i(LOG_TAG, "#onCreatePrinterDiscoverySession()");
return new UploadPrintDiscoverySession(this);
}
#Override
protected void onRequestCancelPrintJob(PrintJob printJob) {
// standard cancel
if ((printJob.isStarted() && (!printJob.isCancelled()))) {
printJob.cancel();
}
}
#Override
protected void onPrintJobQueued(final PrintJob printJob) {
Log.i(LOG_TAG, "#onPrintJobQueued");
printJob.start();
}
}
And the PrinterDiscoverySession is implemented in a way, such that it always returns the same printer. See here:
public class UploadPrintDiscoverySession extends PrinterDiscoverySession {
private static final String LOG_TAG = UploadPrintDiscoverySession.class.getSimpleName();
private PrintService printService = null;
private static final String PRINTER_ID = "my.uploadprinter.id";
public UploadPrintDiscoverySession(PrintService printService) {
super();
Log.i(LOG_TAG, "new discovery session!");
this.printService = printService;
}
#Override
public void onStartPrinterDiscovery(List<PrinterId> list) {
Log.i(LOG_TAG, "#onStartPrinterDiscovery");
addUploadPrinter();
}
#Override
public void onStopPrinterDiscovery() {
Log.i(LOG_TAG, "#onStopPrinterDiscovery");
}
#Override
public void onValidatePrinters(List<PrinterId> list) {
Log.i(LOG_TAG, "#onValidatePrinters");
addUploadPrinter();
}
#Override
public void onStartPrinterStateTracking(PrinterId printerId) {
Log.i(LOG_TAG, "#onStartPrinterStateTracking");
addUploadPrinter();
}
#Override
public void onStopPrinterStateTracking(PrinterId printerId) {
Log.i(LOG_TAG, "#onStopPrinterStateTracking");
}
#Override
public void onDestroy() {
Log.i(LOG_TAG, "#onDestroy");
}
private void addUploadPrinter() {
Log.i(LOG_TAG, "#addUploadPrinter");
PrinterId uploadPrinterId = printService.generatePrinterId(PRINTER_ID);
PrinterInfo.Builder printerInfoBuilder = new PrinterInfo.Builder(uploadPrinterId,
"Mighty Printer", PrinterInfo.STATUS_IDLE);
PrinterCapabilitiesInfo.Builder capBuilder =
new PrinterCapabilitiesInfo.Builder(uploadPrinterId);
capBuilder.addMediaSize(PrintAttributes.MediaSize.ISO_A4, true);
capBuilder.addMediaSize(PrintAttributes.MediaSize.ISO_A3, false);
capBuilder.addResolution(new PrintAttributes.Resolution(
"Default", "default resolution", 600, 600), true);
capBuilder.setColorModes(PrintAttributes.COLOR_MODE_COLOR
| PrintAttributes.COLOR_MODE_MONOCHROME,
PrintAttributes.COLOR_MODE_COLOR);
printerInfoBuilder.setCapabilities(capBuilder.build());
Log.i(LOG_TAG, "add *the* printer to the list...");
List<PrinterInfo> discoveredPrinterList = new ArrayList<PrinterInfo>();
discoveredPrinterList.add(printerInfoBuilder.build());
this.addPrinters(discoveredPrinterList);
}
}
Thanks for the Logcat-hint, I was already wondering why I see no error but when I disabled the filter which was activated by default, then I see the following error:
09-05 20:06:05.523 27568-27568/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.printspooler, PID: 27568
java.lang.IllegalArgumentException: end cannot be less than zero.
at android.print.PageRange.<init>(PageRange.java:50)
at com.android.printspooler.util.PageRangeUtils.asAbsoluteRange(PageRangeUtils.java:199)
at com.android.printspooler.ui.PrintActivity$DocumentTransformer.computePagesToShred(PrintActivity.java:2620)
at com.android.printspooler.ui.PrintActivity$DocumentTransformer.<init>(PrintActivity.java:2496)
at com.android.printspooler.ui.PrintActivity.transformDocumentAndFinish(PrintActivity.java:1733)
at com.android.printspooler.ui.PrintActivity.requestCreatePdfFileOrFinish(PrintActivity.java:967)
at com.android.printspooler.ui.PrintActivity.onUpdateCompleted(PrintActivity.java:492)
at com.android.printspooler.model.RemotePrintDocument.notifyUpdateCompleted(RemotePrintDocument.java:385)
at com.android.printspooler.model.RemotePrintDocument.access$900(RemotePrintDocument.java:55)
at com.android.printspooler.model.RemotePrintDocument$1.onDone(RemotePrintDocument.java:117)
at com.android.printspooler.model.RemotePrintDocument$WriteCommand.handleOnWriteFinished(RemotePrintDocument.java:1000)
at com.android.printspooler.model.RemotePrintDocument$WriteCommand.access$2200(RemotePrintDocument.java:867)
at com.android.printspooler.model.RemotePrintDocument$WriteCommand$WriteHandler.handleMessage(RemotePrintDocument.java:1061)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:234)
at android.app.ActivityThread.main(ActivityThread.java:5526)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
0
And some lines later there I found:
09-05 20:06:06.956 1005-3292/? I/WindowState: WIN DEATH: Window{ff8499c u0 com.android.printspooler/com.android.printspooler.ui.PrintActivity}
09-05 20:06:06.956 1005-3325/? W/UserState: Not stopping printer state tracking - session destroyed
09-05 20:06:06.956 1005-3924/? D/GraphicsStats: Buffer count: 7
09-05 20:06:06.957 1005-1005/? D/RemotePrintSpooler: Error clearing print spooler client
android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:503)
at android.print.IPrintSpooler$Stub$Proxy.setClient(IPrintSpooler.java:358)
at com.android.server.print.RemotePrintSpooler.clearClientLocked(RemotePrintSpooler.java:424)
at com.android.server.print.RemotePrintSpooler.access$400(RemotePrintSpooler.java:53)
at com.android.server.print.RemotePrintSpooler$MyServiceConnection.onServiceDisconnected(RemotePrintSpooler.java:456)
at android.app.LoadedApk$ServiceDispatcher.doDeath(LoadedApk.java:1232)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1246)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:234)
at com.android.server.SystemServer.run(SystemServer.java:302)
at com.android.server.SystemServer.main(SystemServer.java:174)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintDiscoverySession: #onStopPrinterStateTracking
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintDiscoverySession: #onStopPrinterDiscovery
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintDiscoverySession: #onDestroy
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintService: #onDisconnected()
09-05 20:06:07.006 1005-3886/? I/ActivityManager: Process com.android.printspooler (pid 27568) has died
09-05 20:06:07.006 1005-3886/? W/ActivityManager: Scheduling restart of crashed service com.android.printspooler/.model.PrintSpoolerService in 1000ms
09-05 20:06:07.188 1005-1237/? W/AppOps: Finishing op nesting under-run: uid 1000 pkg android code 24 time=1462541465446 duration=2311 nesting=0
09-05 20:06:08.024 1005-1185/? I/ActivityManager: Start proc 5263:com.android.printspooler/u0a159 for service com.android.printspooler/.model.PrintSpoolerService
09-05 20:06:09.953 391-3149/? D/audio_hw_primary: out_standby: enter: stream (0xb5bf7240) usecase(0: deep-buffer-playback)
Related
I'm using the AltBeacon library for detecting iBeacons in my Android app. The code I have works on the following devices:
Xiaomi MI9 (Android 10.0)
Motorola Moto G4 (Android 6.0.1)
Huawei P Smart (Android 8.0)
Samsung Galaxy S8 (Android 9.0)
However, the same code doesn't work for a OnePlus 6 (Android 10, OxygenOS 10.3.2). It doesn't detect any beacons in my app. I tried to detect the beacons using an other app (Locate), that works. The creator of the AltBeacon library told me that Locate uses the AltBeacon library, so the beacons are detectable. This means my code setup is wrong. Can you help me by finding out what is wrong with my setup?
I checked (e.g.) this answer, although it didn't fix my problem. I turned debugging on for the BeaconManager but nothing interesting came out of that (an example at the bottom of this question).
In the ViewModel I call the MyStateManager. It contains a List regionsInRange, which contains beacons that are in range. I left out some code because I think it is irrelevant. If you feel like I left out too much, I will add it.
public class MyStateManager implements BootstrapNotifier {
private static final MyStateManager instance = new MyStateManager();
private final MyBeaconHelper myBeaconHelper;
// ViewModel accessess this List to retrieve the beacons that are found.
public final List<Region> regionsInRange = new ArrayList<>();
private PresenceRegistrationStateManager() {
presenceRegistrationBeaconHelper = new PresenceRegistrationBeaconHelper(this);
updateScanningRegions();
}
#Override
public Context getApplicationContext() {
return MyApplication.getAppContext();
}
#Override
public void didEnterRegion(Region region) {
//Empty method
}
#Override
public void didExitRegion(Region region) {
//Empty method
}
#Override
public void didDetermineStateForRegion(int status, Region region) {
if (status == OUTSIDE) {
regionsInRange.remove(region);
} else {
if (!regionsInRange.contains(region)) {
regionsInRange.add(region);
}
}
updateState();
}
public static MyStateManager getInstance() {
return instance;
}
public void updateState() {
// Own implementation here
}
private void updateScanningRegions() {
// add all the regions here
}
}
In addition, this is the MyBeaconHelper:
public class MyBeaconHelper implements BeaconConsumer, Serializable {
private transient final RegionBootstrap regionBootstrap;
private List<Region> scanRegions = new ArrayList<>();
public MyBeaconHelper(BootstrapNotifier bootstrapNotifier) {
BeaconManager beaconManager = BeaconManager.getInstanceForApplication(getApplicationContext());
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
LogManager.setVerboseLoggingEnabled(true);
beaconManager.bind(this);
regionBootstrap = new RegionBootstrap(bootstrapNotifier, new ArrayList<>());
}
#Override
public void onBeaconServiceConnect() {
//Empty method
}
#Override
public Context getApplicationContext() {
return MyApplication.getAppContext();
}
#Override
public void unbindService(ServiceConnection serviceConnection) {
getApplicationContext().unbindService(serviceConnection);
}
#Override
public boolean bindService(Intent intent, ServiceConnection serviceConnection, int i) {
return getApplicationContext().bindService(intent, serviceConnection, i);
}
public void updateScanRegions(List<Region> newRegions) {
for (Region oldRegion : this.scanRegions) {
if (!newRegions.contains(oldRegion)) {
regionBootstrap.removeRegion(oldRegion);
}
}
for (Region newRegion : newRegions) {
if (!this.scanRegions.contains(newRegion)) {
regionBootstrap.addRegion(newRegion);
}
}
this.scanRegions = newRegions;
}
}
When I turned debugging on for the BeaconManager, it showed me this a lot of times:
2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: starting a new scan cycle
2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: We are already scanning and have been for 1134 millis
2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: Waiting to stop scan cycle for another 1100 milliseconds
2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: Scan started
2020-03-31 11:57:31.213 25259-25259/com.my.app D/CycledLeScanner: Waiting to stop scan cycle for another 69 milliseconds
2020-03-31 11:57:31.323 25259-25259/com.my.app D/CycledLeScanner: Done with scan cycle
It keeps printing these lines over and over again...
The log messages shown (these are for OnePlus, yes?) indicate that BLE scanning is started. Do you see any log lines showing hex bytes of the packets detected? If BLE scanning is actually functioning you should. You may want to compare the logs output by the other devices.
Are you certain proper location permission has been granted to your app on the OnePlus? You can check in Settings -> Apps - > You App -> Permissions. Also confirm Bluetooth is on and location is on for the global phone settings (but if Locate works on the same device, this should not be a problem .)
It is not clear if this is related, but the use of beaconManager.bind() at the same time as RegionBootstrap is unnecessary and may cause conflicts. The code appears to not use the BeaconConsumer interface that is called back by the bind method. I suggest you remove the bind call, the use of BeaconConsumer and remove all that interface's callback methods just to be sure.
I am trying to work with NSD and I find myself stuck at the very begining..
I set up a very basic layout with a single big button. This button's purpose is to start and register a service on my device so other devices would be able to connect to it through LAN. One press of the said button calls the folowing method in my only Activity :
public void startService(View view){
initSocket();
initRegList();
regService();
}
Following the DevBytes: Network Service Discovery video, I implemented the methods called above, like so (pardon my YOLO-ing for debugging purposes) :
public void initSocket(){
try {
mSocket = new ServerSocket(0);
} catch (IOException e) {
e.printStackTrace();
}
mPort = mSocket.getLocalPort();
Log.e("YOLO-PORT", String.valueOf(mPort));
}
public void regService(){
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setServiceName("MyCoolService");
serviceInfo.setServiceType("_myapp.tcp.");
serviceInfo.setPort(mPort);
mNsdman = (NsdManager) this.getSystemService(this.NSD_SERVICE);
mNsdman.registerService(serviceInfo,NsdManager.PROTOCOL_DNS_SD,mReglist);
}
public void initRegList() {
mReglist = new NsdManager.RegistrationListener() {
#Override
public void onRegistrationFailed(NsdServiceInfo nsdServiceInfo, int i) {
Log.e("YOLO-FAIL", "REG_FAIL, errcode = " + String.valueOf(i));
}
#Override
public void onUnregistrationFailed(NsdServiceInfo nsdServiceInfo, int i) {
Log.e("YOLO-FAIL", "UNREG_FAIL, errcode = " + String.valueOf(i));
}
#Override
public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {
mServName = nsdServiceInfo.getServiceName();
Log.e("YOLO-NAME", mServName);
}
#Override
public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) {
Log.e("YOLO-OK", "UNREG");
}
};
}
My problem is I keep falling into onUnregistrationFailed method of the listener with a return code = 0.
Below you will find Logcat entries apearing when I press the said button :
09-14 21:54:03.904 18672-18672/fr.lpnsk.lollibox E/YOLO-PORT﹕ 48321
09-14 21:54:04.124 180-531/? E/MDnsDS﹕ service register request 22 got an error from DNSServiceRegister -65540
09-14 21:54:04.125 538-607/? E/NsdService﹕ Failed to execute registerService com.android.server.NativeDaemonConnector$NativeDaemonArgumentException: command '76 mdnssd register 22 MyCoolService _myapp.tcp. 48321' failed with '501 76 serviceRegister request got an error from DNSServiceRegister'
09-14 21:54:04.126 180-531/? E/MDnsDS﹕ register stop used unknown requestId 22
09-14 21:54:04.126 538-607/? E/NsdService﹕ Failed to execute unregisterService com.android.server.NativeDaemonConnector$NativeDaemonArgumentException: command '77 mdnssd stop-register 22' failed with '501 77 Unknown requestId'
09-14 21:54:04.127 18672-19953/fr.lpnsk.lollibox E/YOLO-FAIL﹕ REG_FAIL, errcode = 0
Am I missing something obvious here ?
Thank you for your help !
Am I missing something obvious here?
Yes. You missed the underscore _ sign before tcp when setting the service type. It should be:
serviceInfo.setServiceType("_myapp._tcp.");
From the official documentation:
...the service type specifies which protocol and transport layer the application uses. The syntax is "_protocol._transportlayer".
I have an application uploaded to Google Play. The app is supposed to scan a QR-code from a pole to register a visit. It works on all devices but Sony XPERIA models. In Google Play Developer Console I get a lot of one particular crash:
java.lang.RuntimeException: autoFocus failed
at android.hardware.Camera.native_autoFocus(Native Method)
at android.hardware.Camera.autoFocus(Camera.java:975)
at me.dm7.barcodescanner.core.CameraPreview$1.run(CameraPreview.java:196)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:5225)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:741)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
The only place I call the camera is is here:
public class ScannerActivity extends Activity implements ZXingScannerView.ResultHandler {
private ZXingScannerView m_ScannerView;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
m_ScannerView = new ZXingScannerView(this);
setContentView(m_ScannerView);
}
#Override
public void onResume() {
super.onResume();
m_ScannerView.setResultHandler(ScannerActivity.this);
m_ScannerView.startCamera();
}
#Override
public void onPause() {
super.onPause();
m_ScannerView.stopCamera();
}
As far as I can tell, this is a bug in ZXing. You can implement a workaround by replacing ZXingSurfaceView:AutoFocus with an implementation that catches the exception. (You'll also have to replace a few other files if you go this route, or re-compile ZXing on your own). This doesn't resolve the root cause, though.
This bug was fixed in ZXing on July 29 2015, so updating to the latest version is probably easier.
public void AutoFocus()
{
if (camera != null)
{
if (!tokenSource.IsCancellationRequested)
{
global::Android.Util.Log.Debug("ZXING", "AutoFocus Requested");
try
{
camera.AutoFocus(this);
}
catch (RuntimeException ex)
{
Console.WriteLine("ZXING: Warning: Caught RuntimeException during AutoFocus.");
}
}
}
}
During the first implementation of the NSDManager using the examples and the tutorial on the developer page , the application successfully started the discovery and found the devices.
However now it seems to be broken...
When the program is started, after some initialization, the code enters the following method and successfully run:
public void discoverServices() {
Log.d(TAG, "Initializing discovery on NSD");
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
The log-message is received. After a good while (say approx 5 mins.) this is outputted from the program:
05-21 11:08:32.518: E/NsdCamera(12236): Discovery failed: Error code:0
05-21 11:08:32.518: W/dalvikvm(12236): threadid=12: thread exiting with uncaught exception (group=0x40c9c930)
05-21 11:08:32.518: E/AndroidRuntime(12236): FATAL EXCEPTION: NsdManager
05-21 11:08:32.518: E/AndroidRuntime(12236): java.lang.NullPointerException
05-21 11:08:32.518: E/AndroidRuntime(12236): at android.net.nsd.NsdManager$ServiceHandler.handleMessage(NsdManager.java:338)
05-21 11:08:32.518: E/AndroidRuntime(12236): at android.os.Handler.dispatchMessage(Handler.java:99)
05-21 11:08:32.518: E/AndroidRuntime(12236): at android.os.Looper.loop(Looper.java:137)
05-21 11:08:32.518: E/AndroidRuntime(12236): at android.os.HandlerThread.run(HandlerThread.java:60)
Also from the services:
05-21 11:50:49.108: E/NativeDaemonConnector.ResponseQueue(8858): Timeout waiting for response
05-21 11:50:49.108: E/mDnsConnector(8858): timed-out waiting for response to 10 mdnssd discover 6 _http._tcp.
05-21 11:50:49.108: E/NsdService(8858): Failed to discoverServices com.android.server.NativeDaemonConnector$NativeDaemonFailureException: command '10 mdnssd discover 6 _http._tcp.' failed with 'null'
Error code "0" is described in the NSDManager class as an internal error.
The major updates I did was the access to the context in the helper-class called NsdCamera.
Here is some probably evil code-snippets:
Helper-class constructor:
public NsdCamera(CameraChooseActivity context) {
mContext = context;
updateUI = new UpdateUI();
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
mServiceName = new Vector<NsdServiceInfo>();
Helper-class NSD initialization:
public void initializeNsd() {
initializeDiscoveryListener();
}
public void initializeDiscoveryListener() {
mDiscoveryListener = new NsdManager.DiscoveryListener() {
#Override
public void onDiscoveryStarted(String regType) {
Log.d(TAG, "Service discovery started");
}
/**
* A name check to see if the DNS discovery was correct. Checks if it contains
* AXIS and has the desired MAC address-space
* #param hostname ,the inputted hostname from the discovery cycle
* #return true if it's an Axis camera.
*/
public boolean nameCheck(String hostname){
return (hostname.contains("AXIS") && hostname.contains("00408C"));
}
#Override
public void onServiceFound(NsdServiceInfo service) {
Log.d(TAG, "Service discovery success: " + service.getServiceName());
if (!service.getServiceType().equals(SERVICE_TYPE)) {
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
} else if (nameCheck(service.getServiceName())){
mServiceName.add(service);
// updateUI.execute(new BundleUI(mContext,service, null));
}
}
#Override
public void onServiceLost(NsdServiceInfo service) {
Log.e(TAG, "service lost" + service);
if(mServiceName.remove(service)){
//TODO
Log.e(TAG, "remove the view, service is lost");
}
}
#Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "Discovery stopped: " + serviceType);
//Necessary??
mServiceName.clear();
}
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}
CameraChooseActivity -> onCreate is calling the helper-class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camerachoose);
//Setup the animation for the text in the Relativelayout
mDescription = (TextSwitcher) findViewById(R.id.camera_add);
mDescription.setFactory(this);
mDescription.setInAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
mDescription.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
mDescription.setText(getText(R.string.camera_add));
//Building alert dialog
mBuilder = new AlertDialog.Builder(this,AlertDialog.THEME_HOLO_DARK);
mBuilder.setMessage(R.string.dialog_about).setTitle(R.string.action_about);
mBuilder.setIcon(android.R.drawable.ic_dialog_info);
mLayout = (RelativeLayout) findViewById(R.id.layout_camerachoose);
//Initialize the NSD
mNSDHelper = new NsdCamera(this);
mNSDHelper.initializeNsd();
Base on my experience, I suppose this is a listener lifetime issue.
Because you supply two listeners to the system NSD service, one is for startServiceDiscovery() and another for stopServiceDiscovery(). you need to make sure these listeners still alive when the system accesses these listeners.
One fact is that onStartDiscoveryFailed() is called 2 minutes after startServiceDiscovery() is called, it should be a long time compared to the lifetime of the listener.
So if the listener is a local object and is released after calling the startServiceDiscovery(), it maybe cause the NSD service to crash.
public void stopServiceDiscovery (NsdManager.DiscoveryListener
listener)
Stop service discovery initiated with discoverServices(). An active
service discovery is notified to the application with
onDiscoveryStarted(String) and it stays active until the application
invokes a stop service discovery. A successful stop is notified to
with a call to onDiscoveryStopped(String).
Upon failure to stop service discovery, application is notified
through onStopDiscoveryFailed(String, int).
Parameters listener This should be the listener object that was passed
to discoverServices(String, int, NsdManager.DiscoveryListener). It
identifies the discovery that should be stopped and notifies of a
successful stop.
and below snippet make sure do not call any NsdManager api.
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.i(TAG, "onStartDiscoveryFailed : Error code:" + errorCode);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.i(TAG, "onStopDiscoveryFailed : Error code:" + errorCode);
}
Good Luck.
A simple restart of the DUT proved to be the solution. Must say that the error is pretty odd.
I think the daemon crashed and didn't restart.
(If someone can post an analysis or have a much better solution, please post it)
I am currently trying to implement Google's LVL into my wallpaper but seem to have run into an issue with an exception I am not familiar with. I found this Question which helped me greatly, LVL licensing in a Live Wallpaper?. One of the suggestions is to place code within the Engine and I opted to place it in the Class above. The code seems to compile fine but on run time I get an exception, apparently for my Public Key.
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to create service <my package>.MyWallpaper: java.lang.IllegalArgumentException: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2076)
at android.app.ActivityThread.access$2500(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:993)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3835)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
at com.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:121)
at com.android.vending.licensing.LicenseChecker.<init>(LicenseChecker.java:92)
at com.metastable.epicvis.vis1.ScopeVisualizer.onCreate(ScopeVisualizer.java:41)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2066)
... 10 more
Caused by: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
at org.bouncycastle.jce.provider.JDKKeyFactory.engineGeneratePublic(JDKKeyFactory.java:92)
at org.bouncycastle.jce.provider.JDKKeyFactory$RSA.engineGeneratePublic(JDKKeyFactory.java:396)
at java.security.KeyFactory.generatePublic(KeyFactory.java:177)
at com.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:112)
... 13 more
Here is the code that I use:
public class MyWallpaper extends WallpaperService implements LicenseCheckerCallback {
private LicenseChecker mChecker;
private static final String BASE64_PUBLIC_KEY = "My public key from google";
private byte[] salt = new byte[] {<20 random int>};
private String deviceId;
private AESObfuscator aes;
#Override
public void onCreate() {
super.onCreate();
deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
aes = new AESObfuscator(salt, getPackageName(), deviceId);
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, aes), BASE64_PUBLIC_KEY);
mChecker.checkAccess(this);
}
#Override
public void onDestroy() {
super.onDestroy();
mChecker.onDestroy();
}
#Override
public Engine onCreateEngine() {
return new VisualizerEngine();
}
class MyEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener {
<Unrelevant code removed>
}
#Override
public void allow() {
Toast.makeText(this, "Allowed", Toast.LENGTH_SHORT);
}
#Override
public void dontAllow() {
Toast.makeText(this, "Not Allowed", Toast.LENGTH_SHORT);
}
#Override
public void applicationError(ApplicationErrorCode errorCode) {
// TODO Auto-generated method stub
}
}
Is there a certain way I should format my public key or is it something entirely different?
The exception comes from : mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, aes), BASE64_PUBLIC_KEY);
Any advice would be greatly appreciated.
I have since figured out the issue, apparently I'm terrible and copy and pasting. In stead of click dragging and selecting my key, which I did many times and continued to fail, I simply triple clicked and it copied properly. Heh.