One of my Android projects needs to switch between 2 HDMI inputs from time to time, possibly once a minute. One HDMI input is from an android device's HDMI output and one is from an external, uncontrollable source.
I found an HDMI switch that automatically switches between 2 sources when the signal becomes available.
My question is, is there a way to temporarily (one minute for example) cut HDMI output of my Android device so that the switch can automatically use the second HDMI input? Then, I need to restore the HDMI output so that the switch will show my device's HDMI output.
I found this question but I am not sure I need to disable HDMI output but rather redirect the display in some way and restore it back after 1 minute.
UPDATE
I want to start a bounty so I will clarify my request a bit: I have an HDMI-enabled TV with 2 ports. My android device is connected on port 1, another device is connected on port 2. The TV automatically switches to the next HDMI port that has signal.
For example, if HDMI1 and HDMI2 have signals, I put my TV on HDMI1. When the first device "closes" its HDMI output, the TV will switch to HDMI2. After a while (5 minutes) the first devices "re-opens" HDMI1 (meaning the first device enables its HDMI output) and the second device "closes" its HDMI output so the TV will switch back to HDMI1. This way I can make a mix of videos.
The technical difficulty I am facing is how to control the HDMI output in Android systems. My Android device only has HDMI interface for displaying, it doesn't have a dedicated screen.
The only stuff close enough to what I need is this SO post, but it doesn't really help in my case.
The best approach is to use to use the set of commands related to DisplayID, that allows you to listen for displays to be added, changed or removed.
Here is a quick example how it goes to change your display/HDMI:
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
#Override
public void onDisplayAdded(int displayId) {
Log.d(TAG, "Display #" + displayId + " added.");
mDisplayListAdapter.updateContents();
}
#Override
public void onDisplayChanged(int displayId) {
Log.d(TAG, "Display #" + displayId + " changed.");
mDisplayListAdapter.updateContents();
}
#Override
public void onDisplayRemoved(int displayId) {
Log.d(TAG, "Display #" + displayId + " removed.");
mDisplayListAdapter.updateContents();
}
};
And here how to get all your HDMI/display devices available to connect:
protected void onResume() {
// Be sure to call the super class.
super.onResume();
// Update our list of displays on resume.
mDisplayListAdapter.updateContents();
// Restore presentations from before the activity was paused.
final int numDisplays = mDisplayListAdapter.getCount();
for (int i = 0; i < numDisplays; i++) {
final Display display = mDisplayListAdapter.getItem(i);
final PresentationContents contents =
mSavedPresentationContents.get(display.getDisplayId());
if (contents != null) {
showPresentation(display, contents);
}
}
mSavedPresentationContents.clear();
// Register to receive events from the display manager.
mDisplayManager.registerDisplayListener(mDisplayListener, null);
}
To unregister you use:
//unregisterDisplayListener(DisplayManager.DisplayListener);
#Override
protected void onPause() {
// Be sure to call the super class.
super.onPause();
// Unregister from the display manager.
mDisplayManager.unregisterDisplayListener(mDisplayListener);
// Dismiss all of our presentations but remember their contents.
Log.d(TAG, "Activity is being paused. Dismissing all active presentation.");
for (int i = 0; i < mActivePresentations.size(); i++) {
DemoPresentation presentation = mActivePresentations.valueAt(i);
int displayId = mActivePresentations.keyAt(i);
mSavedPresentationContents.put(displayId, presentation.mContents);
presentation.dismiss();
}
mActivePresentations.clear();
}
About "invalidate" HDMI output, if it eventually occurs, just redraw it. This should solve any "invalidate", in case it happens.
You might find useful to check further documentation.
Related
I'm using the Brother Print SDK for Android. My code is based on the example code as shown in the manual:
void printTemplate(int templateKey, String newText) {
// Specify Printer
final Printer printer = new Printer();
PrinterInfo settings = printer.getPrinterInfo();
settings.printerModel = Model.QL_1110NWB;
settings.ipAddress = "your-printer-ip";
// Connect, then print
new Thread(new Runnable() {
#Override
public void run() {
if (printer.startCommunication()) {
// Specify the template key and the printer encode
if (startPTTPrint(templateKey, null)) {
// Replace text object with new text
replaceText(newText);
// Start print
PrinterStatus result = printer.flushPTTPrint();
if (result.errorCode != ErrorCode.ERROR_NONE) {
Log.d("TAG", "ERROR - " + result.errorCode);
}
}
printer.endCommunication();
}
}
}).start();
}
When the printer has its cover open, the flushPTTPrint() function does immediately return with a status of ERROR_COVER_OPEN. That is great.
When the printer is out of paper, the flushPTTPrint() function only returns after about three minutes with a status of ERROR_COMMUNICATION_ERROR. Not so great.
QUESTION: how can I detect when the printer is out of paper? Any method would be fine, either be getting flushPTTPrint() to return immediately with a out of paper staus or by querying the printer actively beforehand.
EDIT (in response to Matt Clark's suggestion)
One can set a handler to process status messages from the printer. On a regular printout (and also on the last printout before the paper is empty) the following messages arrive in this order:
MESSAGE_START_COMMUNICATION
MESSAGE_START_CONNECT
MESSAGE_END_CONNECTED
MESSAGE_START_SEND_STATUS_REQUEST
MESSAGE_END_READ_PRINTER_STATUS
MESSAGE_START_SEND_DATA
MESSAGE_END_SEND_DATA
When the last paper was used, the printer immediately turns a red led on and shows on its display the out of paper notice. When trying to print in this situation, the following messages arrive:
MESSAGE_START_COMMUNICATION
MESSAGE_START_CONNECT
MESSAGE_END_CONNECTED
MESSAGE_START_SEND_STATUS_REQUEST
...about three minutes later...
MESSAGE_START_SOCKET_CLOSE
MESSAGE_END_SOCKET_CLOSE
The out of paper message (MESSAGE_PAPER_EMPTY) is never seen.
EDIT 2
I just figured out that this problem only happens when connecting via Bluetooth. When using WiFi the above mentioned function immediately returns with an error code ERROR_PAPER_EMPTY.
Perhaps try calling printer.getPrinterStatus() before attempting to print?
Reading the documentation, it appears as if the printer is capable of sending asynchronous messages back to your application. This might be useful to catch a variety of things, including determining when the printing is actually complete.
From the documentation:
Section 4.1.2.3 shows a method which you can use to register a callback for these messages received:
void setMessageHandle(Handler handler, int MsgType)
Section 4.2.2.13 has a list of all the message types available, one of them being:
MESSAGE_PAPER_EMPTY
I imagine you would get this message as soon as the printer detects the out of paper state.
I write an app which uses three hardware USB-devices.
When I operate with any single device - both events (USB_DEVICE_ATTACHED/USB_DEVICE_DETACHED) fires normally. Not matter how I bind the Receiver - under the manual registration in the code or in the manifest. And not matter how this single device attached - under the HUB or directly to the device.
The problem is: when I connect three device all in one time (by connecting the filled HUB), USB_DEVICE_ATTACHED event fired for all three devices - I receive notification via onNewIntent callback (or standalone Receiver binded via manifest), and do the permission-approve trip.
But on physical removal all devices behind the HUB (by detaching the HUB itself) DETACH event fires not on all devices. It may fired on random single device, or random two devices. But never on all three devices.
As result, for the time UsbManager holds a lot of dead dev-handles of not physically connected devices. At the same time, when I look into /dev/usb/ folder in connecion/disconnection time, device-files appears and removes correctly. As next result, when app is restarted by the some reason, I can not recognize which device is dead and which device is physically present.
The device is ASUS P1801 tablet, OS 4.2.1
As I can see, it is the last firmware from asus (JOP40D.US_epad-10.6.1.22.5-20130715)
For caching purposes, handles of the wrapped-device I pin to the Application singleton (when device appears with the USB_DEVICE_ATTACHED event or app initialisation):
public class HWMountReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Application.getAppContext().isAppReady() && (Application.getAppContext() != null) && (Application.getAppContext().getUsbHWManager() != null)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
Application.getAppContext().getUsbHWManager().refreshDevice(device);
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(Application.getAppContext(), 0, new Intent(Application.MED_ONLINE_DEVICE_PERMISSION), 0);
((UsbManager) Application.getAppContext().getSystemService(Context.USB_SERVICE)).requestPermission(device, mPermissionIntent);
}
}
}
The singleton:
private static FirstDevice firstDevice;
private static SecondDevice secondDevice;
private static ThirdDevice thirdDevice;
public void refreshDevice(UsbDevice device) {
HWDevice dev = HWDevicesFactory.newInstance(device);
if (dev instanceof FirstDevice) {
firstDevice = (FirstDevice) dev;
} else if (dev instanceof SecondDevice) {
secondDevice = (SecondDevice) dev;
} else if (dev instanceof ThirdDevice) {
thirdDevice = (ThirdDevice) dev;
}
}
Factory do reInstantination of each device-wrapper:
public static HWDevice newInstance(final UsbDevice device) {
int vendorId = device.getVendorId();
int productId = device.getProductId();
if ((vendorId == FIRST_VENDOR_ID) && (productId == FIRST_PRODUCT_ID)) {
return new FirstDevice(device);
...
Device-Wrapper more specific, because each one is very different. But typicaly it contain cached handles on UsbInterface, UsbDeviceConnection, UsbEndpoints and finally UsbDevice itself.
The main thing - DETACH not fired on random device. Not matter how it was "wrapped" by mine
Is there a probably bug in the ASUS firmware,
-or-
I miss some necessary steps/checks with the device connection
-or-
?
As in the title I've been able to connect to Google Game Services, exchange data between two devices and everything is running fine, except one thing: disconnection callbacks.
I tried to intercept both onPeersDisconnected and onP2PDisconnected without any success. The onP2PDisconnected method is being called in the device that get disconnected from Internet but not into device that is still online (so there is no way to tell the player that the other one got disconnected).
After the match is started it seems that the second device is never notified of the accidental disconnection. If the user close the game properly the onPeersLeft method is being called thought.
Is a ping between the two devices really necessary to overcome this "bug"? Am I doing something wrong?
Here is the code I use:
void startQuickGame() {
// quick-start a game with 1 randomly selected opponent
final int MIN_OPPONENTS = 1, MAX_OPPONENTS = 1;
Bundle autoMatchCriteria = RoomConfig.createAutoMatchCriteria(MIN_OPPONENTS,
MAX_OPPONENTS, 0);
RoomConfig.Builder rtmConfigBuilder = RoomConfig.builder(this);
rtmConfigBuilder.setMessageReceivedListener(this);
rtmConfigBuilder.setRoomStatusUpdateListener(this);
rtmConfigBuilder.setAutoMatchCriteria(autoMatchCriteria);
mListener.switchToScreen(R.id.screen_wait);
keepScreenOn();
resetGameVars();
getGamesClient().createRoom(rtmConfigBuilder.build());
}
And here the simple listeners:
#Override
public void onPeersDisconnected(Room room, List<String> peers) {
Log.d(TAG, "onPeersDisconnected");
updateRoom(room);
}
void updateRoom(Room room) {
Log.d(TAG, "UpdateRoom: "+room.getParticipants().size());
mParticipants = room.getParticipants();
}
#Override
public void onP2PDisconnected(String participantId) {
Log.d(TAG, "onP2PDisconnected");
}
public int getPartecipantsInRooom(){
if(mRoom != null)
return mRoom.getParticipants().size();
else
return -123456;
}
Note that calling getPartecipantsInRooom() after one of the two devices disconnects always return 2, and updateRoom never get called.
Just to be sure this might not work for you, for my applications I use this to let me know when another Participant has left the Room, and it is called immediately :
#Override
public void onPeerLeft(Room room, final List<String> participantIds) {
this.mRoomCurrent = room;
this.mRoomId = this.mRoomCurrent.getRoomId();
this.mParticipants = this.mRoomCurrent.getParticipants();
int connected = 0;
for (Participant p : room.getParticipants()) {
if(p.getStatus() == Participant.STATUS_JOINED) {
connected += 1;
}
}
final int fconnected = connected;
for (String s : listIgnoreTheseIDs) {
//checkint to see if we care anymore about this ID.. if out of game already.. nope
if(s.equals(participantIds.get(0))){
return;
}
}
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
mGHInterface.onPeerLeft(fconnected, participantIds.size());
}
});
}
No idea why there are two items, but like you, I realized the onPeersDisconnected() isn't that reliable, but onPeerLeft() normally gets back to the other devices in under 1 second.
onPeerDisconnected() handles disconnects. So if somebody is still in the application but the network connection is lost, this is called for him.
onPeerLeft() handles participants who leave a room. This is called when somebody explizit leaves the room in the application or the application is minimized, and the room is left on the androids onStop() or onDestroy() callback.
I'm making two player game. So I use this approach
#Override
public void onPeerLeft(Room room, List<String> peersWhoLeft) {
updateRoom(room);
Toast.makeText(MyLauncherActivity.this, "Other player left the game", Toast.LENGTH_LONG).show();
quitGame();
}
How to pair a Bluetooth Low Energy(BLE) device with Android to read encrypted data.
Using the information in the Android BLE page, I am able to discover the device, connect to it, discover services and read un-encrypted characteristics.
When I try to read an encrypted characteristic (one that will cause iOS to show a popup asking to pair and then complete the read) I am getting an error code 5, which corresponds to Insufficient Authentication.
I am not sure how to get the device paired or how to provide the authentication information for the read to complete.
I toyed with BluetoothGattCharacteristics by trying to add descriptors, but that did not work either.
Any help is appreciated!
When you get the GATT_INSUFFICIENT_AUTHENTICATION error, the system starts the bonding process for you. In the example below I'm trying to enable notifications and indications on glucose monitor. First I'm enabling the notifications on Glucose Measurement characteristic which can cause the error to appear.
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (GM_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementNotificationEnabled();
if (mGlucoseMeasurementContextCharacteristic != null) {
enableGlucoseMeasurementContextNotification(gatt);
} else {
enableRecordAccessControlPointIndication(gatt);
}
}
if (GM_CONTEXT_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementContextNotificationEnabled();
enableRecordAccessControlPointIndication(gatt);
}
if (RACP_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onRecordAccessControlPointIndicationsEnabled();
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
// this is where the tricky part comes
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
mCallbacks.onBondingRequired();
// I'm starting the Broadcast Receiver that will listen for bonding process changes
final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mContext.registerReceiver(mBondingBroadcastReceiver, filter);
} else {
// this situation happens when you try to connect for the second time to already bonded device
// it should never happen, in my opinion
Logger.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");
// I don't know what to do here
// This error was found on Nexus 7 with KRT16S build of Andorid 4.4. It does not appear on Samsung S4 with Andorid 4.3.
}
} else {
mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status);
}
};
Where the mBondingBroadcastReceiver is:
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
Logger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState);
// skip other devices
if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
return;
if (bondState == BluetoothDevice.BOND_BONDED) {
// Continue to do what you've started before
enableGlucoseMeasurementNotification(mBluetoothGatt);
mContext.unregisterReceiver(this);
mCallbacks.onBonded();
}
}
};
Remember to unregister the broadcast receiver when exiting the activity. It may have not been unregistered by the receicver itself.
You might need to check the Kernel smp.c file, which method of paring it invoke for paring. 1) passkey 2)Just work or etc . i guess if it will be able to invoke MIMT and passkey level of security , there will not be any authentication issue. Make sure all flags is set to invoke the SMP passkey methods. track by putting some print in smp.c file.
A solution which works in ICS : with btmgmt tool in android and hooking it in encryption APIs. with passkey or any other methods. it works. You might need to add the passkey APIs in btmgmt from latest bluez code.
i think new android 4.4 provide pairing method. same problem already i am facing so wait for update and hope over problem solved createBond() method .
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#setPairingConfirmation%28boolean%29
With Google Play Game Services, I'm trying to implement a CallBack such that, if there is an issue with sending a message, then I need to resolve it (as each player "passes" their bid to the next player, and all other players need to see what the player that passed bid)
I thought I would try and use the following to instantiate a RealTimeReliableMessageSentListener for that round of messages, so that I can tell if the message was sent and received by everyone:
(I add the tokenID returned by the call to an ArrayList, and then check off remove each tokenID as it comes back in to track when all messages from this round are received)
#Override
public void sendReadyToPlay() {
dLog("Sending ReadyToPlay");
// Broadcast that I'm ready, and see that they are ready
if (!mMultiplayer){
return; // playing against computer
}
// First byte in message indicates whether it's a final score or not
mMsgBuf[0] = (byte) ('R');
readyToPlayTokens.clear();
// Send to every other participant.
for (Participant p : mParticipants) {
dLog("Participant:" + p.getParticipantId());
if (p.getParticipantId().equals(mMyId)) {
continue;}
if (p.getStatus() != Participant.STATUS_JOINED){
continue;
}
readyToPlayTokens.add(mHelper.getGamesClient().sendReliableRealTimeMessage(new RealTimeReliableMessageSentListener() {
#Override
public void onRealTimeMessageSent(int statusCode, int tokenId, String recipientParticipantId){
dLog("onRealTimeMessageSent number two and size is: " + readyToPlayTokens.size());
if(readyToPlayTokens.contains(tokenId)){
readyToPlayTokens.remove(tokenId);
}
dLog("onRealTimeMessageSent number two and size is: " + readyToPlayTokens.size());
if (statusCode != GamesClient.STATUS_OK) {
mGHInterface.onRealTimeMessageReceived("RTPProblem:" + recipientParticipantId);
} else if (readyToPlayTokens.size() == 0) {
mGHInterface.beginRound();
}
}
}, mMsgBuf, mRoomId, p.getParticipantId()));
dLog("sent to:" + p.getParticipantId());
}
}
I can see the messages coming in almost every time from one device to another, so I can see that the messages are going through, BUT, the RealTimeReliableMessageSent listener is only being fired about 50-60 percent of the time, which isn't very reliable! :)
Can anyone see what I might be doing wrong to keep the listener from firing reliably?
may be it happens because you are using anonymous inner class, try to use in different way like implementing your activity RealTimeReliableMessageSentListener